/** * Research digest builder — aggregates in-window research runs into a * dual markdown+JSON artifact for the Telegram bot (sibling spec) to push. * * Clock discipline: `now`/`since` are injected ISO strings — never new Date() here. * Non-sensitive summary content only (titles/summaries; no raw body values). * * bober: collectRunsFromVault reads vault research notes (1:1 dated artifacts) * rather than hub Findings (content-deduped, historyless, path-less). * Swap if a dedicated digest store is ever introduced. */ /** One research run entry in a digest. */ export interface DigestRun { /** Job title — note frontmatter.title ("Research — "). */ title: string; /** Non-sensitive one-line summary derived from frontmatter.question/title only. */ topFinding: string; /** ISO — note frontmatter.generatedAt. */ generatedAt: string; /** Absolute note path — the source artifact link. */ source: string; } /** The full digest structure written to both .md and .json. */ export interface Digest { since: string; now: string; generatedAt: string; runs: DigestRun[]; } /** Injectable dependencies for buildDigest — keeps it testable without real vault. */ export interface DigestDeps { /** Injected collector — returns in-window runs. Fake in unit tests; real in CLI. */ collectRuns: (since: string, now: string) => Promise; /** * Absolute path to the digests directory. * e.g. /.bober/research/digests — injected; temp dir in tests. */ digestsDir: string; } /** * Render a Digest into a markdown string. * * PURE: no IO, no Date.now(), no side effects. * Mirrors src/hub/priority-md.ts: builds lines[] then joins with "\n". * * Empty-window rule (sc-5-3): when runs.length === 0, the body explicitly * states no new research was produced in the window. */ export declare function renderDigestMarkdown(digest: Digest): string; /** * Collect in-window research runs via deps.collectRuns, render both markdown * and JSON artifacts, write them to deps.digestsDir, and return the result. * * File naming: `now.slice(0, 10)` → YYYY-MM-DD (matches note-writer.ts:24). * JSON format: JSON.stringify(digest, null, 2) + "\n" (mirrors fleet/index.ts:69). * * Empty window: still writes both files with an explicit no-new-research body. * Never throws on empty collectRuns — caller receives both paths. */ export declare function buildDigest(since: string, now: string, deps: DigestDeps): Promise<{ digest: Digest; mdPath: string; jsonPath: string; }>; /** * Real collectRuns implementation: reads research vault notes under * /research/, filters by frontmatter.generatedAt ∈ [since, now], * and maps each matching note to a DigestRun. * * Source selection: vault notes are 1:1 dated run artifacts (runner.ts:186-190 * writes a new file per run). Hub Findings are content-deduped by * sha256(domain|title|kind) and silently undercount a window — not suitable. * * Non-sensitive: topFinding is frontmatter.question/title only — never raw body. * * Window compare: ISO lexicographic (safe because all timestamps are * toISOString() fixed-width — finding-store.ts:101-104). */ export declare function collectRunsFromVault(vaultRoot: string, since: string, now: string): Promise; //# sourceMappingURL=digest.d.ts.map