/** * GLU-07 — captured pages as MCP resources: the URI scheme and the listing. * * A tool call is something an agent must be told to make. A RESOURCE is * something a client can enumerate, attach and re-read on its own, which is * what "read from my brain without a bespoke integration" actually needs. * * THE URI: `capture:///` * * - `` is the knowledge scope, which is also WHICH STORE to look in: * `global` is the personal cross-project brain where `~/.monomind/inbox` * captures land, anything else is this project's store. * - `` is the capture's `canonicalUrl` — the same dedupe key the * ingest uses (RCL-06) — percent-encoded, falling back to the absolute file * path for an ordinary document. Keying on the PAGE and not the path is * what makes the uri survive a re-capture: version 2 of an article lands in * a new timestamped directory, and an agent that wrote the uri down last * week must still reach the same page. * - Percent-encoding leaves exactly one path segment, which matters: the MCP * resource registry in `@monoes/mcp` matches templates with `[^/]+`, so a * raw `https://…` in the path would make the uri unroutable. * - Optional `?v=`, `?chunk=` and `?anchor=` address one VERSION or one * PASSAGE — see `capture-resource-read.ts`. * - `capture://` with no identity is the scope's library index: facet * counts and the newest captures, so a client can orient before paging. * * Nothing here re-implements filtering, provenance or facets — `library.ts` * owns those and this module is the MCP-shaped view over them. * * @module v1/cli/mcp-tools/capture-resources */ import { type CaptureProvenance } from '../knowledge/capture-envelope.js'; import type { DocumentMeta } from '../knowledge/document-pipeline.js'; import { type LibraryEntry, type LibraryFilter, type LibrarySort, libraryFacets } from '../knowledge/library.js'; export declare const CAPTURE_URI_SCHEME = "capture"; export declare const CAPTURE_MIME_TYPE = "text/markdown"; export declare const CAPTURE_JSON_MIME_TYPE = "application/json"; export declare const CAPTURE_URI_TEMPLATE = "capture://{scope}/{identity}"; export declare const CAPTURE_INDEX_URI_TEMPLATE = "capture://{scope}"; export declare const DEFAULT_PAGE_SIZE = 50; export declare const MAX_PAGE_SIZE = 200; export interface CaptureUriExtras { /** A specific stored version (RCL-06), rather than the current one. */ version?: number; /** A single chunk, as reported on a search hit. */ chunkIndex?: number; /** A citation anchor `#-` (RCL-10). */ anchor?: string; } export interface CaptureUri extends CaptureUriExtras { scope: string; /** Empty for the scope's library index. */ identity: string; } export declare function buildCaptureUri(scope: string, identity: string, extras?: CaptureUriExtras): string; /** The page a document IS, for uri purposes: its dedupe key, else its path. */ export declare function captureIdentity(meta: { filePath: string; canonicalUrl?: string; provenance?: CaptureProvenance; }): string; export declare function captureUriFor(meta: DocumentMeta, extras?: CaptureUriExtras): string; export declare function isCaptureUri(uri: string): boolean; /** * Parse a capture uri, or null when it is not one — including when it is * malformed. A caller distinguishes "not mine" from "mine but broken" by * checking `isCaptureUri` first, which is what the router does so a typo in a * capture uri reports itself instead of falling through to another scheme. */ export declare function parseCaptureUri(uri: string): CaptureUri | null; export interface CaptureResourceDescriptor { uri: string; name: string; description: string; mimeType: string; } export declare function captureResourceDescriptor(meta: DocumentMeta): CaptureResourceDescriptor; export declare function captureIndexDescriptor(scope: string, count: number): CaptureResourceDescriptor; export interface ListCaptureResourcesOptions extends LibraryFilter { sort?: LibrarySort; order?: 'asc' | 'desc'; /** Opaque, from a previous page's `nextCursor`. */ cursor?: string; pageSize?: number; /** Also list ordinary indexed files, which are not captures. */ includeLocal?: boolean; now?: number; } export interface CaptureRow extends LibraryEntry { uri: string; } export interface CaptureResourceListResult { /** MCP `resources/list` entries. */ resources: CaptureResourceDescriptor[]; /** The same page, as the structured rows a tool caller wants. */ rows: CaptureRow[]; total: number; nextCursor?: string; } /** Filtered and sorted, before paging. */ export declare function selectCaptureDocuments(docs: DocumentMeta[], opts?: ListCaptureResourcesOptions): DocumentMeta[]; /** * One page of capture resources. Throws on a cursor that does not belong to * these options — paging on silently would hand back a window of a different * list, which is worse than an error the client can retry without a cursor. */ export declare function listCaptureResources(docs: DocumentMeta[], opts?: ListCaptureResourcesOptions): CaptureResourceListResult; /** Scopes that hold at least one capture, so the index resources match what * is actually there rather than a hardcoded pair. */ export declare function captureScopes(docs: DocumentMeta[]): string[]; export interface CaptureLibraryIndex { scope: string; total: number; facets: ReturnType; latest: CaptureRow[]; uriTemplate: string; indexUriTemplate: string; } /** The payload behind `capture://`. */ export declare function captureLibraryIndex(docs: DocumentMeta[], scope: string, limit?: number): CaptureLibraryIndex; export interface CaptureStoreOptions { /** The project store root. Defaults to the resolved project root. */ rootDir?: string; /** The personal cross-project brain. Defaults to `getGlobalBrainDir()`. */ globalRoot?: string; store?: 'project' | 'global' | 'all'; } /** The store root a scope's records live in. */ export declare function captureStoreRoot(scope: string, opts?: CaptureStoreOptions): Promise; /** * Every indexed document, from both stores by default. * * Captures land in `~/.monomind/inbox`, which is outside any project, so * `doc ingest` files them in the GLOBAL brain — listing only the project store * would report an empty library to an agent whose user has captured hundreds * of pages. Ordinary project documents come along; `listCaptureResources` * drops them unless `includeLocal` is set. */ export declare function loadCaptureDocuments(opts?: CaptureStoreOptions): Promise; /** Newest capture time in a set — what a client shows as "last updated". */ export declare function newestCaptureAt(docs: DocumentMeta[]): string | undefined; //# sourceMappingURL=capture-resources.d.ts.map