@cleocode/contracts 2026.4.96 → 2026.4.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/config.d.ts +21 -0
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/facade.d.ts +64 -2
  4. package/dist/facade.d.ts.map +1 -1
  5. package/dist/facade.js +1 -0
  6. package/dist/facade.js.map +1 -1
  7. package/dist/index.d.ts +3 -2
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/operations/brain.d.ts +579 -0
  11. package/dist/operations/brain.d.ts.map +1 -0
  12. package/dist/operations/brain.js +39 -0
  13. package/dist/operations/brain.js.map +1 -0
  14. package/dist/operations/conduit.d.ts +151 -0
  15. package/dist/operations/conduit.d.ts.map +1 -0
  16. package/dist/operations/conduit.js +29 -0
  17. package/dist/operations/conduit.js.map +1 -0
  18. package/dist/operations/index.d.ts +4 -0
  19. package/dist/operations/index.d.ts.map +1 -1
  20. package/dist/operations/index.js +4 -0
  21. package/dist/operations/index.js.map +1 -1
  22. package/dist/operations/lifecycle.d.ts +29 -1
  23. package/dist/operations/lifecycle.d.ts.map +1 -1
  24. package/dist/operations/memory.d.ts +899 -0
  25. package/dist/operations/memory.d.ts.map +1 -0
  26. package/dist/operations/memory.js +26 -0
  27. package/dist/operations/memory.js.map +1 -0
  28. package/dist/operations/nexus.d.ts +577 -0
  29. package/dist/operations/nexus.d.ts.map +1 -0
  30. package/dist/operations/nexus.js +22 -0
  31. package/dist/operations/nexus.js.map +1 -0
  32. package/dist/operations/orchestrate.d.ts +451 -38
  33. package/dist/operations/orchestrate.d.ts.map +1 -1
  34. package/dist/operations/orchestrate.js +6 -0
  35. package/dist/operations/orchestrate.js.map +1 -1
  36. package/dist/operations/release.d.ts +78 -8
  37. package/dist/operations/release.d.ts.map +1 -1
  38. package/dist/operations/session.d.ts +26 -3
  39. package/dist/operations/session.d.ts.map +1 -1
  40. package/dist/operations/tasks.d.ts +140 -2
  41. package/dist/operations/tasks.d.ts.map +1 -1
  42. package/dist/sentient.d.ts +85 -0
  43. package/dist/sentient.d.ts.map +1 -0
  44. package/dist/sentient.js +13 -0
  45. package/dist/sentient.js.map +1 -0
  46. package/dist/status-registry.d.ts +1 -1
  47. package/dist/status-registry.d.ts.map +1 -1
  48. package/dist/status-registry.js +3 -0
  49. package/dist/status-registry.js.map +1 -1
  50. package/dist/task.d.ts +66 -0
  51. package/dist/task.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/src/config.ts +22 -0
  54. package/src/facade.ts +65 -1
  55. package/src/index.ts +12 -0
  56. package/src/operations/brain.ts +635 -0
  57. package/src/operations/conduit.ts +189 -0
  58. package/src/operations/index.ts +4 -0
  59. package/src/operations/lifecycle.ts +29 -1
  60. package/src/operations/memory.ts +1053 -0
  61. package/src/operations/nexus.ts +711 -0
  62. package/src/operations/orchestrate.ts +447 -38
  63. package/src/operations/release.ts +77 -7
  64. package/src/operations/session.ts +26 -3
  65. package/src/operations/tasks.ts +141 -3
  66. package/src/sentient.ts +100 -0
  67. package/src/status-registry.ts +3 -0
  68. package/src/task.ts +75 -0
@@ -0,0 +1,635 @@
1
+ /**
2
+ * BRAIN Super-Domain Operations (8 operations)
3
+ *
4
+ * BRAIN is the **unified cross-substrate graph** wrapping
5
+ * `memory + nexus + tasks + conduit + signaldock` into a single
6
+ * super-graph substrate. It is distinct from (and layered above) the
7
+ * memory-only operations in `./memory.ts` which own observations,
8
+ * patterns, decisions, learnings, tiers, and the PageIndex graph
9
+ * scoped to `brain.db`.
10
+ *
11
+ * These wire-format contracts are the API surface consumed by:
12
+ * - `@cleocode/brain` (T969 — living-brain package extraction)
13
+ * - `packages/studio/src/routes/api/brain/*` HTTP routes (T970 — renamed
14
+ * from `/api/living-brain` as the canonical unified super-graph surface)
15
+ * - CLI / SDK clients performing cross-substrate graph queries
16
+ *
17
+ * Node IDs are **substrate-prefixed** (`"task:T949"`, `"memory:O-abc"`,
18
+ * `"code:symbol:foo"`) so cross-substrate edges are unambiguous and
19
+ * deduplication is safe by ID equality alone. The substrate-specific
20
+ * payload on `BrainNode.data` / `BrainEdge.data` is the ONE place where
21
+ * `Record<string, unknown>` is legitimate — super-graph callers treat
22
+ * it opaquely; individual substrate adapters own the concrete shape.
23
+ *
24
+ * SYNC: Canonical runtime implementation now lives at
25
+ * `@cleocode/brain` (BrainNode, BrainEdge, BrainGraph, adapters, SSE
26
+ * stream). The runtime shapes there are intentionally structurally
27
+ * distinct from these wire-format contracts — runtime `BrainNode` uses
28
+ * `kind: BrainNodeKind` + `meta` + optional adapter-produced `weight`,
29
+ * whereas contract `BrainNode` below uses `type: string` + `data`.
30
+ *
31
+ * @task T962 — Orchestration Coherence v4 (BRAIN super-domain)
32
+ * @task T968 — operations/brain.ts contract authoring (Wave B)
33
+ * @task T969 — `@cleocode/brain` package extraction
34
+ * @task T973 — runtime LB* → Brain* rename
35
+ * @see packages/brain/src/types.ts (runtime shapes)
36
+ * @see packages/contracts/src/operations/memory.ts (distinct domain)
37
+ */
38
+
39
+ // ============================================================================
40
+ // Shared BRAIN types (super-graph wire format)
41
+ // ============================================================================
42
+
43
+ /**
44
+ * Substrate name enum — which underlying database a node/edge came from.
45
+ *
46
+ * @remarks
47
+ * Intentionally distinct from the runtime
48
+ * `@cleocode/brain :: BrainSubstrate` type — the contracts layer uses
49
+ * `memory` (aligning with the cognitive-memory domain rename produced by
50
+ * `./memory.ts` in T965), while the runtime layer uses the legacy
51
+ * `brain` literal to match the on-disk `brain.db` file name. Callers
52
+ * translate between the two naming planes when bridging API wire format
53
+ * to live adapter output.
54
+ *
55
+ * @task T962 / T968
56
+ */
57
+ export type BrainSubstrateName = 'memory' | 'nexus' | 'tasks' | 'conduit' | 'signaldock';
58
+
59
+ /**
60
+ * Concrete node type within a substrate (e.g. `observation`, `symbol`,
61
+ * `task`, `session`, `agent`, `message`). Not constrained here because the
62
+ * set is substrate-owned and open-ended; each substrate adapter documents
63
+ * its own vocabulary.
64
+ *
65
+ * @task T962 / T968
66
+ */
67
+ export type BrainNodeType = string;
68
+
69
+ /**
70
+ * Substrate-prefixed node identifier.
71
+ *
72
+ * @example
73
+ * "task:T949"
74
+ * "memory:O-mo4abc123"
75
+ * "nexus:packages/core/src/store/sqlite-data-accessor.ts::createSqliteDataAccessor"
76
+ * "conduit:msg-7f3a2b1c"
77
+ * "signaldock:agent-cleo-prime"
78
+ *
79
+ * @remarks
80
+ * The substrate prefix (before the first `:`) MUST match one of
81
+ * `BrainSubstrateName`. The remainder is substrate-specific and opaque
82
+ * to super-graph callers.
83
+ *
84
+ * @task T962 / T968
85
+ */
86
+ export type BrainNodeId = string;
87
+
88
+ /**
89
+ * Edge kind taxonomy used across the super-graph.
90
+ *
91
+ * @remarks
92
+ * Concrete built-ins are enumerated for tooling autocompletion; the
93
+ * `string` fallback keeps the type open-ended because substrate
94
+ * adapters may introduce new kinds (e.g. `touches_code`, `authored_by`,
95
+ * `supersedes`, `derived_from`) without a schema migration at this
96
+ * layer.
97
+ *
98
+ * @task T962 / T968
99
+ */
100
+ export type BrainEdgeKind =
101
+ | 'parent'
102
+ | 'depends'
103
+ | 'blocks'
104
+ | 'references'
105
+ | 'discusses'
106
+ | 'cites'
107
+ | 'embeds'
108
+ | 'touches_code'
109
+ | 'messages'
110
+ | string;
111
+
112
+ /**
113
+ * A single node in the BRAIN super-graph.
114
+ *
115
+ * @remarks
116
+ * The `data` field carries substrate-specific metadata (memory-tier info,
117
+ * task status, nexus symbol kind, conduit message preview, etc.). This
118
+ * is the ONE place `Record<string, unknown>` is justified: the
119
+ * super-graph is polymorphic across substrates by definition, and the
120
+ * statically-typed payload belongs inside each substrate adapter.
121
+ *
122
+ * @task T962 / T968
123
+ */
124
+ export interface BrainNode {
125
+ /** Substrate-prefixed identifier (see {@link BrainNodeId}). */
126
+ id: BrainNodeId;
127
+ /** Source substrate. */
128
+ substrate: BrainSubstrateName;
129
+ /** Concrete node type within the substrate (e.g. `observation`, `symbol`). */
130
+ type: BrainNodeType;
131
+ /** Human-readable display label. */
132
+ label: string;
133
+ /**
134
+ * Substrate-specific payload. Shape is owned by the substrate adapter;
135
+ * super-graph callers treat it opaquely.
136
+ */
137
+ data: Record<string, unknown>;
138
+ /** ISO 8601 creation timestamp, when exposed by the substrate. */
139
+ createdAt?: string;
140
+ /** ISO 8601 last-update timestamp, when exposed by the substrate. */
141
+ updatedAt?: string;
142
+ }
143
+
144
+ /**
145
+ * A directed edge between two super-graph nodes.
146
+ *
147
+ * @remarks
148
+ * Both endpoints reference {@link BrainNodeId} values. Edges may be
149
+ * in-substrate (both endpoints share the same prefix) or cross-substrate
150
+ * (bridges between e.g. `memory:…` and `nexus:…`).
151
+ *
152
+ * @task T962 / T968
153
+ */
154
+ export interface BrainEdge {
155
+ /** Source node id. */
156
+ from: BrainNodeId;
157
+ /** Target node id. */
158
+ to: BrainNodeId;
159
+ /** Semantic edge kind (see {@link BrainEdgeKind}). */
160
+ kind: BrainEdgeKind;
161
+ /**
162
+ * Normalised weight in `[0, 1]`. Higher = stronger/more confident.
163
+ * Produced by Hebbian/STDP training on memory edges, relation
164
+ * confidence on nexus edges, and substrate-specific heuristics
165
+ * elsewhere.
166
+ */
167
+ weight?: number;
168
+ /** Substrate-specific payload (opaque at super-graph level). */
169
+ data?: Record<string, unknown>;
170
+ }
171
+
172
+ /**
173
+ * Per-substrate node and edge counters returned inside query results.
174
+ *
175
+ * @task T962 / T968
176
+ */
177
+ export interface BrainSubstrateStats {
178
+ /** Number of nodes contributed by the substrate. */
179
+ nodes: number;
180
+ /** Number of edges contributed by the substrate. */
181
+ edges: number;
182
+ }
183
+
184
+ /**
185
+ * Predicate bag applied per-substrate when filtering graph queries.
186
+ *
187
+ * @remarks
188
+ * Each field is optional; adapters apply them in-substrate and ignore
189
+ * any dimension they don't support. When multiple fields are set the
190
+ * filter is an AND (e.g. `nodeType` ∈ {…} AND `labels` ⊆ node.labels
191
+ * AND `textMatch` matches).
192
+ *
193
+ * @task T962 / T968
194
+ */
195
+ export interface BrainGraphFilter {
196
+ /** Restrict to these node types (per-substrate vocabulary). */
197
+ nodeType?: string[];
198
+ /** Restrict to nodes carrying all of these labels. */
199
+ labels?: string[];
200
+ /** Free-text filter applied to the node label (substrate-dependent matcher). */
201
+ textMatch?: string;
202
+ }
203
+
204
+ // ============================================================================
205
+ // 1. brain.query — fetch unified graph
206
+ // ============================================================================
207
+
208
+ /**
209
+ * Parameters for `brain.query`.
210
+ *
211
+ * @remarks
212
+ * `limit` is a cross-substrate total cap; adapters share the budget
213
+ * evenly (`limit / substrates.length`). Omitting `substrates`
214
+ * requests all five.
215
+ *
216
+ * @task T962 / T968
217
+ */
218
+ export interface BrainQueryParams {
219
+ /** Filter by substrate names. Default: all substrates. */
220
+ substrates?: BrainSubstrateName[];
221
+ /**
222
+ * Maximum total nodes to return across all requested substrates.
223
+ * Per-substrate budget is `limit / substrates.length`. Default `500`.
224
+ */
225
+ limit?: number;
226
+ /** Predicate bag applied per-substrate. */
227
+ filter?: BrainGraphFilter;
228
+ }
229
+
230
+ /**
231
+ * Result of `brain.query`.
232
+ *
233
+ * @task T962 / T968
234
+ */
235
+ export interface BrainQueryResult {
236
+ /** Merged, deduplicated nodes across substrates. */
237
+ nodes: BrainNode[];
238
+ /** Edges (may reference stub nodes injected for cross-substrate targets). */
239
+ edges: BrainEdge[];
240
+ /** Aggregate and per-substrate counters. */
241
+ stats: {
242
+ /** Per-substrate node/edge contribution. */
243
+ perSubstrate: Record<BrainSubstrateName, BrainSubstrateStats>;
244
+ /** Deduplicated total node count. */
245
+ totalNodes: number;
246
+ /** Edge count (no dedup — edges are unique by (from,to,kind)). */
247
+ totalEdges: number;
248
+ };
249
+ }
250
+
251
+ // ============================================================================
252
+ // 2. brain.node — fetch single node by substrate-prefixed id
253
+ // ============================================================================
254
+
255
+ /**
256
+ * Parameters for `brain.node`.
257
+ *
258
+ * @task T962 / T968
259
+ */
260
+ export interface BrainNodeParams {
261
+ /**
262
+ * Substrate-prefixed id to fetch.
263
+ *
264
+ * @example `"task:T949"`, `"memory:O-abc"`, `"code:symbol:foo"`.
265
+ */
266
+ id: BrainNodeId;
267
+ }
268
+
269
+ /**
270
+ * Result of `brain.node`.
271
+ *
272
+ * @task T962 / T968
273
+ */
274
+ export interface BrainNodeResult {
275
+ /** The requested node. */
276
+ node: BrainNode;
277
+ /** Neighbour edges partitioned by direction relative to `node.id`. */
278
+ neighbors: {
279
+ /** Edges whose `to` equals the requested node. */
280
+ inbound: BrainEdge[];
281
+ /** Edges whose `from` equals the requested node. */
282
+ outbound: BrainEdge[];
283
+ };
284
+ }
285
+
286
+ // ============================================================================
287
+ // 3. brain.substrate — fetch all nodes/edges for one substrate
288
+ // ============================================================================
289
+
290
+ /**
291
+ * Parameters for `brain.substrate`.
292
+ *
293
+ * @remarks
294
+ * Equivalent to `brain.query` with `substrates: [substrate]`, but
295
+ * provides a cleaner URL binding at the HTTP layer and emits a
296
+ * structured 400 error for unknown substrate names.
297
+ *
298
+ * @task T962 / T968
299
+ */
300
+ export interface BrainSubstrateParams {
301
+ /** Which substrate to project. */
302
+ substrate: BrainSubstrateName;
303
+ /** Maximum nodes to return. Default `500`. */
304
+ limit?: number;
305
+ /** Predicate bag applied to the substrate. */
306
+ filter?: BrainGraphFilter;
307
+ }
308
+
309
+ /**
310
+ * Result of `brain.substrate`.
311
+ *
312
+ * @task T962 / T968
313
+ */
314
+ export interface BrainSubstrateResult {
315
+ /** The substrate that was projected. */
316
+ substrate: BrainSubstrateName;
317
+ /** Nodes contributed by this substrate. */
318
+ nodes: BrainNode[];
319
+ /** Edges contributed by this substrate. */
320
+ edges: BrainEdge[];
321
+ /** True when the result was capped by `limit`. */
322
+ truncated: boolean;
323
+ }
324
+
325
+ // ============================================================================
326
+ // 4. brain.stream — SSE stream of graph mutation events
327
+ // ============================================================================
328
+
329
+ /**
330
+ * Discriminated union of BRAIN super-graph mutation events.
331
+ *
332
+ * @remarks
333
+ * Emitted as Server-Sent Events by the `brain.stream` endpoint. Every
334
+ * variant carries an ISO 8601 `ts` field so clients can sequence events
335
+ * even when they arrive out-of-order.
336
+ *
337
+ * - `hello` — sent immediately on connect; confirms the stream is live.
338
+ * - `heartbeat` — sent every 30 s to prevent connection timeout.
339
+ * - `node.create` — a new node appeared in any substrate.
340
+ * - `node.update` — an existing node's metadata changed.
341
+ * - `edge.strengthen` — an edge weight was updated (Hebbian/STDP or relation).
342
+ * - `edge.create` — a new edge appeared.
343
+ * - `task.status` — shortcut for tasks-substrate status changes.
344
+ * - `message.send` — shortcut for conduit-substrate message inserts.
345
+ *
346
+ * Mirrors `@cleocode/brain :: BrainStreamEvent` with super-graph-aligned
347
+ * identifiers (ids are substrate-prefixed).
348
+ *
349
+ * @task T962 / T968
350
+ */
351
+ export type BrainStreamEvent =
352
+ | { type: 'hello'; ts: string }
353
+ | { type: 'heartbeat'; ts: string }
354
+ | { type: 'node.create'; node: BrainNode; ts: string }
355
+ | { type: 'node.update'; node: BrainNode; ts: string }
356
+ | {
357
+ type: 'edge.strengthen';
358
+ from: BrainNodeId;
359
+ to: BrainNodeId;
360
+ kind: BrainEdgeKind;
361
+ weight: number;
362
+ ts: string;
363
+ }
364
+ | {
365
+ type: 'edge.create';
366
+ from: BrainNodeId;
367
+ to: BrainNodeId;
368
+ kind: BrainEdgeKind;
369
+ weight?: number;
370
+ ts: string;
371
+ }
372
+ | { type: 'task.status'; taskId: string; status: string; ts: string }
373
+ | {
374
+ type: 'message.send';
375
+ messageId: string;
376
+ fromAgentId: string;
377
+ toAgentId: string;
378
+ preview: string;
379
+ ts: string;
380
+ };
381
+
382
+ /**
383
+ * Parameters for `brain.stream`.
384
+ *
385
+ * @remarks
386
+ * Clients may filter by substrate (only emit events from those DBs) and
387
+ * by event kind (only emit e.g. `node.create`). Both default to "all".
388
+ * `sinceTs` resumes from a prior ISO 8601 cursor when reconnecting.
389
+ *
390
+ * @task T962 / T968
391
+ */
392
+ export interface BrainStreamParams {
393
+ /** Restrict events to these substrates. Default: all. */
394
+ substrates?: BrainSubstrateName[];
395
+ /** Restrict to these event kinds (e.g. `['node.create', 'edge.strengthen']`). */
396
+ kinds?: Array<BrainStreamEvent['type']>;
397
+ /**
398
+ * ISO 8601 resume cursor. When set, the server replays events emitted
399
+ * at or after `sinceTs` before tailing the live stream.
400
+ */
401
+ sinceTs?: string;
402
+ }
403
+
404
+ /**
405
+ * Result of `brain.stream`.
406
+ *
407
+ * @remarks
408
+ * The stream is transport-flexible (HTTP SSE in the reference adapter,
409
+ * WebSocket or long-poll in alternates). The `Result` shape describes
410
+ * the **per-frame** payload clients receive; transport framing is an
411
+ * adapter concern.
412
+ *
413
+ * @task T962 / T968
414
+ */
415
+ export interface BrainStreamResult {
416
+ /** One decoded SSE frame. */
417
+ event: BrainStreamEvent;
418
+ }
419
+
420
+ // ============================================================================
421
+ // 5. brain.bridges — list cross-substrate edges
422
+ // ============================================================================
423
+
424
+ /**
425
+ * Parameters for `brain.bridges`.
426
+ *
427
+ * @remarks
428
+ * Returns edges whose endpoints are in **different** substrates — e.g.
429
+ * `memory:O-abc → nexus:symbol:foo` (cognitive memory citing code) or
430
+ * `task:T949 → memory:D-decision-123` (task grounded in a decision).
431
+ * These are the substrate bridges that let the super-graph behave as a
432
+ * single knowledge surface rather than five isolated databases.
433
+ *
434
+ * @task T962 / T968
435
+ */
436
+ export interface BrainBridgesParams {
437
+ /**
438
+ * Restrict to bridges whose endpoints lie in this substrate set.
439
+ * When set, only bridges where **both** endpoints fall inside
440
+ * `substrates` are returned. Default: all substrates.
441
+ */
442
+ substrates?: BrainSubstrateName[];
443
+ /** Restrict to these edge kinds. Default: all kinds. */
444
+ kinds?: BrainEdgeKind[];
445
+ /** Minimum edge weight to include. Default `0`. */
446
+ minWeight?: number;
447
+ /** Max edges to return. Default `500`. */
448
+ limit?: number;
449
+ }
450
+
451
+ /**
452
+ * Result of `brain.bridges`.
453
+ *
454
+ * @task T962 / T968
455
+ */
456
+ export interface BrainBridgesResult {
457
+ /** Cross-substrate edges matching the query. */
458
+ bridges: BrainEdge[];
459
+ /** Per-pair counts keyed by `"${fromSubstrate}->${toSubstrate}"`. */
460
+ pairCounts: Record<string, number>;
461
+ /** Total bridges returned. */
462
+ total: number;
463
+ }
464
+
465
+ // ============================================================================
466
+ // 6. brain.neighborhood — BFS expand from a seed node, N hops
467
+ // ============================================================================
468
+
469
+ /**
470
+ * Parameters for `brain.neighborhood`.
471
+ *
472
+ * @remarks
473
+ * Breadth-first expansion from `seed` up to `hops` edges. Callers that
474
+ * need only direct neighbours should use `hops: 1`. Deep traversals
475
+ * should pair `hops` with `maxNodes` to bound fan-out.
476
+ *
477
+ * @task T962 / T968
478
+ */
479
+ export interface BrainNeighborhoodParams {
480
+ /** Seed node id. */
481
+ seed: BrainNodeId;
482
+ /** Max hops (BFS depth). Default `1`. */
483
+ hops?: number;
484
+ /** Cap on total returned nodes. Default `200`. */
485
+ maxNodes?: number;
486
+ /** Restrict traversal to these edge kinds. Default: all. */
487
+ edgeKinds?: BrainEdgeKind[];
488
+ /** Restrict traversal to these substrates. Default: all. */
489
+ substrates?: BrainSubstrateName[];
490
+ /** Minimum edge weight to traverse. Default `0`. */
491
+ minWeight?: number;
492
+ }
493
+
494
+ /**
495
+ * A single node visited during neighborhood expansion.
496
+ *
497
+ * @task T962 / T968
498
+ */
499
+ export interface BrainNeighborhoodNode {
500
+ /** The visited node. */
501
+ node: BrainNode;
502
+ /** BFS distance from the seed (`0` = seed itself). */
503
+ depth: number;
504
+ }
505
+
506
+ /**
507
+ * Result of `brain.neighborhood`.
508
+ *
509
+ * @task T962 / T968
510
+ */
511
+ export interface BrainNeighborhoodResult {
512
+ /** Seed node id that was expanded. */
513
+ seed: BrainNodeId;
514
+ /** Nodes visited, annotated with BFS depth. */
515
+ nodes: BrainNeighborhoodNode[];
516
+ /** Edges traversed during expansion. */
517
+ edges: BrainEdge[];
518
+ /** Maximum depth actually reached (≤ requested `hops`). */
519
+ reachedDepth: number;
520
+ /** True when the traversal was capped by `maxNodes`. */
521
+ truncated: boolean;
522
+ }
523
+
524
+ // ============================================================================
525
+ // 7. brain.search — text/label search across all substrates
526
+ // ============================================================================
527
+
528
+ /**
529
+ * Parameters for `brain.search`.
530
+ *
531
+ * @remarks
532
+ * Cross-substrate text search. Each adapter picks the best available
533
+ * matcher (FTS5 for memory.db, identifier-substring for nexus, title
534
+ * match for tasks, etc.) and contributes hits scored on a normalised
535
+ * `[0, 1]` relevance axis. Results are fused by relevance desc.
536
+ *
537
+ * @task T962 / T968
538
+ */
539
+ export interface BrainSearchParams {
540
+ /** Search query (required, non-empty). */
541
+ query: string;
542
+ /** Restrict to these substrates. Default: all. */
543
+ substrates?: BrainSubstrateName[];
544
+ /** Restrict to these node types. Default: all. */
545
+ nodeTypes?: BrainNodeType[];
546
+ /** Max results. Default `50`. */
547
+ limit?: number;
548
+ }
549
+
550
+ /**
551
+ * A single fused search hit.
552
+ *
553
+ * @task T962 / T968
554
+ */
555
+ export interface BrainSearchHit {
556
+ /** The matched node. */
557
+ node: BrainNode;
558
+ /** Normalised relevance in `[0, 1]`. Higher = better. */
559
+ score: number;
560
+ /** Which substrate contributed this hit. */
561
+ substrate: BrainSubstrateName;
562
+ /** Adapter that produced the score (e.g. `fts`, `identifier`, `title`). */
563
+ matcher: string;
564
+ }
565
+
566
+ /**
567
+ * Result of `brain.search`.
568
+ *
569
+ * @task T962 / T968
570
+ */
571
+ export interface BrainSearchResult {
572
+ /** Hits ranked by `score` desc. */
573
+ hits: BrainSearchHit[];
574
+ /** Total hit count (may exceed `hits.length` when `limit` applied). */
575
+ total: number;
576
+ /** Estimated token weight of the payload (for JIT retrieval budgeting). */
577
+ tokensEstimated: number;
578
+ }
579
+
580
+ // ============================================================================
581
+ // 8. brain.stats — graph statistics per substrate
582
+ // ============================================================================
583
+
584
+ /**
585
+ * Parameters for `brain.stats`.
586
+ *
587
+ * @remarks
588
+ * Zero required params — returns the full super-graph telemetry
589
+ * snapshot. `substrates` narrows the report when only part of the
590
+ * graph matters to the caller.
591
+ *
592
+ * @task T962 / T968
593
+ */
594
+ export interface BrainStatsParams {
595
+ /** Restrict the report to these substrates. Default: all. */
596
+ substrates?: BrainSubstrateName[];
597
+ }
598
+
599
+ /**
600
+ * Per-substrate statistics returned inside `BrainStatsResult`.
601
+ *
602
+ * @task T962 / T968
603
+ */
604
+ export interface BrainSubstrateReport {
605
+ /** Substrate name. */
606
+ substrate: BrainSubstrateName;
607
+ /** Node count by {@link BrainNodeType}. */
608
+ nodesByType: Array<{ type: BrainNodeType; count: number }>;
609
+ /** Edge count by {@link BrainEdgeKind}. */
610
+ edgesByKind: Array<{ kind: BrainEdgeKind; count: number }>;
611
+ /** Total nodes for the substrate. */
612
+ totalNodes: number;
613
+ /** Total edges for the substrate. */
614
+ totalEdges: number;
615
+ /** ISO 8601 timestamp of the most recent mutation, when known. */
616
+ lastMutationAt: string | null;
617
+ }
618
+
619
+ /**
620
+ * Result of `brain.stats`.
621
+ *
622
+ * @task T962 / T968
623
+ */
624
+ export interface BrainStatsResult {
625
+ /** Per-substrate telemetry. */
626
+ perSubstrate: BrainSubstrateReport[];
627
+ /** Total nodes across all reported substrates. */
628
+ totalNodes: number;
629
+ /** Total edges across all reported substrates. */
630
+ totalEdges: number;
631
+ /** Count of cross-substrate bridges included in `totalEdges`. */
632
+ bridgeCount: number;
633
+ /** ISO 8601 timestamp when the report was computed. */
634
+ generatedAt: string;
635
+ }