@cleocode/contracts 2026.4.100 → 2026.4.101

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 (90) hide show
  1. package/dist/brain-graph.d.ts +245 -0
  2. package/dist/brain-graph.d.ts.map +1 -0
  3. package/dist/brain-graph.js +30 -0
  4. package/dist/brain-graph.js.map +1 -0
  5. package/dist/exit-codes.d.ts +1 -1
  6. package/dist/exit-codes.d.ts.map +1 -1
  7. package/dist/exit-codes.js +1 -1
  8. package/dist/exit-codes.js.map +1 -1
  9. package/dist/graph.d.ts +2 -0
  10. package/dist/graph.d.ts.map +1 -1
  11. package/dist/index.d.ts +8 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/nexus-contract-ops.d.ts +186 -0
  15. package/dist/nexus-contract-ops.d.ts.map +1 -0
  16. package/dist/nexus-contract-ops.js +11 -0
  17. package/dist/nexus-contract-ops.js.map +1 -0
  18. package/dist/nexus-living-brain-ops.d.ts +314 -0
  19. package/dist/nexus-living-brain-ops.d.ts.map +1 -0
  20. package/dist/nexus-living-brain-ops.js +15 -0
  21. package/dist/nexus-living-brain-ops.js.map +1 -0
  22. package/dist/nexus-query-ops.d.ts +82 -0
  23. package/dist/nexus-query-ops.d.ts.map +1 -0
  24. package/dist/nexus-query-ops.js +11 -0
  25. package/dist/nexus-query-ops.js.map +1 -0
  26. package/dist/nexus-route-ops.d.ts +103 -0
  27. package/dist/nexus-route-ops.d.ts.map +1 -0
  28. package/dist/nexus-route-ops.js +10 -0
  29. package/dist/nexus-route-ops.js.map +1 -0
  30. package/dist/nexus-tasks-bridge-ops.d.ts +68 -0
  31. package/dist/nexus-tasks-bridge-ops.d.ts.map +1 -0
  32. package/dist/nexus-tasks-bridge-ops.js +11 -0
  33. package/dist/nexus-tasks-bridge-ops.js.map +1 -0
  34. package/dist/nexus-wiki-ops.d.ts +51 -0
  35. package/dist/nexus-wiki-ops.d.ts.map +1 -0
  36. package/dist/nexus-wiki-ops.js +11 -0
  37. package/dist/nexus-wiki-ops.js.map +1 -0
  38. package/dist/operations/admin.d.ts +1781 -0
  39. package/dist/operations/admin.d.ts.map +1 -0
  40. package/dist/operations/admin.js +27 -0
  41. package/dist/operations/admin.js.map +1 -0
  42. package/dist/operations/brain.d.ts +34 -26
  43. package/dist/operations/brain.d.ts.map +1 -1
  44. package/dist/operations/brain.js +7 -6
  45. package/dist/operations/brain.js.map +1 -1
  46. package/dist/operations/docs.d.ts +279 -0
  47. package/dist/operations/docs.d.ts.map +1 -0
  48. package/dist/operations/docs.js +31 -0
  49. package/dist/operations/docs.js.map +1 -0
  50. package/dist/operations/intelligence.d.ts +319 -0
  51. package/dist/operations/intelligence.d.ts.map +1 -0
  52. package/dist/operations/intelligence.js +24 -0
  53. package/dist/operations/intelligence.js.map +1 -0
  54. package/dist/operations/orchestrate.d.ts +113 -2
  55. package/dist/operations/orchestrate.d.ts.map +1 -1
  56. package/dist/operations/orchestrate.js +3 -2
  57. package/dist/operations/orchestrate.js.map +1 -1
  58. package/dist/operations/session.d.ts +185 -47
  59. package/dist/operations/session.d.ts.map +1 -1
  60. package/dist/operations/session.js +7 -6
  61. package/dist/operations/session.js.map +1 -1
  62. package/dist/operations/sticky.d.ts +264 -0
  63. package/dist/operations/sticky.d.ts.map +1 -0
  64. package/dist/operations/sticky.js +19 -0
  65. package/dist/operations/sticky.js.map +1 -0
  66. package/dist/operations/validate.d.ts +145 -19
  67. package/dist/operations/validate.d.ts.map +1 -1
  68. package/dist/operations/validate.js +3 -3
  69. package/dist/task-record.d.ts +19 -0
  70. package/dist/task-record.d.ts.map +1 -1
  71. package/package.json +41 -1
  72. package/src/brain-graph.ts +282 -0
  73. package/src/exit-codes.ts +1 -1
  74. package/src/graph.ts +2 -0
  75. package/src/index.ts +109 -0
  76. package/src/nexus-contract-ops.ts +244 -0
  77. package/src/nexus-living-brain-ops.ts +345 -0
  78. package/src/nexus-query-ops.ts +100 -0
  79. package/src/nexus-route-ops.ts +134 -0
  80. package/src/nexus-tasks-bridge-ops.ts +71 -0
  81. package/src/nexus-wiki-ops.ts +53 -0
  82. package/src/operations/admin.ts +2087 -0
  83. package/src/operations/brain.ts +34 -26
  84. package/src/operations/docs.ts +322 -0
  85. package/src/operations/intelligence.ts +399 -0
  86. package/src/operations/orchestrate.ts +117 -2
  87. package/src/operations/session.ts +217 -48
  88. package/src/operations/sticky.ts +308 -0
  89. package/src/operations/validate.ts +161 -55
  90. package/src/task-record.ts +19 -0
@@ -21,12 +21,13 @@
21
21
  * `Record<string, unknown>` is legitimate — super-graph callers treat
22
22
  * it opaquely; individual substrate adapters own the concrete shape.
23
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`.
24
+ * SYNC: Canonical runtime shapes (`BrainNode`, `BrainEdge`, `BrainGraph`)
25
+ * live at `packages/contracts/src/brain-graph.ts` (T989 unification).
26
+ * The types in this file are **wire-format only** and are named with a
27
+ * `Wire` suffix (`BrainNodeWire`, `BrainEdgeWire`, `BrainStreamEventWire`)
28
+ * to prevent collision with the canonical runtime types. Runtime
29
+ * `BrainNode` uses `kind: BrainNodeKind` + `meta` + optional `weight`,
30
+ * whereas `BrainNodeWire` uses `type: string` + `data`.
30
31
  *
31
32
  * @task T962 — Orchestration Coherence v4 (BRAIN super-domain)
32
33
  * @task T968 — operations/brain.ts contract authoring (Wave B)
@@ -120,8 +121,10 @@ export type BrainEdgeKind =
120
121
  * statically-typed payload belongs inside each substrate adapter.
121
122
  *
122
123
  * @task T962 / T968
124
+ * @remarks Wire-format type. The canonical runtime shape is {@link BrainNode}
125
+ * from `@cleocode/contracts` (`packages/contracts/src/brain-graph.ts`).
123
126
  */
124
- export interface BrainNode {
127
+ export interface BrainNodeWire {
125
128
  /** Substrate-prefixed identifier (see {@link BrainNodeId}). */
126
129
  id: BrainNodeId;
127
130
  /** Source substrate. */
@@ -149,9 +152,12 @@ export interface BrainNode {
149
152
  * in-substrate (both endpoints share the same prefix) or cross-substrate
150
153
  * (bridges between e.g. `memory:…` and `nexus:…`).
151
154
  *
155
+ * Wire-format type. The canonical runtime shape is {@link BrainEdge}
156
+ * from `@cleocode/contracts` (`packages/contracts/src/brain-graph.ts`).
157
+ *
152
158
  * @task T962 / T968
153
159
  */
154
- export interface BrainEdge {
160
+ export interface BrainEdgeWire {
155
161
  /** Source node id. */
156
162
  from: BrainNodeId;
157
163
  /** Target node id. */
@@ -234,9 +240,9 @@ export interface BrainQueryParams {
234
240
  */
235
241
  export interface BrainQueryResult {
236
242
  /** Merged, deduplicated nodes across substrates. */
237
- nodes: BrainNode[];
243
+ nodes: BrainNodeWire[];
238
244
  /** Edges (may reference stub nodes injected for cross-substrate targets). */
239
- edges: BrainEdge[];
245
+ edges: BrainEdgeWire[];
240
246
  /** Aggregate and per-substrate counters. */
241
247
  stats: {
242
248
  /** Per-substrate node/edge contribution. */
@@ -273,13 +279,13 @@ export interface BrainNodeParams {
273
279
  */
274
280
  export interface BrainNodeResult {
275
281
  /** The requested node. */
276
- node: BrainNode;
282
+ node: BrainNodeWire;
277
283
  /** Neighbour edges partitioned by direction relative to `node.id`. */
278
284
  neighbors: {
279
285
  /** Edges whose `to` equals the requested node. */
280
- inbound: BrainEdge[];
286
+ inbound: BrainEdgeWire[];
281
287
  /** Edges whose `from` equals the requested node. */
282
- outbound: BrainEdge[];
288
+ outbound: BrainEdgeWire[];
283
289
  };
284
290
  }
285
291
 
@@ -315,9 +321,9 @@ export interface BrainSubstrateResult {
315
321
  /** The substrate that was projected. */
316
322
  substrate: BrainSubstrateName;
317
323
  /** Nodes contributed by this substrate. */
318
- nodes: BrainNode[];
324
+ nodes: BrainNodeWire[];
319
325
  /** Edges contributed by this substrate. */
320
- edges: BrainEdge[];
326
+ edges: BrainEdgeWire[];
321
327
  /** True when the result was capped by `limit`. */
322
328
  truncated: boolean;
323
329
  }
@@ -343,16 +349,18 @@ export interface BrainSubstrateResult {
343
349
  * - `task.status` — shortcut for tasks-substrate status changes.
344
350
  * - `message.send` — shortcut for conduit-substrate message inserts.
345
351
  *
346
- * Mirrors `@cleocode/brain :: BrainStreamEvent` with super-graph-aligned
347
- * identifiers (ids are substrate-prefixed).
352
+ * Wire-format event union. The canonical runtime event type is
353
+ * `{@link BrainStreamEvent}` from `@cleocode/contracts` (`brain-graph.ts`).
354
+ * The main difference: wire-format uses `from`/`to`/`kind` for edge events,
355
+ * runtime uses `fromId`/`toId`/`edgeType` for compatibility with studio SSE.
348
356
  *
349
357
  * @task T962 / T968
350
358
  */
351
- export type BrainStreamEvent =
359
+ export type BrainStreamEventWire =
352
360
  | { type: 'hello'; ts: string }
353
361
  | { type: 'heartbeat'; ts: string }
354
- | { type: 'node.create'; node: BrainNode; ts: string }
355
- | { type: 'node.update'; node: BrainNode; ts: string }
362
+ | { type: 'node.create'; node: BrainNodeWire; ts: string }
363
+ | { type: 'node.update'; node: BrainNodeWire; ts: string }
356
364
  | {
357
365
  type: 'edge.strengthen';
358
366
  from: BrainNodeId;
@@ -393,7 +401,7 @@ export interface BrainStreamParams {
393
401
  /** Restrict events to these substrates. Default: all. */
394
402
  substrates?: BrainSubstrateName[];
395
403
  /** Restrict to these event kinds (e.g. `['node.create', 'edge.strengthen']`). */
396
- kinds?: Array<BrainStreamEvent['type']>;
404
+ kinds?: Array<BrainStreamEventWire['type']>;
397
405
  /**
398
406
  * ISO 8601 resume cursor. When set, the server replays events emitted
399
407
  * at or after `sinceTs` before tailing the live stream.
@@ -414,7 +422,7 @@ export interface BrainStreamParams {
414
422
  */
415
423
  export interface BrainStreamResult {
416
424
  /** One decoded SSE frame. */
417
- event: BrainStreamEvent;
425
+ event: BrainStreamEventWire;
418
426
  }
419
427
 
420
428
  // ============================================================================
@@ -455,7 +463,7 @@ export interface BrainBridgesParams {
455
463
  */
456
464
  export interface BrainBridgesResult {
457
465
  /** Cross-substrate edges matching the query. */
458
- bridges: BrainEdge[];
466
+ bridges: BrainEdgeWire[];
459
467
  /** Per-pair counts keyed by `"${fromSubstrate}->${toSubstrate}"`. */
460
468
  pairCounts: Record<string, number>;
461
469
  /** Total bridges returned. */
@@ -498,7 +506,7 @@ export interface BrainNeighborhoodParams {
498
506
  */
499
507
  export interface BrainNeighborhoodNode {
500
508
  /** The visited node. */
501
- node: BrainNode;
509
+ node: BrainNodeWire;
502
510
  /** BFS distance from the seed (`0` = seed itself). */
503
511
  depth: number;
504
512
  }
@@ -514,7 +522,7 @@ export interface BrainNeighborhoodResult {
514
522
  /** Nodes visited, annotated with BFS depth. */
515
523
  nodes: BrainNeighborhoodNode[];
516
524
  /** Edges traversed during expansion. */
517
- edges: BrainEdge[];
525
+ edges: BrainEdgeWire[];
518
526
  /** Maximum depth actually reached (≤ requested `hops`). */
519
527
  reachedDepth: number;
520
528
  /** True when the traversal was capped by `maxNodes`. */
@@ -554,7 +562,7 @@ export interface BrainSearchParams {
554
562
  */
555
563
  export interface BrainSearchHit {
556
564
  /** The matched node. */
557
- node: BrainNode;
565
+ node: BrainNodeWire;
558
566
  /** Normalised relevance in `[0, 1]`. Higher = better. */
559
567
  score: number;
560
568
  /** Which substrate contributed this hit. */
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Docs Domain Operations Contract (5 operations)
3
+ *
4
+ * Query operations: 3
5
+ * Mutate operations: 2
6
+ *
7
+ * Docs domain handles attachment management and document generation via `cleo docs`:
8
+ * - add — attach a local file or URL to a CLEO owner entity (task, session, observation)
9
+ * - list — list attachments for an owner entity
10
+ * - generate — generate llms.txt summary for a task/epic, optionally attach as blob
11
+ * - fetch — retrieve attachment bytes and metadata by ID or SHA-256
12
+ * - remove — remove an attachment ref; purges blob when refCount hits zero
13
+ *
14
+ * Owner type is auto-detected from the owner ID prefix:
15
+ * T### → 'task'
16
+ * ses_* → 'session'
17
+ * O-* → 'observation'
18
+ * D-* (dec_*) → 'decision'
19
+ * L-* (lrn_*) → 'learning'
20
+ * P-* (pat_*) → 'pattern'
21
+ * (default) → 'task'
22
+ *
23
+ * SYNC: Canonical implementations at packages/core/src/store/attachment*.
24
+ * Wire-format types live here; they are the API contract for CLI + HTTP dispatch.
25
+ *
26
+ * @task T980 — Orchestration Coherence v4 (contract surface completion)
27
+ * @see packages/cleo/src/dispatch/domains/docs.ts
28
+ * @see packages/contracts/src/operations/index.ts
29
+ */
30
+
31
+ // ============================================================================
32
+ // Shared Attachment Types (API wire format)
33
+ // ============================================================================
34
+
35
+ /**
36
+ * Supported attachment owner type.
37
+ *
38
+ * Inferred from owner ID prefix; controls which table attachment refs are stored in.
39
+ */
40
+ export type AttachmentOwnerType =
41
+ | 'task'
42
+ | 'session'
43
+ | 'observation'
44
+ | 'decision'
45
+ | 'learning'
46
+ | 'pattern';
47
+
48
+ /**
49
+ * Supported attachment kind (storage mode).
50
+ *
51
+ * - `local-file` — file path tracked in metadata; bytes stored in blob
52
+ * - `blob` — inline content uploaded; bytes stored in blob
53
+ * - `url` — URL-only reference; no bytes stored
54
+ * - `llms-txt` — generated content from `docs.generate --attach`
55
+ */
56
+ export type AttachmentKind = 'local-file' | 'blob' | 'url' | 'llms-txt';
57
+
58
+ /**
59
+ * Attachment metadata fragment returned by query operations.
60
+ *
61
+ * Includes kind, mime type, size (when applicable), description, and labels.
62
+ */
63
+ export interface AttachmentMetadata {
64
+ /** Attachment identifier (UUID-like string). */
65
+ id: string;
66
+ /** SHA-256 hash of content; truncated to 8 chars in list views. */
67
+ sha256: string;
68
+ /** Attachment kind / storage mode. */
69
+ kind: AttachmentKind;
70
+ /** MIME type (when applicable; omitted for url kind). */
71
+ mime?: string;
72
+ /** Content size in bytes (only for local-file and blob kinds). */
73
+ size?: number;
74
+ /** Optional human-readable description. */
75
+ description?: string;
76
+ /** Optional labels array for categorization. */
77
+ labels?: string[];
78
+ /** ISO 8601 creation timestamp. */
79
+ createdAt: string;
80
+ /** Current reference count across all owners. */
81
+ refCount: number;
82
+ }
83
+
84
+ /**
85
+ * Supported attachment backend.
86
+ *
87
+ * - `legacy` — original file-based store (.cleo/attachments)
88
+ * - `llmstxt-v2` — llmtxt-backed manifest store
89
+ */
90
+ export type AttachmentBackend = 'legacy' | 'llmstxt-v2';
91
+
92
+ /**
93
+ * Detailed attachment record with full metadata and optional byte content.
94
+ *
95
+ * Returned by `docs.fetch` operation.
96
+ */
97
+ export interface AttachmentRecord {
98
+ /** Attachment metadata. */
99
+ metadata: AttachmentMetadata;
100
+ /** File system path where bytes are stored (if applicable). */
101
+ path?: string;
102
+ /** Size in bytes. */
103
+ sizeBytes: number;
104
+ /** Base64-encoded content (only for attachments <= 1 MB). */
105
+ bytesBase64?: string;
106
+ /** True when bytesBase64 is populated. */
107
+ inlined: boolean;
108
+ }
109
+
110
+ // ============================================================================
111
+ // Query Operations
112
+ // ============================================================================
113
+
114
+ // --------------------------------------------------------------------------
115
+ // docs.list — list attachments for an owner
116
+ // --------------------------------------------------------------------------
117
+
118
+ /**
119
+ * Parameters for `docs.list`.
120
+ *
121
+ * Exactly one of `task`, `session`, or `observation` must be provided.
122
+ */
123
+ export interface DocsListParams {
124
+ /** Task identifier to list attachments for. */
125
+ task?: string;
126
+ /** Session identifier to list attachments for. */
127
+ session?: string;
128
+ /** Observation identifier to list attachments for. */
129
+ observation?: string;
130
+ }
131
+
132
+ /**
133
+ * Result of `docs.list`.
134
+ */
135
+ export interface DocsListResult {
136
+ /** Owner entity ID. */
137
+ ownerId: string;
138
+ /** Inferred owner type. */
139
+ ownerType: AttachmentOwnerType;
140
+ /** Count of attachments for this owner. */
141
+ count: number;
142
+ /** Attachment metadata array. */
143
+ attachments: AttachmentMetadata[];
144
+ /** Current attachment backend in use. */
145
+ attachmentBackend?: AttachmentBackend;
146
+ }
147
+
148
+ // --------------------------------------------------------------------------
149
+ // docs.fetch — retrieve attachment bytes and metadata by ID or SHA-256
150
+ // --------------------------------------------------------------------------
151
+
152
+ /**
153
+ * Parameters for `docs.fetch`.
154
+ */
155
+ export interface DocsFetchParams {
156
+ /** Attachment reference: attachment ID or SHA-256 hex string (required). */
157
+ attachmentRef: string;
158
+ }
159
+
160
+ /**
161
+ * Result of `docs.fetch`.
162
+ */
163
+ export interface DocsFetchResult {
164
+ /** Attachment record with metadata and optional inline bytes. */
165
+ metadata: AttachmentMetadata;
166
+ /** File system path where bytes are stored (if applicable). */
167
+ path?: string;
168
+ /** Total size in bytes. */
169
+ sizeBytes: number;
170
+ /** Base64-encoded content (only for attachments <= 1 MB). */
171
+ bytesBase64?: string;
172
+ /** True when bytesBase64 is populated. */
173
+ inlined: boolean;
174
+ /** Current attachment backend in use. */
175
+ attachmentBackend?: AttachmentBackend;
176
+ }
177
+
178
+ // --------------------------------------------------------------------------
179
+ // docs.generate — generate llms.txt summary and optionally attach
180
+ // --------------------------------------------------------------------------
181
+
182
+ /**
183
+ * Parameters for `docs.generate`.
184
+ */
185
+ export interface DocsGenerateParams {
186
+ /** Task or epic ID to generate llms.txt for (required). */
187
+ for: string;
188
+ /** When true, attach the generated content as a blob (optional). */
189
+ attach?: boolean;
190
+ }
191
+
192
+ /**
193
+ * Result of `docs.generate`.
194
+ */
195
+ export interface DocsGenerateResult {
196
+ /** ID of the task/epic that was summarized. */
197
+ forId: string;
198
+ /** Generated llms.txt content. */
199
+ content: string;
200
+ /** Count of attachments that were included in the summary. */
201
+ attachmentCount: number;
202
+ /** True when the llmtxt package was used (false = fallback). */
203
+ usedLlmtxtPackage: boolean;
204
+ /** True when --attach was specified and attachment succeeded. */
205
+ attached: boolean;
206
+ /** Attachment ID if attached (when `attached === true`). */
207
+ attachmentId?: string;
208
+ /** SHA-256 hash of attachment if attached (when `attached === true`). */
209
+ attachmentSha256?: string;
210
+ }
211
+
212
+ // ============================================================================
213
+ // Mutate Operations
214
+ // ============================================================================
215
+
216
+ // --------------------------------------------------------------------------
217
+ // docs.add — attach a local file or URL to an owner
218
+ // --------------------------------------------------------------------------
219
+
220
+ /**
221
+ * Parameters for `docs.add`.
222
+ *
223
+ * Exactly one of `file` or `url` must be provided.
224
+ */
225
+ export interface DocsAddParams {
226
+ /** Owner entity ID (task, session, observation, etc.) — required. */
227
+ ownerId: string;
228
+ /** Local file path to attach (mutually exclusive with `url`). */
229
+ file?: string;
230
+ /** URL to attach as reference (mutually exclusive with `file`). */
231
+ url?: string;
232
+ /** Optional human-readable description. */
233
+ desc?: string;
234
+ /** Optional comma-separated labels for categorization. */
235
+ labels?: string;
236
+ /** Agent or service that attached this file (default: 'human'). */
237
+ attachedBy?: string;
238
+ }
239
+
240
+ /**
241
+ * Result of `docs.add`.
242
+ */
243
+ export interface DocsAddResult {
244
+ /** Newly-created or existing attachment ID. */
245
+ attachmentId: string;
246
+ /** SHA-256 hash of the attached content. */
247
+ sha256: string;
248
+ /** Current reference count for this attachment. */
249
+ refCount: number;
250
+ /** Attachment kind that was stored. */
251
+ kind: AttachmentKind;
252
+ /** Owner entity ID. */
253
+ ownerId: string;
254
+ /** Inferred owner type. */
255
+ ownerType: AttachmentOwnerType;
256
+ /** URL if `kind === 'url'` (otherwise omitted). */
257
+ url?: string;
258
+ /** Current attachment backend in use. */
259
+ attachmentBackend?: AttachmentBackend;
260
+ }
261
+
262
+ // --------------------------------------------------------------------------
263
+ // docs.remove — remove an attachment ref
264
+ // --------------------------------------------------------------------------
265
+
266
+ /**
267
+ * Parameters for `docs.remove`.
268
+ */
269
+ export interface DocsRemoveParams {
270
+ /** Attachment reference: attachment ID or SHA-256 hex (required). */
271
+ attachmentRef: string;
272
+ /** Owner entity ID to remove the ref from (required). */
273
+ from: string;
274
+ }
275
+
276
+ /**
277
+ * Result of `docs.remove`.
278
+ */
279
+ export interface DocsRemoveResult {
280
+ /** True when the attachment blob was fully purged (refCount hit zero). */
281
+ removed: boolean;
282
+ /** Attachment ID that was dereferenced. */
283
+ attachmentId: string;
284
+ /** Owner entity ID. */
285
+ from: string;
286
+ /** Reference count after dereference (0 if blob was purged). */
287
+ refCountAfter: number;
288
+ /** True when blob was purged (duplicate of `removed` for clarity). */
289
+ blobPurged: boolean;
290
+ /** Current attachment backend in use. */
291
+ attachmentBackend?: AttachmentBackend;
292
+ }
293
+
294
+ // ============================================================================
295
+ // Discriminated Union (DocsOps)
296
+ // ============================================================================
297
+
298
+ /**
299
+ * Discriminated union of all docs domain operations.
300
+ *
301
+ * Consumed by `packages/cleo/src/dispatch/domains/docs.ts` via `TypedDomainHandler<DocsOps>`.
302
+ *
303
+ * @remarks
304
+ * Pattern: each variant specifies `op` (operation name), `params` (input),
305
+ * and `result` (output). The dispatch layer uses the `op` discriminator to
306
+ * route to the correct handler method and validate types.
307
+ */
308
+ export type DocsOps =
309
+ | { op: 'docs.list'; params: DocsListParams; result: DocsListResult }
310
+ | { op: 'docs.fetch'; params: DocsFetchParams; result: DocsFetchResult }
311
+ | { op: 'docs.generate'; params: DocsGenerateParams; result: DocsGenerateResult }
312
+ | { op: 'docs.add'; params: DocsAddParams; result: DocsAddResult }
313
+ | { op: 'docs.remove'; params: DocsRemoveParams; result: DocsRemoveResult };
314
+
315
+ /**
316
+ * Enumeration of all docs domain operation names.
317
+ *
318
+ * @remarks
319
+ * Useful for dynamic operation dispatch, type narrowing, or documentation.
320
+ * Kept in sync with the `DocsOps` discriminated union above.
321
+ */
322
+ export type DocsOp = 'docs.list' | 'docs.fetch' | 'docs.generate' | 'docs.add' | 'docs.remove';