/** * The capture library (RCL-09) — browsing what has been captured, rather than * searching it. * * `listDocuments` answers "what is indexed". A library answers a different * question: everything from this site, captured last week, tagged `reading`, * newest first. The facets come from the capture envelope's `meta.json` * (RCL-07), which is already on every record — this module is the query layer * over them, and the data layer the desktop GUI renders. * * Rules, once, here: * - within a facet values are OR'd, across facets AND'd (`--site a --site b * --tag x` = "from a or b, tagged x"); * - `--site example.com` matches `www.example.com` and `docs.example.com`, * because nobody browsing their own library means the bare host only; * - a document with no provenance (an ordinary file on disk) sorts by its * index time and matches no capture facet — it is not a capture. * * @module v1/cli/knowledge/library */ import type { CaptureProvenance } from './capture-envelope.js'; import type { DocumentMeta } from './document-pipeline.js'; export interface LibraryFilter { /** Host, or a parent domain of it. */ site?: string[]; tag?: string[]; collection?: string[]; /** `extension` | `monobrowse` | `crawl`. */ source?: string[]; /** ISO date/time, or a relative age: `7d`, `24h`, `30m`. */ since?: string; until?: string; /** Only documents that came from a capture envelope. */ capturedOnly?: boolean; scope?: string; /** Substring over title, URL and path. */ text?: string; } export type LibrarySort = 'captured' | 'indexed' | 'title' | 'path' | 'size'; export interface LibraryEntry { filePath: string; scope: string; title: string; url?: string; site?: string; capturedAt: string; indexedAt: string; source?: string; collection?: string; tags: string[]; chunkCount: number; size: number; version?: number; /** False for ordinary files on disk: no capture envelope backed this one. */ captured: boolean; } /** The host a document was captured from, or undefined for a local file. */ export declare function documentSite(meta: { canonicalUrl?: string; provenance?: CaptureProvenance; }): string | undefined; /** When the page was captured; falls back to when it was indexed. */ export declare function documentCapturedAt(meta: { indexedAt?: string; provenance?: CaptureProvenance; }): string; /** * A point in time from `2026-09-01`, a full ISO stamp, or an AGE like `7d` * (meaning "7 days ago"). Returns null for anything unparseable so a typo * cannot silently filter the whole library away. */ export declare function parseWhen(value: string | undefined, now?: number): number | null; /** True when a document belongs in this view. */ export declare function matchesLibraryFilter(meta: DocumentMeta, filter?: LibraryFilter, now?: number): boolean; export declare function filterDocuments(docs: DocumentMeta[], filter?: LibraryFilter, now?: number): DocumentMeta[]; export declare function sortDocuments(docs: DocumentMeta[], sort?: LibrarySort, order?: 'asc' | 'desc'): DocumentMeta[]; /** The flat, JSON-friendly row the GUI and `--json` consumers read. */ export declare function libraryEntry(meta: DocumentMeta): LibraryEntry; export interface ListLibraryOptions extends LibraryFilter { sort?: LibrarySort; order?: 'asc' | 'desc'; limit?: number; now?: number; } /** Browse the library: filter, sort, cap. Never throws on an empty store. */ export declare function listLibrary(docs: DocumentMeta[], opts?: ListLibraryOptions): LibraryEntry[]; /** Facet counts for the current view — what a sidebar renders. */ export declare function libraryFacets(docs: DocumentMeta[]): { sites: Array<{ value: string; count: number; }>; tags: Array<{ value: string; count: number; }>; collections: Array<{ value: string; count: number; }>; sources: Array<{ value: string; count: number; }>; }; //# sourceMappingURL=library.d.ts.map