@agentskit/doc-bridge 1.4.1 → 1.5.0

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 (42) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/action.yml +1 -1
  3. package/dist/cli/program.js +2461 -274
  4. package/dist/cli/program.js.map +1 -1
  5. package/dist/config/index.d.ts +1 -1
  6. package/dist/config/index.js +77 -4
  7. package/dist/config/index.js.map +1 -1
  8. package/dist/{index-DAeq_OIi.d.ts → index-Di7PkJuf.d.ts} +209 -8
  9. package/dist/index.d.ts +1942 -4
  10. package/dist/index.js +2190 -193
  11. package/dist/index.js.map +1 -1
  12. package/docs/PRD-doc-bridge-knowledge-engine.md +338 -0
  13. package/docs/knowledge-engine-runbook.md +44 -0
  14. package/ecosystem-claims.json +19 -19
  15. package/ecosystem-upstream.json +2 -2
  16. package/ecosystem.json +117 -109
  17. package/mcpb/manifest.json +25 -1
  18. package/package.json +2 -2
  19. package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
  20. package/src/agents/registry-adapter.ts +97 -0
  21. package/src/cli/program.ts +285 -3
  22. package/src/config/defaults.ts +14 -1
  23. package/src/config/schema.ts +69 -0
  24. package/src/conformance/ecosystem-contract.ts +6 -3
  25. package/src/discovery/documentation.ts +320 -0
  26. package/src/discovery/repository.ts +514 -0
  27. package/src/fixes/proposals.ts +165 -0
  28. package/src/index-builder/content-hash.ts +9 -2
  29. package/src/index-builder/human-adapters/plain-markdown.ts +17 -1
  30. package/src/index-builder/llms-txt.ts +22 -2
  31. package/src/index-builder/scan-corpus.ts +17 -1
  32. package/src/index.ts +99 -2
  33. package/src/mcp/server.ts +178 -8
  34. package/src/reconciliation/reconcile.ts +227 -0
  35. package/src/report/html.ts +74 -0
  36. package/src/rules/engine.ts +180 -0
  37. package/src/safety/repository.ts +84 -0
  38. package/src/schemas/knowledge.ts +315 -0
  39. package/src/validate.ts +24 -0
  40. package/src/version.ts +1 -1
  41. package/src/workflow/engine.ts +238 -0
  42. package/tsup.config.ts +2 -1
package/ecosystem.json CHANGED
@@ -1,13 +1,22 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "$comment": "Canonical registry of AgentsKit ecosystem products. Stable identity lives in products[] (seven). Numeric values live in the generated ecosystem-claims ledger. The properties array is the full seven-product v1 projection of products[] (same order) for sibling consumers.",
3
+ "$comment": "Canonical registry of AgentsKit ecosystem products. Stable identity lives in products[] (seven). Numeric values live in the generated ecosystem-claims ledger. The deprecated properties array remains a v1 four-product shim for Doc Bridge / sibling consumers until those schemas accept the full seven-product set \u2014 do not treat properties as the product catalog.",
4
4
  "parentBrand": {
5
5
  "id": "agentskit",
6
6
  "name": "AgentsKit"
7
7
  },
8
+ "positioning": {
9
+ "canonicalDescription": "AgentsKit is the open-source TypeScript ecosystem for building production AI agents without locking application architecture to a model provider, framework, database, or hosted platform.",
10
+ "metaDescription": "Open-source TypeScript ecosystem for production AI agents. Swap models, providers, tools, memory, RAG, and interfaces without architectural lock-in.",
11
+ "commercialBoundary": "AgentsKit, Chat, Registry, Playbook, Doc Bridge, and Code Review are free and open source. AKOS is the optional paid managed control plane for teams that need enterprise operations, governance, and infrastructure.",
12
+ "openSourceProductIds": ["agentskit", "registry", "agentskit-chat", "playbook", "doc-bridge", "code-review"],
13
+ "managedProductIds": ["akos"]
14
+ },
8
15
  "products": [
9
16
  {
10
17
  "id": "agentskit",
18
+ "public": true,
19
+ "distributionClass": "open-source",
11
20
  "name": "AgentsKit",
12
21
  "shortName": "AgentsKit",
13
22
  "kind": "library",
@@ -16,6 +25,34 @@
16
25
  "maturity": "beta",
17
26
  "repo": "AgentsKit-io/agentskit",
18
27
  "accent": "#2EA043",
28
+ "metadata": {
29
+ "alternateName": "AgentsKit.js",
30
+ "description": "A free, MIT-licensed TypeScript ecosystem for production AI agents with replaceable contracts for models, runtimes, tools, memory, RAG, observability, sandboxing, evaluation, and interfaces.",
31
+ "dateCreated": "2026-04-02",
32
+ "applicationCategory": "DeveloperApplication",
33
+ "runtimePlatform": "JavaScript runtimes supporting ES2022",
34
+ "license": "MIT",
35
+ "author": {
36
+ "givenName": "Emerson",
37
+ "familyName": "Braun",
38
+ "url": "https://github.com/EmersonBraun"
39
+ },
40
+ "keywords": [
41
+ "AI agents",
42
+ "agent framework",
43
+ "TypeScript",
44
+ "JavaScript",
45
+ "LLM",
46
+ "multi-agent",
47
+ "tools",
48
+ "memory",
49
+ "RAG",
50
+ "observability",
51
+ "sandboxing",
52
+ "evaluation",
53
+ "MCP"
54
+ ]
55
+ },
19
56
  "showcase": {
20
57
  "claimSource": {
21
58
  "url": "https://www.agentskit.io/api/stats.json",
@@ -30,20 +67,19 @@
30
67
  "stage": "Build",
31
68
  "headline": "One foundation. Every layer stays yours.",
32
69
  "detail": "Compose runtime, adapters, tools, memory, RAG, and UI without glue code or lock-in.",
33
- "proof": "{{packages}} packages · <{{core-size-kb-gzip}} KB core",
70
+ "proof": "22 packages · 10 KB core budget",
34
71
  "sales": {
35
72
  "kind": "integration-stack",
36
73
  "headline": "Swap the stack. Keep the agent.",
37
74
  "metrics": [
38
- { "value": "{{catalog-providers}}", "label": "providers" },
39
- { "value": "{{native-adapters}}", "label": "adapters" },
40
- { "value": "{{integrations}}", "label": "integrations" }
75
+ { "value": "140+", "label": "providers" },
76
+ { "value": "25", "label": "adapters" },
77
+ { "value": "50", "label": "integrations" }
41
78
  ],
42
79
  "capabilities": ["Tools", "RAG", "Memory", "MCP"],
43
80
  "steps": ["Choose any adapter", "Add tools and memory", "Ship without rewrites"]
44
81
  },
45
- "cta": "Build with AgentsKit",
46
- "ctaSurface": "docs"
82
+ "cta": "Build with AgentsKit"
47
83
  },
48
84
  "surfaces": {
49
85
  "home": "https://www.agentskit.io",
@@ -68,6 +104,8 @@
68
104
  },
69
105
  {
70
106
  "id": "registry",
107
+ "public": true,
108
+ "distributionClass": "open-source",
71
109
  "name": "AgentsKit Registry",
72
110
  "shortName": "Registry",
73
111
  "kind": "registry",
@@ -90,15 +128,14 @@
90
128
  "proof": "Ready-made · source-owned",
91
129
  "sales": {
92
130
  "kind": "registry-install",
93
- "headline": "Ready-to-use agents from the live Registry.",
94
- "metric": "{{agents}}",
95
- "metricLabel": "shadcn-like agents",
96
- "capabilities": ["Research", "Support", "Coding", "Data", "Marketing", "{{remaining-categories}} additional categories"],
131
+ "headline": "Source-owned agents for your project.",
132
+ "metric": "Source-owned",
133
+ "metricLabel": "agent code",
134
+ "capabilities": ["Ready-made agents", "Source ownership", "CLI installation"],
97
135
  "steps": ["Find the right agent", "Run npx agentskit add", "Own every line"],
98
136
  "command": "npx agentskit add research"
99
137
  },
100
- "cta": "Explore the Registry",
101
- "ctaSurface": "home"
138
+ "cta": "Explore the Registry"
102
139
  },
103
140
  "surfaces": {
104
141
  "home": "https://registry.agentskit.io",
@@ -123,6 +160,8 @@
123
160
  },
124
161
  {
125
162
  "id": "agentskit-chat",
163
+ "public": true,
164
+ "distributionClass": "open-source",
126
165
  "name": "AgentsKit Chat",
127
166
  "shortName": "Chat",
128
167
  "kind": "framework",
@@ -134,24 +173,22 @@
134
173
  "showcase": {
135
174
  "stage": "Deliver",
136
175
  "headline": "One agent. Every conversation surface.",
137
- "detail": "Define the experience once and deliver it across web, desktop, CLI, and mobile.",
138
- "proof": "Web · Desktop · CLI · Mobile",
176
+ "detail": "Define the experience once and connect the conversation surface that fits the product.",
177
+ "proof": "Human ↔ agent · shared experience",
139
178
  "sales": {
140
179
  "kind": "human-agent",
141
180
  "headline": "Human ↔ agent. Without losing control.",
142
- "metric": "4",
143
- "metricLabel": "surfaces · one conversation",
181
+ "metric": "One",
182
+ "metricLabel": "agent experience",
144
183
  "logos": [
145
- { "id": "web", "label": "Web" },
146
- { "id": "desktop", "label": "Desktop" },
147
- { "id": "cli", "label": "CLI" },
148
- { "id": "mobile", "label": "Mobile" }
184
+ { "id": "human", "label": "Human" },
185
+ { "id": "agent", "label": "Agent" },
186
+ { "id": "tools", "label": "Tools" }
149
187
  ],
150
- "capabilities": ["Streaming", "Approvals", "Tool results", "Shared state"],
151
- "steps": ["Agent requests a protected action", "Human approves", "The conversation continues everywhere"]
188
+ "capabilities": ["Conversation", "Human control", "Tool results"],
189
+ "steps": ["Define the agent experience", "Connect the conversation surface", "Keep the human in control"]
152
190
  },
153
- "cta": "Explore AgentsKit Chat",
154
- "ctaSurface": "home"
191
+ "cta": "Explore AgentsKit Chat"
155
192
  },
156
193
  "surfaces": {
157
194
  "home": "https://chat.agentskit.io",
@@ -175,19 +212,21 @@
175
212
  },
176
213
  {
177
214
  "id": "playbook",
215
+ "public": true,
216
+ "distributionClass": "open-source",
178
217
  "name": "Agents Playbook",
179
218
  "shortName": "Playbook",
180
219
  "kind": "methodology",
181
220
  "role": "discipline",
182
- "promise": "Train coding agents to ship code your team would merge.",
221
+ "promise": "Make agents ship code a human would actually merge.",
183
222
  "maturity": "stable",
184
223
  "repo": "AgentsKit-io/agents-playbook",
185
224
  "accent": "#8B5CF6",
186
225
  "showcase": {
187
226
  "stage": "Standardize",
188
- "headline": "The open engineering harness for coding agents.",
189
- "detail": "Open rules, prompts, memory, evals, and executable gates turn every correction into behavior coding agents can repeat.",
190
- "proof": "Train the behavior · not the model",
227
+ "headline": "Engineering standards agents can execute.",
228
+ "detail": "Turn repeatable practices into guidance that coding agents can follow in every repository.",
229
+ "proof": "Convention → executable guidance",
191
230
  "sales": {
192
231
  "kind": "standards-flow",
193
232
  "headline": "Your standards. Every agent. Every repository.",
@@ -202,8 +241,7 @@
202
241
  "capabilities": ["Repository rules", "Review criteria", "Agent guidance", "Team conventions"],
203
242
  "steps": ["Define the standard once", "Agents receive executable guidance", "Review consistent output"]
204
243
  },
205
- "cta": "Explore the harness",
206
- "ctaSurface": "home"
244
+ "cta": "Explore the Playbook"
207
245
  },
208
246
  "surfaces": {
209
247
  "home": "https://playbook.agentskit.io",
@@ -228,6 +266,8 @@
228
266
  },
229
267
  {
230
268
  "id": "doc-bridge",
269
+ "public": true,
270
+ "distributionClass": "open-source",
231
271
  "name": "Doc Bridge",
232
272
  "shortName": "Doc Bridge",
233
273
  "kind": "developer-tool",
@@ -255,8 +295,7 @@
255
295
  "capabilities": ["ADRs", "Handoffs", "Agent findings", "Human-readable docs"],
256
296
  "steps": ["Humans document decisions", "Agents receive precise context", "Agent findings return to humans"]
257
297
  },
258
- "cta": "Generate your first handoff",
259
- "ctaSurface": "home"
298
+ "cta": "Explore Doc Bridge"
260
299
  },
261
300
  "surfaces": {
262
301
  "home": "https://doc-bridge.agentskit.io/",
@@ -280,6 +319,8 @@
280
319
  },
281
320
  {
282
321
  "id": "code-review",
322
+ "public": true,
323
+ "distributionClass": "open-source",
283
324
  "name": "AgentsKit Code Review",
284
325
  "shortName": "Code Review",
285
326
  "kind": "developer-tool",
@@ -310,35 +351,38 @@
310
351
  },
311
352
  {
312
353
  "id": "akos",
313
- "name": "AgentsKit OS",
354
+ "public": false,
355
+ "distributionClass": "managed-service",
356
+ "accessModel": "paid-managed-service",
357
+ "aliases": ["AgentsKit OS"],
358
+ "name": "AKOS",
314
359
  "shortName": "AKOS",
315
- "kind": "product",
360
+ "kind": "managed-service",
316
361
  "role": "operation",
317
- "promise": "Run and govern agents in production.",
362
+ "promise": "Add optional managed operations when production governance calls for it.",
318
363
  "maturity": "stable",
319
- "repo": "AgentsKit-io/agentskit-os",
364
+ "repo": null,
365
+ "distributionPolicy": "Public commercial references only; never use private implementation as contribution evidence.",
320
366
  "accent": "#34D399",
321
367
  "showcase": {
322
368
  "stage": "Operate",
323
- "headline": "Run and govern agents in production.",
324
- "detail": "Add orchestration, governance, and operational control when your system needs it.",
325
- "proof": "Orchestration · governance · control",
369
+ "headline": "Optional managed operations for agents.",
370
+ "detail": "A managed layer for teams that need additional operational controls. AgentsKit can be used without it.",
371
+ "proof": "Optional · managed operations",
326
372
  "sales": {
327
373
  "kind": "enterprise-control",
328
- "headline": "The enterprise control plane for agents.",
329
- "metric": "Enterprise",
330
- "metricLabel": "operations and governance",
374
+ "headline": "Managed operations for production agents.",
375
+ "metric": "Optional",
376
+ "metricLabel": "managed layer",
331
377
  "logos": [
332
- { "id": "logs", "label": "Logs" },
333
- { "id": "approvals", "label": "Approvals" },
334
- { "id": "rbac", "label": "RBAC" },
335
- { "id": "policies", "label": "Policies" }
378
+ { "id": "managed", "label": "Managed" },
379
+ { "id": "optional", "label": "Optional" },
380
+ { "id": "operations", "label": "Operations" }
336
381
  ],
337
- "capabilities": ["Logs", "Approvals", "RBAC", "Policies", "Tracing", "Costs"],
338
- "steps": ["Agent requests a protected action", "RBAC and policy gates evaluate", "Human approves; logs and trace persist"]
382
+ "capabilities": ["Managed operations", "Production support", "Optional adoption"],
383
+ "steps": ["Assess the operational need", "Evaluate the managed layer", "Adopt it only when it fits"]
339
384
  },
340
- "cta": "Explore AgentsKit OS",
341
- "ctaSurface": "home"
385
+ "cta": "Evaluate managed operations"
342
386
  },
343
387
  "surfaces": {
344
388
  "home": "https://akos.agentskit.io",
@@ -369,29 +413,16 @@
369
413
  "stats": "https://www.agentskit.io/api/stats.json"
370
414
  },
371
415
  {
372
- "id": "registry",
373
- "name": "AgentsKit Registry",
374
- "barLabel": "Registry",
375
- "domain": "registry.agentskit.io",
376
- "url": "https://registry.agentskit.io",
377
- "repo": "AgentsKit-io/agentskit-registry",
378
- "tagline": "Copy ready-made agents and own the source.",
379
- "kind": "registry",
380
- "accent": "#58A6FF",
381
- "llms": "https://registry.agentskit.io/llms.txt",
382
- "stats": "https://registry.agentskit.io/r/index.json"
383
- },
384
- {
385
- "id": "agentskit-chat",
386
- "name": "AgentsKit Chat",
387
- "barLabel": "Chat",
388
- "domain": "chat.agentskit.io",
389
- "url": "https://chat.agentskit.io",
390
- "repo": "AgentsKit-io/agentskit-chat",
391
- "tagline": "Define one agent experience and deliver it across interfaces.",
392
- "kind": "framework",
393
- "accent": "#F59E0B",
394
- "llms": "https://chat.agentskit.io/llms.txt"
416
+ "id": "akos",
417
+ "name": "AKOS",
418
+ "barLabel": "AKOS",
419
+ "domain": "akos.agentskit.io",
420
+ "url": "https://akos.agentskit.io",
421
+ "repo": null,
422
+ "tagline": "Add optional managed operations when production governance calls for it.",
423
+ "kind": "managed-service",
424
+ "accent": "#34D399",
425
+ "llms": "https://akos.agentskit.io/llms.txt"
395
426
  },
396
427
  {
397
428
  "id": "playbook",
@@ -400,47 +431,24 @@
400
431
  "domain": "playbook.agentskit.io",
401
432
  "url": "https://playbook.agentskit.io",
402
433
  "repo": "AgentsKit-io/agents-playbook",
403
- "tagline": "Train coding agents to ship code your team would merge.",
434
+ "tagline": "Make agents ship code a human would actually merge.",
404
435
  "kind": "methodology",
405
436
  "accent": "#8B5CF6",
406
437
  "llms": "https://playbook.agentskit.io/llms.txt",
407
438
  "stats": "https://playbook.agentskit.io/api/stats.json"
408
439
  },
409
440
  {
410
- "id": "doc-bridge",
411
- "name": "Doc Bridge",
412
- "barLabel": "Doc Bridge",
413
- "domain": "doc-bridge.agentskit.io",
414
- "url": "https://doc-bridge.agentskit.io/",
415
- "repo": "AgentsKit-io/doc-bridge",
416
- "tagline": "Turn repository documentation into executable agent handoffs.",
417
- "kind": "developer-tool",
418
- "accent": "#06B6D4",
419
- "llms": "https://doc-bridge.agentskit.io/llms.txt"
420
- },
421
- {
422
- "id": "code-review",
423
- "name": "AgentsKit Code Review",
424
- "barLabel": "Code Review",
425
- "domain": "github.com",
426
- "url": "https://github.com/AgentsKit-io/code-review-cli",
427
- "repo": "AgentsKit-io/code-review-cli",
428
- "tagline": "Run deep, low-noise review with the model already in use.",
429
- "kind": "developer-tool",
430
- "accent": "#F97316",
431
- "llms": "https://raw.githubusercontent.com/AgentsKit-io/code-review-cli/main/llms.txt"
432
- },
433
- {
434
- "id": "akos",
435
- "name": "AgentsKit OS",
436
- "barLabel": "AKOS",
437
- "domain": "akos.agentskit.io",
438
- "url": "https://akos.agentskit.io",
439
- "repo": "AgentsKit-io/agentskit-os",
440
- "tagline": "Run and govern agents in production.",
441
- "kind": "product",
442
- "accent": "#34D399",
443
- "llms": "https://akos.agentskit.io/llms.txt"
441
+ "id": "registry",
442
+ "name": "AgentsKit Registry",
443
+ "barLabel": "Registry",
444
+ "domain": "registry.agentskit.io",
445
+ "url": "https://registry.agentskit.io",
446
+ "repo": "AgentsKit-io/agentskit-registry",
447
+ "tagline": "Copy ready-made agents and own the source.",
448
+ "kind": "registry",
449
+ "accent": "#58A6FF",
450
+ "llms": "https://registry.agentskit.io/llms.txt",
451
+ "stats": "https://registry.agentskit.io/r/index.json"
444
452
  }
445
453
  ],
446
454
  "builder": {
@@ -2,7 +2,7 @@
2
2
  "manifest_version": "0.3",
3
3
  "name": "doc-bridge",
4
4
  "display_name": "Doc Bridge",
5
- "version": "1.4.1",
5
+ "version": "1.5.0",
6
6
  "description": "Deterministic repository handoffs for coding agents, running locally without an LLM or API key.",
7
7
  "long_description": "Doc Bridge turns a repository's own documentation and ownership metadata into deterministic handoffs: where an agent should start, which paths it may edit, which checks it must run, and when a human must take over. The local connector exposes the same read-only contract available through Doc Bridge CLI and CI.",
8
8
  "author": {
@@ -63,6 +63,30 @@
63
63
  {
64
64
  "name": "registry.topology",
65
65
  "description": "Return the static Doc Bridge curator and delegate topology."
66
+ },
67
+ {
68
+ "name": "docbridge.snapshot",
69
+ "description": "Read the latest discovery snapshot from the resumable workflow."
70
+ },
71
+ {
72
+ "name": "docbridge.report",
73
+ "description": "Read the latest reconciliation report from the resumable workflow."
74
+ },
75
+ {
76
+ "name": "docbridge.diagnostics",
77
+ "description": "Read reconciliation diagnostics from the latest workflow report."
78
+ },
79
+ {
80
+ "name": "docbridge.relations",
81
+ "description": "Read bounded architecture relations from the latest workflow snapshot."
82
+ },
83
+ {
84
+ "name": "docbridge.run",
85
+ "description": "Read the latest resumable Doc Bridge workflow state."
86
+ },
87
+ {
88
+ "name": "docbridge.proposals",
89
+ "description": "Create, inspect, approve, and apply human-gated Doc Bridge proposals."
66
90
  }
67
91
  ],
68
92
  "tools_generated": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentskit/doc-bridge",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "mcpName": "io.github.AgentsKit-io/doc-bridge",
5
5
  "description": "Human↔agent documentation bridge — deterministic handoffs, doc-site links, memory→docs, optional AgentsKit RAG/chat.",
6
6
  "type": "module",
@@ -117,6 +117,7 @@
117
117
  "github-slugger": "^2.0.0",
118
118
  "mermaid": "^11.16.1",
119
119
  "minimatch": "^10.2.6",
120
+ "typescript": "^6.0.3",
120
121
  "zod": "^3.24.2"
121
122
  },
122
123
  "peerDependencies": {
@@ -171,7 +172,6 @@
171
172
  "react-dom": "19.2.0",
172
173
  "tailwindcss": "4.3.2",
173
174
  "tsup": "^8.5.0",
174
- "typescript": "^6.0.3",
175
175
  "vitest": "^4.1.9"
176
176
  },
177
177
  "directories": {
@@ -3,7 +3,7 @@
3
3
  import { spawnSync } from 'node:child_process'
4
4
  import { isAbsolute } from 'node:path'
5
5
 
6
- const VERSION = '1.4.1'
6
+ const VERSION = '1.5.0'
7
7
  const kinds = new Set(['package', 'ownership'])
8
8
  const args = process.argv.slice(2)
9
9
  const id = args[0]
@@ -0,0 +1,97 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'
2
+ import { join, resolve } from 'node:path'
3
+ import { pathToFileURL } from 'node:url'
4
+ import { z } from 'zod'
5
+
6
+ import type { DocBridgeConfigV1 } from '../config/schema.js'
7
+ import { AgentProposalV1Schema, type AgentProposalV1, type DiscoverySnapshotV1, type ReconciliationReportV1 } from '../schemas/knowledge.js'
8
+ import { contentHashForArtifactV1 } from '../index-builder/content-hash.js'
9
+ import { containedPath, redactValue } from '../safety/repository.js'
10
+
11
+ export const DEFAULT_REGISTRY_AGENT_ID = 'ecosystem-doc-bridge-corpus-scanner'
12
+
13
+ const RegistryAgentMetadataSchema = z.object({
14
+ id: z.string().min(1).max(256),
15
+ version: z.string().min(1).max(64),
16
+ provider: z.string().min(1).max(128).optional(),
17
+ model: z.string().min(1).max(256).optional(),
18
+ capabilities: z.array(z.string().min(1).max(128)).max(32).default([]),
19
+ }).strict()
20
+
21
+ export type RegistryAgentMetadata = z.infer<typeof RegistryAgentMetadataSchema> & { readonly root: string }
22
+
23
+ export type RegistryAgentContext = {
24
+ readonly snapshot: DiscoverySnapshotV1
25
+ readonly report: ReconciliationReportV1
26
+ readonly evidence: readonly ReconciliationReportV1['diagnostics'][number]['evidence'][number][]
27
+ readonly capabilities: readonly ['snapshot.read', 'evidence.read', 'proposal.write']
28
+ readonly network: false
29
+ readonly shell: false
30
+ }
31
+
32
+ export type RegistryAgentRunner = (context: RegistryAgentContext) => Promise<unknown> | unknown
33
+
34
+ export type RegistryAgentAdapter = {
35
+ readonly metadata: RegistryAgentMetadata
36
+ readonly run: (snapshot: DiscoverySnapshotV1, report: ReconciliationReportV1, evidence?: readonly RegistryAgentContext['evidence'][number][]) => Promise<AgentProposalV1>
37
+ }
38
+
39
+ const deepFreeze = <T>(value: T): T => {
40
+ if (value && typeof value === 'object' && !Object.isFrozen(value)) {
41
+ Object.freeze(value)
42
+ for (const child of Object.values(value as Record<string, unknown>)) deepFreeze(child)
43
+ }
44
+ return value
45
+ }
46
+
47
+ const registryConfig = (config: DocBridgeConfigV1) => config.intelligence?.registry
48
+
49
+ export const loadRegistryAgentRunner = async (root: string, config: DocBridgeConfigV1): Promise<RegistryAgentRunner> => {
50
+ const metadata = loadRegistryAgentMetadata(root, config)
51
+ const configured = registryConfig(config)?.runnerModule
52
+ const modulePath = configured ? containedPath(root, configured) : containedPath(root, join(metadata.root, 'doc-bridge-adapter.js'))
53
+ if (!modulePath || !existsSync(modulePath)) throw new Error(`Registry agent "${metadata.id}" has no local runner module. Configure intelligence.registry.runnerModule or add doc-bridge-adapter.js to the installed agent.`)
54
+ const loaded = await import(pathToFileURL(modulePath).href) as { default?: unknown; run?: unknown }
55
+ const runner = typeof loaded.run === 'function' ? loaded.run : typeof loaded.default === 'function' ? loaded.default : loaded.default && typeof loaded.default === 'object' && 'run' in loaded.default && typeof loaded.default.run === 'function' ? loaded.default.run : undefined
56
+ if (!runner) throw new Error(`Registry agent runner at ${modulePath} must export a function or { run }. `)
57
+ return runner as RegistryAgentRunner
58
+ }
59
+
60
+ export const loadRegistryAgentMetadata = (root: string, config: DocBridgeConfigV1): RegistryAgentMetadata => {
61
+ const settings = registryConfig(config)
62
+ const id = settings?.agentId ?? DEFAULT_REGISTRY_AGENT_ID
63
+ const agentRoot = settings?.agentRoot ?? 'agents'
64
+ const agentPath = containedPath(root, join(agentRoot, id))
65
+ if (!agentPath || !existsSync(agentPath)) throw new Error(`AgentsKit Registry agent "${id}" is not installed at ${join(agentRoot, id)}. Install it with: npx agentskit add ${id}`)
66
+ const metadataPath = [join(agentPath, 'agent.json'), join(agentPath, 'manifest.json')].find(existsSync)
67
+ if (!metadataPath) throw new Error(`Registry agent "${id}" is installed but has no agent.json or manifest.json metadata.`)
68
+ const metadata = RegistryAgentMetadataSchema.parse(JSON.parse(readFileSync(metadataPath, 'utf8')) as unknown)
69
+ if (metadata.id !== id) throw new Error(`Installed Registry agent metadata id "${metadata.id}" does not match configured id "${id}".`)
70
+ return { ...metadata, root: agentPath }
71
+ }
72
+
73
+ export const createRegistryAgentAdapter = (root: string, config: DocBridgeConfigV1, runner: RegistryAgentRunner): RegistryAgentAdapter => {
74
+ if (!registryConfig(config)?.enabled) throw new Error('Registry agents are disabled. Set intelligence.registry.enabled: true to run an assisted workflow.')
75
+ const metadata = loadRegistryAgentMetadata(resolve(root), config)
76
+ return {
77
+ metadata,
78
+ run: async (snapshot, report, evidence = report.diagnostics.flatMap((diagnostic) => diagnostic.evidence).slice(0, 64)) => {
79
+ const context = deepFreeze({ snapshot: redactValue(snapshot), report: redactValue(report), evidence: redactValue(evidence), capabilities: ['snapshot.read', 'evidence.read', 'proposal.write'] as const, network: false as const, shell: false as const }) as RegistryAgentContext
80
+ const proposal = AgentProposalV1Schema.parse(await runner(context))
81
+ if (proposal.contentHash !== contentHashForArtifactV1(proposal)) throw new Error('Registry agent proposal contentHash does not match its canonical contents.')
82
+ if (proposal.baseSnapshotHash !== snapshot.contentHash || proposal.baseReportHash !== report.contentHash) throw new Error('Registry agent proposal is not based on the supplied snapshot/report hashes.')
83
+ if (proposal.origin.kind !== 'registry-agent' || proposal.origin.id !== metadata.id) throw new Error(`Registry agent proposal origin must be ${metadata.id}.`)
84
+ return proposal
85
+ },
86
+ }
87
+ }
88
+
89
+ export const persistRegistryAgentProposal = (stateDir: string, proposal: AgentProposalV1): string => {
90
+ AgentProposalV1Schema.parse(proposal)
91
+ if (proposal.contentHash !== contentHashForArtifactV1(proposal)) throw new Error('Cannot persist a Registry agent proposal with an invalid contentHash.')
92
+ const safeHash = contentHashForArtifactV1(proposal)
93
+ mkdirSync(join(resolve(stateDir), 'agents'), { recursive: true })
94
+ const path = join(resolve(stateDir), 'agents', `${proposal.origin.id}-${safeHash}.json`)
95
+ writeFileSync(path, `${JSON.stringify(proposal, null, 2)}\n`, 'utf8')
96
+ return path
97
+ }