@geraldmaron/construct 1.4.2 → 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 (519) hide show
  1. package/.env.example +36 -0
  2. package/README.md +41 -7
  3. package/bin/construct +1027 -64
  4. package/examples/distribution/sources/deck-one-pager.md +1 -1
  5. package/lib/acp/server.mjs +21 -7
  6. package/lib/adapters-sync.mjs +2 -1
  7. package/lib/audit-trail.mjs +185 -2
  8. package/lib/beads/auto-close.mjs +2 -1
  9. package/lib/beads/drift.mjs +2 -1
  10. package/lib/bridges/copilot-proxy.mjs +20 -5
  11. package/lib/certification/skill-inventory.mjs +10 -1
  12. package/lib/cli/approvals.mjs +147 -0
  13. package/lib/cli-commands.mjs +105 -14
  14. package/lib/comment-lint.mjs +127 -8
  15. package/lib/config/schema.mjs +6 -29
  16. package/lib/config/source-target-registry.mjs +70 -0
  17. package/lib/config/source-targets.mjs +179 -205
  18. package/lib/contracts/coverage.mjs +77 -0
  19. package/lib/contracts/validate.mjs +102 -13
  20. package/lib/contracts/violation-log.mjs +50 -4
  21. package/lib/db/migrate.mjs +69 -0
  22. package/lib/db/migrations/001_orchestration_runs.sql +9 -0
  23. package/lib/db/migrations/002_queue_provider.sql +50 -0
  24. package/lib/db/migrations/003_worker_registry.sql +17 -0
  25. package/lib/db/migrations/004_trace_events.sql +16 -0
  26. package/lib/db/migrations/005_shared_memory.sql +15 -0
  27. package/lib/db/migrations/006_orchestration_runs_tenant.sql +5 -0
  28. package/lib/decisions/enforced-baseline.json +0 -2
  29. package/lib/decisions/registry.mjs +3 -2
  30. package/lib/deployment/parity-contract.mjs +1 -1
  31. package/lib/deployment-mode.mjs +78 -2
  32. package/lib/diagram-export.mjs +10 -1
  33. package/lib/distill.mjs +5 -2
  34. package/lib/docs-verify.mjs +2 -1
  35. package/lib/doctor/cli.mjs +1 -0
  36. package/lib/doctor/command-on-path.mjs +24 -0
  37. package/lib/doctor/diagnosis.mjs +89 -0
  38. package/lib/doctor/embedding-health.mjs +50 -0
  39. package/lib/doctor/engine-health.mjs +93 -0
  40. package/lib/doctor/graph-validate.mjs +47 -0
  41. package/lib/doctor/index.mjs +18 -4
  42. package/lib/doctor/sidecar-providers.mjs +56 -0
  43. package/lib/doctor/watchers/consistency.mjs +93 -1
  44. package/lib/doctor/watchers/cx-budget.mjs +1 -1
  45. package/lib/doctor/watchers/graph-staleness.mjs +1 -1
  46. package/lib/doctor/watchers/mcp-protocol.mjs +17 -0
  47. package/lib/doctor/watchers/oracle-liveness.mjs +92 -0
  48. package/lib/doctor/watchers/orchestration-runs.mjs +108 -0
  49. package/lib/doctor/watchers/provider-breaker.mjs +78 -0
  50. package/lib/document-export.mjs +52 -27
  51. package/lib/document-extract/docling-client.mjs +9 -5
  52. package/lib/document-extract/docling-sidecar.py +30 -0
  53. package/lib/document-extract.mjs +1 -1
  54. package/lib/document-ingest.mjs +9 -0
  55. package/lib/embed/approval-queue.mjs +184 -88
  56. package/lib/embed/authority-guard.mjs +65 -2
  57. package/lib/embed/capability-jobs.mjs +365 -0
  58. package/lib/embed/capability-lifecycle.mjs +219 -0
  59. package/lib/embed/capability-loader.mjs +303 -0
  60. package/lib/embed/capability-runtime.mjs +58 -0
  61. package/lib/embed/cli.mjs +185 -8
  62. package/lib/embed/config.mjs +4 -0
  63. package/lib/embed/daemon.mjs +125 -6
  64. package/lib/embed/demand-fetch.mjs +190 -54
  65. package/lib/embed/inbox.mjs +12 -10
  66. package/lib/embed/presets/ops-triage.mjs +236 -0
  67. package/lib/embed/presets/pm-feedback.mjs +341 -0
  68. package/lib/embed/presets/tpm.mjs +401 -0
  69. package/lib/embed/providers/jira.mjs +72 -1
  70. package/lib/embed/providers/registry.mjs +140 -33
  71. package/lib/embedded-contract/capability.mjs +4 -0
  72. package/lib/embedded-contract/execution.mjs +1 -1
  73. package/lib/embedded-contract/model-resolve.mjs +53 -3
  74. package/lib/embedded-contract/workflow-defs.mjs +48 -73
  75. package/lib/embedded-contract/workflow-invoke.mjs +144 -4
  76. package/lib/embedded-contract/workflows/architecture-review.manifest.json +15 -0
  77. package/lib/embedded-contract/workflows/data-structure.manifest.json +14 -0
  78. package/lib/embedded-contract/workflows/evidence-ingest.manifest.json +14 -0
  79. package/lib/embedded-contract/workflows/memo-draft.manifest.json +14 -0
  80. package/lib/embedded-contract/workflows/operations-triage.manifest.json +18 -0
  81. package/lib/embedded-contract/workflows/operations.manifest.json +18 -0
  82. package/lib/embedded-contract/workflows/pm-feedback.manifest.json +18 -0
  83. package/lib/embedded-contract/workflows/prd-draft.manifest.json +15 -0
  84. package/lib/embedded-contract/workflows/proposal-review.manifest.json +15 -0
  85. package/lib/embedded-contract/workflows/research-synthesis.manifest.json +14 -0
  86. package/lib/embedded-contract/workflows/risk-review.manifest.json +15 -0
  87. package/lib/embedded-contract/workflows/structure-notes.manifest.json +14 -0
  88. package/lib/embedded-contract/workflows/transcript-process.manifest.json +14 -0
  89. package/lib/embedded-contract/workflows/triage.manifest.json +14 -0
  90. package/lib/env-config.mjs +50 -9
  91. package/lib/extensions/index.mjs +27 -0
  92. package/lib/extensions/loader.mjs +120 -0
  93. package/lib/extensions/manifest-schema.mjs +141 -0
  94. package/lib/extensions/manifests/anthropic.manifest.json +12 -0
  95. package/lib/extensions/manifests/atlassian-confluence.manifest.json +12 -0
  96. package/lib/extensions/manifests/atlassian-jira.manifest.json +53 -0
  97. package/lib/extensions/manifests/directory.manifest.json +12 -0
  98. package/lib/extensions/manifests/docling.manifest.json +37 -0
  99. package/lib/extensions/manifests/echo.manifest.json +8 -0
  100. package/lib/extensions/manifests/feedback.manifest.json +12 -0
  101. package/lib/extensions/manifests/github-copilot.manifest.json +12 -0
  102. package/lib/extensions/manifests/github.manifest.json +52 -0
  103. package/lib/extensions/manifests/linear.manifest.json +50 -0
  104. package/lib/extensions/manifests/local.manifest.json +12 -0
  105. package/lib/extensions/manifests/ollama.manifest.json +12 -0
  106. package/lib/extensions/manifests/openai.manifest.json +12 -0
  107. package/lib/extensions/manifests/openrouter-anthropic.manifest.json +12 -0
  108. package/lib/extensions/manifests/openrouter-deepseek.manifest.json +12 -0
  109. package/lib/extensions/manifests/openrouter-google.manifest.json +12 -0
  110. package/lib/extensions/manifests/openrouter-llama.manifest.json +12 -0
  111. package/lib/extensions/manifests/openrouter-qwen.manifest.json +12 -0
  112. package/lib/extensions/manifests/openrouter.manifest.json +12 -0
  113. package/lib/extensions/manifests/postgres.manifest.json +12 -0
  114. package/lib/extensions/manifests/salesforce.manifest.json +12 -0
  115. package/lib/extensions/manifests/slack.manifest.json +58 -0
  116. package/lib/extensions/manifests/whisper.manifest.json +36 -0
  117. package/lib/extensions/validate.mjs +175 -0
  118. package/lib/features.mjs +13 -9
  119. package/lib/flows/checkpoint.mjs +184 -0
  120. package/lib/flows/constants.mjs +27 -0
  121. package/lib/flows/define.mjs +146 -0
  122. package/lib/flows/engine.mjs +249 -0
  123. package/lib/flows/errors.mjs +19 -0
  124. package/lib/flows/index.mjs +27 -0
  125. package/lib/flows/joins.mjs +18 -0
  126. package/lib/flows/schema.mjs +90 -0
  127. package/lib/flows/state.mjs +31 -0
  128. package/lib/frameworks/loader.mjs +99 -0
  129. package/lib/frameworks/schema.mjs +157 -0
  130. package/lib/graph/build-from-corpus.mjs +67 -0
  131. package/lib/graph/build-from-embed.mjs +82 -0
  132. package/lib/graph/build-from-registry.mjs +164 -3
  133. package/lib/graph/cli.mjs +456 -12
  134. package/lib/graph/gap-queries.mjs +156 -0
  135. package/lib/graph/gaps.mjs +41 -0
  136. package/lib/graph/impacted.mjs +129 -0
  137. package/lib/graph/runtime-evidence.mjs +177 -0
  138. package/lib/graph/security-coverage.mjs +113 -0
  139. package/lib/graph/staleness.mjs +241 -10
  140. package/lib/graph/store.mjs +24 -7
  141. package/lib/graph/validate.mjs +161 -0
  142. package/lib/headhunt.mjs +9 -8
  143. package/lib/health-check.mjs +15 -7
  144. package/lib/hook-health.mjs +1 -1
  145. package/lib/hooks/agent-tracker.mjs +10 -4
  146. package/lib/hooks/edit-guard.mjs +3 -3
  147. package/lib/hooks/graph-impact-advisory.mjs +2 -2
  148. package/lib/hooks/guard-bash.mjs +41 -15
  149. package/lib/hooks/mcp-health-check.mjs +11 -4
  150. package/lib/hooks/model-fallback.mjs +50 -6
  151. package/lib/hooks/orchestration-dispatch-guard.mjs +14 -3
  152. package/lib/hooks/pre-compact.mjs +181 -173
  153. package/lib/hooks/rule-verifier.mjs +2 -1
  154. package/lib/hooks/session-reflect.mjs +2 -1
  155. package/lib/hooks/session-start.mjs +3 -3
  156. package/lib/host-capabilities.mjs +13 -2
  157. package/lib/host-disposition.mjs +19 -7
  158. package/lib/identity.mjs +92 -0
  159. package/lib/ingest/degraded-extract.mjs +96 -0
  160. package/lib/ingest/docling-remote.mjs +2 -1
  161. package/lib/ingest/provider-extract.mjs +7 -19
  162. package/lib/ingest/sidecar-providers.mjs +196 -0
  163. package/lib/ingest-tooling.mjs +11 -5
  164. package/lib/init-unified.mjs +55 -38
  165. package/lib/init-update.mjs +2 -1
  166. package/lib/install/legacy-global-cleanup.mjs +25 -0
  167. package/lib/intake/daemon.mjs +99 -8
  168. package/lib/intake/git-queue.mjs +110 -38
  169. package/lib/intake/queue-registry.mjs +50 -0
  170. package/lib/intake/queue.mjs +133 -17
  171. package/lib/intake/session-prelude.mjs +57 -8
  172. package/lib/integrations/intake-integrations.mjs +61 -111
  173. package/lib/intent-classifier.mjs +43 -5
  174. package/lib/libreoffice-export.mjs +8 -8
  175. package/lib/logging/rotate.mjs +5 -4
  176. package/lib/mcp/broker.mjs +332 -17
  177. package/lib/mcp/denied-store.mjs +95 -0
  178. package/lib/mcp/destructive-gate.mjs +30 -0
  179. package/lib/mcp/dispatch-envelope.mjs +199 -0
  180. package/lib/mcp/memory-bridge.mjs +2 -1
  181. package/lib/mcp/server.mjs +154 -1411
  182. package/lib/mcp/tool-definitions-memory.mjs +376 -0
  183. package/lib/mcp/tool-definitions-project.mjs +271 -0
  184. package/lib/mcp/tool-definitions-skills.mjs +311 -0
  185. package/lib/mcp/tool-definitions-workflow.mjs +398 -0
  186. package/lib/mcp/tool-definitions.mjs +25 -0
  187. package/lib/mcp/tool-registry.mjs +107 -0
  188. package/lib/mcp/tool-safety.mjs +1 -0
  189. package/lib/mcp/tools/orchestration-delegation-next.tool.mjs +68 -0
  190. package/lib/mcp/tools/orchestration-run.mjs +165 -25
  191. package/lib/mcp/tools/orchestration-task-result.tool.mjs +77 -0
  192. package/lib/mcp/tools/provider-write.mjs +187 -0
  193. package/lib/mcp/tools/scope.mjs +0 -3
  194. package/lib/mcp/tools/skills.mjs +1 -1
  195. package/lib/mcp/tools/storage.mjs +0 -8
  196. package/lib/mcp/transport/auth.mjs +238 -0
  197. package/lib/mcp/transport/http.mjs +136 -0
  198. package/lib/mcp/transport/mode.mjs +31 -0
  199. package/lib/mcp/transport/stdio.mjs +22 -0
  200. package/lib/mcp-catalog.json +4 -4
  201. package/lib/mcp-manager.mjs +34 -23
  202. package/lib/mcp-platform-config.mjs +31 -7
  203. package/lib/mode-capabilities.mjs +109 -0
  204. package/lib/model-router.mjs +42 -9
  205. package/lib/models/catalog.mjs +40 -1
  206. package/lib/net-guard.mjs +247 -0
  207. package/lib/observation-store.mjs +6 -2
  208. package/lib/ollama/provision-context.mjs +2 -1
  209. package/lib/opencode-config.mjs +22 -3
  210. package/lib/opencode-runtime-plugin.mjs +120 -2
  211. package/lib/oracle/actions.mjs +204 -10
  212. package/lib/oracle/cli.mjs +24 -3
  213. package/lib/oracle/dispatch.mjs +2 -1
  214. package/lib/oracle/execute.mjs +2 -2
  215. package/lib/oracle/gaps.mjs +3 -3
  216. package/lib/oracle/heartbeat.mjs +53 -0
  217. package/lib/oracle/read-model.mjs +69 -13
  218. package/lib/oracle/reconcile.mjs +3 -46
  219. package/lib/oracle/routing.mjs +37 -31
  220. package/lib/oracle/synthesize.mjs +1 -1
  221. package/lib/orchestration/classification.mjs +434 -0
  222. package/lib/orchestration/delegation-flow.mjs +132 -0
  223. package/lib/orchestration/flow-selection.mjs +418 -0
  224. package/lib/orchestration/gates.mjs +244 -0
  225. package/lib/orchestration/host-sampling.mjs +121 -0
  226. package/lib/orchestration/policy-constants.mjs +48 -0
  227. package/lib/orchestration/provider-outcome.mjs +197 -0
  228. package/lib/orchestration/readiness.mjs +114 -13
  229. package/lib/orchestration/run-store-postgres.mjs +32 -26
  230. package/lib/orchestration/run-store-sqlite.mjs +8 -14
  231. package/lib/orchestration/run-store.mjs +25 -12
  232. package/lib/orchestration/runtime.mjs +446 -39
  233. package/lib/orchestration/store.mjs +87 -12
  234. package/lib/orchestration/trace-store.mjs +125 -0
  235. package/lib/orchestration/web-capability.mjs +3 -2
  236. package/lib/orchestration/worker-runtime.mjs +162 -0
  237. package/lib/orchestration/worker.mjs +528 -89
  238. package/lib/orchestration-policy.mjs +67 -1111
  239. package/lib/packs/cli.mjs +144 -0
  240. package/lib/packs/core-pack.mjs +112 -0
  241. package/lib/packs/enablement.mjs +187 -0
  242. package/lib/packs/index.mjs +23 -0
  243. package/lib/packs/loader.mjs +176 -0
  244. package/lib/packs/manifest-schema.mjs +58 -0
  245. package/lib/packs/prompts.mjs +120 -0
  246. package/lib/packs/validate.mjs +208 -0
  247. package/lib/plugin-registry.mjs +4 -5
  248. package/lib/policy/audit-gate.mjs +42 -0
  249. package/lib/policy/consumption-budget.mjs +149 -0
  250. package/lib/policy/engine.mjs +81 -6
  251. package/lib/policy/role-authority.mjs +89 -0
  252. package/lib/prompt-composer.js +19 -3
  253. package/lib/providers/contract/adapters/confluence/governed-write.mjs +215 -0
  254. package/lib/providers/contract/adapters/confluence/manifest.json +17 -0
  255. package/lib/providers/contract/adapters/confluence/transport.mjs +135 -0
  256. package/lib/providers/contract/adapters/github/governed-write.mjs +121 -0
  257. package/lib/providers/contract/adapters/github/index.mjs +38 -3
  258. package/lib/providers/contract/adapters/jira/adf.mjs +151 -0
  259. package/lib/providers/contract/adapters/jira/createmeta.mjs +143 -0
  260. package/lib/providers/contract/adapters/jira/governed-write.mjs +182 -0
  261. package/lib/providers/contract/adapters/jira/manifest.json +17 -0
  262. package/lib/providers/contract/adapters/jira/transport.mjs +119 -0
  263. package/lib/providers/contract.mjs +207 -0
  264. package/lib/providers/credential-bootstrap.mjs +7 -4
  265. package/lib/providers/credential-sources.mjs +14 -2
  266. package/lib/providers/directory/index.mjs +261 -0
  267. package/lib/providers/feedback/index.mjs +392 -0
  268. package/lib/providers/filter-audit.mjs +68 -0
  269. package/lib/providers/filter-schema.mjs +54 -0
  270. package/lib/providers/github/index.mjs +31 -0
  271. package/lib/providers/instance-config.mjs +215 -0
  272. package/lib/providers/op-locate.mjs +96 -0
  273. package/lib/providers/op-run.mjs +64 -9
  274. package/lib/providers/registry.mjs +26 -3
  275. package/lib/providers/secret-audit-wiring.mjs +6 -0
  276. package/lib/providers/secret-resolver.mjs +240 -23
  277. package/lib/publish-template.mjs +6 -3
  278. package/lib/publish-tooling.mjs +4 -0
  279. package/lib/publish.mjs +32 -4
  280. package/lib/queue/pg-queue.mjs +395 -0
  281. package/lib/reflect.mjs +2 -1
  282. package/lib/registry/assemble.mjs +28 -2
  283. package/lib/registry/consolidation.mjs +8 -1
  284. package/lib/registry/custom-scaffold.mjs +200 -0
  285. package/lib/registry/custom-schema.mjs +137 -0
  286. package/lib/registry/loader.mjs +8 -3
  287. package/lib/registry/manifests/format-engines.default.json +15 -0
  288. package/lib/registry/manifests/surface-map.default.json +46 -0
  289. package/lib/registry/retired-paths.mjs +1 -0
  290. package/lib/registry/surface-map.mjs +100 -50
  291. package/lib/render-visual-check.mjs +240 -0
  292. package/lib/resources/budget.mjs +40 -17
  293. package/lib/roles/flavor-bindings.mjs +36 -14
  294. package/lib/roles/gateway.mjs +15 -8
  295. package/lib/roots.mjs +107 -0
  296. package/lib/runtime/uv-bootstrap.mjs +32 -6
  297. package/lib/runtime/whisper-bootstrap.mjs +11 -3
  298. package/lib/runtime-env.mjs +5 -2
  299. package/lib/scheduler/index.mjs +8 -20
  300. package/lib/schema-infer.mjs +31 -2
  301. package/lib/scopes/lifecycle.mjs +29 -25
  302. package/lib/scopes/loader.mjs +49 -12
  303. package/lib/scopes/teams.mjs +1 -1
  304. package/lib/security/ingest-boundary.mjs +80 -0
  305. package/lib/security/recall-wrapper.mjs +99 -0
  306. package/lib/security/trust.mjs +132 -0
  307. package/lib/service-manager.mjs +38 -19
  308. package/lib/setup.mjs +41 -23
  309. package/lib/skills-apply.mjs +4 -2
  310. package/lib/specialists/postconditions.mjs +2 -2
  311. package/lib/state-root.mjs +147 -0
  312. package/lib/status.mjs +597 -6
  313. package/lib/storage/admin.mjs +77 -5
  314. package/lib/storage/backend-registry.mjs +73 -0
  315. package/lib/storage/backend.mjs +63 -9
  316. package/lib/storage/embeddings-openai.mjs +12 -2
  317. package/lib/storage/hybrid-query.mjs +11 -3
  318. package/lib/storage/retrieval-hardening.mjs +384 -0
  319. package/lib/storage/shared-memory.mjs +158 -0
  320. package/lib/storage/vector-client.mjs +69 -2
  321. package/lib/team/health.mjs +72 -0
  322. package/lib/telemetry/backends/local.mjs +9 -3
  323. package/lib/telemetry/client.mjs +3 -7
  324. package/lib/template-registry.mjs +10 -12
  325. package/lib/tenant/context.mjs +82 -0
  326. package/lib/tenant/isolation.mjs +129 -0
  327. package/lib/test-corpus-inventory.mjs +103 -2
  328. package/lib/uninstall/uninstall.mjs +78 -12
  329. package/lib/validator.mjs +4 -6
  330. package/lib/worker/entrypoint.mjs +2 -1
  331. package/lib/worker/run.mjs +2 -2
  332. package/lib/worker/trace.mjs +5 -11
  333. package/lib/workflow-state.mjs +52 -8
  334. package/lib/workflows/liveness.mjs +203 -0
  335. package/lib/workflows/loader.mjs +177 -0
  336. package/lib/workflows/manifest-schema.mjs +71 -0
  337. package/lib/workflows/surface-parity.mjs +118 -0
  338. package/lib/workflows/validate.mjs +127 -0
  339. package/lib/writes/control-plane.mjs +140 -0
  340. package/lib/writes/envelope.mjs +206 -0
  341. package/lib/writes/sent-log.mjs +86 -0
  342. package/lib/writes/write-intent.mjs +109 -0
  343. package/package.json +16 -8
  344. package/personas/construct.md +12 -3
  345. package/registry/capabilities.json +143 -36
  346. package/rules/common/comments.md +1 -0
  347. package/schemas/project-config.schema.json +0 -12
  348. package/schemas/unified-registry.schema.json +2 -4
  349. package/scripts/sync-specialists.mjs +284 -81
  350. package/skills/docs/adr-workflow.md +1 -1
  351. package/skills/docs/codebase-research-workflow.md +3 -3
  352. package/skills/docs/prd-workflow.md +5 -6
  353. package/skills/docs/runbook-workflow.md +2 -2
  354. package/skills/docs/user-research-workflow.md +3 -3
  355. package/skills/operating/fleet-health-routing.md +77 -0
  356. package/skills/roles/ai-engineer.md +1 -1
  357. package/skills/roles/architect.md +0 -1
  358. package/skills/roles/business-strategist.md +1 -1
  359. package/skills/roles/data-analyst.telemetry.md +1 -1
  360. package/skills/roles/data-engineer.md +1 -1
  361. package/skills/roles/data-engineer.pipeline.md +1 -1
  362. package/skills/roles/data-engineer.vector-retrieval.md +1 -2
  363. package/skills/roles/data-engineer.warehouse.md +1 -1
  364. package/skills/roles/designer.accessibility.md +1 -1
  365. package/skills/roles/designer.md +0 -1
  366. package/skills/roles/devil-advocate.md +1 -1
  367. package/skills/roles/docs-keeper.md +1 -1
  368. package/skills/roles/evaluator.md +1 -1
  369. package/skills/roles/explorer.md +1 -1
  370. package/skills/roles/platform-engineer.md +1 -1
  371. package/skills/roles/qa.ai-eval.md +1 -2
  372. package/skills/roles/qa.api-contract.md +0 -1
  373. package/skills/roles/qa.data-pipeline.md +0 -1
  374. package/skills/roles/qa.md +0 -1
  375. package/skills/roles/qa.web-ui.md +0 -1
  376. package/skills/roles/release-manager.md +1 -1
  377. package/skills/roles/researcher.md +0 -2
  378. package/skills/roles/reviewer.md +0 -3
  379. package/skills/roles/security.ai.md +1 -1
  380. package/skills/roles/security.legal-compliance.md +1 -1
  381. package/skills/roles/security.md +0 -1
  382. package/skills/roles/security.privacy.md +0 -1
  383. package/skills/roles/security.supply-chain.md +1 -1
  384. package/skills/roles/sre.md +1 -1
  385. package/skills/roles/test-automation.md +1 -1
  386. package/skills/roles/trace-reviewer.md +1 -1
  387. package/skills/roles/ux-researcher.md +1 -1
  388. package/specialists/artifact-manifest.json +36 -36
  389. package/specialists/org/contracts/accessibility-to-qa.json +11 -3
  390. package/specialists/org/contracts/any-to-business-strategist.json +19 -7
  391. package/specialists/org/contracts/any-to-debugger.json +7 -1
  392. package/specialists/org/contracts/any-to-designer.json +7 -1
  393. package/specialists/org/contracts/any-to-docs-keeper.json +18 -4
  394. package/specialists/org/contracts/any-to-explorer.json +13 -4
  395. package/specialists/org/contracts/any-to-sre-incident.json +6 -2
  396. package/specialists/org/contracts/any-to-trace-reviewer.json +16 -4
  397. package/specialists/org/contracts/architect-to-ai-engineer.json +6 -2
  398. package/specialists/org/contracts/architect-to-data-engineer.json +17 -5
  399. package/specialists/org/contracts/architect-to-devil-advocate.json +11 -3
  400. package/specialists/org/contracts/architect-to-engineer.json +20 -4
  401. package/specialists/org/contracts/architect-to-evaluator.json +15 -5
  402. package/specialists/org/contracts/architect-to-legal-compliance.json +15 -5
  403. package/specialists/org/contracts/architect-to-operations.json +17 -4
  404. package/specialists/org/contracts/architect-to-platform-engineer.json +20 -4
  405. package/specialists/org/contracts/construct-to-orchestrator.json +10 -2
  406. package/specialists/org/contracts/data-analyst-to-product-manager.json +11 -2
  407. package/specialists/org/contracts/engineer-to-qa.json +20 -4
  408. package/specialists/org/contracts/engineer-to-reviewer.json +29 -5
  409. package/specialists/org/contracts/explorer-to-engineer.json +11 -3
  410. package/specialists/org/contracts/legal-compliance-to-release-manager.json +12 -4
  411. package/specialists/org/contracts/operations-to-user.json +53 -0
  412. package/specialists/org/contracts/operations-triage-output.json +53 -0
  413. package/specialists/org/contracts/pm-requirements-candidates.json +53 -0
  414. package/specialists/org/contracts/product-manager-to-architect.json +30 -10
  415. package/specialists/org/contracts/product-manager-to-data-analyst.json +13 -3
  416. package/specialists/org/contracts/product-manager-to-ux-researcher.json +15 -5
  417. package/specialists/org/contracts/qa-to-release-manager.json +11 -3
  418. package/specialists/org/contracts/researcher-to-architect.json +10 -2
  419. package/specialists/org/contracts/researcher-to-product-manager.json +16 -5
  420. package/specialists/org/contracts/reviewer-to-security.json +17 -3
  421. package/specialists/org/contracts/test-automation-to-engineer.json +11 -3
  422. package/specialists/org/contracts/trace-reviewer-to-sre.json +12 -4
  423. package/specialists/org/contracts/user-to-construct.json +11 -4
  424. package/specialists/org/frameworks/cx-architect-constraint-option-failure.md +66 -0
  425. package/specialists/org/frameworks/cx-engineer-feasibility-blast-radius.md +66 -0
  426. package/specialists/org/frameworks/cx-ops-dependency-sequencing.md +74 -0
  427. package/specialists/org/frameworks/cx-pm-value-tradeoff.md +66 -0
  428. package/specialists/org/frameworks/cx-qa-risk-based-coverage.md +69 -0
  429. package/specialists/org/groups/engineering-group.json +2 -6
  430. package/specialists/org/groups/governance-group.json +2 -3
  431. package/specialists/org/groups/operations-group.json +5 -8
  432. package/specialists/org/groups/product-group.json +4 -8
  433. package/specialists/org/groups/quality-group.json +3 -7
  434. package/specialists/org/groups/strategy-group.json +6 -9
  435. package/specialists/org/models.json.example +8 -0
  436. package/specialists/org/scopes/creative.json +6 -1
  437. package/specialists/org/scopes/operations.json +7 -1
  438. package/specialists/org/scopes/research.json +6 -1
  439. package/specialists/org/scopes/rnd.json +7 -1
  440. package/specialists/org/specialists/cx-architect.json +27 -8
  441. package/specialists/org/specialists/cx-designer.json +22 -8
  442. package/specialists/org/specialists/cx-engineer.json +71 -7
  443. package/specialists/org/specialists/cx-operations.json +89 -15
  444. package/specialists/org/specialists/cx-orchestrator.json +16 -4
  445. package/specialists/org/specialists/cx-product-manager.json +28 -9
  446. package/specialists/org/specialists/cx-qa.json +16 -6
  447. package/specialists/org/specialists/cx-researcher.json +40 -7
  448. package/specialists/org/specialists/cx-reviewer.json +61 -11
  449. package/specialists/org/specialists/cx-security.json +30 -10
  450. package/specialists/org/teams/design-team.json +3 -4
  451. package/specialists/org/teams/engineering-team.json +3 -10
  452. package/specialists/org/teams/governance-team.json +3 -5
  453. package/specialists/org/teams/operations-team.json +6 -12
  454. package/specialists/org/teams/product-management-team.json +2 -3
  455. package/specialists/org/teams/quality-team.json +4 -12
  456. package/specialists/org/teams/research-team.json +3 -3
  457. package/specialists/org/teams/strategy-team.json +7 -14
  458. package/specialists/prompts/cx-architect.md +20 -1
  459. package/specialists/prompts/cx-data-analyst.md +1 -1
  460. package/specialists/prompts/cx-designer.md +12 -4
  461. package/specialists/prompts/cx-engineer.md +15 -1
  462. package/specialists/prompts/cx-operations.md +14 -2
  463. package/specialists/prompts/cx-orchestrator.md +9 -5
  464. package/specialists/prompts/cx-product-manager.md +5 -1
  465. package/specialists/prompts/cx-qa.md +6 -2
  466. package/specialists/prompts/cx-researcher.md +25 -30
  467. package/specialists/prompts/cx-reviewer.md +19 -1
  468. package/specialists/prompts/cx-security.md +5 -1
  469. package/templates/distribution/construct-brand.typ +123 -59
  470. package/templates/distribution/construct-decision.typ +6 -3
  471. package/templates/distribution/construct-pdf.typ +11 -4
  472. package/templates/distribution/construct-prd.typ +6 -3
  473. package/templates/distribution/construct-research.typ +7 -4
  474. package/lib/providers/contract/adapters/git/index.mjs +0 -115
  475. package/lib/providers/contract/adapters/slack/index.mjs +0 -175
  476. package/specialists/org/contracts/business-strategist-to-product-manager.json +0 -39
  477. package/specialists/org/contracts/construct-to-rd-lead.json +0 -53
  478. package/specialists/org/contracts/data-engineer-to-platform-engineer.json +0 -36
  479. package/specialists/org/contracts/designer-to-accessibility.json +0 -36
  480. package/specialists/org/contracts/platform-engineer-to-engineer.json +0 -31
  481. package/specialists/org/contracts/qa-to-test-automation.json +0 -42
  482. package/specialists/org/contracts/rd-lead-to-architect.json +0 -38
  483. package/specialists/org/contracts/sre-to-release-manager.json +0 -36
  484. package/specialists/org/specialists/cx-accessibility.json +0 -69
  485. package/specialists/org/specialists/cx-ai-engineer.json +0 -75
  486. package/specialists/org/specialists/cx-business-strategist.json +0 -72
  487. package/specialists/org/specialists/cx-data-engineer.json +0 -71
  488. package/specialists/org/specialists/cx-devil-advocate.json +0 -71
  489. package/specialists/org/specialists/cx-docs-keeper.json +0 -82
  490. package/specialists/org/specialists/cx-evaluator.json +0 -69
  491. package/specialists/org/specialists/cx-explorer.json +0 -69
  492. package/specialists/org/specialists/cx-legal-compliance.json +0 -74
  493. package/specialists/org/specialists/cx-oracle.json +0 -46
  494. package/specialists/org/specialists/cx-platform-engineer.json +0 -80
  495. package/specialists/org/specialists/cx-rd-lead.json +0 -73
  496. package/specialists/org/specialists/cx-release-manager.json +0 -77
  497. package/specialists/org/specialists/cx-sre.json +0 -94
  498. package/specialists/org/specialists/cx-test-automation.json +0 -69
  499. package/specialists/org/specialists/cx-trace-reviewer.json +0 -69
  500. package/specialists/org/specialists/cx-ux-researcher.json +0 -68
  501. package/specialists/org/teams/accessibility-team.json +0 -39
  502. package/specialists/org/teams/ux-research-team.json +0 -39
  503. package/specialists/prompts/cx-accessibility.md +0 -55
  504. package/specialists/prompts/cx-ai-engineer.md +0 -124
  505. package/specialists/prompts/cx-business-strategist.md +0 -58
  506. package/specialists/prompts/cx-data-engineer.md +0 -55
  507. package/specialists/prompts/cx-devil-advocate.md +0 -59
  508. package/specialists/prompts/cx-docs-keeper.md +0 -164
  509. package/specialists/prompts/cx-evaluator.md +0 -49
  510. package/specialists/prompts/cx-explorer.md +0 -71
  511. package/specialists/prompts/cx-legal-compliance.md +0 -58
  512. package/specialists/prompts/cx-oracle.md +0 -98
  513. package/specialists/prompts/cx-platform-engineer.md +0 -97
  514. package/specialists/prompts/cx-rd-lead.md +0 -59
  515. package/specialists/prompts/cx-release-manager.md +0 -54
  516. package/specialists/prompts/cx-sre.md +0 -111
  517. package/specialists/prompts/cx-test-automation.md +0 -55
  518. package/specialists/prompts/cx-trace-reviewer.md +0 -101
  519. package/specialists/prompts/cx-ux-researcher.md +0 -53
@@ -0,0 +1,157 @@
1
+ /**
2
+ * lib/frameworks/schema.mjs — ADR-0062 persona reasoning framework schema validator.
3
+ *
4
+ * A framework is Markdown with YAML frontmatter (same convention as
5
+ * specialists/prompts/*.md). validateFrameworkFrontmatter() checks the
6
+ * frontmatter object in isolation (required fields, step shape, unique
7
+ * `emits` tokens, `cites` enum, known `appliesToRole`) — it never reads
8
+ * files itself, so it is usable directly against a parsed object in tests.
9
+ * parseFrameworkFile() does the frontmatter extraction plus validation for
10
+ * a file on disk, mirroring lib/packs/prompts.mjs's parseFrontmatter shape.
11
+ *
12
+ * Invalid frameworks fail closed: every error names the offending field and
13
+ * (when available) the file path, per ADR-0062 §4 — no silent skip.
14
+ */
15
+
16
+ import { readFileSync } from 'node:fs';
17
+ import yaml from 'js-yaml';
18
+
19
+ const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?/;
20
+
21
+ const CITES_VALUES = new Set(['source', 'prior-step']);
22
+
23
+ const STEP_REQUIRED_FIELDS = ['id', 'move', 'question', 'emits', 'cites'];
24
+
25
+ const MIN_STEPS = 3;
26
+ const MAX_STEPS = 6;
27
+
28
+ export function knownRolesFromSpecialists(specialists) {
29
+ const roles = new Set();
30
+ for (const spec of specialists || []) {
31
+ if (spec && typeof spec.role === 'string' && spec.role) roles.add(spec.role);
32
+ }
33
+ return roles;
34
+ }
35
+
36
+ /**
37
+ * Validate a parsed frontmatter object against the ADR-0062 schema.
38
+ *
39
+ * @param {object} fm parsed YAML frontmatter
40
+ * @param {object} opts
41
+ * @param {string} [opts.filePath] for error-message prefixing
42
+ * @param {Set<string>|string[]} [opts.knownRoles] roles appliesToRole may name; skipped when omitted
43
+ * @returns {{valid: boolean, errors: string[]}}
44
+ */
45
+ export function validateFrameworkFrontmatter(fm, { filePath, knownRoles } = {}) {
46
+ const prefix = filePath ? `${filePath}: ` : '';
47
+ const errors = [];
48
+
49
+ if (!fm || typeof fm !== 'object' || Array.isArray(fm)) {
50
+ return { valid: false, errors: [`${prefix}frontmatter must be a YAML object`] };
51
+ }
52
+
53
+ if (!fm.id || typeof fm.id !== 'string') {
54
+ errors.push(`${prefix}missing required field: id`);
55
+ }
56
+ if (fm.version === undefined || fm.version === null) {
57
+ errors.push(`${prefix}missing required field: version`);
58
+ }
59
+ if (!fm.appliesToRole || typeof fm.appliesToRole !== 'string') {
60
+ errors.push(`${prefix}missing required field: appliesToRole`);
61
+ } else if (knownRoles) {
62
+ const roles = knownRoles instanceof Set ? knownRoles : new Set(knownRoles);
63
+ if (roles.size > 0 && !roles.has(fm.appliesToRole)) {
64
+ errors.push(`${prefix}appliesToRole '${fm.appliesToRole}' is not a known role`);
65
+ }
66
+ }
67
+ if (!fm.summary || typeof fm.summary !== 'string') {
68
+ errors.push(`${prefix}missing required field: summary`);
69
+ }
70
+
71
+ if (!Array.isArray(fm.steps) || fm.steps.length === 0) {
72
+ errors.push(`${prefix}steps must be a non-empty array`);
73
+ return { valid: errors.length === 0, errors };
74
+ }
75
+
76
+ if (fm.steps.length < MIN_STEPS || fm.steps.length > MAX_STEPS) {
77
+ errors.push(`${prefix}steps must contain ${MIN_STEPS}-${MAX_STEPS} entries (got ${fm.steps.length})`);
78
+ }
79
+
80
+ const emitsSeen = new Map();
81
+ const stepIdsSeen = new Set();
82
+
83
+ fm.steps.forEach((step, idx) => {
84
+ const stepPrefix = `${prefix}steps[${idx}]`;
85
+
86
+ if (!step || typeof step !== 'object' || Array.isArray(step)) {
87
+ errors.push(`${stepPrefix}: must be an object`);
88
+ return;
89
+ }
90
+
91
+ for (const field of STEP_REQUIRED_FIELDS) {
92
+ if (!step[field] || typeof step[field] !== 'string') {
93
+ errors.push(`${stepPrefix}: missing required field: ${field}`);
94
+ }
95
+ }
96
+
97
+ if (step.id) {
98
+ if (stepIdsSeen.has(step.id)) {
99
+ errors.push(`${stepPrefix}: duplicate step id '${step.id}'`);
100
+ }
101
+ stepIdsSeen.add(step.id);
102
+ }
103
+
104
+ if (step.emits) {
105
+ if (emitsSeen.has(step.emits)) {
106
+ errors.push(
107
+ `${prefix}emits token '${step.emits}' is not unique within the framework (also used by step '${emitsSeen.get(step.emits)}')`
108
+ );
109
+ } else {
110
+ emitsSeen.set(step.emits, step.id || `steps[${idx}]`);
111
+ }
112
+ }
113
+
114
+ if (step.cites && !CITES_VALUES.has(step.cites)) {
115
+ errors.push(`${stepPrefix}: cites must be one of ${[...CITES_VALUES].join(', ')} (got '${step.cites}')`);
116
+ }
117
+ });
118
+
119
+ return { valid: errors.length === 0, errors };
120
+ }
121
+
122
+ function parseFrontmatter(content) {
123
+ const match = content.match(FRONTMATTER_RE);
124
+ if (!match) return null;
125
+ try {
126
+ return yaml.load(match[1]) || {};
127
+ } catch {
128
+ return null;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Read and validate a framework file from disk.
134
+ *
135
+ * @param {string} filePath
136
+ * @param {object} opts
137
+ * @param {Set<string>|string[]} [opts.knownRoles]
138
+ * @returns {{valid: boolean, errors: string[], frontmatter: object|null, body: string|null}}
139
+ */
140
+ export function parseFrameworkFile(filePath, { knownRoles } = {}) {
141
+ let raw;
142
+ try {
143
+ raw = readFileSync(filePath, 'utf8');
144
+ } catch (err) {
145
+ return { valid: false, errors: [`${filePath}: failed to read file (${err.message})`], frontmatter: null, body: null };
146
+ }
147
+
148
+ const fm = parseFrontmatter(raw);
149
+ if (!fm) {
150
+ return { valid: false, errors: [`${filePath}: missing or invalid frontmatter`], frontmatter: null, body: null };
151
+ }
152
+
153
+ const result = validateFrameworkFrontmatter(fm, { filePath, knownRoles });
154
+ const body = raw.replace(FRONTMATTER_RE, '');
155
+
156
+ return { valid: result.valid, errors: result.errors, frontmatter: fm, body };
157
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * lib/graph/build-from-corpus.mjs — corpus-annotation edges for the dependency graph.
3
+ *
4
+ * buildFromRegistry only derives test --validates--> capability edges from
5
+ * registry/capabilities.json's verification.functional / hostEmulation pointers,
6
+ * so a capability verified solely by unit/integration tests (e.g. local.model.tier,
7
+ * which declares an explicit untestableRationale for functional coverage) or a
8
+ * capability tracked only in tests/capabilities/ledger.json never gets an edge.
9
+ * Walking @capability annotations across the whole test corpus (via
10
+ * lib/test-corpus-inventory.mjs) and emitting the same validates edge shape,
11
+ * sourced 'corpus-annotation', closes that gap and merges with (rather than
12
+ * replaces) registry-derived edges in the store's dedup-by-key write path.
13
+ *
14
+ * A capability id tagged in a test but absent from both registry/capabilities.json
15
+ * and tests/capabilities/ledger.json is not a fabricated node — the ledger and
16
+ * registry are the id authorities — so annotation-only ids without a known
17
+ * capability node are skipped and reported back to the caller as orphaned tags.
18
+ */
19
+
20
+ import { readFileSync } from 'node:fs';
21
+ import path from 'node:path';
22
+
23
+ import { extractCapabilityTestEdges } from '../test-corpus-inventory.mjs';
24
+ import { loadCapabilityRegistry } from '../registry/validate.mjs';
25
+ import { defaultLedgerPath } from '../capability-ledger.mjs';
26
+ import { nodeId } from './store.mjs';
27
+
28
+ function readJsonSafe(filePath) {
29
+ try { return JSON.parse(readFileSync(filePath, 'utf8')); } catch { return null; }
30
+ }
31
+
32
+ /**
33
+ * @param {object} opts
34
+ * @param {string} opts.rootDir
35
+ * @returns {{ nodes: object[], edges: object[], orphanedCapabilityIds: string[] }}
36
+ */
37
+ export function buildFromCorpus({ rootDir }) {
38
+ const registry = loadCapabilityRegistry({ rootDir });
39
+ const registryIds = new Set((registry.capabilities ?? []).map((cap) => cap.id).filter(Boolean));
40
+
41
+ const ledger = readJsonSafe(defaultLedgerPath(rootDir));
42
+ const ledgerIds = new Set((ledger?.capabilities ?? []).map((cap) => cap.id).filter(Boolean));
43
+
44
+ const nodes = [];
45
+ const edges = [];
46
+ const orphaned = new Set();
47
+ const ledgerNodesEmitted = new Set();
48
+
49
+ for (const { testPath, capabilityId } of extractCapabilityTestEdges({ rootDir })) {
50
+ const known = registryIds.has(capabilityId) || ledgerIds.has(capabilityId);
51
+ if (!known) { orphaned.add(capabilityId); continue; }
52
+
53
+ // Ledger-only capabilities (not in registry/capabilities.json) have no
54
+ // node anywhere else in the graph, so this is the sole place they're created.
55
+
56
+ if (!registryIds.has(capabilityId) && !ledgerNodesEmitted.has(capabilityId)) {
57
+ ledgerNodesEmitted.add(capabilityId);
58
+ nodes.push({ id: nodeId('capability', capabilityId), type: 'capability', name: capabilityId, attrs: { source: 'ledger' } });
59
+ }
60
+
61
+ const testId = nodeId('test', testPath);
62
+ nodes.push({ id: testId, type: 'test', name: testPath, attrs: { path: testPath, exists: true } });
63
+ edges.push({ from: testId, to: nodeId('capability', capabilityId), rel: 'validates', source: 'corpus-annotation' });
64
+ }
65
+
66
+ return { nodes, edges, orphanedCapabilityIds: [...orphaned].sort() };
67
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * lib/graph/build-from-embed.mjs — seed the living graph with embed-capability
3
+ * nodes and edges from loaded embed manifests (LMCP-P6).
4
+ *
5
+ * Embedded specialists (ADR-0061) were invisible to the graph: build-from-
6
+ * registry seeds provider/specialist/contract nodes but knows nothing of the
7
+ * `type:"embed"` manifests, so C8's drift gate could not protect a preset whose
8
+ * test was deleted or whose binding target broke. This seeder closes that gap.
9
+ *
10
+ * Per embed manifest it emits one `embed:<id>` node plus edges into nodes the
11
+ * registry seeder already produces, reusing the existing relation vocabulary
12
+ * rather than inventing one:
13
+ * embed --uses--> provider (each embed.providerBindings entry)
14
+ * embed --owned_by--> specialist (embed.specialist — who runs it)
15
+ * embed --governed_by--> contract (embed.outputContract)
16
+ * test --validates--> embed (`@embed <id>` acceptance-test tag, C10 format)
17
+ *
18
+ * The binding-target nodes are NOT created here — an embed that names a
19
+ * provider/specialist/contract with no node of its own is drift, and
20
+ * lib/graph/validate.mjs reports the dangling target as an error (strict) so
21
+ * the C8 gate fails instead of the graph quietly gaining an orphan endpoint.
22
+ */
23
+
24
+ import { nodeId } from './store.mjs';
25
+ import { loadEmbedCapabilities } from '../embed/capability-loader.mjs';
26
+ import { extractEmbedTestEdges } from '../test-corpus-inventory.mjs';
27
+
28
+ /**
29
+ * @param {{ rootDir: string }} opts
30
+ * @returns {{ nodes: object[], edges: object[], errors: string[] }}
31
+ */
32
+ export function buildFromEmbed({ rootDir }) {
33
+ const { capabilities, errors } = loadEmbedCapabilities({ rootDir });
34
+
35
+ const nodes = [];
36
+ const edges = [];
37
+ const embedIds = new Set();
38
+
39
+ for (const manifest of capabilities) {
40
+ const embed = manifest.embed ?? {};
41
+ const id = manifest.id;
42
+ if (!id) continue;
43
+ embedIds.add(id);
44
+
45
+ const from = nodeId('embed', id);
46
+ nodes.push({
47
+ id: from,
48
+ type: 'embed',
49
+ name: id,
50
+ attrs: {
51
+ specialist: embed.specialist ?? null,
52
+ outputContract: embed.outputContract ?? null,
53
+ providerBindings: embed.providerBindings ?? [],
54
+ runtime: embed.runtime ?? null,
55
+ proposalAuthority: embed.proposalAuthority ?? null,
56
+ },
57
+ });
58
+
59
+ for (const providerId of embed.providerBindings ?? []) {
60
+ edges.push({ from, to: nodeId('provider', providerId), rel: 'uses', source: 'embed-manifest' });
61
+ }
62
+ if (embed.specialist) {
63
+ edges.push({ from, to: nodeId('specialist', embed.specialist), rel: 'owned_by', source: 'embed-manifest' });
64
+ }
65
+ if (embed.outputContract) {
66
+ edges.push({ from, to: nodeId('contract', embed.outputContract), rel: 'governed_by', source: 'embed-manifest' });
67
+ }
68
+ }
69
+
70
+ // A `@embed <id>` tag on an id with no loaded manifest is a stale annotation,
71
+ // not a fabricated node — skip it rather than mint a phantom embed node. The
72
+ // tagging test may carry no `@capability`, so its node is minted here (the
73
+ // store dedups by id if build-from-corpus also emitted it).
74
+ for (const { testPath, embedId } of extractEmbedTestEdges({ rootDir })) {
75
+ if (!embedIds.has(embedId)) continue;
76
+ const testId = nodeId('test', testPath);
77
+ nodes.push({ id: testId, type: 'test', name: testPath, attrs: { path: testPath, exists: true } });
78
+ edges.push({ from: testId, to: nodeId('embed', embedId), rel: 'validates', source: 'embed-manifest' });
79
+ }
80
+
81
+ return { nodes, edges, errors };
82
+ }
@@ -3,19 +3,30 @@
3
3
  * authoritative declarative catalogs.
4
4
  *
5
5
  * Ingests registry/capabilities.json, lib/embedded-contract/workflow-defs.mjs,
6
- * and specialists/org into typed nodes and directed edges:
6
+ * specialists/org into typed nodes and directed edges:
7
7
  * capability --embeds--> workflow (embeddedWorkflow)
8
8
  * test --validates--> capability (verification.functional / hostEmulation / per-surface test)
9
9
  * capability --uses--> skill | rule (skill + dependencies.skills/.rules)
10
10
  * capability --governed_by-->contract (contracts[])
11
11
  * capability --exposes--> surface (supported surfaces)
12
+ *
13
+ * Extended seeding (LMCP-C1) also produces:
14
+ * provider --owned_by--> specialist (manifest owner)
15
+ * provider --requires--> tool (manifest capabilities/operations)
16
+ * specialist --owned_by--> specialist (team membership)
17
+ * specialist --uses--> skill (specialist skills)
18
+ * doc --documents--> workflow|provider (heuristic linking)
19
+ *
20
+ * Embed binding seeding (LMCP-E4) also produces:
21
+ * specialist --reads--> provider (pack embedBindings[].providers, read/search grant)
22
+ *
12
23
  * Node existence on disk (tests, skills, rules) is stamped as an attr so the
13
24
  * Oracle collector can later distinguish declared-but-missing from realized.
14
25
  * Covers the registry half of the hybrid population; the import-graph half
15
26
  * (file/module nodes, imports/covers/realizes) lands in build-import-graph.
16
27
  */
17
28
 
18
- import { existsSync, readFileSync, statSync } from 'node:fs';
29
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
19
30
  import { loadRegistry } from '../registry/loader.mjs';
20
31
  import path from 'node:path';
21
32
  import { createHash } from 'node:crypto';
@@ -23,6 +34,9 @@ import { createHash } from 'node:crypto';
23
34
  import { listWorkflowDefs } from '../embedded-contract/workflow-defs.mjs';
24
35
  import { loadCapabilityRegistry } from '../registry/validate.mjs';
25
36
  import { nodeId } from './store.mjs';
37
+ import { loadManifestsFromDir, resolveManifestDirs } from '../extensions/loader.mjs';
38
+ import { assembleRegistry } from '../registry/assemble.mjs';
39
+ import { loadAllPacks } from '../packs/loader.mjs';
26
40
 
27
41
  function readJsonSafe(filePath) {
28
42
  try { return JSON.parse(readFileSync(filePath, 'utf8')); } catch { return null; }
@@ -49,6 +63,23 @@ function declarationImplFiles(cap, rootDir) {
49
63
  return [...new Set(files.filter((rel) => existsRel(rootDir, rel)))];
50
64
  }
51
65
 
66
+ const DOC_EXTS = new Set(['.md', '.html', '.json']);
67
+
68
+ function scanDocFiles(dir, baseDir) {
69
+ const docs = [];
70
+ let entries;
71
+ try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return []; }
72
+ for (const entry of entries) {
73
+ const full = path.join(dir, entry.name);
74
+ if (entry.isDirectory()) {
75
+ docs.push(...scanDocFiles(full, baseDir));
76
+ } else if (entry.isFile() && DOC_EXTS.has(path.extname(entry.name).toLowerCase())) {
77
+ docs.push(path.relative(baseDir, full));
78
+ }
79
+ }
80
+ return docs;
81
+ }
82
+
52
83
  function hashFiles(rootDir, rels) {
53
84
  const h = createHash('sha256');
54
85
  for (const rel of rels) {
@@ -69,7 +100,7 @@ export function buildFromRegistry({ rootDir }) {
69
100
  const nodes = [];
70
101
  const edges = [];
71
102
  const node = (type, key, name, attrs) => nodes.push({ id: nodeId(type, key), type, name: name ?? key, attrs: attrs || {} });
72
- const edge = (from, rel, to) => edges.push({ from, to, rel, source: 'registry' });
103
+ const edge = (from, rel, to, source) => edges.push({ from, to, rel, source: source || 'registry' });
73
104
 
74
105
  // Workflow catalog: every embedded workflow type is a node regardless of
75
106
  // capability coverage, so reverse queries see uncovered workflows.
@@ -148,10 +179,140 @@ export function buildFromRegistry({ rootDir }) {
148
179
  }
149
180
  }
150
181
 
182
+ // --- Provider nodes from extension manifests ---
183
+ // Loads builtin manifests and creates provider, tool, and specialist nodes.
184
+ const manifestDirs = resolveManifestDirs({ rootDir });
185
+ const builtinManifests = loadManifestsFromDir(manifestDirs.builtin);
186
+ const manifests = builtinManifests.manifests || [];
187
+
188
+ for (const m of manifests) {
189
+ const provId = nodeId('provider', m.id);
190
+ node('provider', m.id, m.id, {
191
+ kind: m.kind,
192
+ version: m.version,
193
+ owner: m.owner || null,
194
+ capabilities: m.capabilities || [],
195
+ operations: m.operations || [],
196
+ });
197
+
198
+ if (m.owner) {
199
+ const specId = nodeId('specialist', m.owner);
200
+ node('specialist', m.owner, m.owner, { autoCreated: true });
201
+ edge(provId, 'owned_by', specId, 'manifest-loader');
202
+ }
203
+
204
+ const tokens = new Set([
205
+ ...(m.capabilities || []),
206
+ ...(m.operations || []),
207
+ ]);
208
+ for (const token of tokens) {
209
+ node('tool', token, token, {});
210
+ edge(provId, 'requires', nodeId('tool', token), 'manifest-loader');
211
+ }
212
+ }
213
+
214
+ // --- Specialist --reads--> provider edges from pack embedBindings ---
215
+ // Every pack (core + user + project tiers) may declare embedBindings
216
+ // (LMCP-E4); surfacing the read/search grant here makes it visible in
217
+ // `construct graph`/`construct matrix` alongside the authority-guard
218
+ // enforcement in lib/embed/authority-guard.mjs, rather than only living in
219
+ // pack JSON. Errors loading packs are swallowed — a broken project-tier
220
+ // pack should not blank out the whole registry-seeded graph.
221
+ try {
222
+ const { packs } = loadAllPacks({ rootDir });
223
+ for (const pack of packs) {
224
+ for (const [specId, binding] of Object.entries(pack.embedBindings || {})) {
225
+ const specNodeId = nodeId('specialist', specId);
226
+ node('specialist', specId, specId, { autoCreated: true });
227
+ for (const providerBinding of binding.providers || []) {
228
+ if (!providerBinding?.id) continue;
229
+ const provNodeId = nodeId('provider', providerBinding.id);
230
+ node('provider', providerBinding.id, providerBinding.id, {});
231
+ edge(specNodeId, 'reads', provNodeId, 'pack-embed-binding');
232
+ }
233
+ }
234
+ }
235
+ } catch (err) {
236
+ // pack loading failures should not abort registry graph seeding
237
+ }
238
+
239
+ // --- Specialist nodes from role registry ---
240
+ try {
241
+ const orgRegistry = assembleRegistry(rootDir);
242
+ const specialists = orgRegistry.specialists || {};
243
+ const teams = orgRegistry.teams || {};
244
+
245
+ for (const [specId, spec] of Object.entries(specialists)) {
246
+ node('specialist', specId, spec.name || specId, {
247
+ role: spec.role || null,
248
+ modelTier: spec.modelTier || null,
249
+ team: spec.team || null,
250
+ teamId: spec.teamId || null,
251
+ groupId: spec.groupId || null,
252
+ skills: spec.skills || [],
253
+ });
254
+
255
+ if (spec.teamId && teams[spec.teamId]) {
256
+ edge(nodeId('specialist', specId), 'owned_by', nodeId('specialist', spec.teamId), 'registry');
257
+ }
258
+
259
+ for (const skillRef of spec.skills || []) {
260
+ edge(nodeId('specialist', specId), 'uses', nodeId('skill', skillRef), 'registry');
261
+ }
262
+ }
263
+ } catch (err) {
264
+ // specialists/org may not exist in all contexts; skip gracefully
265
+ }
266
+
267
+ // --- Doc nodes from docs/ directory ---
268
+ const docsDir = path.join(rootDir, 'docs');
269
+ const docFiles = scanDocFiles(docsDir, rootDir);
270
+ for (const docRel of docFiles) {
271
+ node('doc', docRel, docRel, { path: docRel });
272
+ }
273
+
274
+ // --- Documents edges (heuristic linking) ---
275
+ const providerNodeIds = new Set(nodes.filter(n => n.type === 'provider').map(n => n.id));
276
+ const workflowNodeIds = new Set(nodes.filter(n => n.type === 'workflow').map(n => n.id));
277
+
278
+ for (const dn of nodes) {
279
+ if (dn.type !== 'doc') continue;
280
+ const docPath = dn.attrs?.path || dn.name || '';
281
+
282
+ if (docPath.includes('adr/') && docPath.toLowerCase().includes('workflow')) {
283
+ for (const wfId of workflowNodeIds) {
284
+ edge(dn.id, 'documents', wfId, 'doc-scan');
285
+ }
286
+ }
287
+
288
+ if (docPath.includes('adr/') && docPath.toLowerCase().includes('provider')) {
289
+ for (const provId of providerNodeIds) {
290
+ edge(dn.id, 'documents', provId, 'doc-scan');
291
+ }
292
+ }
293
+
294
+ if (docPath.includes('adr/') && docPath.toLowerCase().includes('manifest')) {
295
+ for (const provId of providerNodeIds) {
296
+ edge(dn.id, 'documents', provId, 'doc-scan');
297
+ }
298
+ }
299
+ }
300
+
151
301
  const sourceHash = hashFiles(rootDir, [
152
302
  'registry/capabilities.json',
153
303
  'specialists/org',
154
304
  'lib/embedded-contract/workflow-defs.mjs',
305
+ 'lib/embedded-contract/workflows',
306
+ 'lib/extensions/manifest-schema.mjs',
307
+ 'lib/extensions/loader.mjs',
308
+ 'lib/extensions/validate.mjs',
309
+ 'lib/extensions/manifests',
310
+ 'docs',
311
+ 'lib/registry/assemble.mjs',
312
+ 'specialists/org',
313
+ 'lib/packs/manifest-schema.mjs',
314
+ 'lib/packs/loader.mjs',
315
+ 'lib/packs/core-pack.mjs',
155
316
  ]);
156
317
 
157
318
  return { nodes, edges, sourceHash };