notification

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2026 License: MIT Imports: 35 Imported by: 0

Documentation

Index

Constants

View Source
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.

View Source
const FeedDigestLimit = 7

FeedDigestLimit caps how many recent digests appear in the RSS/Atom feeds.

View Source
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

func DigestHTMLFilename(digest models.Digest) string

DigestHTMLFilename returns a filesystem-safe filename for the digest HTML file.

func RenderDigestHTML

func RenderDigestHTML(digest models.Digest, theme string) ([]byte, error)

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

func RenderDigestIndex(theme string) ([]byte, error)

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

func RenderSwipeHTML(digest models.Digest, digestFilename string, theme string) ([]byte, error)

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

func SampleDigest(id string, createdAt time.Time) models.Digest

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

func SendDiscordMessage(webhookURL, content string) error

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

func SwipeHTMLFilename(digest models.Digest) string

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

type DigestLister func(limit int) ([]models.Digest, error)

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"`
	Footer      *DiscordEmbedFooter `json:"footer,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 {
	Text string `json:"text"`
}

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

func LoadManifest(path string) (Manifest, error)

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

func (m *Manifest) Remove(filename string) bool

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.

func (Manifest) Write

func (m Manifest) Write(path string) error

Write atomically serializes the manifest to path.

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 Notifier

type Notifier interface {
	SendDigest(digest models.Digest) error
}

Notifier defines the interface for sending digests to notification platforms

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

type RenderedGlossaryTerm struct {
	Term       string
	Definition template.HTML
}

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 TOCGroup

type TOCGroup struct {
	Label string
	Rows  []TOCRow
}

TOCGroup is a labelled section 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).

type TagCount

type TagCount struct {
	Name  string
	Count int
}

TagCount is a tag and the number of TOC rows that carry it (matching the row-level tag filter), used to render per-tag match counts in the filter cloud.

Directories

Path Synopsis
Package devserver runs a local HTTP preview of the digest HTML templates with browser live-reload.
Package devserver runs a local HTTP preview of the digest HTML templates with browser live-reload.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL