Documentation
¶
Index ¶
- Constants
- func BuildDigestFeeds(digests []models.Digest, outputDir, baseURL string) (rss, atom []byte, err error)
- func DigestHTMLFilename(digest models.Digest) string
- func RenderDigestHTML(digest models.Digest, theme string) ([]byte, error)
- func RenderDigestIndex(theme string) ([]byte, error)
- func RenderSwipeHTML(digest models.Digest, digestFilename string, theme string) ([]byte, error)
- func SampleDigest(id string, createdAt time.Time) models.Digest
- func SendDiscordMessage(webhookURL, content string) error
- func SetTemplateDir(dir string)
- func SwipeHTMLFilename(digest models.Digest) string
- type ArticleEntry
- type DigestLister
- type DiscordEmbed
- type DiscordEmbedField
- type DiscordEmbedFooter
- type DiscordEmbedImage
- type DiscordNotifier
- type DiscordWebhookPayload
- type GitHubPagesPublisher
- func (p *GitHubPagesPublisher) InitPages(reinit bool) error
- func (p *GitHubPagesPublisher) ManifestTitles() ([]string, error)
- func (p *GitHubPagesPublisher) RemoveDigest(title string) (string, error)
- func (p *GitHubPagesPublisher) Republish(digest models.Digest, wait bool) error
- func (p *GitHubPagesPublisher) RepublishAll(digests []models.Digest, theme string, dryRun, wait bool) error
- func (p *GitHubPagesPublisher) RepublishIndex(dryRun, wait bool) error
- func (p *GitHubPagesPublisher) SendDigest(digest models.Digest) error
- func (p *GitHubPagesPublisher) SetDigestLister(fn DigestLister)
- func (p *GitHubPagesPublisher) SetProgress(pr PublishProgress)
- func (p *GitHubPagesPublisher) WaitForPagesBuild(commitSHA string) error
- type Manifest
- type ManifestEntry
- type Notifier
- type OverviewSection
- type PublishProgress
- type RenderedAnalysis
- type RenderedGlossaryTerm
- type RenderedReport
- type TOCEntry
- type TOCGroup
- type TOCRow
- type TagCount
Constants ¶
const ( RSSFilename = "rss.xml" AtomFilename = "atom.xml" )
RSSFilename and AtomFilename are the basenames of the subscription feeds written at the root of the Pages branch on every push.
const FeedDigestLimit = 7
FeedDigestLimit caps how many recent digests appear in the RSS/Atom feeds.
const ManifestFilename = "manifest.json"
ManifestFilename is the basename of the manifest checked into the Pages branch.
Variables ¶
This section is empty.
Functions ¶
func BuildDigestFeeds ¶ added in v0.2.0
func BuildDigestFeeds(digests []models.Digest, outputDir, baseURL string) (rss, atom []byte, err error)
BuildDigestFeeds renders RSS and Atom feeds for the given digests (expected newest-first). Each digest becomes one feed entry whose HTML body lists, for every article in the digest, its TLDR and key points. Links point at the published digest HTML page under baseURL/outputDir; when baseURL is empty the links are relative to the site root.
func DigestHTMLFilename ¶
DigestHTMLFilename returns a filesystem-safe filename for the digest HTML file.
func RenderDigestHTML ¶
RenderDigestHTML generates a self-contained HTML file for the given digest. The digest must have Articles, DigestAnalyses (with Analysis preloaded), and ProviderResults populated. theme selects the visual style; an empty string or "dark" uses the default dark theme.
The provider/model switcher in the rendered page is populated client-side from manifest.json - the page itself only embeds the digest id and a hash of its article set used to filter siblings.
func RenderDigestIndex ¶
RenderDigestIndex generates the index HTML shell. The digest list is populated client-side by fetching manifest.json, so the rendered bytes are constant for a given template.
func RenderSwipeHTML ¶
RenderSwipeHTML generates the self-contained Tinder-style triage page for a digest. digestFilename is the filename of the companion list-view page (used for the back link).
func SampleDigest ¶ added in v0.2.0
SampleDigest builds a small, fully-populated digest fixture for rendering without a database. It backs both the test suite and the digest dev server.
article-b scores 95 (Must Read) with full analysis and a referenced report; article-a scores 80 (Should Read) with minimal analysis.
func SendDiscordMessage ¶
SendDiscordMessage posts a plain-text message to a Discord webhook URL. Intended for lightweight one-line notifications (e.g. "new page published").
func SetTemplateDir ¶ added in v0.2.0
func SetTemplateDir(dir string)
SetTemplateDir switches template loading to read from dir on disk. Pass an empty string to fall back to the embedded templates. Intended for the dev preview server.
func SwipeHTMLFilename ¶
SwipeHTMLFilename returns the filename for the swipe triage view of a digest.
Types ¶
type ArticleEntry ¶
type ArticleEntry struct {
Id string
Title string
Source string
Link string
PublishedAt string
Category string // article category (one of the fixed set), empty if unset
Tags []string // entity tags (actors/tools/techniques/country/stakeholders), without '#'
ImportanceScore int
ReadTag string
DuplicateGroup string
IsMostComprehensive bool
HasAnalysis bool
AnalysisError string // non-empty when HasAnalysis is false and a classified error is available
Analysis *RenderedAnalysis
}
ArticleEntry holds enriched article data for template rendering
type DigestLister ¶ added in v0.2.0
DigestLister returns up to limit newest digests with full payload (provider results + analyses). It lets the publisher build the RSS/Atom feeds without depending on the store: callers that have DB or client access supply it via SetDigestLister. A nil lister disables feed generation.
type DiscordEmbed ¶
type DiscordEmbed struct {
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Color int `json:"color,omitempty"`
Fields []DiscordEmbedField `json:"fields,omitempty"`
Timestamp string `json:"timestamp,omitempty"`
Image *DiscordEmbedImage `json:"image,omitempty"`
}
DiscordEmbed represents a Discord embed
type DiscordEmbedField ¶
type DiscordEmbedField struct {
Name string `json:"name"`
Value string `json:"value"`
Inline bool `json:"inline,omitempty"`
}
DiscordEmbedField represents a field in a Discord embed
type DiscordEmbedFooter ¶
type DiscordEmbedFooter struct {
}
DiscordEmbedFooter represents a footer in a Discord embed
type DiscordEmbedImage ¶
type DiscordEmbedImage struct {
URL string `json:"url"`
}
DiscordEmbedImage represents an image in a Discord embed
type DiscordNotifier ¶
type DiscordNotifier struct {
// contains filtered or unexported fields
}
DiscordNotifier implements the Notifier interface for Discord webhooks
func NewDiscordNotifier ¶
func NewDiscordNotifier(webhookURL string) *DiscordNotifier
NewDiscordNotifier creates a new Discord notifier
func (*DiscordNotifier) SendDigest ¶
func (d *DiscordNotifier) SendDigest(digest models.Digest) error
SendDigest sends a digest to Discord
func (*DiscordNotifier) SendHTMLFile ¶
func (d *DiscordNotifier) SendHTMLFile(filename string, data []byte) error
SendHTMLFile uploads a digest HTML file to the Discord webhook as an attachment.
type DiscordWebhookPayload ¶
type DiscordWebhookPayload struct {
Content string `json:"content,omitempty"`
Embeds []DiscordEmbed `json:"embeds,omitempty"`
}
DiscordWebhookPayload represents the Discord webhook message structure
type GitHubPagesPublisher ¶
type GitHubPagesPublisher struct {
// contains filtered or unexported fields
}
GitHubPagesPublisher publishes digest HTML files to a GitHub Pages repository.
Each publish writes the new digest HTML and updates a manifest.json that lists every published digest. Both the per-digest switcher and the index page are static shells that read manifest.json in the browser, so old HTML files are never rewritten on subsequent publishes.
func NewGitHubPagesPublisher ¶
func NewGitHubPagesPublisher(cfg models.GitHubPagesNotificationConfig) *GitHubPagesPublisher
NewGitHubPagesPublisher creates a new GitHubPagesPublisher.
func (*GitHubPagesPublisher) InitPages ¶
func (p *GitHubPagesPublisher) InitPages(reinit bool) error
InitPages sets up (or re-initialises) the GitHub Pages repository.
It creates the remote branch as a clean orphan if it is absent, optionally configures the GitHub Pages source via the API (when configure_pages is true), clones the branch locally, and seeds the initial static files (manifest.json and index pages). Files that already exist are not overwritten; the operation is idempotent.
When reinit is true the remote branch and the local clone directory are deleted before re-creating them from scratch.
func (*GitHubPagesPublisher) ManifestTitles ¶
func (p *GitHubPagesPublisher) ManifestTitles() ([]string, error)
ManifestTitles clones (or updates) the repo and returns the list of digest titles from the manifest, newest-first. Returns an empty slice when the manifest has no entries.
func (*GitHubPagesPublisher) RemoveDigest ¶
func (p *GitHubPagesPublisher) RemoveDigest(title string) (string, error)
RemoveDigest removes the digest identified by title from the archive. It resolves the title to a filename via the manifest, deletes both the digest and swipe HTML files, updates manifest.json, commits, and pushes. It returns the SHA of the pushed commit so callers can wait for the corresponding GitHub Pages build to deploy (see WaitForPagesBuild).
func (*GitHubPagesPublisher) Republish ¶ added in v0.2.0
func (p *GitHubPagesPublisher) Republish(digest models.Digest, wait bool) error
Republish removes a single digest from the archive and re-publishes it with the current templates (equivalent to remove followed by add). The removal is always awaited before the re-add is pushed: GitHub cancels an in-flight Pages build when a newer commit lands, so pushing the re-add immediately would skip deploying the removal. The final deploy is only awaited when wait is true.
func (*GitHubPagesPublisher) RepublishAll ¶
func (p *GitHubPagesPublisher) RepublishAll(digests []models.Digest, theme string, dryRun, wait bool) error
RepublishAll re-renders every digest with the current templates and pushes the result as a single commit. The manifest is rebuilt from scratch so stale entries are removed. Pass dryRun=true to render and stage locally without committing or pushing. When wait is true (and not a dry run) it blocks until the resulting GitHub Pages build deploys.
func (*GitHubPagesPublisher) RepublishIndex ¶
func (p *GitHubPagesPublisher) RepublishIndex(dryRun, wait bool) error
RepublishIndex re-renders the archive index pages with the current templates and pushes the result as a single commit. The manifest and digest HTML files are not touched. Pass dryRun=true to write locally without committing. When wait is true (and not a dry run) it blocks until the resulting GitHub Pages build deploys.
func (*GitHubPagesPublisher) SendDigest ¶
func (p *GitHubPagesPublisher) SendDigest(digest models.Digest) error
SendDigest renders the digest HTML, updates manifest.json, and pushes the result to the GitHub Pages repo. Old digest pages are not touched.
func (*GitHubPagesPublisher) SetDigestLister ¶ added in v0.2.0
func (p *GitHubPagesPublisher) SetDigestLister(fn DigestLister)
SetDigestLister attaches the lister used to fetch recent digests when building the RSS/Atom feeds on each push. Passing nil disables feed generation.
func (*GitHubPagesPublisher) SetProgress ¶ added in v0.2.0
func (p *GitHubPagesPublisher) SetProgress(pr PublishProgress)
SetProgress attaches a PublishProgress sink so callers can render live step progress for publish/republish operations. Passing nil disables reporting.
func (*GitHubPagesPublisher) WaitForPagesBuild ¶
func (p *GitHubPagesPublisher) WaitForPagesBuild(commitSHA string) error
WaitForPagesBuild blocks until the GitHub Pages build for commitSHA has finished deploying. It is a thin wrapper over waitForDeploy that does not emit step progress; kept for callers that only need the sequencing behaviour.
type Manifest ¶
type Manifest struct {
GeneratedAt string `json:"generated_at"`
SourceRepo string `json:"source_repo"`
Digests []ManifestEntry `json:"digests"`
}
Manifest is the JSON document checked into the Pages branch listing every published digest. The digest index reads it directly in the browser.
func LoadManifest ¶
LoadManifest reads the manifest at path. When the file is missing, it returns an empty manifest in the current schema.
func (*Manifest) FindByTitle ¶
func (m *Manifest) FindByTitle(title string) (ManifestEntry, bool)
FindByTitle returns the first entry whose Title matches title (case-insensitive). The second return value is false when no match is found.
func (*Manifest) Remove ¶
Remove removes the entry with the given filename from the manifest. Returns true if an entry was found and removed.
func (*Manifest) Upsert ¶
func (m *Manifest) Upsert(entry ManifestEntry)
Upsert inserts entry or replaces an existing entry with the same filename, then re-sorts newest-first by filename timestamp.
type ManifestEntry ¶
type ManifestEntry struct {
Filename string `json:"filename"`
StartedAt string `json:"started_at"`
PeriodStart string `json:"period_start,omitempty"`
TimeWindow string `json:"time_window"`
ArticleCount int `json:"article_count"`
MustCount int `json:"must_count"`
ShouldCount int `json:"should_count"`
MayCount int `json:"may_count"`
OptCount int `json:"opt_count"`
Provider string `json:"provider"`
Model string `json:"model"`
Models []string `json:"models,omitempty"` // all unique model names across summary + article analysis
Title string `json:"title,omitempty"`
Headlines []string `json:"headlines"`
HeadlinePriorities []string `json:"headline_priorities,omitempty"`
Summary string `json:"summary"`
}
ManifestEntry describes a single published digest in the manifest.
func ManifestEntryFromDigest ¶
func ManifestEntryFromDigest(d models.Digest) ManifestEntry
ManifestEntryFromDigest builds a ManifestEntry for the given digest using the archive-index manifest schema.
type OverviewSection ¶
type OverviewSection struct {
Tag string // e.g. "EXEC", "01", "02"
Title string // section heading
Body template.HTML // rendered markdown body
}
OverviewSection is a single cell in the Intelligence Brief 2-column grid.
type PublishProgress ¶ added in v0.2.0
type PublishProgress interface {
Start(step, label string) // begin a step (spinner row)
Update(step, label string) // relabel an in-flight step
Complete(step string, ok bool, note string) // finish a step (✓ / ✗)
}
PublishProgress receives coarse step updates during publish/republish so a CLI front-end can render live progress. A nil PublishProgress disables reporting (used by the automatic server publish path).
type RenderedAnalysis ¶
type RenderedAnalysis struct {
ProviderType string
ModelName string
Tldr template.HTML
Justification template.HTML
BriefOverview template.HTML
StandardSynthesis template.HTML
ComprehensiveSynthesis template.HTML
KeyPoints []template.HTML
Insights []template.HTML
ReferencedReports []RenderedReport
GlossaryExplanation template.HTML
GlossaryTerms []RenderedGlossaryTerm
}
RenderedAnalysis holds markdown-converted HTML versions of analysis text fields. Text fields are template.HTML because matched entity tags are wrapped in <mark class="tag-hl"> at build time (see highlight* helpers).
type RenderedGlossaryTerm ¶ added in v0.3.0
RenderedGlossaryTerm is a glossary-mode jargon term prepared for the template, with its definition tag-highlighted.
type RenderedReport ¶
type RenderedReport struct {
Title string
URL string
Publisher string
Category string
Primary bool
Context template.HTML
}
RenderedReport is a referenced report prepared for the digest template, with its context prose tag-highlighted.
type TOCEntry ¶
type TOCEntry struct {
Id string
Title string
Category string // article category (one of the fixed set), empty if unset
ImportanceScore int
ScoreTip string // rubric dimension breakdown shown on hover, empty if no dimensions
ReadTag string
DuplicateGroup string
IsMostComprehensive bool
}
TOCEntry holds data for a single article row in the table of contents.
type TOCRow ¶
type TOCRow struct {
IsCluster bool
Entry TOCEntry // used when IsCluster == false
Canonical TOCEntry // used when IsCluster == true: the most-comprehensive article
Others []TOCEntry // used when IsCluster == true: remaining members
Group string // duplicate group key, used for colour
Detail *ArticleEntry // full detail for non-cluster row
CanonDetail *ArticleEntry // full detail for cluster canonical
OtherDetails []*ArticleEntry // full detail for each cluster member
}
TOCRow is a single rendered row in a TOC group: either a plain article entry or a duplicate cluster (one canonical article + its alternates in a <details> block).