@unrdf/kgc-runtime 26.4.2

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 (70) hide show
  1. package/IMPLEMENTATION_SUMMARY.json +150 -0
  2. package/PLUGIN_SYSTEM_SUMMARY.json +149 -0
  3. package/README.md +98 -0
  4. package/TRANSACTION_IMPLEMENTATION.json +119 -0
  5. package/capability-map.md +93 -0
  6. package/docs/api-stability.md +269 -0
  7. package/docs/extensions/plugin-development.md +382 -0
  8. package/package.json +40 -0
  9. package/plugins/registry.json +35 -0
  10. package/src/admission-gate.mjs +414 -0
  11. package/src/api-version.mjs +373 -0
  12. package/src/atomic-admission.mjs +310 -0
  13. package/src/bounds.mjs +289 -0
  14. package/src/bulkhead-manager.mjs +280 -0
  15. package/src/capsule.mjs +524 -0
  16. package/src/crdt.mjs +361 -0
  17. package/src/enhanced-bounds.mjs +614 -0
  18. package/src/executor.mjs +73 -0
  19. package/src/freeze-restore.mjs +521 -0
  20. package/src/index.mjs +62 -0
  21. package/src/materialized-views.mjs +371 -0
  22. package/src/merge.mjs +472 -0
  23. package/src/plugin-isolation.mjs +392 -0
  24. package/src/plugin-manager.mjs +441 -0
  25. package/src/projections-api.mjs +336 -0
  26. package/src/projections-cli.mjs +238 -0
  27. package/src/projections-docs.mjs +300 -0
  28. package/src/projections-ide.mjs +278 -0
  29. package/src/receipt.mjs +340 -0
  30. package/src/rollback.mjs +258 -0
  31. package/src/saga-orchestrator.mjs +355 -0
  32. package/src/schemas.mjs +1330 -0
  33. package/src/storage-optimization.mjs +359 -0
  34. package/src/tool-registry.mjs +272 -0
  35. package/src/transaction.mjs +466 -0
  36. package/src/validators.mjs +485 -0
  37. package/src/work-item.mjs +449 -0
  38. package/templates/plugin-template/README.md +58 -0
  39. package/templates/plugin-template/index.mjs +162 -0
  40. package/templates/plugin-template/plugin.json +19 -0
  41. package/test/admission-gate.test.mjs +583 -0
  42. package/test/api-version.test.mjs +74 -0
  43. package/test/atomic-admission.test.mjs +155 -0
  44. package/test/bounds.test.mjs +341 -0
  45. package/test/bulkhead-manager.test.mjs +236 -0
  46. package/test/capsule.test.mjs +625 -0
  47. package/test/crdt.test.mjs +215 -0
  48. package/test/enhanced-bounds.test.mjs +487 -0
  49. package/test/freeze-restore.test.mjs +472 -0
  50. package/test/materialized-views.test.mjs +243 -0
  51. package/test/merge.test.mjs +665 -0
  52. package/test/plugin-isolation.test.mjs +109 -0
  53. package/test/plugin-manager.test.mjs +208 -0
  54. package/test/projections-api.test.mjs +293 -0
  55. package/test/projections-cli.test.mjs +204 -0
  56. package/test/projections-docs.test.mjs +173 -0
  57. package/test/projections-ide.test.mjs +230 -0
  58. package/test/receipt.test.mjs +295 -0
  59. package/test/rollback.test.mjs +132 -0
  60. package/test/saga-orchestrator.test.mjs +279 -0
  61. package/test/schemas.test.mjs +716 -0
  62. package/test/storage-optimization.test.mjs +503 -0
  63. package/test/tool-registry.test.mjs +341 -0
  64. package/test/transaction.test.mjs +189 -0
  65. package/test/validators.test.mjs +463 -0
  66. package/test/work-item.test.mjs +548 -0
  67. package/test/work-item.test.mjs.bak +548 -0
  68. package/var/kgc/test-atomic-log.json +519 -0
  69. package/var/kgc/test-cascading-log.json +145 -0
  70. package/vitest.config.mjs +18 -0
@@ -0,0 +1,1330 @@
1
+ /**
2
+ * @file KGC Runtime Schemas - Comprehensive Zod validation for governance substrate
3
+ * @module @unrdf/kgc-runtime/schemas
4
+ *
5
+ * @description
6
+ * Type-safe Zod schemas for KGC (Knowledge Graph Computation) governance runtime:
7
+ * - Receipt: Versioned, immutable audit records with cryptographic anchoring
8
+ * - RunCapsule: Δ_run representation capturing input/output/trace/artifacts
9
+ * - ToolTraceEntry: Atomic tool call records for deterministic replay
10
+ * - Bounds: Capacity limits enforcing resource constraints
11
+ * - WorkItem: Async task node states for distributed execution
12
+ * - ProjectionManifest: Surface definitions for CLI/docs/IDE integration
13
+ * - KGCMarkdown AST: Front matter + fenced block structured documents
14
+ *
15
+ * All schemas are v1 format with strict validation and comprehensive examples.
16
+ *
17
+ * @example
18
+ * import { ReceiptSchema, RunCapsuleSchema } from '@unrdf/kgc-runtime/schemas';
19
+ *
20
+ * const receipt = ReceiptSchema.parse({
21
+ * version: '1.0.0',
22
+ * id: crypto.randomUUID(),
23
+ * timestamp: Date.now(),
24
+ * runId: 'run-001',
25
+ * actor: 'agent:orchestrator',
26
+ * action: 'execute',
27
+ * payload: { command: 'test' },
28
+ * });
29
+ */
30
+
31
+ import { z } from 'zod';
32
+
33
+ // =============================================================================
34
+ // Core Type Definitions
35
+ // =============================================================================
36
+
37
+ /**
38
+ * ISO 8601 timestamp string schema
39
+ * @constant
40
+ */
41
+ const TimestampSchema = z.coerce.date();
42
+
43
+ /**
44
+ * Semantic version schema (semver)
45
+ * @constant
46
+ */
47
+ const SemanticVersionSchema = z
48
+ .string()
49
+ .regex(/^\d+\.\d+\.\d+$/, 'Must be semantic version format (x.y.z)');
50
+
51
+ /**
52
+ * UUID v4 schema
53
+ * @constant
54
+ */
55
+ const UUIDSchema = z.string().uuid('Must be a valid UUID v4');
56
+
57
+ /**
58
+ * Content-addressable hash schema (SHA-256)
59
+ * @constant
60
+ */
61
+ const SHA256HashSchema = z
62
+ .string()
63
+ .length(64)
64
+ .regex(/^[a-f0-9]{64}$/, 'Must be a valid SHA-256 hash (64 hex chars)');
65
+
66
+ /**
67
+ * Actor identifier schema (agent:name, user:id, system:component)
68
+ * @constant
69
+ */
70
+ const ActorIdSchema = z
71
+ .string()
72
+ .regex(/^(agent|user|system):[a-zA-Z0-9_-]+$/, 'Must be formatted as type:identifier');
73
+
74
+ // =============================================================================
75
+ // Receipt Schema - Versioned Immutable Audit Records
76
+ // =============================================================================
77
+
78
+ /**
79
+ * Receipt schema for versioned, immutable audit records
80
+ *
81
+ * Captures complete execution trace with cryptographic anchoring:
82
+ * - Immutable event log (never modified, only appended)
83
+ * - Content-addressable storage (hash-based retrieval)
84
+ * - Cryptographic verification (signatures + merkle proofs)
85
+ * - Version-aware format (v1.0.0 schema)
86
+ * - Actor attribution (who executed what when)
87
+ *
88
+ * @example
89
+ * {
90
+ * version: '1.0.0',
91
+ * id: '550e8400-e29b-41d4-a716-446655440000',
92
+ * timestamp: 1703001600000,
93
+ * runId: 'run-2024-001',
94
+ * actor: 'agent:orchestrator',
95
+ * action: 'execute_workflow',
96
+ * payload: { workflowId: 'wf-001', input: { x: 42 } },
97
+ * result: { success: true, output: { y: 84 } },
98
+ * contentHash: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
99
+ * previousHash: 'a1b2c3d4...',
100
+ * signature: {
101
+ * algorithm: 'ed25519',
102
+ * publicKey: '0x1234...',
103
+ * value: '0xabcd...'
104
+ * }
105
+ * }
106
+ *
107
+ * @constant
108
+ * @type {z.ZodObject}
109
+ */
110
+ export const ReceiptSchema = z.object({
111
+ /** Schema version for forward compatibility */
112
+ version: SemanticVersionSchema.default('1.0.0'),
113
+ /** Unique receipt identifier (UUID v4) */
114
+ id: UUIDSchema,
115
+ /** Receipt creation timestamp (Unix epoch ms) */
116
+ timestamp: z.number().int().positive(),
117
+ /** Associated run/execution identifier */
118
+ runId: z.string().min(1).max(200),
119
+ /** Actor who initiated the action */
120
+ actor: ActorIdSchema,
121
+ /** Action performed (execute, validate, commit, rollback, etc.) */
122
+ action: z.enum([
123
+ 'execute',
124
+ 'validate',
125
+ 'commit',
126
+ 'rollback',
127
+ 'checkpoint',
128
+ 'snapshot',
129
+ 'merge',
130
+ 'fork',
131
+ ]),
132
+ /** Action-specific payload (flexible structure) */
133
+ payload: z.record(z.string(), z.any()),
134
+ /** Execution result (success/failure + output) */
135
+ result: z
136
+ .object({
137
+ success: z.boolean(),
138
+ output: z.any().optional(),
139
+ error: z.string().optional(),
140
+ duration: z.number().nonnegative().optional(),
141
+ })
142
+ .optional(),
143
+ /** SHA-256 hash of receipt content (for integrity) */
144
+ contentHash: SHA256HashSchema.optional(),
145
+ /** Hash of previous receipt (blockchain-style linking) */
146
+ previousHash: SHA256HashSchema.optional().nullable(),
147
+ /** Cryptographic signature for authenticity */
148
+ signature: z
149
+ .object({
150
+ algorithm: z.enum(['ed25519', 'ecdsa', 'rsa']),
151
+ publicKey: z.string().min(1),
152
+ value: z.string().min(1),
153
+ })
154
+ .optional(),
155
+ /** Merkle tree proof for batch verification */
156
+ merkleProof: z
157
+ .object({
158
+ root: SHA256HashSchema,
159
+ path: z.array(SHA256HashSchema),
160
+ index: z.number().int().nonnegative(),
161
+ })
162
+ .optional(),
163
+ /** External anchoring references (git commit, blockchain tx, etc.) */
164
+ anchors: z
165
+ .array(
166
+ z.object({
167
+ type: z.enum(['git', 'blockchain', 'timestamp', 'ipfs']),
168
+ reference: z.string().min(1),
169
+ timestamp: z.number().int().positive().optional(),
170
+ })
171
+ )
172
+ .optional(),
173
+ /** Additional metadata */
174
+ metadata: z.record(z.string(), z.any()).optional(),
175
+ });
176
+
177
+ // =============================================================================
178
+ // ToolTraceEntry Schema - Atomic Tool Call Records
179
+ // =============================================================================
180
+
181
+ /**
182
+ * Tool trace entry schema for atomic tool call records
183
+ *
184
+ * Captures individual tool invocations for:
185
+ * - Deterministic replay (recreate exact execution)
186
+ * - Debugging/audit trails (what happened when)
187
+ * - Performance profiling (tool-level metrics)
188
+ * - Causality tracking (input → output chains)
189
+ *
190
+ * @example
191
+ * {
192
+ * id: '123e4567-e89b-12d3-a456-426614174000',
193
+ * timestamp: 1703001600000,
194
+ * toolName: 'Bash',
195
+ * input: { command: 'npm test', timeout: 5000 },
196
+ * output: { stdout: '✅ All tests passed', stderr: '', exitCode: 0 },
197
+ * duration: 2314,
198
+ * status: 'success',
199
+ * parentId: 'parent-trace-001'
200
+ * }
201
+ *
202
+ * @constant
203
+ * @type {z.ZodObject}
204
+ */
205
+ export const ToolTraceEntrySchema = z.object({
206
+ /** Unique trace entry identifier */
207
+ id: UUIDSchema,
208
+ /** Tool invocation timestamp (Unix epoch ms) */
209
+ timestamp: z.number().int().positive(),
210
+ /** Tool name (Bash, Read, Write, Grep, etc.) */
211
+ toolName: z.string().min(1).max(100),
212
+ /** Tool input parameters (preserves exact call signature) */
213
+ input: z.record(z.string(), z.any()),
214
+ /** Tool output/result */
215
+ output: z.any().optional(),
216
+ /** Execution duration in milliseconds */
217
+ duration: z.number().nonnegative(),
218
+ /** Execution status */
219
+ status: z.enum(['success', 'error', 'timeout', 'cancelled']),
220
+ /** Error details if status is 'error' */
221
+ error: z
222
+ .object({
223
+ message: z.string(),
224
+ code: z.string().optional(),
225
+ stack: z.string().optional(),
226
+ })
227
+ .optional(),
228
+ /** Parent trace entry (for nested calls) */
229
+ parentId: UUIDSchema.optional().nullable(),
230
+ /** Causal dependencies (trace IDs this call depends on) */
231
+ dependencies: z.array(UUIDSchema).optional(),
232
+ /** Resource usage metrics */
233
+ resources: z
234
+ .object({
235
+ cpuTime: z.number().nonnegative().optional(),
236
+ memoryPeak: z.number().nonnegative().optional(),
237
+ ioBytes: z.number().nonnegative().optional(),
238
+ })
239
+ .optional(),
240
+ /** Metadata (tags, annotations, etc.) */
241
+ metadata: z.record(z.string(), z.any()).optional(),
242
+ });
243
+
244
+ // =============================================================================
245
+ // RunCapsule Schema - Δ_run Representation
246
+ // =============================================================================
247
+
248
+ /**
249
+ * Run capsule schema for complete execution snapshot (Δ_run)
250
+ *
251
+ * Encapsulates entire run lifecycle:
252
+ * - Input: Initial state + parameters
253
+ * - Output: Final results + artifacts
254
+ * - Trace: Execution path (tool calls, decisions)
255
+ * - Artifacts: Generated files, data, proofs
256
+ * - Provenance: Who/what/when/why attribution
257
+ *
258
+ * Enables:
259
+ * - Reproducibility: Re-execute from capsule
260
+ * - Auditing: Complete execution history
261
+ * - Caching: Reuse results for identical inputs
262
+ * - Debugging: Replay with full context
263
+ *
264
+ * @example
265
+ * {
266
+ * id: 'run-2024-12-26-001',
267
+ * version: '1.0.0',
268
+ * startTime: 1703001600000,
269
+ * endTime: 1703001620000,
270
+ * status: 'completed',
271
+ * input: {
272
+ * task: 'implement feature X',
273
+ * parameters: { timeout: 5000 },
274
+ * context: { workingDir: '/home/user/project' }
275
+ * },
276
+ * output: {
277
+ * success: true,
278
+ * results: { filesChanged: 5, testsAdded: 12 },
279
+ * artifacts: [
280
+ * { type: 'file', path: '/home/user/project/src/feature.mjs', hash: 'abc123...' }
281
+ * ]
282
+ * },
283
+ * trace: [
284
+ * { id: 'trace-001', toolName: 'Bash', input: { command: 'npm test' }, ... },
285
+ * { id: 'trace-002', toolName: 'Write', input: { file_path: '...' }, ... }
286
+ * ],
287
+ * bounds: {
288
+ * maxFiles: 100,
289
+ * maxBytes: 10485760,
290
+ * maxOps: 1000,
291
+ * maxRuntime: 300000
292
+ * },
293
+ * actor: 'agent:backend-dev',
294
+ * receipt: { id: 'receipt-001', ... }
295
+ * }
296
+ *
297
+ * @constant
298
+ * @type {z.ZodObject}
299
+ */
300
+ export const RunCapsuleSchema = z.object({
301
+ /** Unique run identifier */
302
+ id: z.string().min(1).max(200),
303
+ /** Schema version */
304
+ version: SemanticVersionSchema.default('1.0.0'),
305
+ /** Run start timestamp (Unix epoch ms) */
306
+ startTime: z.number().int().positive(),
307
+ /** Run end timestamp (Unix epoch ms, null if in progress) */
308
+ endTime: z.number().int().positive().optional().nullable(),
309
+ /** Run execution status */
310
+ status: z.enum(['pending', 'running', 'completed', 'failed', 'cancelled', 'timeout']),
311
+ /** Input specification */
312
+ input: z.object({
313
+ /** Task description/objective */
314
+ task: z.string().min(1).max(10000),
315
+ /** Execution parameters */
316
+ parameters: z.record(z.string(), z.any()).optional(),
317
+ /** Initial context (env vars, working dir, etc.) */
318
+ context: z.record(z.string(), z.any()).optional(),
319
+ /** Input artifacts/files */
320
+ artifacts: z
321
+ .array(
322
+ z.object({
323
+ type: z.enum(['file', 'directory', 'url', 'inline']),
324
+ path: z.string().optional(),
325
+ content: z.string().optional(),
326
+ hash: SHA256HashSchema.optional(),
327
+ metadata: z.record(z.string(), z.any()).optional(),
328
+ })
329
+ )
330
+ .optional(),
331
+ }),
332
+ /** Output results */
333
+ output: z
334
+ .object({
335
+ /** Whether run succeeded */
336
+ success: z.boolean(),
337
+ /** Structured results */
338
+ results: z.record(z.string(), z.any()).optional(),
339
+ /** Generated artifacts */
340
+ artifacts: z
341
+ .array(
342
+ z.object({
343
+ type: z.enum(['file', 'directory', 'url', 'inline', 'proof', 'receipt']),
344
+ path: z.string().optional(),
345
+ content: z.string().optional(),
346
+ hash: SHA256HashSchema.optional(),
347
+ size: z.number().nonnegative().optional(),
348
+ metadata: z.record(z.string(), z.any()).optional(),
349
+ })
350
+ )
351
+ .optional(),
352
+ /** Error information if failed */
353
+ error: z
354
+ .object({
355
+ message: z.string(),
356
+ code: z.string().optional(),
357
+ stack: z.string().optional(),
358
+ recoverable: z.boolean().optional(),
359
+ })
360
+ .optional(),
361
+ })
362
+ .optional(),
363
+ /** Execution trace (ordered tool calls) */
364
+ trace: z.array(ToolTraceEntrySchema).optional(),
365
+ /** Resource bounds enforced during execution */
366
+ bounds: z
367
+ .object({
368
+ maxFiles: z.number().int().positive().optional(),
369
+ maxBytes: z.number().int().positive().optional(),
370
+ maxOps: z.number().int().positive().optional(),
371
+ maxRuntime: z.number().int().positive().optional(),
372
+ maxGraphRewrites: z.number().int().positive().optional(),
373
+ })
374
+ .optional(),
375
+ /** Actor who initiated the run */
376
+ actor: ActorIdSchema,
377
+ /** Associated receipt */
378
+ receipt: ReceiptSchema.optional(),
379
+ /** Provenance chain (parent runs, dependencies) */
380
+ provenance: z
381
+ .object({
382
+ parentRunId: z.string().optional(),
383
+ dependencies: z.array(z.string()).optional(),
384
+ derivedFrom: z.array(z.string()).optional(),
385
+ })
386
+ .optional(),
387
+ /** Checkpoints for long-running tasks */
388
+ checkpoints: z
389
+ .array(
390
+ z.object({
391
+ id: UUIDSchema,
392
+ timestamp: z.number().int().positive(),
393
+ state: z.record(z.string(), z.any()),
394
+ progress: z.number().min(0).max(1).optional(),
395
+ })
396
+ )
397
+ .optional(),
398
+ /** Metadata */
399
+ metadata: z.record(z.string(), z.any()).optional(),
400
+ });
401
+
402
+ // =============================================================================
403
+ // Bounds Schema - Capacity Limits
404
+ // =============================================================================
405
+
406
+ /**
407
+ * Bounds schema for resource capacity limits
408
+ *
409
+ * Enforces governance constraints:
410
+ * - File limits: Max number of files created/modified
411
+ * - Byte limits: Max storage used
412
+ * - Operation limits: Max tool calls/graph operations
413
+ * - Runtime limits: Max execution time
414
+ * - Graph rewrite limits: Max structural changes to knowledge graph
415
+ *
416
+ * Prevents:
417
+ * - Resource exhaustion attacks
418
+ * - Runaway processes
419
+ * - Storage abuse
420
+ * - Performance degradation
421
+ *
422
+ * @example
423
+ * {
424
+ * maxFiles: 100,
425
+ * maxBytes: 10485760, // 10 MB
426
+ * maxOps: 1000,
427
+ * maxRuntime: 300000, // 5 minutes
428
+ * maxGraphRewrites: 50,
429
+ * enforcementPolicy: 'strict',
430
+ * warnings: {
431
+ * filesThreshold: 0.8,
432
+ * bytesThreshold: 0.9,
433
+ * opsThreshold: 0.75,
434
+ * runtimeThreshold: 0.9
435
+ * }
436
+ * }
437
+ *
438
+ * @constant
439
+ * @type {z.ZodObject}
440
+ */
441
+ export const BoundsSchema = z.object({
442
+ /** Maximum number of files that can be created/modified */
443
+ maxFiles: z.number().int().positive().max(10000).default(100),
444
+ /** Maximum total bytes that can be written */
445
+ maxBytes: z
446
+ .number()
447
+ .int()
448
+ .positive()
449
+ .max(1024 * 1024 * 1024)
450
+ .default(10 * 1024 * 1024), // 10 MB
451
+ /** Maximum number of operations/tool calls */
452
+ maxOps: z.number().int().positive().max(100000).default(1000),
453
+ /** Maximum runtime in milliseconds */
454
+ maxRuntime: z.number().int().positive().max(3600000).default(300000), // 5 minutes
455
+ /** Maximum graph structure rewrites */
456
+ maxGraphRewrites: z.number().int().positive().max(1000).default(50),
457
+ /** Enforcement policy */
458
+ enforcementPolicy: z.enum(['strict', 'soft', 'monitor']).default('strict'),
459
+ /** Warning thresholds (0.0-1.0 as fraction of limit) */
460
+ warnings: z
461
+ .object({
462
+ filesThreshold: z.number().min(0).max(1).default(0.8),
463
+ bytesThreshold: z.number().min(0).max(1).default(0.9),
464
+ opsThreshold: z.number().min(0).max(1).default(0.75),
465
+ runtimeThreshold: z.number().min(0).max(1).default(0.9),
466
+ graphRewritesThreshold: z.number().min(0).max(1).default(0.8),
467
+ })
468
+ .optional(),
469
+ /** Current usage (for monitoring) */
470
+ currentUsage: z
471
+ .object({
472
+ files: z.number().int().nonnegative().default(0),
473
+ bytes: z.number().int().nonnegative().default(0),
474
+ ops: z.number().int().nonnegative().default(0),
475
+ runtime: z.number().nonnegative().default(0),
476
+ graphRewrites: z.number().int().nonnegative().default(0),
477
+ })
478
+ .optional(),
479
+ /** Metadata */
480
+ metadata: z.record(z.string(), z.any()).optional(),
481
+ });
482
+
483
+ // =============================================================================
484
+ // WorkItem Schema - Async Task Node States
485
+ // =============================================================================
486
+
487
+ /**
488
+ * Work item schema for async task node states
489
+ *
490
+ * Represents distributed task execution:
491
+ * - State machine: queued → running → succeeded/failed/denied
492
+ * - Priority queue: Higher priority = earlier execution
493
+ * - Dependencies: Task dependencies graph (DAG)
494
+ * - Retries: Automatic retry with exponential backoff
495
+ * - Timeout: Per-task execution time limits
496
+ *
497
+ * State transitions:
498
+ * - queued: Waiting for execution slot
499
+ * - running: Currently executing
500
+ * - succeeded: Completed successfully
501
+ * - failed: Failed (may retry if retries remain)
502
+ * - denied: Governance policy denied execution
503
+ *
504
+ * @example
505
+ * {
506
+ * id: 'work-001',
507
+ * type: 'file_operation',
508
+ * state: 'running',
509
+ * priority: 75,
510
+ * createdAt: 1703001600000,
511
+ * startedAt: 1703001605000,
512
+ * payload: {
513
+ * operation: 'write',
514
+ * path: '/home/user/file.txt',
515
+ * content: 'Hello World'
516
+ * },
517
+ * dependencies: ['work-000'],
518
+ * retries: { max: 3, current: 0, backoff: 'exponential' },
519
+ * timeout: 30000,
520
+ * assignedTo: 'agent:worker-01'
521
+ * }
522
+ *
523
+ * @constant
524
+ * @type {z.ZodObject}
525
+ */
526
+ export const WorkItemSchema = z.object({
527
+ /** Unique work item identifier */
528
+ id: UUIDSchema,
529
+ /** Work item type/category */
530
+ type: z.string().min(1).max(100),
531
+ /** Current state */
532
+ state: z.enum(['queued', 'running', 'succeeded', 'failed', 'denied', 'cancelled']),
533
+ /** Priority (0-100, higher = more important) */
534
+ priority: z.number().int().min(0).max(100).default(50),
535
+ /** Creation timestamp (Unix epoch ms) */
536
+ createdAt: z.number().int().positive(),
537
+ /** Start timestamp (when state became 'running') */
538
+ startedAt: z.number().int().positive().optional().nullable(),
539
+ /** Completion timestamp (when state became terminal) */
540
+ completedAt: z.number().int().positive().optional().nullable(),
541
+ /** Work item payload (task-specific data) */
542
+ payload: z.record(z.string(), z.any()),
543
+ /** Work item result (populated on completion) */
544
+ result: z.any().optional(),
545
+ /** Error information if failed */
546
+ error: z
547
+ .object({
548
+ message: z.string(),
549
+ code: z.string().optional(),
550
+ stack: z.string().optional(),
551
+ retryable: z.boolean().default(true),
552
+ })
553
+ .optional(),
554
+ /** Dependency work item IDs (must complete before this can run) */
555
+ dependencies: z.array(UUIDSchema).optional(),
556
+ /** Retry configuration */
557
+ retries: z
558
+ .object({
559
+ max: z.number().int().nonnegative().max(10).default(3),
560
+ current: z.number().int().nonnegative().default(0),
561
+ backoff: z.enum(['constant', 'linear', 'exponential']).default('exponential'),
562
+ delay: z.number().int().positive().default(1000), // Base delay in ms
563
+ })
564
+ .optional(),
565
+ /** Execution timeout (milliseconds) */
566
+ timeout: z.number().int().positive().max(3600000).default(30000),
567
+ /** Agent/worker assigned to execute this work item */
568
+ assignedTo: ActorIdSchema.optional().nullable(),
569
+ /** Governance policy evaluation result */
570
+ policyEvaluation: z
571
+ .object({
572
+ allowed: z.boolean(),
573
+ reason: z.string().optional(),
574
+ constraints: z.record(z.string(), z.any()).optional(),
575
+ })
576
+ .optional(),
577
+ /** Progress tracking (0.0-1.0) */
578
+ progress: z.number().min(0).max(1).optional(),
579
+ /** Metadata */
580
+ metadata: z.record(z.string(), z.any()).optional(),
581
+ });
582
+
583
+ // =============================================================================
584
+ // ProjectionManifest Schema - Surface Definitions
585
+ // =============================================================================
586
+
587
+ /**
588
+ * Projection manifest schema for surface definitions
589
+ *
590
+ * Defines how KGC runtime projects to different surfaces:
591
+ * - CLI: Command-line interface configuration
592
+ * - Docs: Documentation generation settings
593
+ * - IDE: Editor integration (LSP, snippets, etc.)
594
+ * - API: HTTP/GraphQL endpoints
595
+ * - UI: Web dashboard configuration
596
+ *
597
+ * Enables multi-surface governance:
598
+ * - Consistent UX across interfaces
599
+ * - Auto-generated integrations
600
+ * - Policy-driven access control
601
+ * - Version-aware compatibility
602
+ *
603
+ * @example
604
+ * {
605
+ * version: '1.0.0',
606
+ * surfaces: {
607
+ * cli: {
608
+ * commands: [
609
+ * {
610
+ * name: 'run',
611
+ * description: 'Execute a workflow',
612
+ * options: [{ name: 'file', required: true, type: 'string' }]
613
+ * }
614
+ * ]
615
+ * },
616
+ * docs: {
617
+ * generator: 'typedoc',
618
+ * outputDir: './docs',
619
+ * includes: ['**\/*.mjs'],
620
+ * theme: 'default'
621
+ * },
622
+ * ide: {
623
+ * lsp: { enabled: true, port: 9000 },
624
+ * snippets: [
625
+ * { prefix: 'run', body: 'RunCapsuleSchema.parse({ ... })' }
626
+ * ]
627
+ * }
628
+ * }
629
+ * }
630
+ *
631
+ * @constant
632
+ * @type {z.ZodObject}
633
+ */
634
+ export const ProjectionManifestSchema = z.object({
635
+ /** Schema version */
636
+ version: SemanticVersionSchema.default('1.0.0'),
637
+ /** Surface definitions */
638
+ surfaces: z.object({
639
+ /** CLI surface configuration */
640
+ cli: z
641
+ .object({
642
+ commands: z
643
+ .array(
644
+ z.object({
645
+ name: z.string().min(1).max(100),
646
+ description: z.string().max(500).optional(),
647
+ aliases: z.array(z.string()).optional(),
648
+ options: z
649
+ .array(
650
+ z.object({
651
+ name: z.string().min(1),
652
+ type: z.enum(['string', 'number', 'boolean', 'array']),
653
+ required: z.boolean().default(false),
654
+ default: z.any().optional(),
655
+ description: z.string().optional(),
656
+ })
657
+ )
658
+ .optional(),
659
+ examples: z.array(z.string()).optional(),
660
+ })
661
+ )
662
+ .optional(),
663
+ globalOptions: z.record(z.string(), z.any()).optional(),
664
+ })
665
+ .optional(),
666
+ /** Documentation surface configuration */
667
+ docs: z
668
+ .object({
669
+ generator: z.enum(['typedoc', 'jsdoc', 'docusaurus', 'mkdocs']).optional(),
670
+ outputDir: z.string().default('./docs'),
671
+ includes: z.array(z.string()).optional(),
672
+ excludes: z.array(z.string()).optional(),
673
+ theme: z.string().optional(),
674
+ navigation: z
675
+ .array(
676
+ z.object({
677
+ title: z.string(),
678
+ path: z.string(),
679
+ children: z.array(z.any()).optional(),
680
+ })
681
+ )
682
+ .optional(),
683
+ })
684
+ .optional(),
685
+ /** IDE surface configuration */
686
+ ide: z
687
+ .object({
688
+ lsp: z
689
+ .object({
690
+ enabled: z.boolean().default(true),
691
+ port: z.number().int().positive().default(9000),
692
+ features: z
693
+ .array(z.enum(['completion', 'hover', 'goto', 'diagnostics', 'formatting']))
694
+ .optional(),
695
+ })
696
+ .optional(),
697
+ snippets: z
698
+ .array(
699
+ z.object({
700
+ prefix: z.string().min(1),
701
+ body: z.string().min(1),
702
+ description: z.string().optional(),
703
+ scope: z.string().optional(),
704
+ })
705
+ )
706
+ .optional(),
707
+ schemas: z
708
+ .array(
709
+ z.object({
710
+ fileMatch: z.array(z.string()),
711
+ schema: z.record(z.string(), z.any()),
712
+ })
713
+ )
714
+ .optional(),
715
+ })
716
+ .optional(),
717
+ /** API surface configuration */
718
+ api: z
719
+ .object({
720
+ type: z.enum(['rest', 'graphql', 'grpc']).default('rest'),
721
+ baseUrl: z.string().url().optional(),
722
+ endpoints: z
723
+ .array(
724
+ z.object({
725
+ path: z.string(),
726
+ method: z.enum(['GET', 'POST', 'PUT', 'DELETE', 'PATCH']).optional(),
727
+ schema: z.record(z.string(), z.any()).optional(),
728
+ auth: z.enum(['none', 'bearer', 'api-key', 'oauth2']).optional(),
729
+ })
730
+ )
731
+ .optional(),
732
+ versioning: z
733
+ .object({
734
+ strategy: z.enum(['url', 'header', 'query']),
735
+ current: z.string(),
736
+ })
737
+ .optional(),
738
+ })
739
+ .optional(),
740
+ /** UI surface configuration */
741
+ ui: z
742
+ .object({
743
+ type: z.enum(['web', 'desktop', 'mobile']).default('web'),
744
+ framework: z.string().optional(),
745
+ routes: z
746
+ .array(
747
+ z.object({
748
+ path: z.string(),
749
+ component: z.string(),
750
+ title: z.string().optional(),
751
+ })
752
+ )
753
+ .optional(),
754
+ theme: z.record(z.string(), z.any()).optional(),
755
+ })
756
+ .optional(),
757
+ }),
758
+ /** Access control per surface */
759
+ accessControl: z
760
+ .object({
761
+ default: z.enum(['allow', 'deny']).default('allow'),
762
+ rules: z
763
+ .array(
764
+ z.object({
765
+ surface: z.string(),
766
+ action: z.string(),
767
+ allowed: z.boolean(),
768
+ roles: z.array(z.string()).optional(),
769
+ })
770
+ )
771
+ .optional(),
772
+ })
773
+ .optional(),
774
+ /** Metadata */
775
+ metadata: z.record(z.string(), z.any()).optional(),
776
+ });
777
+
778
+ // =============================================================================
779
+ // KGCMarkdown AST Schema - Front Matter + Fenced Blocks
780
+ // =============================================================================
781
+
782
+ /**
783
+ * KGC Markdown AST node schema
784
+ *
785
+ * Structured representation of KGC-flavored markdown:
786
+ * - Front matter: YAML metadata block
787
+ * - Fenced blocks: Code blocks with type annotations
788
+ * - Content blocks: Prose, lists, tables
789
+ * - Semantic annotations: RDF/semantic web metadata
790
+ *
791
+ * Supports:
792
+ * - Literate programming (code + docs interleaved)
793
+ * - Executable notebooks (runnable code blocks)
794
+ * - Semantic documentation (RDF-annotated content)
795
+ * - Multi-format export (HTML, PDF, slides)
796
+ *
797
+ * @example
798
+ * {
799
+ * type: 'document',
800
+ * frontMatter: {
801
+ * title: 'KGC Example',
802
+ * version: '1.0.0',
803
+ * ontology: ['http://schema.org/']
804
+ * },
805
+ * children: [
806
+ * {
807
+ * type: 'heading',
808
+ * level: 1,
809
+ * content: 'Introduction',
810
+ * id: 'intro',
811
+ * metadata: {}
812
+ * },
813
+ * {
814
+ * type: 'fenced-block',
815
+ * language: 'javascript',
816
+ * attributes: { executable: true, output: 'inline' },
817
+ * content: 'console.log("Hello KGC");',
818
+ * metadata: { runId: 'run-001' }
819
+ * },
820
+ * {
821
+ * type: 'paragraph',
822
+ * content: 'This is a paragraph with **bold** text.',
823
+ * semanticAnnotations: [
824
+ * {
825
+ * predicate: 'http://schema.org/description',
826
+ * object: 'Introduction paragraph'
827
+ * }
828
+ * ]
829
+ * }
830
+ * ],
831
+ * metadata: {}
832
+ * }
833
+ *
834
+ * @constant
835
+ * @type {z.ZodObject}
836
+ */
837
+
838
+ // Define base node schema (all AST nodes share these properties)
839
+ const BaseASTNodeSchema = z.object({
840
+ /** Node type */
841
+ type: z.string().min(1),
842
+ /** Node metadata */
843
+ metadata: z.record(z.string(), z.any()).optional(),
844
+ });
845
+
846
+ // Recursive AST node schema (allows nested children)
847
+ const ASTNodeSchema = BaseASTNodeSchema.extend({
848
+ /** Text content (for leaf nodes) */
849
+ content: z.string().optional(),
850
+ /** Child nodes (for container nodes) */
851
+ children: z.lazy(() => z.array(ASTNodeSchema).optional()),
852
+ });
853
+
854
+ /**
855
+ * KGC Markdown document AST schema
856
+ */
857
+ export const KGCMarkdownSchema = z.object({
858
+ /** Root node type */
859
+ type: z.literal('document'),
860
+ /** Front matter (YAML metadata) */
861
+ frontMatter: z
862
+ .object({
863
+ title: z.string().max(200).optional(),
864
+ version: SemanticVersionSchema.optional(),
865
+ author: z.string().max(100).optional(),
866
+ date: TimestampSchema.optional(),
867
+ ontology: z.array(z.string().url()).optional(),
868
+ tags: z.array(z.string()).optional(),
869
+ custom: z.record(z.string(), z.any()).optional(),
870
+ })
871
+ .optional(),
872
+ /** Document child nodes */
873
+ children: z.array(
874
+ z.discriminatedUnion('type', [
875
+ // Heading node
876
+ BaseASTNodeSchema.extend({
877
+ type: z.literal('heading'),
878
+ level: z.number().int().min(1).max(6),
879
+ content: z.string().min(1),
880
+ id: z.string().optional(),
881
+ }),
882
+ // Paragraph node
883
+ BaseASTNodeSchema.extend({
884
+ type: z.literal('paragraph'),
885
+ content: z.string(),
886
+ semanticAnnotations: z
887
+ .array(
888
+ z.object({
889
+ predicate: z.string().url(),
890
+ object: z.string(),
891
+ datatype: z.string().optional(),
892
+ })
893
+ )
894
+ .optional(),
895
+ }),
896
+ // Fenced block node (code blocks)
897
+ BaseASTNodeSchema.extend({
898
+ type: z.literal('fenced-block'),
899
+ language: z.string().max(50).optional(),
900
+ attributes: z.record(z.string(), z.any()).optional(),
901
+ content: z.string(),
902
+ output: z.string().optional(),
903
+ executable: z.boolean().default(false),
904
+ }),
905
+ // List node
906
+ BaseASTNodeSchema.extend({
907
+ type: z.literal('list'),
908
+ ordered: z.boolean().default(false),
909
+ items: z.array(z.string()),
910
+ }),
911
+ // Table node
912
+ BaseASTNodeSchema.extend({
913
+ type: z.literal('table'),
914
+ headers: z.array(z.string()).optional(),
915
+ rows: z.array(z.array(z.string())),
916
+ alignment: z.array(z.enum(['left', 'center', 'right'])).optional(),
917
+ }),
918
+ // Link node
919
+ BaseASTNodeSchema.extend({
920
+ type: z.literal('link'),
921
+ url: z.string().url(),
922
+ text: z.string(),
923
+ title: z.string().optional(),
924
+ }),
925
+ // Image node
926
+ BaseASTNodeSchema.extend({
927
+ type: z.literal('image'),
928
+ url: z.string().url(),
929
+ alt: z.string().optional(),
930
+ title: z.string().optional(),
931
+ width: z.number().int().positive().optional(),
932
+ height: z.number().int().positive().optional(),
933
+ }),
934
+ // Blockquote node
935
+ BaseASTNodeSchema.extend({
936
+ type: z.literal('blockquote'),
937
+ content: z.string(),
938
+ }),
939
+ ])
940
+ ),
941
+ /** Document metadata */
942
+ metadata: z.record(z.string(), z.any()).optional(),
943
+ });
944
+
945
+ // =============================================================================
946
+ // Validation Helper Functions
947
+ // =============================================================================
948
+
949
+ /**
950
+ * Validate a receipt
951
+ * @param {any} receipt - The receipt to validate
952
+ * @returns {Object} Validation result { success, data, errors }
953
+ */
954
+ export function validateReceipt(receipt) {
955
+ try {
956
+ const validated = ReceiptSchema.parse(receipt);
957
+ return { success: true, data: validated, errors: [] };
958
+ } catch (error) {
959
+ if (error instanceof z.ZodError) {
960
+ return {
961
+ success: false,
962
+ data: null,
963
+ errors: (error.issues || error.errors || []).map(err => ({
964
+ path: err.path?.join('.') || 'unknown',
965
+ message: err.message || 'Unknown error',
966
+ code: err.code || 'unknown',
967
+ })),
968
+ };
969
+ }
970
+ throw error;
971
+ }
972
+ }
973
+
974
+ /**
975
+ * Validate a run capsule
976
+ * @param {any} capsule - The run capsule to validate
977
+ * @returns {Object} Validation result { success, data, errors }
978
+ */
979
+ export function validateRunCapsule(capsule) {
980
+ try {
981
+ const validated = RunCapsuleSchema.parse(capsule);
982
+ return { success: true, data: validated, errors: [] };
983
+ } catch (error) {
984
+ if (error instanceof z.ZodError) {
985
+ return {
986
+ success: false,
987
+ data: null,
988
+ errors: (error.issues || error.errors || []).map(err => ({
989
+ path: err.path?.join('.') || 'unknown',
990
+ message: err.message || 'Unknown error',
991
+ code: err.code || 'unknown',
992
+ })),
993
+ };
994
+ }
995
+ throw error;
996
+ }
997
+ }
998
+
999
+ /**
1000
+ * Validate a tool trace entry
1001
+ * @param {any} entry - The tool trace entry to validate
1002
+ * @returns {Object} Validation result { success, data, errors }
1003
+ */
1004
+ export function validateToolTraceEntry(entry) {
1005
+ try {
1006
+ const validated = ToolTraceEntrySchema.parse(entry);
1007
+ return { success: true, data: validated, errors: [] };
1008
+ } catch (error) {
1009
+ if (error instanceof z.ZodError) {
1010
+ return {
1011
+ success: false,
1012
+ data: null,
1013
+ errors: (error.issues || error.errors || []).map(err => ({
1014
+ path: err.path?.join('.') || 'unknown',
1015
+ message: err.message || 'Unknown error',
1016
+ code: err.code || 'unknown',
1017
+ })),
1018
+ };
1019
+ }
1020
+ throw error;
1021
+ }
1022
+ }
1023
+
1024
+ /**
1025
+ * Validate bounds
1026
+ * @param {any} bounds - The bounds to validate
1027
+ * @returns {Object} Validation result { success, data, errors }
1028
+ */
1029
+ export function validateBounds(bounds) {
1030
+ try {
1031
+ const validated = BoundsSchema.parse(bounds);
1032
+ return { success: true, data: validated, errors: [] };
1033
+ } catch (error) {
1034
+ if (error instanceof z.ZodError) {
1035
+ return {
1036
+ success: false,
1037
+ data: null,
1038
+ errors: (error.issues || error.errors || []).map(err => ({
1039
+ path: err.path?.join('.') || 'unknown',
1040
+ message: err.message || 'Unknown error',
1041
+ code: err.code || 'unknown',
1042
+ })),
1043
+ };
1044
+ }
1045
+ throw error;
1046
+ }
1047
+ }
1048
+
1049
+ /**
1050
+ * Validate a work item
1051
+ * @param {any} workItem - The work item to validate
1052
+ * @returns {Object} Validation result { success, data, errors }
1053
+ */
1054
+ export function validateWorkItem(workItem) {
1055
+ try {
1056
+ const validated = WorkItemSchema.parse(workItem);
1057
+ return { success: true, data: validated, errors: [] };
1058
+ } catch (error) {
1059
+ if (error instanceof z.ZodError) {
1060
+ return {
1061
+ success: false,
1062
+ data: null,
1063
+ errors: (error.issues || error.errors || []).map(err => ({
1064
+ path: err.path?.join('.') || 'unknown',
1065
+ message: err.message || 'Unknown error',
1066
+ code: err.code || 'unknown',
1067
+ })),
1068
+ };
1069
+ }
1070
+ throw error;
1071
+ }
1072
+ }
1073
+
1074
+ /**
1075
+ * Validate a projection manifest
1076
+ * @param {any} manifest - The projection manifest to validate
1077
+ * @returns {Object} Validation result { success, data, errors }
1078
+ */
1079
+ export function validateProjectionManifest(manifest) {
1080
+ try {
1081
+ const validated = ProjectionManifestSchema.parse(manifest);
1082
+ return { success: true, data: validated, errors: [] };
1083
+ } catch (error) {
1084
+ if (error instanceof z.ZodError) {
1085
+ return {
1086
+ success: false,
1087
+ data: null,
1088
+ errors: (error.issues || error.errors || []).map(err => ({
1089
+ path: err.path?.join('.') || 'unknown',
1090
+ message: err.message || 'Unknown error',
1091
+ code: err.code || 'unknown',
1092
+ })),
1093
+ };
1094
+ }
1095
+ throw error;
1096
+ }
1097
+ }
1098
+
1099
+ /**
1100
+ * Validate a KGC Markdown AST
1101
+ * @param {any} ast - The AST to validate
1102
+ * @returns {Object} Validation result { success, data, errors }
1103
+ */
1104
+ export function validateKGCMarkdown(ast) {
1105
+ try {
1106
+ const validated = KGCMarkdownSchema.parse(ast);
1107
+ return { success: true, data: validated, errors: [] };
1108
+ } catch (error) {
1109
+ if (error instanceof z.ZodError) {
1110
+ return {
1111
+ success: false,
1112
+ data: null,
1113
+ errors: (error.issues || error.errors || []).map(err => ({
1114
+ path: err.path?.join('.') || 'unknown',
1115
+ message: err.message || 'Unknown error',
1116
+ code: err.code || 'unknown',
1117
+ })),
1118
+ };
1119
+ }
1120
+ throw error;
1121
+ }
1122
+ }
1123
+
1124
+ // =============================================================================
1125
+ // Plugin System Schemas
1126
+ // =============================================================================
1127
+
1128
+ /**
1129
+ * Plugin manifest schema
1130
+ *
1131
+ * Defines plugin metadata, capabilities, and API requirements:
1132
+ * - Name and version (semver)
1133
+ * - Entry point and dependencies
1134
+ * - Required capabilities
1135
+ * - API version compatibility
1136
+ *
1137
+ * @example
1138
+ * {
1139
+ * name: 'custom-receipt',
1140
+ * version: '1.0.0',
1141
+ * description: 'Custom receipt type plugin',
1142
+ * entryPoint: './plugin.mjs',
1143
+ * capabilities: ['custom-receipt', 'receipt:validate'],
1144
+ * api_version: '5.0.1',
1145
+ * author: 'Plugin Developer',
1146
+ * license: 'MIT'
1147
+ * }
1148
+ *
1149
+ * @constant
1150
+ * @type {z.ZodObject}
1151
+ */
1152
+ export const PluginManifestSchema = z.object({
1153
+ /** Plugin name (unique identifier) */
1154
+ name: z.string().min(1).max(100).regex(/^[a-z0-9-]+$/),
1155
+ /** Plugin version (semver) */
1156
+ version: SemanticVersionSchema,
1157
+ /** Plugin description */
1158
+ description: z.string().max(500).optional(),
1159
+ /** Entry point module path */
1160
+ entryPoint: z.string().min(1),
1161
+ /** Required capabilities */
1162
+ capabilities: z.array(z.string()).default([]),
1163
+ /** Required API version */
1164
+ api_version: SemanticVersionSchema,
1165
+ /** Plugin author */
1166
+ author: z.string().optional(),
1167
+ /** Plugin license */
1168
+ license: z.string().optional(),
1169
+ /** Dependencies (other plugins) */
1170
+ dependencies: z.record(z.string(), z.string()).optional(),
1171
+ /** Plugin metadata */
1172
+ metadata: z.record(z.string(), z.any()).optional(),
1173
+ });
1174
+
1175
+ /**
1176
+ * Plugin state schema
1177
+ *
1178
+ * Tracks plugin lifecycle state:
1179
+ * - registered: Plugin manifest registered
1180
+ * - loaded: Plugin code loaded into memory
1181
+ * - executing: Plugin actively executing
1182
+ * - unloaded: Plugin unloaded from memory
1183
+ * - failed: Plugin failed to load/execute
1184
+ *
1185
+ * @constant
1186
+ * @type {z.ZodEnum}
1187
+ */
1188
+ export const PluginStateSchema = z.enum([
1189
+ 'registered',
1190
+ 'loaded',
1191
+ 'executing',
1192
+ 'unloaded',
1193
+ 'failed',
1194
+ ]);
1195
+
1196
+ /**
1197
+ * Plugin capability schema
1198
+ *
1199
+ * Defines capability format: "category:action"
1200
+ *
1201
+ * Examples:
1202
+ * - receipt:generate
1203
+ * - receipt:validate
1204
+ * - schema:validate
1205
+ * - custom:my-action
1206
+ *
1207
+ * @constant
1208
+ * @type {z.ZodString}
1209
+ */
1210
+ export const PluginCapabilitySchema = z
1211
+ .string()
1212
+ .regex(/^[a-z_-]+:[a-z_-]+$/, 'Must be format "category:action"');
1213
+
1214
+ /**
1215
+ * Plugin receipt schema
1216
+ *
1217
+ * Extended receipt schema for plugin-generated receipts
1218
+ * Includes plugin metadata and custom receipt types
1219
+ *
1220
+ * @example
1221
+ * {
1222
+ * version: '1.0.0',
1223
+ * id: '550e8400-e29b-41d4-a716-446655440000',
1224
+ * timestamp: 1703001600000,
1225
+ * runId: 'run-001',
1226
+ * actor: 'plugin:custom-receipt@1.0.0',
1227
+ * action: 'custom_action',
1228
+ * payload: { customData: 'value' },
1229
+ * result: { success: true },
1230
+ * pluginMetadata: {
1231
+ * pluginName: 'custom-receipt',
1232
+ * pluginVersion: '1.0.0',
1233
+ * receiptType: 'custom'
1234
+ * }
1235
+ * }
1236
+ *
1237
+ * @constant
1238
+ * @type {z.ZodObject}
1239
+ */
1240
+ export const PluginReceiptSchema = ReceiptSchema.extend({
1241
+ /** Plugin-specific metadata */
1242
+ pluginMetadata: z
1243
+ .object({
1244
+ pluginName: z.string(),
1245
+ pluginVersion: SemanticVersionSchema,
1246
+ receiptType: z.string().default('standard'),
1247
+ customFields: z.record(z.string(), z.any()).optional(),
1248
+ })
1249
+ .optional(),
1250
+ });
1251
+
1252
+ /**
1253
+ * Validate a plugin manifest
1254
+ * @param {any} manifest - The manifest to validate
1255
+ * @returns {Object} Validation result { success, data, errors }
1256
+ */
1257
+ export function validatePluginManifest(manifest) {
1258
+ try {
1259
+ const validated = PluginManifestSchema.parse(manifest);
1260
+ return { success: true, data: validated, errors: [] };
1261
+ } catch (error) {
1262
+ if (error instanceof z.ZodError) {
1263
+ return {
1264
+ success: false,
1265
+ data: null,
1266
+ errors: (error.issues || error.errors || []).map(err => ({
1267
+ path: err.path?.join('.') || 'unknown',
1268
+ message: err.message || 'Unknown error',
1269
+ code: err.code || 'unknown',
1270
+ })),
1271
+ };
1272
+ }
1273
+ throw error;
1274
+ }
1275
+ }
1276
+
1277
+ /**
1278
+ * Validate a plugin receipt
1279
+ * @param {any} receipt - The receipt to validate
1280
+ * @returns {Object} Validation result { success, data, errors }
1281
+ */
1282
+ export function validatePluginReceipt(receipt) {
1283
+ try {
1284
+ const validated = PluginReceiptSchema.parse(receipt);
1285
+ return { success: true, data: validated, errors: [] };
1286
+ } catch (error) {
1287
+ if (error instanceof z.ZodError) {
1288
+ return {
1289
+ success: false,
1290
+ data: null,
1291
+ errors: (error.issues || error.errors || []).map(err => ({
1292
+ path: err.path?.join('.') || 'unknown',
1293
+ message: err.message || 'Unknown error',
1294
+ code: err.code || 'unknown',
1295
+ })),
1296
+ };
1297
+ }
1298
+ throw error;
1299
+ }
1300
+ }
1301
+
1302
+ // =============================================================================
1303
+ // Module Exports
1304
+ // =============================================================================
1305
+
1306
+ export default {
1307
+ // Schemas
1308
+ ReceiptSchema,
1309
+ RunCapsuleSchema,
1310
+ ToolTraceEntrySchema,
1311
+ BoundsSchema,
1312
+ WorkItemSchema,
1313
+ ProjectionManifestSchema,
1314
+ KGCMarkdownSchema,
1315
+ PluginManifestSchema,
1316
+ PluginStateSchema,
1317
+ PluginCapabilitySchema,
1318
+ PluginReceiptSchema,
1319
+
1320
+ // Validation functions
1321
+ validateReceipt,
1322
+ validateRunCapsule,
1323
+ validateToolTraceEntry,
1324
+ validateBounds,
1325
+ validateWorkItem,
1326
+ validateProjectionManifest,
1327
+ validateKGCMarkdown,
1328
+ validatePluginManifest,
1329
+ validatePluginReceipt,
1330
+ };