/** * Graph auto-population helpers for CLEO BRAIN. * * Provides upsertGraphNode and addGraphEdge helpers that write to the * brain_page_nodes and brain_page_edges tables whenever memory entries * are created via the legitimate write paths (storeDecision, observeBrain, * storePattern, storeLearning, and task completion). * * Design constraints: * - Legacy writes are best-effort; scoped projections propagate failures. * - All writes are gated on brain.autoCapture via isAutoCaptureEnabled. * - Uses INSERT OR REPLACE (onConflictDoUpdate) for upsert semantics. * - Edge inserts are idempotent via the composite PK (fromId, toId, edgeType). * * @task T537 * @epic T523 */ import type { OperationExecutionContext } from '@cleocode/contracts/jobs'; import type { DocsGraphProjectionResult } from '@cleocode/contracts/operations/docs'; import type { BrainEdgeType, BrainNodeType } from '../store/schema/memory-schema.js'; export type { BrainEdgeType, BrainNodeType }; /** * Options for a graph write the user asked for explicitly (T13600). * @example * ```ts * await addGraphEdge(root, 'decision:D1', 'llmtxt:abc', 'references', 1, 'manual', undefined, { * explicit: true, * }); * ``` */ export interface GraphWriteOptions { /** * Write even when `brain.autoCapture` is off, and throw on failure instead of * logging: that gate governs automatic capture, not an explicit request. */ readonly explicit?: boolean; /** Create the node only when absent; an existing node is left unchanged (nodes only). */ readonly ifAbsent?: boolean; } /** * Upsert a graph node for a typed table entry. * * Uses INSERT OR REPLACE to handle both new and existing entries. If the * node already exists (same id), its label, qualityScore, lastActivityAt, * updatedAt, and metadataJson are refreshed while createdAt is preserved. * * The contentHash is derived from a SHA-256 prefix of the canonical content. * External-reference nodes (task, session, epic) may pass an empty string for * content; their hash will be null so duplicates are not rejected. * * This function is gated on brain.autoCapture. If the gate is disabled or any * error occurs, legacy calls return silently. Context-aware calls throw failures. * * @param projectRoot - Absolute path to the project root directory. * @param nodeId - Stable composite ID in the form ':'. * @param nodeType - Discriminated type from BRAIN_NODE_TYPES. * @param label - Human-readable label (title, task ID, etc.). * @param qualityScore - 0.0 (noise) to 1.0 (canonical). * @param content - Canonical text used to derive the content hash. * @param metadata - Optional type-specific metadata blob. * @param context - Captured scope; when supplied, failures throw and writes check cancellation. * @param options - An explicit write skips the capture gate and throws; `ifAbsent` keeps an existing node. * * @remarks Scoped calls pin storage routing and refuse to join an unowned transaction. * @example * ```ts * await upsertGraphNode(root, 'task:T123', 'task', 'Task', 0.7, ''); * ``` * @task T537 */ export declare function upsertGraphNode(projectRoot: string, nodeId: string, nodeType: BrainNodeType, label: string, qualityScore: number, content: string, metadata?: Record, context?: OperationExecutionContext, options?: GraphWriteOptions): Promise; /** * Add a directed, typed edge between two graph nodes (idempotent). * * The composite primary key (fromId, toId, edgeType) prevents duplicate edges * of the same type. Conflicting rows are ignored so this is safe to call * multiple times with the same arguments. * * This function is gated on brain.autoCapture. If the gate is disabled or any * error occurs, legacy calls return silently. Context-aware calls throw failures. * * @param projectRoot - Absolute path to the project root directory. * @param fromId - Source node ID (brain_page_nodes.id). * @param toId - Target node ID (brain_page_nodes.id or external nexus ID). * @param edgeType - Typed relationship from BRAIN_EDGE_TYPES. * @param weight - Edge confidence/weight (0.0–1.0). Defaults to 1.0. * @param provenance - Human-readable note on why this edge was emitted. * @param context - Captured scope; when supplied, failures throw and writes check cancellation. * @param options - An explicit write skips the capture gate and throws on failure. * * @remarks Scoped calls pin storage routing and refuse to join an unowned transaction. * @example * ```ts * await addGraphEdge(root, 'task:T123', 'llmtxt:hash', 'embeds'); * ``` * @task T537 */ export declare function addGraphEdge(projectRoot: string, fromId: string, toId: string, edgeType: BrainEdgeType, weight?: number, provenance?: string, context?: OperationExecutionContext, options?: GraphWriteOptions): Promise; /** * Upsert a `task:T###` graph node for a task at creation time (not completion). * * Prior to T945 Stage A, task nodes were only minted by `completeTask`, which * meant brand-new tasks were invisible in the graph until they shipped. This * hook fixes that gap by wiring `task:T###` nodes into `addTask` with a * quality score of 0.7 (provisional, not yet verified by gate evidence). * * Best-effort: any failure is swallowed so graph writes never block the * task-creation write path. * * @param projectRoot - Absolute path to the project root directory. * @param taskId - CLEO task ID in `T###` format. * @param title - Task title (used as node label). * @param metadata - Optional type-specific metadata (priority, type, etc.). * * @task T945 */ export declare function ensureTaskNode(projectRoot: string, taskId: string, title: string, metadata?: Record): Promise; /** * Upsert an `llmtxt:` graph node for an attachment blob and emit an * `embeds` edge from the owning entity to the blob. * * `cleo docs add` stores attachment blobs content-addressably; the blob's * SHA-256 becomes its canonical node ID so duplicate attachments across tasks * collapse to a single graph node with multiple incoming `embeds` edges. * * Best-effort: any failure is swallowed. * * @param projectRoot - Absolute path to the project root directory. * @param sha256 - Hex-encoded SHA-256 of the blob (content-address). * @param ownerId - Full graph node ID of the owner (e.g. `task:T123`). * @param label - Human-readable label for the blob (filename or title). * * @task T945 */ export declare function ensureLlmtxtNode(projectRoot: string, sha256: string, ownerId: string, label: string): Promise; /** Provenance of the canonical `llmtxt --documents--> owner` link (T13985). */ export declare const DOCUMENTS_EDGE_PROVENANCE = "docs-add"; /** * Create the owner node of a `documents` edge when it is absent, so the edge * never dangles: with `brain.autoCapture` off nothing else creates `task:` * (T13985). An existing node is left unchanged. * * @param projectRoot - Project whose brain is written. * @param ownerId - Qualified owner node id, e.g. `task:T123`. * @param context - Captured scope for projection writes; omitted by the backfill. * @example * ```ts * await ensureDocumentOwnerNode(root, 'task:T123'); * ``` */ export declare function ensureDocumentOwnerNode(projectRoot: string, ownerId: string, context?: OperationExecutionContext): Promise; /** * Project a canonical document into the graph with captured scope and visible failures. * * Always writes the `llmtxt:` node and its `llmtxt --documents--> owner` * edge: the document link is canonical (T13985, D11180). The owner's `embeds` * edge is auto-capture and follows `brain.autoCapture`; `status: 'disabled'` * reports that only the canonical link was written. * * @remarks Each synchronous write checks the same absolute deadline. This does not preempt * SQLite or promise atomicity across the node and edge; a failed edge leaves an * idempotently resumable partial projection. Canonical document bytes are untouched. * * @param context - Caller-owned immutable identity, deadline and cancellation. * @param sha256 - Canonical document content hash. * @param ownerId - Qualified graph owner identity. * @param label - Document display label. * @returns Completed or explicitly disabled graph projection in the captured project. * @throws Error - Configuration, storage, cancellation or deadline failure. * @example * ```ts * const result = await ensureLlmtxtNodeScoped(context, sha256, 'task:T123', 'Design'); * ``` */ export declare function ensureLlmtxtNodeScoped(context: OperationExecutionContext, sha256: string, ownerId: string, label: string): Promise; /** * Upsert a `msg:` graph node for a CONDUIT message and, when the message * body references one or more `T###` task IDs, emit `discusses` edges from * the message to each referenced task. * * Task IDs are extracted from the message content via `TASK_ID_REGEX`. Only * unique IDs are linked; duplicates within the same message collapse. * * Best-effort: any failure is swallowed. * * @param projectRoot - Absolute path to the project root directory. * @param msgId - CONDUIT message ID (soft FK into conduit.db). * @param content - Full message body (scanned for task references). * * @task T945 */ export declare function ensureMessageNode(projectRoot: string, msgId: string, content: string): Promise; /** Separator between the repository key and the path or sha of a repo-qualified node id (T14012). */ export declare const REPO_ID_SEPARATOR = "::"; /** * Graph node id for a file path or commit sha, qualified by its repository in a * multi-repo store: `:::`, or `:` when `repo` is * `null` (the store's own repository, so single-repo stores keep their ids). * * @param prefix - Node id prefix, `file` or `commit`. * @param repo - Repository key, or `null` for the store's own repository. * @param key - Repo-relative POSIX path or commit sha. * @returns The node id. * @example * ```ts * repoQualifiedNodeId('file', 'github.com/o/r', 'src/x.ts'); // 'file:github.com/o/r::src/x.ts' * ``` * @task T14012 */ export declare function repoQualifiedNodeId(prefix: 'file' | 'commit', repo: string | null, key: string): string; /** * Upsert a `commit:` graph node for a git commit and emit a `touches_code` * edge from the associated task to the commit node. * * Used by the Tier 3 autonomy audit trail: every commit produced by an agent * is recorded as a graph node so operators can traverse task → commit → files * touched to reconstruct the audit chain. * * Best-effort: any failure is swallowed. * * @param projectRoot - Absolute path to the project root directory. * @param sha - Full git commit SHA (40 hex chars; short SHAs accepted). * @param taskId - CLEO task ID this commit resolves (`T###`). * @param options - `provenance` of the edge (default `auto:commit-hook`); `explicit` * writes even when `brain.autoCapture` is off (validated evidence, T13950); * `repo` qualifies the node id with a repository key in a multi-repo store * (T14012). * * @task T945 * @task T13950 */ export declare function ensureCommitNode(projectRoot: string, sha: string, taskId: string, options?: { provenance?: string; explicit?: boolean; repo?: string | null; }): Promise; /** * Write graph nodes (created only when absent) and edges (idempotent) in one * brain transaction, whatever `brain.autoCapture` says; failures throw. * * @param projectRoot - Project whose brain graph is written. * @param nodes - Nodes to create when absent. * @param edges - Edges to add. * @example * ```ts * await writeGraphBatch(root, [{ id: 'file:a.ts', nodeType: 'file', label: 'a.ts', qualityScore: 0.8 }], []); * ``` * @task T13950 */ export declare function writeGraphBatch(projectRoot: string, nodes: ReadonlyArray<{ id: string; nodeType: BrainNodeType; label: string; qualityScore: number; }>, edges: ReadonlyArray<{ fromId: string; toId: string; edgeType: BrainEdgeType; provenance: string; }>): Promise; //# sourceMappingURL=graph-auto-populate.d.ts.map