@khoavu882/doflow 2.0.0-beta.5 → 2.0.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 (471) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -2
  4. package/core/.claude-plugin/plugin.json +1 -1
  5. package/core/.codex-plugin/plugin.json +1 -1
  6. package/core/.plugin/plugin.json +1 -1
  7. package/core/harnesses/claude/hooks/lib.sh +43 -24
  8. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  9. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  10. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  11. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  12. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  13. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  14. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  15. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  16. package/core/harnesses/claude/settings/settings.json +18 -0
  17. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  18. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  19. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  20. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  21. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  22. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  23. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  24. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  25. package/core/harnesses/codex/hooks/lib.sh +44 -25
  26. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  27. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  28. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  29. package/core/harnesses/codex/hooks/subagent-audit.sh +1 -0
  30. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  31. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  32. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  33. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  34. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  35. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  36. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  37. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  38. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  39. package/core/harnesses/kiro/agents/doflow.json +1 -1
  40. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  41. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +1 -0
  42. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +1 -0
  43. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +1 -0
  44. package/core/harnesses/kiro/hooks/session-start.sh +1 -0
  45. package/core/harnesses/kiro/hooks/stop-check.sh +1 -0
  46. package/core/harnesses/pi/extensions/doflow-guard.js +8 -0
  47. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +0 -1
  48. package/core/harnesses/shared/hooks/bridge/bridge.sh +102 -9
  49. package/core/harnesses/shared/hooks/bridge/envelope.jq +87 -18
  50. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  51. package/core/harnesses/shared/hooks/bridge/respond.sh +10 -2
  52. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  53. package/core/harnesses/shared/hooks/policies/capture-failure.sh +48 -15
  54. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  55. package/core/harnesses/shared/hooks/policies/contract.sh +3 -0
  56. package/core/harnesses/shared/hooks/policies/deny-json.sh +2 -11
  57. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  58. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  59. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  60. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  61. package/core/harnesses/shared/hooks/policies/lib.sh +63 -40
  62. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +3 -2
  63. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +213 -12
  64. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +114 -38
  65. package/core/harnesses/shared/hooks/policies/session-context.sh +30 -1
  66. package/core/harnesses/shared/hooks/policies/stop-check.sh +20 -9
  67. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +5 -2
  68. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  69. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +60 -155
  70. package/core/harnesses/shared/hooks/stream-hook-runner.js +47 -8
  71. package/core/harnesses/shared/locator/doflow-run +2 -3
  72. package/core/registry/advice.json +3 -3
  73. package/core/registry/assets.json +55 -82
  74. package/core/registry/capabilities.json +12 -0
  75. package/core/registry/contracts.json +58 -31
  76. package/core/registry/contribution-points.json +32 -0
  77. package/core/registry/gates.json +32 -0
  78. package/core/registry/guidance-caps.json +40 -0
  79. package/core/registry/harnesses.json +1442 -363
  80. package/core/registry/lifecycle.json +485 -304
  81. package/core/registry/mcp.json +5 -1
  82. package/core/registry/models.json +7 -1
  83. package/core/registry/package-templates/README.md +19 -0
  84. package/core/registry/package-templates/agent/files/agent.md +9 -0
  85. package/core/registry/package-templates/agent/template.json +4 -0
  86. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  87. package/core/registry/package-templates/capability-provider/template.json +11 -0
  88. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  89. package/core/registry/package-templates/debate-preset/template.json +4 -0
  90. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  91. package/core/registry/package-templates/review-preset/template.json +4 -0
  92. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  93. package/core/registry/package-templates/skill/template.json +4 -0
  94. package/core/registry/package-templates/worker/files/worker.json +92 -0
  95. package/core/registry/package-templates/worker/template.json +11 -0
  96. package/core/registry/packages/doflow/doflow-package.json +15 -0
  97. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  98. package/core/registry/protocols.json +61 -0
  99. package/core/registry/routes.json +17 -0
  100. package/core/registry/rules.json +431 -0
  101. package/core/registry/settings.json +276 -0
  102. package/core/registry/storage.json +679 -31
  103. package/core/registry/telemetry.json +236 -0
  104. package/core/registry/transcripts.json +142 -0
  105. package/core/registry/verification.json +76 -1
  106. package/core/registry/workflows.json +55 -0
  107. package/core/shared/agent-specs/core-implementer.md +3 -0
  108. package/core/shared/agent-specs/delivery-lead.md +68 -0
  109. package/core/shared/agent-specs/quality-guardian.md +5 -1
  110. package/core/shared/agent-specs/research-writer.md +10 -3
  111. package/core/shared/agent-specs/reviewer.md +53 -0
  112. package/core/shared/agent-specs/spec-analyst.md +5 -6
  113. package/core/shared/agent-specs/system-architect.md +5 -1
  114. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  115. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  116. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  117. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  118. package/core/shared/guidance/pointers/codex.md +1 -4
  119. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  120. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  121. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  122. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  123. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  124. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  125. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  126. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  127. package/core/shared/guidance/rules/RULES.md +45 -0
  128. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  129. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  130. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  131. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  132. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  133. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  134. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  135. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  136. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  137. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  138. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  139. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  140. package/core/shared/scripts/doflow/bin/doflow-run +149 -34
  141. package/core/shared/skills/do/SKILL.md +12 -10
  142. package/core/shared/skills/do/references/advice_calls.md +26 -0
  143. package/core/shared/skills/do/references/pm_routing.md +1 -2
  144. package/core/shared/skills/do/references/program_mode.md +31 -0
  145. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  146. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  147. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  148. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  149. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  150. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  151. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  152. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  153. package/core/shared/skills/do-design/SKILL.md +18 -17
  154. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  155. package/core/shared/skills/do-document/SKILL.md +11 -1
  156. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  157. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  158. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  159. package/core/shared/skills/do-execute-plan/SKILL.md +15 -58
  160. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  161. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  162. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +26 -1
  163. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  164. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  165. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  166. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  167. package/core/shared/skills/do-flow/SKILL.md +8 -9
  168. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  169. package/core/shared/skills/do-git/SKILL.md +4 -0
  170. package/core/shared/skills/do-implement/SKILL.md +4 -7
  171. package/core/shared/skills/do-plan/SKILL.md +26 -15
  172. package/core/shared/skills/do-test/SKILL.md +7 -4
  173. package/core/shared/templates/doflow/constitution-template.md +9 -3
  174. package/core/shared/templates/doflow/data-model-template.md +1 -1
  175. package/core/shared/templates/doflow/design-template.md +113 -16
  176. package/core/shared/templates/doflow/plan-template.md +11 -10
  177. package/core/shared/templates/doflow/question-log-template.md +14 -2
  178. package/core/shared/templates/doflow/requirement-template.md +1 -1
  179. package/core/worker-evidence/antigravity/checks.json +14 -0
  180. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  181. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  182. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  183. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  184. package/core/worker-evidence/codex/checks.json +38 -0
  185. package/package.json +10 -6
  186. package/src/adapters/antigravity/index.js +143 -66
  187. package/src/adapters/claude/index.js +24 -4
  188. package/src/adapters/codex/agents.js +25 -15
  189. package/src/adapters/codex/index.js +48 -13
  190. package/src/adapters/codex/native-projection.js +6 -2
  191. package/src/adapters/copilot/index.js +58 -23
  192. package/src/adapters/copy-tree.js +290 -44
  193. package/src/adapters/guidance-manifest.js +71 -0
  194. package/src/adapters/guidance-pointer.js +19 -0
  195. package/src/adapters/hook-commands.js +6 -10
  196. package/src/adapters/index.js +1 -0
  197. package/src/adapters/kiro/index.js +23 -12
  198. package/src/adapters/opencode/index.js +8 -8
  199. package/src/adapters/pi/hooks.js +2 -1
  200. package/src/adapters/pi/index.js +14 -7
  201. package/src/adapters/resolve-source.js +26 -2
  202. package/src/cli/commands/install.js +2 -1
  203. package/src/cli/commands/reconcile.js +53 -9
  204. package/src/cli/commands/remove.js +2 -2
  205. package/src/cli/commands/rollback.js +6 -3
  206. package/src/cli/commands/self-update.js +18 -9
  207. package/src/cli/commands/status.js +21 -2
  208. package/src/cli/commands/ui.js +99 -0
  209. package/src/cli/commands/update.js +2 -1
  210. package/src/cli/index.js +322 -29
  211. package/src/cli/runtime-commands.js +209 -57
  212. package/src/cli/shared.js +0 -2
  213. package/src/helper/git.js +1 -1
  214. package/src/helper/guardrails.js +1 -1
  215. package/src/helper/marker-merge.js +31 -13
  216. package/src/helper/package-ids.js +37 -0
  217. package/src/helper/semver.js +94 -0
  218. package/src/install/backup.js +105 -15
  219. package/src/install/context.js +1 -1
  220. package/src/install/targets.js +31 -16
  221. package/src/lifecycle/coverage.js +20 -3
  222. package/src/lifecycle/hook-tier.js +160 -0
  223. package/src/lifecycle/index.js +412 -78
  224. package/src/lifecycle/retired-harnesses.js +318 -0
  225. package/src/lifecycle/view.js +35 -15
  226. package/src/registry/index.js +551 -26
  227. package/src/registry/worker-ids.js +45 -0
  228. package/src/release/build-package.js +0 -3
  229. package/src/release/docs-blocks.js +492 -0
  230. package/src/release/preflight.js +425 -0
  231. package/src/release/rehearse.js +401 -0
  232. package/src/release/release-workflow.js +733 -0
  233. package/src/release/sync-plugin-versions.js +43 -7
  234. package/src/runtime/advice/bench-gate.js +25 -0
  235. package/src/runtime/advice/cli.js +59 -16
  236. package/src/runtime/advice/client.js +32 -9
  237. package/src/runtime/advice/config.js +98 -133
  238. package/src/runtime/advice/doctor.js +1 -1
  239. package/src/runtime/advice/elevation.js +97 -0
  240. package/src/runtime/advice/endpoint-guard.js +9 -3
  241. package/src/runtime/advice/mode.js +37 -0
  242. package/src/runtime/advice/record.js +18 -5
  243. package/src/runtime/advice/registry.js +4 -1
  244. package/src/runtime/advice/shadow-config.js +229 -0
  245. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  246. package/src/runtime/brief-rules.js +81 -0
  247. package/src/runtime/brief-tools.js +111 -34
  248. package/src/runtime/candidate.js +20 -11
  249. package/src/runtime/capabilities/executor.js +450 -0
  250. package/src/runtime/capabilities/loopback.js +41 -0
  251. package/src/runtime/capabilities/sanitizer.js +88 -0
  252. package/src/runtime/capability-router.js +135 -3
  253. package/src/runtime/checkouts.js +73 -11
  254. package/src/runtime/claims.js +13 -7
  255. package/src/runtime/cli.js +196 -19
  256. package/src/runtime/config-home.js +42 -0
  257. package/src/runtime/context/arbitrate.js +767 -0
  258. package/src/runtime/context/delivery-store.js +4 -6
  259. package/src/runtime/context/emission-rules.js +118 -0
  260. package/src/runtime/context/identity.js +227 -0
  261. package/src/runtime/context/primary-command.js +117 -0
  262. package/src/runtime/context/primary.js +344 -0
  263. package/src/runtime/context/summary-store.js +655 -0
  264. package/src/runtime/context-pack.js +154 -78
  265. package/src/runtime/decision-register.js +13 -4
  266. package/src/runtime/dispatch/admission.js +392 -0
  267. package/src/runtime/dispatch/attempt-end.js +274 -0
  268. package/src/runtime/dispatch/command.js +628 -0
  269. package/src/runtime/dispatch/controls.js +904 -0
  270. package/src/runtime/dispatch/envelope.js +276 -0
  271. package/src/runtime/dispatch/grants.js +310 -0
  272. package/src/runtime/dispatch/integrate.js +617 -0
  273. package/src/runtime/dispatch/loop.js +1835 -0
  274. package/src/runtime/dispatch/store.js +352 -0
  275. package/src/runtime/dispatch/verify-run.js +201 -0
  276. package/src/runtime/evidence-ledger.js +34 -7
  277. package/src/runtime/failure/capture.js +3 -1
  278. package/src/runtime/failure/cli.js +25 -9
  279. package/src/runtime/failure/home.js +57 -30
  280. package/src/runtime/failure/store.js +7 -2
  281. package/src/runtime/feature-pointer.js +174 -0
  282. package/src/runtime/feature-resolve.js +13 -2
  283. package/src/runtime/fleet/command.js +77 -0
  284. package/src/runtime/fleet/projects.js +178 -0
  285. package/src/runtime/fleet/tree.js +383 -0
  286. package/src/runtime/freshness.js +33 -3
  287. package/src/runtime/git-memo.js +46 -0
  288. package/src/runtime/guidance/ablation.js +427 -0
  289. package/src/runtime/health.js +565 -17
  290. package/src/runtime/history-compactor.js +13 -3
  291. package/src/runtime/implementation-gate.js +277 -22
  292. package/src/runtime/inventory/coverage.js +1 -1
  293. package/src/runtime/inventory/index.js +1 -1
  294. package/src/runtime/inventory/precedence.js +2 -2
  295. package/src/runtime/inventory/siblings.js +6 -4
  296. package/src/runtime/knowledge/code-corpus.js +277 -0
  297. package/src/runtime/knowledge/code-lexical.js +130 -0
  298. package/src/runtime/knowledge/code-retrieval.js +307 -0
  299. package/src/runtime/knowledge/code-validation.js +106 -0
  300. package/src/runtime/knowledge/gp3-gate.js +74 -0
  301. package/src/runtime/knowledge/graph-adapter.js +288 -0
  302. package/src/runtime/knowledge/graph-fallback.js +394 -0
  303. package/src/runtime/knowledge/hybrid.js +136 -8
  304. package/src/runtime/knowledge/retrieval.js +34 -1
  305. package/src/runtime/knowledge/rtk-compress.js +77 -0
  306. package/src/runtime/knowledge/semble-bridge.py +106 -0
  307. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  308. package/src/runtime/knowledge/semble-provider.js +365 -0
  309. package/src/runtime/lifecycle/cli.js +16 -6
  310. package/src/runtime/lifecycle/event-store.js +8 -6
  311. package/src/runtime/lifecycle/followup.js +6 -1
  312. package/src/runtime/lifecycle/overview.js +24 -1
  313. package/src/runtime/lifecycle/report-store.js +8 -10
  314. package/src/runtime/lifecycle/retention.js +95 -31
  315. package/src/runtime/lifecycle/root.js +9 -1
  316. package/src/runtime/lifecycle/status.js +34 -17
  317. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  318. package/src/runtime/mask.js +134 -7
  319. package/src/runtime/mcp-consultations.js +40 -6
  320. package/src/runtime/model-router.js +79 -7
  321. package/src/runtime/models/catalogue.js +191 -0
  322. package/src/runtime/models/command.js +153 -0
  323. package/src/runtime/off-words.js +12 -0
  324. package/src/runtime/outcome.js +2 -2
  325. package/src/runtime/packages/command.js +1009 -0
  326. package/src/runtime/packages/contributions.js +116 -0
  327. package/src/runtime/packages/digest.js +132 -0
  328. package/src/runtime/packages/fetch.js +182 -0
  329. package/src/runtime/packages/grants.js +192 -0
  330. package/src/runtime/packages/index-file.js +134 -0
  331. package/src/runtime/packages/instruction.js +90 -0
  332. package/src/runtime/packages/manifest.js +331 -0
  333. package/src/runtime/packages/points.js +477 -0
  334. package/src/runtime/packages/programs.js +216 -0
  335. package/src/runtime/packages/scaffold.js +277 -0
  336. package/src/runtime/packages/source.js +90 -0
  337. package/src/runtime/packages/state.js +164 -0
  338. package/src/runtime/packages/store.js +449 -0
  339. package/src/runtime/packages/tar.js +106 -0
  340. package/src/runtime/packages/view.js +406 -0
  341. package/src/runtime/plan-check.js +59 -0
  342. package/src/runtime/plan-content.js +324 -0
  343. package/src/runtime/policy-init.js +118 -0
  344. package/src/runtime/profiles/doctor.js +96 -0
  345. package/src/runtime/profiles/resolve.js +244 -0
  346. package/src/runtime/profiles/rollback.js +254 -0
  347. package/src/runtime/profiles/sampler.js +41 -0
  348. package/src/runtime/readiness-record.js +16 -11
  349. package/src/runtime/readiness.js +46 -5
  350. package/src/runtime/research-request.js +50 -25
  351. package/src/runtime/retrieval-plan.js +10 -30
  352. package/src/runtime/retrieval-record.js +75 -5
  353. package/src/runtime/review/command.js +246 -0
  354. package/src/runtime/review/dominance.js +68 -0
  355. package/src/runtime/review/findings.js +434 -0
  356. package/src/runtime/review/identity.js +255 -0
  357. package/src/runtime/review/protocol-command.js +109 -0
  358. package/src/runtime/review/protocols.js +405 -0
  359. package/src/runtime/review/resolve-protocol.js +302 -0
  360. package/src/runtime/review/start.js +530 -0
  361. package/src/runtime/roadmap/facts.js +479 -0
  362. package/src/runtime/roadmap/gates.js +270 -0
  363. package/src/runtime/roadmap/loop.js +1636 -0
  364. package/src/runtime/roadmap/merge.js +381 -0
  365. package/src/runtime/roadmap/rows.js +1113 -0
  366. package/src/runtime/roadmap/seed.js +951 -0
  367. package/src/runtime/rules-report.js +336 -0
  368. package/src/runtime/scaffold/artifacts.js +60 -9
  369. package/src/runtime/scaffold/generate.js +21 -9
  370. package/src/runtime/settings/autopilot.js +106 -0
  371. package/src/runtime/settings/cli.js +280 -0
  372. package/src/runtime/settings/config-write.js +314 -0
  373. package/src/runtime/settings/files.js +271 -0
  374. package/src/runtime/settings/legacy.js +154 -0
  375. package/src/runtime/settings/lexical.js +56 -0
  376. package/src/runtime/settings/prepared-run.js +269 -0
  377. package/src/runtime/settings/project-layers.js +118 -0
  378. package/src/runtime/settings/refs.js +288 -0
  379. package/src/runtime/settings/registry.js +553 -0
  380. package/src/runtime/settings/resolve.js +713 -0
  381. package/src/runtime/settings/shared.js +37 -0
  382. package/src/runtime/settings/worker-billing.js +107 -0
  383. package/src/runtime/settings/write.js +269 -0
  384. package/src/runtime/slot-command.js +78 -0
  385. package/src/runtime/slots.js +671 -0
  386. package/src/runtime/source-version.js +1 -0
  387. package/src/runtime/state-root.js +217 -0
  388. package/src/runtime/storage/cli.js +12 -5
  389. package/src/runtime/storage/engine.js +9 -2
  390. package/src/runtime/storage/registry.js +14 -1
  391. package/src/runtime/storage/roots.js +66 -16
  392. package/src/runtime/storage/rules.js +82 -10
  393. package/src/runtime/storage/upkeep.js +10 -2
  394. package/src/runtime/storage/work-status.js +245 -26
  395. package/src/runtime/task-attempts.js +589 -69
  396. package/src/runtime/task-classifier.js +47 -11
  397. package/src/runtime/task-graph.js +373 -0
  398. package/src/runtime/task-run.js +778 -0
  399. package/src/runtime/task-scope.js +176 -55
  400. package/src/runtime/task-sources.js +147 -0
  401. package/src/runtime/task-state.js +374 -64
  402. package/src/runtime/team/admission.js +301 -0
  403. package/src/runtime/team/envelope.js +324 -0
  404. package/src/runtime/team/review-guard.js +156 -0
  405. package/src/runtime/trace/analyze.js +427 -0
  406. package/src/runtime/trace/baseline.js +770 -0
  407. package/src/runtime/trace/ledger.js +63 -140
  408. package/src/runtime/trace/otlp-export.js +568 -0
  409. package/src/runtime/trace/otlp-map.js +481 -0
  410. package/src/runtime/trace/spans.js +745 -0
  411. package/src/runtime/trace/telemetry.js +225 -0
  412. package/src/runtime/trace/views.js +1 -0
  413. package/src/runtime/transcripts/command.js +98 -0
  414. package/src/runtime/transcripts/cursor.js +326 -0
  415. package/src/runtime/transcripts/read.js +126 -0
  416. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  417. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  418. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  419. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  420. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  421. package/src/runtime/transcripts/registry.js +161 -0
  422. package/src/runtime/transcripts/stats.js +161 -0
  423. package/src/runtime/verification/check-key.js +628 -0
  424. package/src/runtime/verification/contract-runner.js +546 -11
  425. package/src/runtime/verification/engine.js +499 -9
  426. package/src/runtime/verification/impact.js +617 -0
  427. package/src/runtime/verification/inflight.js +205 -0
  428. package/src/runtime/verification/registry.js +176 -0
  429. package/src/runtime/verification/reuse.js +184 -0
  430. package/src/runtime/verification/telemetry-emit.js +254 -0
  431. package/src/runtime/verification/test-selection.js +67 -7
  432. package/src/runtime/worker/active.js +90 -0
  433. package/src/runtime/worker/cancel.js +222 -0
  434. package/src/runtime/worker/catalogue.js +122 -0
  435. package/src/runtime/worker/command.js +677 -0
  436. package/src/runtime/worker/evidence.js +288 -0
  437. package/src/runtime/worker/launch.js +288 -0
  438. package/src/runtime/worker/models.js +137 -0
  439. package/src/runtime/worker/parsers.js +218 -0
  440. package/src/runtime/worker/probes/index.js +706 -0
  441. package/src/runtime/worker/process-tree.js +415 -0
  442. package/src/runtime/worker/quota.js +43 -0
  443. package/src/runtime/worker/readiness.js +713 -0
  444. package/src/runtime/worker/run-store.js +166 -0
  445. package/src/runtime/worker/supervisor.js +541 -0
  446. package/src/runtime/worker/worktree-check.js +252 -0
  447. package/src/runtime/workflow-engine.js +5 -1
  448. package/src/runtime/workflow-orchestrator.js +578 -63
  449. package/src/runtime/worktree.js +149 -22
  450. package/src/state/index.js +1 -1
  451. package/src/state/lockfile.js +64 -10
  452. package/src/state/run-lock.js +1 -1
  453. package/types/node-commonjs.d.ts +106 -7
  454. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  455. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  456. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -10
  457. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  458. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -10
  459. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  460. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -10
  461. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  462. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  463. package/core/harnesses/gemini/hooks/session-start.sh +0 -7
  464. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  465. package/core/shared/guidance/FLAGS.md +0 -25
  466. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  467. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  468. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  469. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  470. package/src/adapters/gemini/hooks.js +0 -251
  471. package/src/adapters/gemini/index.js +0 -429
@@ -0,0 +1,477 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * The contribution point registry (122 IC-002): `core/registry/contribution-points.json` read on its own, not
5
+ * through `loadRegistry`, so a bad file disables only non-bundled packages and never fails an installer command
6
+ * (the advice pattern, 063 DEC-025). `loadPoints` returns an error result and never throws; the caller reports
7
+ * it. `POINT_VALIDATORS` is a literal map so module reachability stays auditable, as `ADAPTERS` in
8
+ * `src/runtime/advice/client.js` is. A point is `open` once its validator is registered here (PN-6); a reserved
9
+ * point refuses every entry with `point-reserved`.
10
+ */
11
+
12
+ const fs = require('node:fs');
13
+ const path = require('node:path');
14
+ const { REPO_ROOT } = require('../../helper/repo-root.js');
15
+ const { validatePreset } = require('../review/protocols.js');
16
+ const { skillValidator, agentValidator } = require('./instruction.js');
17
+ const { projectedName, qualifiedId } = require('../../helper/package-ids.js');
18
+ const { dominates } = require('../review/dominance.js');
19
+ const { SEGMENT } = require('./digest.js');
20
+
21
+ const POINTS_FILE = 'core/registry/contribution-points.json';
22
+
23
+ const TOP_KEYS = ['version', 'trustPolicyVersion', 'forbiddenFields', 'limits', 'points', 'bundled'];
24
+ const LIMIT_KEYS = ['files', 'bytes', 'fileBytes', 'pathLength'];
25
+ const POINT_KEYS = ['id', 'versions', 'tier', 'status', 'entry', 'validator', 'combine', 'consumer', 'referencedBy', 'slice', 'opensWith', 'template'];
26
+ const BUNDLED_KEYS = ['id', 'dir', 'contentDigest'];
27
+ const TIERS = ['inert', 'instruction', 'executable'];
28
+ const STATUSES = ['open', 'reserved'];
29
+ const ENTRIES = ['file', 'dir'];
30
+ const COMBINES = ['add-only'];
31
+ const POINT_ID = /^[a-z][a-z0-9-]*$/;
32
+ const DIGEST = /^[0-9a-f]{64}$/;
33
+
34
+ /** A preset contributed under a preset point: the point fixes the kind, the body goes through the one preset validator. */
35
+ function presetValidator(kind ) {
36
+ return (id , preset , context = {}) => {
37
+ const errors = validatePreset(id, preset, context);
38
+ if (preset && typeof preset === 'object' && preset.kind !== kind) {
39
+ errors.push(`presets.${id}.kind must be '${kind}' for a ${kind}-preset contribution`);
40
+ }
41
+ return errors;
42
+ };
43
+ }
44
+
45
+ function workerValidator(id , worker , context = {}) {
46
+ const errors = [];
47
+ const location = context.packageId ? `package '${context.packageId}' worker '${id}'` : `worker '${id}'`;
48
+ const { validateWorker } = require('../../registry/index.js');
49
+ validateWorker(worker, location, errors);
50
+ const { PARSERS } = require('../worker/parsers.js');
51
+ if (worker && typeof worker === 'object' && worker.structuredOutput && typeof worker.structuredOutput === 'object') {
52
+ if (typeof worker.structuredOutput.parser === 'string' && !Object.hasOwn(PARSERS, worker.structuredOutput.parser)) {
53
+ errors.push(`${location} worker 'structuredOutput': parser '${worker.structuredOutput.parser}' is not a registered core parser`);
54
+ }
55
+ }
56
+ return errors;
57
+ }
58
+
59
+ function capabilityProviderValidator(id , entry , context = {}) {
60
+ const errors = [];
61
+ const location = context.packageId ? `package '${context.packageId}' provider '${id}'` : `provider '${id}'`;
62
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
63
+ errors.push(`${location} must be a JSON object`);
64
+ return errors;
65
+ }
66
+
67
+ const CAPABILITY_ID = /^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$/;
68
+ if (typeof entry.capability !== 'string' || !entry.capability.trim() || !CAPABILITY_ID.test(entry.capability)) {
69
+ errors.push(`${location} 'capability' must be a dot-separated capability identifier (e.g. 'text.compress')`);
70
+ }
71
+
72
+ if (typeof entry.name !== 'string' || !entry.name.trim() || entry.name.length > 64) {
73
+ errors.push(`${location} 'name' must be a non-empty string of at most 64 characters`);
74
+ }
75
+
76
+ if (entry.kind !== 'http' && entry.kind !== 'cli') {
77
+ errors.push(`${location} 'kind' must be 'http' or 'cli'`);
78
+ }
79
+
80
+ if (entry.sourceMode !== 'live' && entry.sourceMode !== 'index') {
81
+ errors.push(`${location} 'sourceMode' must be 'live' or 'index'`);
82
+ }
83
+
84
+ if (entry.costTier !== undefined) {
85
+ const validTiers = ['free', 'compute', 'local-index', 'local-graph'];
86
+ if (!validTiers.includes(entry.costTier)) {
87
+ errors.push(`${location} 'costTier' must be one of: ${validTiers.join(', ')}`);
88
+ }
89
+ }
90
+
91
+ if (entry.timeoutMs !== undefined) {
92
+ if (!Number.isInteger(entry.timeoutMs) || entry.timeoutMs < 1 || entry.timeoutMs > 60000) {
93
+ errors.push(`${location} 'timeoutMs' must be a positive integer between 1 and 60000`);
94
+ }
95
+ }
96
+
97
+ const { validateLoopbackUrl } = require('../capabilities/loopback.js');
98
+
99
+ if (entry.kind === 'http') {
100
+ if (entry.program !== undefined) {
101
+ errors.push(`${location} 'program' is forbidden when kind is 'http'`);
102
+ }
103
+ if (typeof entry.endpoint !== 'string' || !entry.endpoint) {
104
+ errors.push(`${location} 'endpoint' is required when kind is 'http'`);
105
+ } else {
106
+ const valid = validateLoopbackUrl(entry.endpoint);
107
+ if (!valid.ok) {
108
+ errors.push(`${location} 'endpoint' is not a loopback URL: ${valid.reason || 'DISALLOWED_REMOTE_ENDPOINT'}`);
109
+ }
110
+ }
111
+
112
+ if (entry.healthEndpoint !== undefined) {
113
+ if (typeof entry.healthEndpoint !== 'string' || !entry.healthEndpoint) {
114
+ errors.push(`${location} 'healthEndpoint' must be a loopback URL: DISALLOWED_REMOTE_ENDPOINT`);
115
+ } else {
116
+ const valid = validateLoopbackUrl(entry.healthEndpoint);
117
+ if (!valid.ok) {
118
+ errors.push(`${location} 'healthEndpoint' must be a loopback URL: ${valid.reason || 'DISALLOWED_REMOTE_ENDPOINT'}`);
119
+ }
120
+ }
121
+ }
122
+
123
+ if (entry.method !== undefined && entry.method !== 'POST' && entry.method !== 'GET') {
124
+ errors.push(`${location} 'method' must be 'POST' or 'GET'`);
125
+ }
126
+ if (entry.headers !== undefined && (!entry.headers || typeof entry.headers !== 'object' || Array.isArray(entry.headers))) {
127
+ errors.push(`${location} 'headers' must be an object of string key-values`);
128
+ }
129
+ if (entry.requestTemplate !== undefined && (!entry.requestTemplate || typeof entry.requestTemplate !== 'object' || Array.isArray(entry.requestTemplate))) {
130
+ errors.push(`${location} 'requestTemplate' must be an object`);
131
+ }
132
+ if (entry.responsePath !== undefined && (typeof entry.responsePath !== 'string' || !entry.responsePath.trim())) {
133
+ errors.push(`${location} 'responsePath' must be a non-empty string`);
134
+ }
135
+ }
136
+
137
+ if (entry.kind === 'cli') {
138
+ if (entry.endpoint !== undefined) {
139
+ errors.push(`${location} 'endpoint' is forbidden when kind is 'cli'`);
140
+ }
141
+ if (typeof entry.program !== 'string' || !entry.program.trim()) {
142
+ errors.push(`${location} 'program' is required when kind is 'cli'`);
143
+ }
144
+ if (entry.argvTemplate !== undefined) {
145
+ if (!Array.isArray(entry.argvTemplate) || entry.argvTemplate.some((a ) => typeof a !== 'string')) {
146
+ errors.push(`${location} 'argvTemplate' must be an array of strings`);
147
+ }
148
+ }
149
+ if (context?.manifest) {
150
+ const programs = Array.isArray(context.manifest.programs) ? context.manifest.programs : [];
151
+ const declared = programs.find((p ) => p && (p.id === entry.program || p.binary === entry.program));
152
+ if (!declared) {
153
+ errors.push(`${location} program '${entry.program}' is not declared in manifest.programs`);
154
+ } else if (declared.argv !== 'capability-cli') {
155
+ errors.push(`${location} program '${entry.program}' must declare argv: 'capability-cli'`);
156
+ }
157
+ }
158
+ }
159
+
160
+ return errors;
161
+ }
162
+
163
+ // Keep this map literal: a validator is reachable only if it is named here.
164
+ const POINT_VALIDATORS = Object.freeze({
165
+ 'review-preset-v1': presetValidator('review'),
166
+ 'debate-preset-v1': presetValidator('debate'),
167
+ 'skill-v1': skillValidator,
168
+ 'agent-v1': agentValidator,
169
+ 'worker-v1': workerValidator,
170
+ 'capability-provider-v1': capabilityProviderValidator,
171
+ });
172
+
173
+ function isObject(value ) {
174
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
175
+ }
176
+ const isPositiveInt = (value ) => Number.isInteger(value) && value > 0;
177
+ const isNonEmptyString = (value ) => typeof value === 'string' && value.length > 0;
178
+
179
+ /** Validate a parsed point registry against the closed IC-002 shape. Errors name the field; never throws. */
180
+ function validatePoints(registry ) {
181
+ const errors = [];
182
+ if (!isObject(registry)) return { ok: false, errors: ['registry must be an object'] };
183
+ for (const key of Object.keys(registry)) if (!TOP_KEYS.includes(key)) errors.push(`registry has unknown key '${key}'`);
184
+
185
+ if (registry.version !== 1) errors.push('version must be 1');
186
+ if (!isPositiveInt(registry.trustPolicyVersion)) errors.push('trustPolicyVersion must be a positive integer');
187
+
188
+ if (!Array.isArray(registry.forbiddenFields) || !registry.forbiddenFields.every(isNonEmptyString)) {
189
+ errors.push('forbiddenFields must be an array of non-empty strings');
190
+ } else if (new Set(registry.forbiddenFields).size !== registry.forbiddenFields.length) {
191
+ errors.push('forbiddenFields must not repeat a name');
192
+ }
193
+
194
+ if (!isObject(registry.limits)) errors.push('limits must be an object');
195
+ else {
196
+ for (const key of Object.keys(registry.limits)) if (!LIMIT_KEYS.includes(key)) errors.push(`limits has unknown key '${key}'`);
197
+ for (const key of LIMIT_KEYS) if (!isPositiveInt(registry.limits[key])) errors.push(`limits.${key} must be a positive integer`);
198
+ }
199
+
200
+ if (!Array.isArray(registry.points) || registry.points.length === 0) errors.push('points must be a non-empty array');
201
+ else {
202
+ const seen = new Set ();
203
+ registry.points.forEach((point , i ) => {
204
+ const where = `points[${i}]`;
205
+ if (!isObject(point)) { errors.push(`${where} must be an object`); return; }
206
+ for (const key of Object.keys(point)) if (!POINT_KEYS.includes(key)) errors.push(`${where} has unknown key '${key}'`);
207
+ if (typeof point.id !== 'string' || !POINT_ID.test(point.id)) errors.push(`${where}.id must match ${POINT_ID}`);
208
+ else if (seen.has(point.id)) errors.push(`${where}.id '${point.id}' is a duplicate point id`);
209
+ else seen.add(point.id);
210
+ const versions = point.versions;
211
+ if (!Array.isArray(versions) || !versions.every(isPositiveInt) || versions.some((v , j ) => j > 0 && v <= versions[j - 1])) {
212
+ errors.push(`${where}.versions must be an ascending array of positive integers`);
213
+ }
214
+ if (!TIERS.includes(point.tier)) errors.push(`${where}.tier must be one of ${TIERS.join(', ')}`);
215
+ if (!STATUSES.includes(point.status)) errors.push(`${where}.status must be one of ${STATUSES.join(', ')}`);
216
+ if (!ENTRIES.includes(point.entry)) errors.push(`${where}.entry must be one of ${ENTRIES.join(', ')}`);
217
+ if (!COMBINES.includes(point.combine)) errors.push(`${where}.combine must be one of ${COMBINES.join(', ')}`);
218
+ if (point.validator === null) {
219
+ if (point.status === 'open') errors.push(`${where}.validator is required on an open point`);
220
+ } else if (typeof point.validator !== 'string' || !Object.hasOwn(POINT_VALIDATORS, point.validator)) {
221
+ errors.push(`${where}.validator '${point.validator}' is not a key of POINT_VALIDATORS (${Object.keys(POINT_VALIDATORS).join(', ')})`);
222
+ }
223
+ if (point.status === 'open' && Array.isArray(versions) && versions.length === 0) errors.push(`${where}.versions must not be empty on an open point`);
224
+ if (point.consumer !== null && !isNonEmptyString(point.consumer)) errors.push(`${where}.consumer must be a module path or null`);
225
+ if (!Array.isArray(point.referencedBy) || !point.referencedBy.every(isNonEmptyString)) errors.push(`${where}.referencedBy must be an array of settings keys`);
226
+ if (!isNonEmptyString(point.slice)) errors.push(`${where}.slice must be a non-empty string`);
227
+ if (point.status === 'reserved' && !isNonEmptyString(point.opensWith)) errors.push(`${where}.opensWith is required on a reserved point`);
228
+ else if ('opensWith' in point && !isNonEmptyString(point.opensWith)) errors.push(`${where}.opensWith must be a non-empty string`);
229
+ if (point.status === 'open') {
230
+ if (!Object.hasOwn(point, 'template')) errors.push(`${where}.template is required on an open point`);
231
+ else if (point.template !== `package-templates/${point.id}`) errors.push(`${where}.template must be package-templates/${point.id} on an open point`);
232
+ } else if (Object.hasOwn(point, 'template')) errors.push(`${where}.template is refused on a reserved point`);
233
+ });
234
+ }
235
+
236
+ if (!Array.isArray(registry.bundled)) errors.push('bundled must be an array');
237
+ else {
238
+ registry.bundled.forEach((entry , i ) => {
239
+ const where = `bundled[${i}]`;
240
+ if (!isObject(entry)) { errors.push(`${where} must be an object`); return; }
241
+ for (const key of Object.keys(entry)) if (!BUNDLED_KEYS.includes(key)) errors.push(`${where} has unknown key '${key}'`);
242
+ if (!isNonEmptyString(entry.id)) errors.push(`${where}.id must be a non-empty string`);
243
+ if (!isNonEmptyString(entry.dir)) errors.push(`${where}.dir must be a non-empty string`);
244
+ if (typeof entry.contentDigest !== 'string' || !DIGEST.test(entry.contentDigest)) errors.push(`${where}.contentDigest must be 64 lower-case hex characters`);
245
+ });
246
+ }
247
+ return { ok: errors.length === 0, errors };
248
+ }
249
+
250
+ /** Read and validate the point registry. An error result, never a throw: the caller reports it and disables non-bundled packages. */
251
+ function loadPoints({ repoRoot = REPO_ROOT, file, fsImpl = fs } = {}) {
252
+ const target = file || path.join(path.resolve(repoRoot), POINTS_FILE);
253
+ let registry ;
254
+ try {
255
+ registry = JSON.parse(fsImpl.readFileSync(target, 'utf8'));
256
+ } catch (error ) {
257
+ return { ok: false, errors: [`${target}: ${error.message}`] };
258
+ }
259
+ const checked = validatePoints(registry);
260
+ return checked.ok ? { ok: true, registry, errors: [] } : { ok: false, errors: checked.errors.map((e) => `${target}: ${e}`) };
261
+ }
262
+
263
+ /** One row per point for `package --action points`. */
264
+ function pointRows(registry ) {
265
+ return registry.points.map((p ) => ({
266
+ id: p.id, versions: p.versions, tier: p.tier, status: p.status, entry: p.entry, opensWith: p.opensWith ?? null,
267
+ }));
268
+ }
269
+
270
+ /**
271
+ * Check the templates named by open points, plus the package README when checking the complete registry.
272
+ * Template defects are scaffold findings and do not affect loading installed packages.
273
+ */
274
+ function templateFindings({ registry, repoRoot = REPO_ROOT, pointId, fsImpl = fs } = {}) {
275
+ const findings = [];
276
+ const add = (field , message , allowed = 'a valid package template') => {
277
+ findings.push({ package: null, field, code: 'template-invalid', severity: 'error', message, allowed });
278
+ };
279
+ const placeholders = new Set(['package', 'local', 'qualified', 'projected', 'version', 'host']);
280
+ const validatePlaceholders = (text , field , isReadme = false) => {
281
+ const allowed = isReadme ? new Set([...placeholders, 'contributions', 'next']) : placeholders;
282
+ const matches = text.match(/\{\{[^{}]*\}\}/g) ?? [];
283
+ for (const match of matches) {
284
+ if (!allowed.has(match.slice(2, -2))) add(field, `unknown template placeholder ${match}`, [...allowed]);
285
+ }
286
+ if (text.replace(/\{\{[^{}]*\}\}/g, '').includes('{{')) add(field, 'template contains an unclosed placeholder', [...allowed]);
287
+ };
288
+ const readTemplateFiles = (root , field ) => {
289
+ const files = [];
290
+ const visit = (dir , relDir ) => {
291
+ let entries ;
292
+ try {
293
+ entries = fsImpl.readdirSync(dir, { withFileTypes: true });
294
+ } catch (error ) {
295
+ add(field, `cannot read template files: ${error.message}`);
296
+ return;
297
+ }
298
+ for (const entry of entries) {
299
+ const rel = relDir ? `${relDir}/${entry.name}` : entry.name;
300
+ const abs = path.join(dir, entry.name);
301
+ let stat ;
302
+ try {
303
+ stat = fsImpl.lstatSync(abs);
304
+ } catch (error ) {
305
+ add(`${field}.${rel}`, `cannot inspect template entry: ${error.message}`);
306
+ continue;
307
+ }
308
+ if (stat.isSymbolicLink()) {
309
+ add(`${field}.${rel}`, `${rel} is a symbolic link`, 'regular files and directories only');
310
+ } else if (stat.isDirectory()) {
311
+ visit(abs, rel);
312
+ } else if (stat.isFile()) {
313
+ files.push({ rel, abs });
314
+ } else {
315
+ add(`${field}.${rel}`, `${rel} is a special file`, 'regular files and directories only');
316
+ }
317
+ }
318
+ };
319
+ visit(root, '');
320
+ return files;
321
+ };
322
+ const root = path.resolve(repoRoot);
323
+ const points = Array.isArray(registry?.points) ? registry.points : [];
324
+ const selected = pointId === undefined ? points.filter((point ) => point?.status === 'open') : points.filter((point ) => point?.id === pointId);
325
+ for (const point of selected) {
326
+ if (point?.status !== 'open' || typeof point.id !== 'string') continue;
327
+ const baseField = `templates.${point.id}`;
328
+ const templateDir = path.join(root, 'core', 'registry', String(point.template ?? `package-templates/${point.id}`));
329
+ let dirStat ;
330
+ try {
331
+ dirStat = fsImpl.lstatSync(templateDir);
332
+ } catch {
333
+ add(baseField, `template directory is missing: ${path.relative(root, templateDir)}`);
334
+ continue;
335
+ }
336
+ if (!dirStat.isDirectory() || dirStat.isSymbolicLink()) {
337
+ add(baseField, 'template path must be a regular directory');
338
+ continue;
339
+ }
340
+
341
+ const configPath = path.join(templateDir, 'template.json');
342
+ let configText = '';
343
+ let config = null;
344
+ try {
345
+ configText = fsImpl.readFileSync(configPath, 'utf8');
346
+ config = JSON.parse(configText);
347
+ } catch (error ) {
348
+ add(`${baseField}.template.json`, `template.json is not valid JSON: ${error.message}`);
349
+ }
350
+ if (config !== null) {
351
+ if (!config || typeof config !== 'object' || Array.isArray(config)) {
352
+ add(`${baseField}.template.json`, 'template.json must be an object');
353
+ } else {
354
+ for (const key of Object.keys(config)) {
355
+ if (!['template', 'path', 'programs'].includes(key)) add(`${baseField}.template.json`, `template.json has unknown key '${key}'`, ['template', 'path', 'programs']);
356
+ }
357
+ if (config.template !== 1) add(`${baseField}.template.json`, 'template must be 1', 1);
358
+ const qualified = qualifiedId('acme', point.id);
359
+ const projected = qualified ? projectedName(qualified) : null;
360
+ if (typeof config.path !== 'string' || !config.path || config.path.startsWith('/') || config.path.includes('\\')) {
361
+ add(`${baseField}.path`, 'path must be a POSIX relative pattern');
362
+ } else {
363
+ if (!config.path.includes('{{local}}') && !config.path.includes('{{projected}}')) {
364
+ add(`${baseField}.path`, 'path must contain {{local}} or {{projected}}');
365
+ }
366
+ const sample = config.path
367
+ .replaceAll('{{package}}', 'acme')
368
+ .replaceAll('{{local}}', point.id)
369
+ .replaceAll('{{qualified}}', qualified ?? 'acme.invalid')
370
+ .replaceAll('{{projected}}', projected ?? 'acme-invalid')
371
+ .replaceAll('{{version}}', '0.1.0')
372
+ .replaceAll('{{host}}', '2.0.0');
373
+ const segments = sample.split('/');
374
+ if (segments.some((segment ) => !segment || !SEGMENT.test(segment))) {
375
+ add(`${baseField}.path`, 'path segments must match the package path grammar');
376
+ }
377
+ if (sample.length > (registry?.limits?.pathLength ?? 0)) {
378
+ add(`${baseField}.path`, `path exceeds the ${registry?.limits?.pathLength ?? 0} character path limit`);
379
+ }
380
+ const rawLast = config.path.split('/').pop();
381
+ if (point.id === 'skill' && rawLast !== '{{projected}}') {
382
+ add(`${baseField}.path`, 'skill path must end in {{projected}}');
383
+ }
384
+ if (point.id === 'agent' && rawLast !== '{{projected}}.md') {
385
+ add(`${baseField}.path`, 'agent path must end in {{projected}}.md');
386
+ }
387
+ }
388
+ const executable = point.tier === 'executable';
389
+ if (executable !== Object.hasOwn(config, 'programs')) {
390
+ add(`${baseField}.programs`, executable ? 'programs is required on an executable point' : 'programs is refused on a non-executable point', executable ? 'an array of program declarations' : 'no programs key');
391
+ }
392
+ if (Object.hasOwn(config, 'programs')) {
393
+ if (!Array.isArray(config.programs)) add(`${baseField}.programs`, 'programs must be an array');
394
+ else config.programs.forEach((program , index ) => {
395
+ const field = `${baseField}.programs[${index}]`;
396
+ if (!program || typeof program !== 'object' || Array.isArray(program)) {
397
+ add(field, 'program declaration must be an object');
398
+ return;
399
+ }
400
+ if (typeof program.id !== 'string' || !program.id) add(`${field}.id`, 'program id must be a non-empty string');
401
+ const hasBinary = typeof program.binary === 'string' && program.binary.length > 0;
402
+ const hasPath = typeof program.path === 'string' && program.path.length > 0;
403
+ if (hasBinary === hasPath) add(field, 'program declaration must have exactly one of binary or path', ['binary', 'path']);
404
+ if (typeof program.argv !== 'string' || !program.argv) add(`${field}.argv`, 'program argv must be a non-empty string');
405
+ for (const key of Object.keys(program)) if (!['id', 'binary', 'path', 'argv'].includes(key)) add(field, `program declaration has unknown key '${key}'`);
406
+ });
407
+ }
408
+ }
409
+ }
410
+ validatePlaceholders(configText, `${baseField}.template.json`);
411
+
412
+ const filesDir = path.join(templateDir, 'files');
413
+ const files = readTemplateFiles(filesDir, `${baseField}.files`);
414
+ if (point.entry === 'file' && files.length !== 1) add(`${baseField}.files`, 'a file-entry template must hold exactly one regular file');
415
+ if (point.entry === 'dir' && files.length < 1) add(`${baseField}.files`, 'a directory-entry template must hold at least one regular file');
416
+ let totalBytes = 0;
417
+ for (const file of files) {
418
+ const field = `${baseField}.${file.rel}`;
419
+ let bytes ;
420
+ let text ;
421
+ try {
422
+ bytes = fsImpl.readFileSync(file.abs);
423
+ text = bytes.toString('utf8');
424
+ } catch (error ) {
425
+ add(field, `cannot read template file: ${error.message}`);
426
+ continue;
427
+ }
428
+ if (!Buffer.from(text, 'utf8').equals(bytes)) add(field, 'template file is not valid UTF-8');
429
+ totalBytes += bytes.length;
430
+ if (bytes.length > (registry?.limits?.fileBytes ?? 0)) add(field, `file exceeds the ${registry?.limits?.fileBytes ?? 0} byte limit`);
431
+ if (file.rel.length > (registry?.limits?.pathLength ?? 0)) add(field, `file path exceeds the ${registry?.limits?.pathLength ?? 0} character limit`);
432
+ validatePlaceholders(text, field);
433
+ }
434
+ if (files.length > (registry?.limits?.files ?? 0)) add(`${baseField}.files`, `template has more than ${registry?.limits?.files ?? 0} files`);
435
+ if (totalBytes > (registry?.limits?.bytes ?? 0)) add(`${baseField}.files`, `template exceeds the ${registry?.limits?.bytes ?? 0} byte limit`);
436
+ }
437
+
438
+ if (pointId === undefined) {
439
+ const readmePath = path.join(root, 'core', 'registry', 'package-templates', 'README.md');
440
+ const field = 'templates.README.md';
441
+ try {
442
+ const bytes = fsImpl.readFileSync(readmePath);
443
+ const text = bytes.toString('utf8');
444
+ if (!Buffer.from(text, 'utf8').equals(bytes)) add(field, 'README template is not valid UTF-8');
445
+ for (const heading of ['## What and why', '## Contributions', '## Check, add and trust', '## Editing after it is added']) {
446
+ if (!text.split(/\r?\n/).includes(heading)) add(field, `README template is missing '${heading}'`);
447
+ }
448
+ if (!/edit[\s\S]*check[\s\S]*update --id[\s\S]*update --plan/i.test(text)) add(field, 'README must describe the edit, check, update --id, update --plan loop');
449
+ if (!/above inert[\s\S]*new trust line/i.test(text)) add(field, 'README must require a new trust line for changed content above inert');
450
+ validatePlaceholders(text, field, true);
451
+ } catch (error ) {
452
+ add(field, `README template cannot be read: ${error.message}`);
453
+ }
454
+ }
455
+ return findings;
456
+ }
457
+
458
+ /**
459
+ * Judge one manifest contribution entry against the registry (IC-002, IC-020). Returns an IC-004 finding, or null
460
+ * when the point is open and the version supported. `index` locates the entry in `contributions[]`.
461
+ */
462
+ function judgeContribution(registry , entry , { packageId, index } ) {
463
+ const point = registry.points.find((p ) => p.id === entry?.point);
464
+ const open = registry.points.filter((p ) => p.status === 'open').map((p ) => p.id);
465
+ const finding = (field , code , message , allowed ) => (
466
+ { package: packageId, field: `contributions[${index}].${field}`, code, severity: 'error', message, allowed });
467
+ if (!point) return finding('point', 'undeclared-point', `point '${entry?.point}' is not declared; open points: ${open.join(', ')}`, open);
468
+ if (point.status === 'reserved') {
469
+ return finding('point', 'point-reserved', `point '${point.id}' is reserved and opens with ${point.opensWith}; it accepts no contribution yet`, open);
470
+ }
471
+ if (!point.versions.includes(entry.version)) {
472
+ return finding('version', 'unsupported-point-version', `point '${point.id}' does not support version ${entry.version}; supported: ${point.versions.join(', ')}`, point.versions);
473
+ }
474
+ return null;
475
+ }
476
+
477
+ module.exports = { loadPoints, validatePoints, judgeContribution, pointRows, templateFindings, POINT_VALIDATORS, POINTS_FILE };