@planu/cli 4.14.1 → 5.1.1

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 (452) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/LICENSE +55 -12
  3. package/README.md +10 -2
  4. package/dist/cli/commands/install.d.ts +1 -12
  5. package/dist/cli/commands/install.js +9 -65
  6. package/dist/cli/commands/job.js +4 -3
  7. package/dist/cli/commands/spec.js +12 -3
  8. package/dist/cli/commands/validate.js +2 -2
  9. package/dist/cli/router.js +1 -3
  10. package/dist/config/environment-schema.json +1 -3
  11. package/dist/config/official-sdd-tools.d.ts +4 -0
  12. package/dist/config/official-sdd-tools.js +35 -0
  13. package/dist/config/product-public.d.ts +139 -3
  14. package/dist/config/product-public.js +8 -1
  15. package/dist/config/product-public.json +7 -36
  16. package/dist/config/registries/hosts/codex.json +20 -363
  17. package/dist/config/release-policy.json +84 -2
  18. package/dist/config/runtime-policy.json +12 -1
  19. package/dist/config/skill-templates/planu-resume-work.md +2 -2
  20. package/dist/core/index.d.ts +1 -1
  21. package/dist/core/spec-validator.d.ts +4 -4
  22. package/dist/core/spec-validator.js +33 -19
  23. package/dist/engine/abortable-process-runner.d.ts +20 -2
  24. package/dist/engine/abortable-process-runner.js +243 -74
  25. package/dist/engine/ambiguity-scorer.js +4 -26
  26. package/dist/engine/auth/scope-mapper.js +1 -7
  27. package/dist/engine/autopilot/state-updater.js +4 -4
  28. package/dist/engine/cascade-hooks/hooks/review-enricher.hook.js +9 -6
  29. package/dist/engine/cascade-hooks/state-drift-detector.d.ts +3 -3
  30. package/dist/engine/cascade-hooks/state-drift-detector.js +1 -1
  31. package/dist/engine/ci-generator/planu-config.js +1 -7
  32. package/dist/engine/clarification-gate/gate.d.ts +3 -3
  33. package/dist/engine/code-scanner/layer-scanner.js +6 -22
  34. package/dist/engine/core-bridge.d.ts +3 -3
  35. package/dist/engine/cost-guardrails.d.ts +1 -1
  36. package/dist/engine/cost-guardrails.js +1 -1
  37. package/dist/engine/criterion-identity.d.ts +1 -0
  38. package/dist/engine/criterion-identity.js +7 -0
  39. package/dist/engine/dashboard/data-loader.js +2 -7
  40. package/dist/engine/dashboard/templates-layout.js +0 -3
  41. package/dist/engine/dashboard/templates-project.js +1 -13
  42. package/dist/engine/docs-site-generator/data-collector.d.ts +1 -1
  43. package/dist/engine/docs-site-generator/data-collector.js +7 -28
  44. package/dist/engine/docs-site-generator/tools-renderer.js +3 -10
  45. package/dist/engine/evidence-gates/artifact-reader.d.ts +12 -1
  46. package/dist/engine/evidence-gates/artifact-reader.js +174 -4
  47. package/dist/engine/evidence-gates/evidence-autofill.d.ts +10 -0
  48. package/dist/engine/evidence-gates/evidence-autofill.js +148 -0
  49. package/dist/engine/evidence-gates/evidence-skeletons.d.ts +19 -0
  50. package/dist/engine/evidence-gates/evidence-skeletons.js +69 -0
  51. package/dist/engine/evidence-gates/lifecycle-gate.js +4 -3
  52. package/dist/engine/evidence-gates/reconciliation-freshness.d.ts +11 -0
  53. package/dist/engine/evidence-gates/reconciliation-freshness.js +72 -0
  54. package/dist/engine/evidence-index/done-drift.d.ts +1 -1
  55. package/dist/engine/evidence-index/done-drift.js +40 -18
  56. package/dist/engine/execution/context.js +3 -0
  57. package/dist/engine/execution/durable-job-heartbeat-runtime.d.ts +4 -0
  58. package/dist/engine/execution/durable-job-heartbeat-runtime.js +400 -0
  59. package/dist/engine/execution/job-runtime.d.ts +30 -0
  60. package/dist/engine/execution/job-runtime.js +114 -6
  61. package/dist/engine/execution/operation-journal.js +10 -4
  62. package/dist/engine/execution/public-job-sanitizer.d.ts +4 -0
  63. package/dist/engine/execution/public-job-sanitizer.js +31 -0
  64. package/dist/engine/execution/validate-job-executor.d.ts +12 -1
  65. package/dist/engine/execution/validate-job-executor.js +549 -86
  66. package/dist/engine/execution/validate-job-payload.js +107 -50
  67. package/dist/engine/execution/validate-job-recovery.js +1 -1
  68. package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
  69. package/dist/engine/execution/validate-worker-runtime.js +90 -2
  70. package/dist/engine/execution/validate-worker-thread.js +17 -24
  71. package/dist/engine/handoff-artifacts/schemas.d.ts +2 -1
  72. package/dist/engine/handoff-artifacts/schemas.js +33 -0
  73. package/dist/engine/handoff-packager.d.ts +19 -0
  74. package/dist/engine/handoff-packager.js +415 -13
  75. package/dist/engine/hooks/effort-configurator.js +1 -1
  76. package/dist/engine/impact-detector/test-break-predictor.js +3 -3
  77. package/dist/engine/impact-detector/tool-registration.js +1 -1
  78. package/dist/engine/implementation-contract/renderer.js +23 -8
  79. package/dist/engine/lifecycle-reconciliation-io.d.ts +11 -0
  80. package/dist/engine/lifecycle-reconciliation-io.js +180 -0
  81. package/dist/engine/lifecycle-reconciliation.d.ts +16 -0
  82. package/dist/engine/lifecycle-reconciliation.js +406 -0
  83. package/dist/engine/local-first/tool-classification.js +2 -0
  84. package/dist/engine/macos-keychain-native-port.d.ts +5 -0
  85. package/dist/engine/macos-keychain-native-port.js +19 -7
  86. package/dist/engine/migrations/remove-commercial-state.d.ts +3 -0
  87. package/dist/engine/migrations/remove-commercial-state.js +343 -0
  88. package/dist/engine/minimality/policy-loader.js +247 -6
  89. package/dist/engine/network-policy.js +1 -0
  90. package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
  91. package/dist/engine/planu-core.darwin-arm64.node.sbom.json +20 -20
  92. package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
  93. package/dist/engine/planu-core.darwin-x64.node.sbom.json +20 -20
  94. package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
  95. package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +20 -20
  96. package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
  97. package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +20 -20
  98. package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
  99. package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +20 -20
  100. package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
  101. package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +20 -20
  102. package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
  103. package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +20 -20
  104. package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
  105. package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +20 -20
  106. package/dist/engine/readiness-checker.d.ts +1 -16
  107. package/dist/engine/readiness-checker.js +27 -88
  108. package/dist/engine/reverse-engineer/api-detector.js +2 -13
  109. package/dist/engine/reverse-engineer/complexity-analyzer.js +2 -13
  110. package/dist/engine/reverse-engineer/config-analyzer.js +2 -13
  111. package/dist/engine/reverse-engineer/dependency-graph.js +2 -13
  112. package/dist/engine/reverse-engineer/test-analyzer.js +2 -13
  113. package/dist/engine/reverse-engineer/walk-ignore.d.ts +3 -0
  114. package/dist/engine/reverse-engineer/walk-ignore.js +26 -0
  115. package/dist/engine/runtime-policy.d.ts +2 -0
  116. package/dist/engine/runtime-policy.js +42 -5
  117. package/dist/engine/runtime-security/rate-limiter.js +0 -1
  118. package/dist/engine/safety/contained-project-file.d.ts +3 -0
  119. package/dist/engine/safety/contained-project-file.js +23 -0
  120. package/dist/engine/scope-boundaries/contradiction-checker.js +63 -1
  121. package/dist/engine/scope-boundaries/scope-validator.js +45 -7
  122. package/dist/engine/session/checkpoint-writer.js +0 -9
  123. package/dist/engine/spec-format/acceptance-criteria.d.ts +6 -2
  124. package/dist/engine/spec-format/acceptance-criteria.js +82 -22
  125. package/dist/engine/spec-format/markdown-sections.d.ts +14 -0
  126. package/dist/engine/spec-format/markdown-sections.js +105 -0
  127. package/dist/engine/spec-format/read-technical-section.js +33 -5
  128. package/dist/engine/spec-format/technical-md-populator.js +3 -2
  129. package/dist/engine/spec-format/text-fences.js +20 -2
  130. package/dist/engine/spec-format/unified-spec-builder.d.ts +7 -0
  131. package/dist/engine/spec-format/unified-spec-builder.js +202 -0
  132. package/dist/engine/spec-migrator/canonical-deduplicator.d.ts +18 -0
  133. package/dist/engine/spec-migrator/canonical-deduplicator.js +479 -0
  134. package/dist/engine/spec-migrator/filesystem-import.d.ts +4 -8
  135. package/dist/engine/spec-migrator/filesystem-import.js +121 -14
  136. package/dist/engine/spec-migrator/frontmatter-parser.js +32 -15
  137. package/dist/engine/spec-migrator/index.d.ts +1 -0
  138. package/dist/engine/spec-migrator/index.js +1 -0
  139. package/dist/engine/spec-state-machine/transition-spec.d.ts +6 -1
  140. package/dist/engine/spec-state-machine/transition-spec.js +10 -1
  141. package/dist/engine/spec-state-syncer.js +1 -1
  142. package/dist/engine/technical-enricher/index.js +16 -8
  143. package/dist/engine/technical-enricher/render-enriched.d.ts +1 -0
  144. package/dist/engine/technical-enricher/render-enriched.js +42 -14
  145. package/dist/engine/telemetry/health-checker.js +53 -17
  146. package/dist/engine/telemetry/telemetry-client.js +26 -8
  147. package/dist/engine/text-signal-boundaries.d.ts +2 -0
  148. package/dist/engine/text-signal-boundaries.js +25 -2
  149. package/dist/engine/time/relative-date.d.ts +3 -0
  150. package/dist/engine/time/relative-date.js +16 -0
  151. package/dist/engine/timing/budget.d.ts +11 -0
  152. package/dist/engine/timing/budget.js +31 -9
  153. package/dist/engine/token-optimizer/analytics.d.ts +1 -1
  154. package/dist/engine/token-optimizer/analytics.js +5 -6
  155. package/dist/engine/usage-tracker/core.d.ts +2 -2
  156. package/dist/engine/usage-tracker/core.js +1 -2
  157. package/dist/engine/usage-tracker/index.d.ts +0 -3
  158. package/dist/engine/usage-tracker/index.js +0 -3
  159. package/dist/engine/usage-tracker/stats.d.ts +2 -2
  160. package/dist/engine/usage-tracker/stats.js +1 -28
  161. package/dist/engine/validation/durable-validation.d.ts +1 -1
  162. package/dist/engine/validation/durable-validation.js +3 -82
  163. package/dist/engine/validation/validation-freshness.d.ts +11 -1
  164. package/dist/engine/validation/validation-freshness.js +231 -91
  165. package/dist/engine/validation/validation-receipt.d.ts +9 -6
  166. package/dist/engine/validation/validation-receipt.js +84 -24
  167. package/dist/engine/validation/validation-source-digest.d.ts +2 -0
  168. package/dist/engine/validation/validation-source-digest.js +86 -0
  169. package/dist/engine/validation/validation-submission.d.ts +5 -4
  170. package/dist/engine/validation/validation-submission.js +25 -11
  171. package/dist/engine/validation/validation-worktree.d.ts +21 -0
  172. package/dist/engine/validation/validation-worktree.js +260 -0
  173. package/dist/engine/validation-impact-planner.d.ts +14 -2
  174. package/dist/engine/validation-impact-planner.js +0 -3
  175. package/dist/engine/validator/dor-dod.d.ts +1 -0
  176. package/dist/engine/validator/dor-dod.js +5 -3
  177. package/dist/engine/validator/extractors.d.ts +1 -5
  178. package/dist/engine/validator/extractors.js +24 -69
  179. package/dist/engine/validator/spec-compliance-runner.d.ts +12 -24
  180. package/dist/engine/validator/spec-compliance-runner.js +429 -211
  181. package/dist/engine/validator.js +35 -22
  182. package/dist/index.js +4 -16
  183. package/dist/resources/usage-stats-resource.js +2 -18
  184. package/dist/security/adapters/linux-secret-service.js +7 -3
  185. package/dist/security/adapters/windows-credential-manager.js +6 -4
  186. package/dist/server/routes/specs.js +13 -1
  187. package/dist/storage/base-store.d.ts +1 -1
  188. package/dist/storage/base-store.js +1 -1
  189. package/dist/storage/feedback-remote.d.ts +2 -3
  190. package/dist/storage/feedback-remote.js +45 -31
  191. package/dist/storage/global-store.d.ts +1 -17
  192. package/dist/storage/global-store.js +1 -42
  193. package/dist/storage/index.d.ts +0 -2
  194. package/dist/storage/index.js +0 -2
  195. package/dist/storage/migrations/canonical-storage.js +124 -11
  196. package/dist/storage/runtime-db.d.ts +9 -0
  197. package/dist/storage/runtime-db.js +64 -8
  198. package/dist/storage/spec-store.d.ts +14 -2
  199. package/dist/storage/spec-store.js +104 -14
  200. package/dist/storage/status-store/atomic-status-write.d.ts +5 -0
  201. package/dist/storage/status-store/atomic-status-write.js +57 -0
  202. package/dist/storage/status-store/file-lock.js +30 -11
  203. package/dist/storage/status-store/self-healing.js +3 -3
  204. package/dist/storage/status-store/version-sync.d.ts +2 -1
  205. package/dist/storage/status-store/version-sync.js +35 -40
  206. package/dist/storage/usage-store.d.ts +1 -5
  207. package/dist/storage/usage-store.js +0 -35
  208. package/dist/tools/auto-update-handler.d.ts +3 -3
  209. package/dist/tools/auto-update-handler.js +3 -3
  210. package/dist/tools/challenge-spec/resilience-challenge-scenarios.d.ts +2 -1
  211. package/dist/tools/challenge-spec/resilience-challenge-scenarios.js +10 -7
  212. package/dist/tools/challenge-spec/scenario-collector.js +1 -1
  213. package/dist/tools/challenge-spec/scenarios-data.js +1 -1
  214. package/dist/tools/challenge-spec/scenarios-utils.d.ts +1 -1
  215. package/dist/tools/challenge-spec/scenarios-utils.js +35 -11
  216. package/dist/tools/challenge-spec-helpers.d.ts +10 -1
  217. package/dist/tools/challenge-spec-helpers.js +63 -22
  218. package/dist/tools/challenge-spec.js +23 -8
  219. package/dist/tools/check-readiness.js +38 -14
  220. package/dist/tools/configure-telemetry.js +30 -2
  221. package/dist/tools/create-spec/spec-builder.d.ts +7 -0
  222. package/dist/tools/create-spec/spec-builder.js +19 -15
  223. package/dist/tools/create-spec.d.ts +1 -0
  224. package/dist/tools/create-spec.js +584 -309
  225. package/dist/tools/git/branch-ops.d.ts +1 -1
  226. package/dist/tools/git/branch-ops.js +3 -2
  227. package/dist/tools/init-project/handler.js +10 -12
  228. package/dist/tools/init-project/host-assets-writer.js +26 -1
  229. package/dist/tools/init-project/lint-scaffolder.d.ts +3 -3
  230. package/dist/tools/init-project/migration-runner.d.ts +2 -4
  231. package/dist/tools/init-project/migration-runner.js +3 -2
  232. package/dist/tools/init-project/portable-index-reconciler.d.ts +4 -0
  233. package/dist/tools/init-project/portable-index-reconciler.js +14 -0
  234. package/dist/tools/init-project/result-builder.js +1 -3
  235. package/dist/tools/jobs/handlers.js +38 -6
  236. package/dist/tools/list-specs.js +5 -26
  237. package/dist/tools/merge-risk-handler.js +2 -2
  238. package/dist/tools/package-handoff.js +2 -0
  239. package/dist/tools/reconcile-spec.js +0 -27
  240. package/dist/tools/register-agent-squad-tools.js +2 -2
  241. package/dist/tools/register-platform-tools/design-stack-tools.js +11 -11
  242. package/dist/tools/register-platform-tools/lifecycle-infra-tools.js +7 -7
  243. package/dist/tools/register-sdd-tools.d.ts +1 -1
  244. package/dist/tools/register-sdd-tools.js +2 -29
  245. package/dist/tools/register-spec-tools/analysis-tools.js +8 -8
  246. package/dist/tools/register-spec-tools/core-spec-tools.js +29 -19
  247. package/dist/tools/safe-handler.d.ts +5 -13
  248. package/dist/tools/safe-handler.js +7 -23
  249. package/dist/tools/schemas/index.d.ts +1 -1
  250. package/dist/tools/schemas/index.js +1 -1
  251. package/dist/tools/schemas/output-schemas.d.ts +0 -23
  252. package/dist/tools/schemas/output-schemas.js +0 -28
  253. package/dist/tools/schemas/spec.d.ts +4 -0
  254. package/dist/tools/schemas/spec.js +3 -0
  255. package/dist/tools/schemas/validate-output-schema.d.ts +11 -0
  256. package/dist/tools/schemas/validate-output-schema.js +7 -0
  257. package/dist/tools/spec-prompt-handler.js +3 -3
  258. package/dist/tools/sync-spec-state-handler.d.ts +1 -1
  259. package/dist/tools/sync-spec-state-handler.js +50 -2
  260. package/dist/tools/tool-entry.d.ts +4 -4
  261. package/dist/tools/tool-entry.js +3 -3
  262. package/dist/tools/tool-registry/core-tools.js +31 -15
  263. package/dist/tools/tool-registry/group-infra.js +27 -110
  264. package/dist/tools/tool-registry/group-quality-compliance.js +26 -26
  265. package/dist/tools/tool-registry/inventory.d.ts +2 -0
  266. package/dist/tools/tool-registry/inventory.js +2 -0
  267. package/dist/tools/tool-registry-helpers.d.ts +3 -3
  268. package/dist/tools/tool-registry-helpers.js +3 -3
  269. package/dist/tools/tool-usage-report/registered-tools.d.ts +1 -1
  270. package/dist/tools/tool-usage-report/registered-tools.js +3 -15
  271. package/dist/tools/update-status/approval-gates.js +3 -0
  272. package/dist/tools/update-status/batch.d.ts +6 -2
  273. package/dist/tools/update-status/batch.js +58 -1
  274. package/dist/tools/update-status/dod-gates.d.ts +16 -1
  275. package/dist/tools/update-status/dod-gates.js +191 -1
  276. package/dist/tools/update-status/done-receipt-verifier.d.ts +8 -0
  277. package/dist/tools/update-status/done-receipt-verifier.js +75 -27
  278. package/dist/tools/update-status/evidence-gate.d.ts +4 -0
  279. package/dist/tools/update-status/evidence-gate.js +103 -3
  280. package/dist/tools/update-status/file-sync.d.ts +4 -3
  281. package/dist/tools/update-status/file-sync.js +57 -6
  282. package/dist/tools/update-status/index.d.ts +25 -1
  283. package/dist/tools/update-status/index.js +292 -78
  284. package/dist/tools/update-status/response-builder.js +3 -3
  285. package/dist/tools/update-status/side-effects.d.ts +2 -0
  286. package/dist/tools/update-status/side-effects.js +2 -2
  287. package/dist/tools/update-status/transition-guard.js +45 -16
  288. package/dist/tools/update-status-actions.d.ts +4 -2
  289. package/dist/tools/update-status-actions.js +16 -14
  290. package/dist/tools/usage-report.js +1 -16
  291. package/dist/tools/usage-stats.js +1 -18
  292. package/dist/tools/usage-tracking.d.ts +4 -0
  293. package/dist/tools/usage-tracking.js +20 -0
  294. package/dist/tools/validate-lint.d.ts +1 -0
  295. package/dist/tools/validate-lint.js +1 -1
  296. package/dist/tools/validate.d.ts +2 -1
  297. package/dist/tools/validate.js +114 -34
  298. package/dist/tools/workspace-dashboard-handler.js +38 -0
  299. package/dist/transports/http-transport.js +6 -8
  300. package/dist/transports/mcp-types.d.ts +0 -2
  301. package/dist/transports/session-context.js +1 -1
  302. package/dist/types/cascade-hooks.d.ts +1 -1
  303. package/dist/types/ci.d.ts +0 -4
  304. package/dist/types/clarification-token.d.ts +1 -1
  305. package/dist/types/claude-code-runtime.d.ts +0 -27
  306. package/dist/types/commercial-migration.d.ts +17 -0
  307. package/dist/types/commercial-migration.js +2 -0
  308. package/dist/types/common/primitives.d.ts +0 -2
  309. package/dist/types/core-bridge.d.ts +4 -10
  310. package/dist/types/dashboard.d.ts +3 -7
  311. package/dist/types/docs.d.ts +0 -1
  312. package/dist/types/durable-job.d.ts +4 -4
  313. package/dist/types/durable-validation.d.ts +100 -2
  314. package/dist/types/durable-validation.js +165 -1
  315. package/dist/types/errors/structured-error.d.ts +3 -3
  316. package/dist/types/estimation.d.ts +2 -0
  317. package/dist/types/evidence-autofill.d.ts +34 -0
  318. package/dist/types/evidence-autofill.js +2 -0
  319. package/dist/types/evidence-gates.d.ts +9 -1
  320. package/dist/types/execution.d.ts +2 -0
  321. package/dist/types/gemini-integration.d.ts +0 -11
  322. package/dist/types/handoff-artifacts.d.ts +41 -0
  323. package/dist/types/hooks-advanced.d.ts +0 -13
  324. package/dist/types/impact-detection.d.ts +2 -2
  325. package/dist/types/index.d.ts +3 -6
  326. package/dist/types/index.js +2 -5
  327. package/dist/types/kiro-integration.d.ts +0 -6
  328. package/dist/types/network-policy.d.ts +1 -1
  329. package/dist/types/project/lint-scaffolder.d.ts +1 -1
  330. package/dist/types/runtime-policy.d.ts +11 -0
  331. package/dist/types/session-safeguard.d.ts +0 -31
  332. package/dist/types/spec/canonical-repair.d.ts +81 -0
  333. package/dist/types/spec/canonical-repair.js +2 -0
  334. package/dist/types/spec/core.d.ts +20 -0
  335. package/dist/types/spec/index.d.ts +1 -0
  336. package/dist/types/spec/index.js +1 -0
  337. package/dist/types/spec/inputs.d.ts +35 -1
  338. package/dist/types/spec-format.d.ts +25 -1
  339. package/dist/types/telemetry.d.ts +4 -1
  340. package/dist/types/transition-log.d.ts +1 -1
  341. package/dist/types/transport.d.ts +0 -2
  342. package/dist/types/usage.d.ts +1 -36
  343. package/dist/types/usage.js +1 -1
  344. package/dist/types/validate-worker.d.ts +6 -0
  345. package/dist/types/validation-receipt.d.ts +1 -1
  346. package/dist/types/validation.d.ts +10 -4
  347. package/package.json +17 -12
  348. package/planu-native.json +1 -1
  349. package/planu-plugin.json +23 -40
  350. package/scripts/lib/pending-release-file.mjs +93 -0
  351. package/src/i18n/messages/en.json +0 -41
  352. package/src/i18n/messages/es.json +0 -41
  353. package/src/i18n/messages/pt.json +0 -41
  354. package/dist/cli/commands/activate.d.ts +0 -14
  355. package/dist/cli/commands/activate.js +0 -174
  356. package/dist/config/license-plans.json +0 -251
  357. package/dist/config/product-public.ts +0 -148
  358. package/dist/config/server-instructions.ts +0 -121
  359. package/dist/config/version-defaults.ts +0 -76
  360. package/dist/config/version.ts +0 -21
  361. package/dist/engine/ai-integration/gemini/settings-generator.d.ts +0 -4
  362. package/dist/engine/ai-integration/gemini/settings-generator.js +0 -195
  363. package/dist/engine/ai-integration/kiro/hooks-generator.d.ts +0 -6
  364. package/dist/engine/ai-integration/kiro/hooks-generator.js +0 -75
  365. package/dist/engine/hooks/full-spectrum-generator.d.ts +0 -32
  366. package/dist/engine/hooks/full-spectrum-generator.js +0 -117
  367. package/dist/engine/license-validator/config-loader.d.ts +0 -5
  368. package/dist/engine/license-validator/config-loader.js +0 -16
  369. package/dist/engine/license-validator/core.d.ts +0 -15
  370. package/dist/engine/license-validator/core.js +0 -151
  371. package/dist/engine/license-validator/fingerprint.d.ts +0 -3
  372. package/dist/engine/license-validator/fingerprint.js +0 -17
  373. package/dist/engine/license-validator/lemon-squeezy.d.ts +0 -5
  374. package/dist/engine/license-validator/lemon-squeezy.js +0 -55
  375. package/dist/engine/license-validator.d.ts +0 -5
  376. package/dist/engine/license-validator.js +0 -6
  377. package/dist/engine/product-intelligence/index.d.ts +0 -7
  378. package/dist/engine/product-intelligence/index.js +0 -211
  379. package/dist/engine/session/auto-save.d.ts +0 -18
  380. package/dist/engine/session/auto-save.js +0 -98
  381. package/dist/engine/session/context-snapshot.d.ts +0 -8
  382. package/dist/engine/session/context-snapshot.js +0 -49
  383. package/dist/engine/session/memory-sync.d.ts +0 -12
  384. package/dist/engine/session/memory-sync.js +0 -34
  385. package/dist/engine/session/session-diff.d.ts +0 -11
  386. package/dist/engine/session/session-diff.js +0 -42
  387. package/dist/engine/session/session-merge.d.ts +0 -12
  388. package/dist/engine/session/session-merge.js +0 -55
  389. package/dist/engine/session-safeguard/checkpoint-runner.d.ts +0 -4
  390. package/dist/engine/session-safeguard/checkpoint-runner.js +0 -70
  391. package/dist/engine/session-safeguard/learnings-buffer.d.ts +0 -15
  392. package/dist/engine/session-safeguard/learnings-buffer.js +0 -91
  393. package/dist/engine/session-safeguard/precompaction-drain.d.ts +0 -10
  394. package/dist/engine/session-safeguard/precompaction-drain.js +0 -82
  395. package/dist/engine/session-safeguard/unpushed-detector.d.ts +0 -7
  396. package/dist/engine/session-safeguard/unpushed-detector.js +0 -59
  397. package/dist/engine/spec-changelog/core.d.ts +0 -16
  398. package/dist/engine/spec-changelog/core.js +0 -176
  399. package/dist/engine/spec-changelog/diff.d.ts +0 -18
  400. package/dist/engine/spec-changelog/diff.js +0 -121
  401. package/dist/engine/spec-changelog/index.d.ts +0 -3
  402. package/dist/engine/spec-changelog/index.js +0 -4
  403. package/dist/engine/trial-engine.d.ts +0 -5
  404. package/dist/engine/trial-engine.js +0 -14
  405. package/dist/engine/usage-tracker/rate-check.d.ts +0 -7
  406. package/dist/engine/usage-tracker/rate-check.js +0 -18
  407. package/dist/engine/usage-tracker/rate-limiter.d.ts +0 -14
  408. package/dist/engine/usage-tracker/rate-limiter.js +0 -73
  409. package/dist/engine/usage-tracker/trial.d.ts +0 -27
  410. package/dist/engine/usage-tracker/trial.js +0 -49
  411. package/dist/engine/webhook/event-handlers.d.ts +0 -25
  412. package/dist/engine/webhook/event-handlers.js +0 -89
  413. package/dist/engine/webhook/index.d.ts +0 -4
  414. package/dist/engine/webhook/index.js +0 -5
  415. package/dist/engine/webhook/server.d.ts +0 -12
  416. package/dist/engine/webhook/server.js +0 -249
  417. package/dist/engine/webhook/signature.d.ts +0 -16
  418. package/dist/engine/webhook/signature.js +0 -49
  419. package/dist/storage/license-store.d.ts +0 -6
  420. package/dist/storage/license-store.js +0 -63
  421. package/dist/storage/session-store.d.ts +0 -20
  422. package/dist/storage/session-store.js +0 -136
  423. package/dist/tools/activate-license.d.ts +0 -6
  424. package/dist/tools/activate-license.js +0 -132
  425. package/dist/tools/checkpoint-handler.d.ts +0 -3
  426. package/dist/tools/checkpoint-handler.js +0 -130
  427. package/dist/tools/export-session.d.ts +0 -3
  428. package/dist/tools/export-session.js +0 -90
  429. package/dist/tools/license-gate.d.ts +0 -18
  430. package/dist/tools/license-gate.js +0 -222
  431. package/dist/tools/license-status.d.ts +0 -3
  432. package/dist/tools/license-status.js +0 -93
  433. package/dist/tools/list-sessions.d.ts +0 -3
  434. package/dist/tools/list-sessions.js +0 -46
  435. package/dist/tools/planu-session-checkpoint.d.ts +0 -6
  436. package/dist/tools/planu-session-checkpoint.js +0 -42
  437. package/dist/tools/restore-session.d.ts +0 -3
  438. package/dist/tools/restore-session.js +0 -71
  439. package/dist/tools/spec-history.d.ts +0 -3
  440. package/dist/tools/spec-history.js +0 -59
  441. package/dist/tools/webhook.d.ts +0 -6
  442. package/dist/tools/webhook.js +0 -150
  443. package/dist/types/changelog.d.ts +0 -49
  444. package/dist/types/changelog.js +0 -3
  445. package/dist/types/licensing.d.ts +0 -109
  446. package/dist/types/licensing.js +0 -4
  447. package/dist/types/product-intelligence.d.ts +0 -60
  448. package/dist/types/product-intelligence.js +0 -3
  449. package/dist/types/session.d.ts +0 -84
  450. package/dist/types/session.js +0 -3
  451. package/dist/types/webhook.d.ts +0 -62
  452. package/dist/types/webhook.js +0 -4
@@ -5,6 +5,7 @@ import { join } from 'node:path';
5
5
  import { stripFrontmatter } from './frontmatter-parser.js';
6
6
  import { hashProjectPath, projectDataDir } from '../storage/base-store.js';
7
7
  import { extractAcceptanceCriteriaTexts } from './spec-format/acceptance-criteria.js';
8
+ import { extractListItems, findMarkdownSectionRange } from './spec-format/markdown-sections.js';
8
9
  // ── Parsing helpers ──────────────────────────────────────────────────────────
9
10
  function extractObjective(huContent, spec) {
10
11
  if (!huContent) {
@@ -71,16 +72,369 @@ function extractFilesFromFicha(fichaContent) {
71
72
  }
72
73
  return { toModify, toCreate };
73
74
  }
75
+ function sectionContentAtLevel(content, heading, level) {
76
+ let offset = 0;
77
+ while (offset < content.length) {
78
+ const range = findMarkdownSectionRange(content.slice(offset), heading);
79
+ if (range === null) {
80
+ return null;
81
+ }
82
+ if (range.level === level) {
83
+ return content.slice(offset + range.contentStart, offset + range.end);
84
+ }
85
+ const nextOffset = offset + range.end;
86
+ if (nextOffset <= offset) {
87
+ return null;
88
+ }
89
+ offset = nextOffset;
90
+ }
91
+ return null;
92
+ }
93
+ function ownershipItems(content) {
94
+ const visibleLines = [];
95
+ const fenced = [];
96
+ let fence = null;
97
+ for (const line of content.split('\n')) {
98
+ const marker = /^[ \t]{0,3}(`{3,}|~{3,})/.exec(line)?.[1];
99
+ if (marker) {
100
+ const type = marker[0];
101
+ if (fence === null) {
102
+ fence = { marker: type, length: marker.length };
103
+ }
104
+ else if (fence.marker === type && marker.length >= fence.length) {
105
+ fence = null;
106
+ }
107
+ continue;
108
+ }
109
+ if (fence !== null) {
110
+ const trimmed = line.trim();
111
+ if (trimmed.length > 0) {
112
+ fenced.push(extractListItems(line)[0] ?? trimmed);
113
+ }
114
+ continue;
115
+ }
116
+ visibleLines.push(line);
117
+ }
118
+ return { items: extractListItems(visibleLines.join('\n')), fenced };
119
+ }
120
+ /** Normalize one repository-relative ownership path without retaining unsafe input in diagnostics. */
121
+ export function normalizeOwnedPath(value) {
122
+ const trimmed = value.trim();
123
+ if (/^none\.?$/i.test(trimmed)) {
124
+ return { status: 'none' };
125
+ }
126
+ const backticked = /^`([^`]+)`/.exec(trimmed)?.[1];
127
+ const candidate = (backticked ?? trimmed.split(/\s+(?:—|–|-)\s+|\s+\(/, 1)[0] ?? '').trim();
128
+ if (candidate.length === 0) {
129
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_EMPTY' };
130
+ }
131
+ if (candidate.startsWith('```') || candidate.startsWith('~~~')) {
132
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_FENCED' };
133
+ }
134
+ if (candidate.includes('\0')) {
135
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_NUL' };
136
+ }
137
+ if (/^[\\/]{2}/.test(candidate)) {
138
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_UNC' };
139
+ }
140
+ const normalizedSeparators = candidate.replaceAll('\\', '/');
141
+ if (normalizedSeparators.startsWith('/')) {
142
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_ABSOLUTE' };
143
+ }
144
+ if (normalizedSeparators.startsWith('~/')) {
145
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_HOME_RELATIVE' };
146
+ }
147
+ if (/^[A-Za-z]:\//.test(normalizedSeparators)) {
148
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_DRIVE_ABSOLUTE' };
149
+ }
150
+ if (/^[A-Za-z][A-Za-z\d+.-]*:/.test(normalizedSeparators)) {
151
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_URI' };
152
+ }
153
+ if (normalizedSeparators.split('/').includes('..')) {
154
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_TRAVERSAL' };
155
+ }
156
+ const path = normalizedSeparators.replace(/\/+/g, '/').replace(/^(?:\.\/)+/, '');
157
+ return path.length > 0
158
+ ? { status: 'valid', path }
159
+ : { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_EMPTY' };
160
+ }
161
+ /** Normalize a raw traceability changed-file value without interpreting Markdown or prose. */
162
+ export function normalizeChangedFilePath(value) {
163
+ const trimmed = value.trim();
164
+ if (trimmed.includes('`') ||
165
+ /^(?:#{1,6}|[-*+]|\d+[.)]|>)\s/u.test(trimmed) ||
166
+ /^\[[ xX]\]\s/u.test(trimmed)) {
167
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_MARKDOWN' };
168
+ }
169
+ if (/\s/u.test(trimmed)) {
170
+ return { status: 'invalid', code: 'INVALID_FILE_OWNERSHIP_DESCRIPTION' };
171
+ }
172
+ return normalizeOwnedPath(trimmed);
173
+ }
174
+ export function extractCanonicalFileOwnership(content) {
175
+ const filesSection = sectionContentAtLevel(content, 'Files', 2);
176
+ if (filesSection === null) {
177
+ return { present: false, toModify: [], toCreate: [], toTest: [], blockers: [] };
178
+ }
179
+ const blockers = [];
180
+ const addBlocker = (blocker) => {
181
+ if (!blockers.includes(blocker)) {
182
+ blockers.push(blocker);
183
+ }
184
+ };
185
+ const parseSection = (heading) => {
186
+ const subsection = sectionContentAtLevel(filesSection, heading, 3);
187
+ if (subsection === null) {
188
+ return [];
189
+ }
190
+ const { items, fenced } = ownershipItems(subsection);
191
+ for (const _value of fenced) {
192
+ addBlocker('INVALID_FILE_OWNERSHIP_FENCED');
193
+ }
194
+ const paths = [];
195
+ for (const value of items) {
196
+ const normalized = normalizeOwnedPath(value);
197
+ if (normalized.status === 'invalid') {
198
+ addBlocker(normalized.code);
199
+ }
200
+ else if (normalized.status === 'valid' && !paths.includes(normalized.path)) {
201
+ paths.push(normalized.path);
202
+ }
203
+ }
204
+ return paths;
205
+ };
206
+ const toCreate = parseSection('Create');
207
+ const toModify = parseSection('Modify');
208
+ const toTest = parseSection('Test');
209
+ const conflicts = [...new Set([...toCreate, ...toModify, ...toTest])].filter((path) => [toCreate, toModify, toTest].filter((paths) => paths.includes(path)).length > 1);
210
+ for (const path of conflicts) {
211
+ addBlocker(`CONFLICTING_FILE_OWNERSHIP: ${path}`);
212
+ }
213
+ return {
214
+ present: true,
215
+ toCreate: toCreate.filter((path) => !conflicts.includes(path)),
216
+ toModify: toModify.filter((path) => !conflicts.includes(path)),
217
+ toTest: toTest.filter((path) => !conflicts.includes(path)),
218
+ blockers,
219
+ };
220
+ }
221
+ const SAFE_OWNERSHIP_ANNOTATION = /^[\p{L}\p{N} .,_:-]+$/u;
222
+ function isSafeOwnershipResidual(value) {
223
+ let remaining = value.trim();
224
+ while (remaining.length > 0) {
225
+ remaining = remaining.trimStart();
226
+ if (remaining.length === 0) {
227
+ return true;
228
+ }
229
+ const connector = /^(?:and|or)\b/iu.exec(remaining)?.[0];
230
+ if (connector) {
231
+ remaining = remaining.slice(connector.length);
232
+ continue;
233
+ }
234
+ if (',;&'.includes(remaining[0] ?? '')) {
235
+ remaining = remaining.slice(1);
236
+ continue;
237
+ }
238
+ if (remaining.startsWith('(')) {
239
+ const end = remaining.indexOf(')');
240
+ if (end < 2 || !SAFE_OWNERSHIP_ANNOTATION.test(remaining.slice(1, end))) {
241
+ return false;
242
+ }
243
+ remaining = remaining.slice(end + 1);
244
+ continue;
245
+ }
246
+ if (remaining.startsWith('—') || remaining.startsWith('-')) {
247
+ const description = remaining.slice(1).trim();
248
+ return description.length > 0 && SAFE_OWNERSHIP_ANNOTATION.test(description);
249
+ }
250
+ return false;
251
+ }
252
+ return true;
253
+ }
254
+ function ownershipBlocker(path, classifications) {
255
+ return `handoff_ownership_invalid path=${path} classifications=${classifications.join(',')}`;
256
+ }
257
+ function stripInertOwnershipMarkup(content) {
258
+ let fence = null;
259
+ let script = false;
260
+ return content
261
+ .split('\n')
262
+ .map((line) => {
263
+ const trimmed = line.trim();
264
+ const marker = /^[ \t]{0,3}(`{3,}|~{3,})/u.exec(line)?.[1];
265
+ if (marker) {
266
+ const type = marker[0];
267
+ if (fence === null) {
268
+ fence = { marker: type, length: marker.length };
269
+ }
270
+ else if (fence.marker === type && marker.length >= fence.length) {
271
+ fence = null;
272
+ }
273
+ return '';
274
+ }
275
+ if (fence !== null) {
276
+ return '';
277
+ }
278
+ if (/<script\b/iu.test(trimmed)) {
279
+ script = !/<\/script>/iu.test(trimmed);
280
+ return '';
281
+ }
282
+ if (script) {
283
+ if (/<\/script>/iu.test(trimmed)) {
284
+ script = false;
285
+ }
286
+ return '';
287
+ }
288
+ return /<\/?[A-Za-z][^>]*>/u.test(trimmed) ? '' : line;
289
+ })
290
+ .join('\n');
291
+ }
292
+ function normalizeStrictOwnedPath(rawValue) {
293
+ const normalized = normalizeOwnedPath(rawValue);
294
+ if (normalized.status !== 'valid') {
295
+ return null;
296
+ }
297
+ return /^[A-Za-z0-9._/-]+$/u.test(normalized.path) ? normalized.path : null;
298
+ }
299
+ function collectStrictOwnershipEntry(rawValue, classification, state) {
300
+ const rawPath = rawValue.trim();
301
+ const backtickedValues = [...rawPath.matchAll(/`([^`\n]+)`/gu)].map((match) => match[1] ?? '');
302
+ const backtickedPaths = backtickedValues.map(normalizeStrictOwnedPath);
303
+ const residual = rawPath.replaceAll(/`[^`\n]+`/gu, '').trim();
304
+ const residualIsSafe = isSafeOwnershipResidual(residual);
305
+ if (backtickedPaths.some((path) => path === null) ||
306
+ (backtickedValues.length > 0 && !residualIsSafe)) {
307
+ state.blockers.push(ownershipBlocker('<redacted>', [classification, 'InvalidPath']));
308
+ return;
309
+ }
310
+ const directPath = normalizeStrictOwnedPath(rawPath);
311
+ const paths = backtickedPaths.length > 0
312
+ ? backtickedPaths
313
+ : directPath === null
314
+ ? []
315
+ : [directPath];
316
+ if (paths.length === 0) {
317
+ const diagnosticPath = /^`[^`]+`$/u.test(rawPath) ? '<redacted>' : rawPath || '<empty>';
318
+ state.blockers.push(ownershipBlocker(diagnosticPath, [classification, 'InvalidPath']));
319
+ return;
320
+ }
321
+ for (const path of paths) {
322
+ collectStrictOwnershipPath(path, classification, state);
323
+ }
324
+ }
325
+ function collectStrictOwnershipPath(path, classification, state) {
326
+ const own = classification === 'Create' ? state.create : state.modify;
327
+ const other = classification === 'Create' ? state.modify : state.create;
328
+ if (own.has(path)) {
329
+ state.blockers.push(ownershipBlocker(path, [classification, classification]));
330
+ return;
331
+ }
332
+ if (other.has(path)) {
333
+ state.blockers.push(ownershipBlocker(path, ['Create', 'Modify']));
334
+ own.delete(path);
335
+ other.delete(path);
336
+ return;
337
+ }
338
+ own.add(path);
339
+ }
340
+ function extractStrictCanonicalOwnership(content) {
341
+ const filesSection = sectionContentAtLevel(content, 'Files', 2);
342
+ if (filesSection === null) {
343
+ return { present: false, toModify: [], toCreate: [], blockers: [] };
344
+ }
345
+ const state = { create: new Set(), modify: new Set(), blockers: [] };
346
+ const parseSection = (classification) => {
347
+ const subsection = sectionContentAtLevel(filesSection, classification, 3);
348
+ if (subsection === null) {
349
+ state.blockers.push(ownershipBlocker('<missing>', [classification, 'MissingSection']));
350
+ return;
351
+ }
352
+ const items = subsection
353
+ .split('\n')
354
+ .map((line) => /^\s*[-*]\s+(.+)$/u.exec(line)?.[1]?.trim())
355
+ .filter((item) => Boolean(item));
356
+ if (items.length === 0) {
357
+ state.blockers.push(ownershipBlocker('<empty>', [classification, 'Malformed']));
358
+ return;
359
+ }
360
+ let explicitNone = false;
361
+ for (const item of items) {
362
+ if (/^none\.?$/iu.test(item.trim())) {
363
+ if (explicitNone) {
364
+ state.blockers.push(ownershipBlocker('<none>', [classification, classification]));
365
+ }
366
+ explicitNone = true;
367
+ continue;
368
+ }
369
+ collectStrictOwnershipEntry(item, classification, state);
370
+ }
371
+ const own = classification === 'Create' ? state.create : state.modify;
372
+ if (explicitNone && own.size > 0) {
373
+ state.blockers.push(ownershipBlocker('<none>', [classification, classification]));
374
+ }
375
+ };
376
+ parseSection('Create');
377
+ parseSection('Modify');
378
+ return {
379
+ present: true,
380
+ toCreate: [...state.create].sort(),
381
+ toModify: [...state.modify].sort(),
382
+ blockers: [...new Set(state.blockers)].sort(),
383
+ };
384
+ }
385
+ function extractFileLevelWorkPlanOwnership(content) {
386
+ const state = { create: new Set(), modify: new Set(), blockers: [] };
387
+ const section = sectionContentAtLevel(content, 'File-Level Work Plan', 3);
388
+ if (section === null) {
389
+ return { present: false, toModify: [], toCreate: [], blockers: [] };
390
+ }
391
+ for (const item of extractListItems(section)) {
392
+ const match = /^(Create|Modify)\s*:\s*(.+?)(?:\s+\([^)]*\))?\s*$/iu.exec(item);
393
+ if (!match?.[1] || !match[2]) {
394
+ continue;
395
+ }
396
+ const classification = match[1].toLowerCase() === 'create' ? 'Create' : 'Modify';
397
+ collectStrictOwnershipEntry(match[2], classification, state);
398
+ }
399
+ return {
400
+ present: state.create.size + state.modify.size + state.blockers.length > 0,
401
+ toCreate: [...state.create].sort(),
402
+ toModify: [...state.modify].sort(),
403
+ blockers: [...new Set(state.blockers)].sort(),
404
+ };
405
+ }
406
+ function validateOwnershipAgreement(canonical, workPlan) {
407
+ if (!canonical.present || !workPlan.present) {
408
+ return [];
409
+ }
410
+ const classification = (ownership, path) => ownership.toCreate.includes(path)
411
+ ? 'Create'
412
+ : ownership.toModify.includes(path)
413
+ ? 'Modify'
414
+ : 'Absent';
415
+ const paths = new Set([
416
+ ...canonical.toCreate,
417
+ ...canonical.toModify,
418
+ ...workPlan.toCreate,
419
+ ...workPlan.toModify,
420
+ ]);
421
+ return [...paths].sort().flatMap((path) => {
422
+ const canonicalClass = classification(canonical, path);
423
+ const workPlanClass = classification(workPlan, path);
424
+ return canonicalClass === workPlanClass
425
+ ? []
426
+ : [ownershipBlocker(path, [`Canonical:${canonicalClass}`, `WorkPlan:${workPlanClass}`])];
427
+ });
428
+ }
74
429
  function extractBacktickedFiles(content) {
75
430
  const files = new Set();
76
- const matches = content.matchAll(/`([^`\n]+\.(?:ts|tsx|js|jsx|mjs|cjs|json|md|yml|yaml|sh|css|scss|html))`/g);
77
- for (const match of matches) {
78
- const filePath = match[1]?.trim();
79
- if (filePath && !filePath.includes(' ')) {
80
- files.add(filePath);
431
+ for (const match of content.matchAll(/`([^`\n]+)`/gu)) {
432
+ const path = match[1] ? normalizeStrictOwnedPath(match[1]) : null;
433
+ if (path) {
434
+ files.add(path);
81
435
  }
82
436
  }
83
- return [...files];
437
+ return [...files].sort();
84
438
  }
85
439
  function extractLinesByKeywords(content, keywords) {
86
440
  return content
@@ -95,11 +449,27 @@ function extractOperationalSections(content, spec) {
95
449
  risks: extractLinesByKeywords(content, /\b(risk|edge|failure|security|drift|migration|breaking|compatibility|rollback)\b/i),
96
450
  ownership: extractLinesByKeywords(content, /\b(owner|ownership|wave|agent|reviewer|arbiter|files?|responsible)\b/i),
97
451
  currentState: `Spec ${spec.id} is ${spec.status}; implementation must follow the approved spec artifact, not chat history.`,
98
- nextAction: spec.status === 'approved'
99
- ? 'Move to implementing with this handoff, then implement only the listed scope.'
100
- : 'Review the current spec status and move through the required SDD gates before implementation.',
452
+ nextAction: lifecycleNextAction(spec.status),
101
453
  };
102
454
  }
455
+ function lifecycleNextAction(status) {
456
+ switch (status) {
457
+ case 'draft':
458
+ return 'Complete the specification, discovery, challenge, and readiness evidence before review.';
459
+ case 'review':
460
+ return 'Resolve reviewer feedback and obtain independent spec approval before implementation.';
461
+ case 'approved':
462
+ return 'Move to implementing with this handoff, then implement only the listed scope.';
463
+ case 'implementing':
464
+ return 'Finish the remaining criteria, persist traceability, obtain independent implementation review, and run validation.';
465
+ case 'done':
466
+ return 'No implementation remains; preserve the validated done contract.';
467
+ case 'discarded':
468
+ return 'Do not implement this discarded specification.';
469
+ default:
470
+ return `Unsupported lifecycle status "${status}"; repair the canonical status before implementation.`;
471
+ }
472
+ }
103
473
  function extractOutOfScope(huContent, spec) {
104
474
  if (!huContent) {
105
475
  return [
@@ -167,10 +537,35 @@ export async function packageHandoff(spec, knowledge) {
167
537
  }
168
538
  const objective = extractObjective(huContent, spec);
169
539
  const criteria = extractAcceptanceCriteriaTexts(rawSpecContent);
170
- const parsedFiles = extractFilesFromFicha(fichaContent);
171
- const discoveredFiles = extractBacktickedFiles(`${huContent}\n${fichaContent}`);
172
- const toModify = parsedFiles.toModify.length > 0 ? parsedFiles.toModify : discoveredFiles;
173
- const toCreate = parsedFiles.toCreate;
540
+ const ownershipContent = stripInertOwnershipMarkup(rawSpecContent);
541
+ const canonicalFiles = extractCanonicalFileOwnership(rawSpecContent);
542
+ const canonicalOwnership = extractStrictCanonicalOwnership(ownershipContent);
543
+ const workPlanOwnership = extractFileLevelWorkPlanOwnership(ownershipContent);
544
+ const testOwnedPaths = new Set(canonicalFiles.toTest);
545
+ const explicitOwnership = canonicalOwnership.present
546
+ ? {
547
+ ...canonicalOwnership,
548
+ toCreate: canonicalOwnership.toCreate.filter((path) => !testOwnedPaths.has(path)),
549
+ toModify: canonicalOwnership.toModify.filter((path) => !testOwnedPaths.has(path)),
550
+ }
551
+ : workPlanOwnership.present
552
+ ? workPlanOwnership
553
+ : null;
554
+ const legacyFiles = extractFilesFromFicha(ownershipContent);
555
+ const hasLegacyOwnership = legacyFiles.toModify.length + legacyFiles.toCreate.length > 0;
556
+ const toModify = explicitOwnership
557
+ ? explicitOwnership.toModify
558
+ : hasLegacyOwnership
559
+ ? legacyFiles.toModify
560
+ : extractBacktickedFiles(ownershipContent);
561
+ const toCreate = explicitOwnership
562
+ ? explicitOwnership.toCreate
563
+ : hasLegacyOwnership
564
+ ? legacyFiles.toCreate
565
+ : [];
566
+ if (!explicitOwnership && toModify.length + toCreate.length > 0) {
567
+ warnings.push('LEGACY_FILE_OWNERSHIP_FALLBACK');
568
+ }
174
569
  const outOfScope = extractOutOfScope(huContent, spec);
175
570
  const constraints = buildConstraints(knowledge);
176
571
  const operational = extractOperationalSections(`${huContent}\n${fichaContent}`, spec);
@@ -183,6 +578,13 @@ export async function packageHandoff(spec, knowledge) {
183
578
  ...(operational.testPlan.length === 0 ? ['Missing test plan'] : []),
184
579
  ...(operational.risks.length === 0 ? ['Missing risk analysis'] : []),
185
580
  ...(operational.ownership.length === 0 ? ['Missing ownership'] : []),
581
+ ...canonicalFiles.blockers,
582
+ ...canonicalOwnership.blockers,
583
+ ...workPlanOwnership.blockers,
584
+ ...validateOwnershipAgreement(canonicalOwnership, workPlanOwnership),
585
+ ...(!['draft', 'review', 'approved', 'implementing', 'done', 'discarded'].includes(spec.status)
586
+ ? [`UNSUPPORTED_LIFECYCLE_STATUS: ${spec.status}`]
587
+ : []),
186
588
  ];
187
589
  const pkg = {
188
590
  specId: spec.id,
@@ -4,7 +4,7 @@
4
4
  // ---------------------------------------------------------------------------
5
5
  export const DEFAULT_EFFORT_RULES = [
6
6
  {
7
- pattern: 'list_specs|usage_stats|license_status',
7
+ pattern: 'list_specs|usage_stats',
8
8
  effort: 'low',
9
9
  reason: 'read-only queries',
10
10
  },
@@ -19,9 +19,9 @@ const BREAK_PATTERNS = [
19
19
  remediation: 'Run scripts/sync-website-counts.sh --apply and commit website/',
20
20
  },
21
21
  {
22
- pattern: /license-plans\.json/,
23
- kind: 'license-plans-sync',
24
- remediation: 'Add new tool name to src/config/license-plans.json',
22
+ pattern: /generate-host-tool-registry/,
23
+ kind: 'tool-registry-sync',
24
+ remediation: 'Run scripts/generate-host-tool-registry.mjs',
25
25
  },
26
26
  ];
27
27
  async function collectTestFiles(dir, results, budget, depth) {
@@ -21,7 +21,7 @@ export function detectsNewToolRegistration(specBody, technicalMd) {
21
21
  export function buildToolRegistrationCriteria() {
22
22
  return [
23
23
  {
24
- text: 'license-plans.json must include the new tool name',
24
+ text: 'The generated host registry must match the canonical tool registry',
25
25
  source: 'impact-detector',
26
26
  autoResolvable: false,
27
27
  },
@@ -7,19 +7,20 @@ export function buildImplementationContractSection(input) {
7
7
  `## ${IMPLEMENTATION_CONTRACT_SECTION}`,
8
8
  '### User Outcome',
9
9
  firstConcreteSentence(input.description) ??
10
+ criteria[0]?.text ??
10
11
  'Needs decision: define the exact observable outcome this spec must deliver.',
11
12
  '',
12
13
  '### Behavior Contract',
13
14
  ...renderBehaviorContract(criteria),
14
15
  '',
15
16
  '### File-Level Work Plan',
16
- ...renderFilePlan(input.files),
17
+ ...renderFilePlan(input.files, criteria.length > 0),
17
18
  '',
18
19
  '### Acceptance-To-Verification Map',
19
20
  ...criteria.map((criterion, index) => renderVerificationRow(criterion.text, index + 1, testFiles, verificationCommands)),
20
21
  '',
21
22
  '### Edge Cases And Failure Modes',
22
- '- Needs decision: identify criterion-specific failure modes from user input or project evidence.',
23
+ ...renderFailureModes(criteria),
23
24
  '',
24
25
  '### Non-Goals And Forbidden Approaches',
25
26
  ...renderNonGoals(input.outOfScope),
@@ -27,7 +28,9 @@ export function buildImplementationContractSection(input) {
27
28
  '### Verification Commands',
28
29
  ...(verificationCommands.length > 0
29
30
  ? verificationCommands.map((command) => `- \`${command}\``)
30
- : ['- Needs decision: provide a repository-supported verification command.']),
31
+ : criteria.length > 0
32
+ ? ['- No repository-supported verification command was grounded for this candidate.']
33
+ : ['- Needs decision: provide a repository-supported verification command.']),
31
34
  '',
32
35
  ];
33
36
  return lines.join('\n');
@@ -48,9 +51,9 @@ function firstConcreteSentence(description) {
48
51
  if (!body) {
49
52
  return null;
50
53
  }
51
- return body.replace(/\s+/g, ' ').slice(0, 240);
54
+ return body.replace(/\s+/g, ' ');
52
55
  }
53
- function renderFilePlan(files) {
56
+ function renderFilePlan(files, hasGroundedBehavior) {
54
57
  const lines = [];
55
58
  for (const [label, entries] of [
56
59
  ['Create', files.create],
@@ -61,7 +64,12 @@ function renderFilePlan(files) {
61
64
  lines.push(`- ${label}: \`${entry.path}\` (${entry.status})`);
62
65
  }
63
66
  }
64
- return lines.length > 0 ? lines : ['- Needs decision: identify expected source and test files.'];
67
+ if (lines.length > 0) {
68
+ return lines;
69
+ }
70
+ return hasGroundedBehavior
71
+ ? ['- No file ownership was grounded for this behavior.']
72
+ : ['- Needs decision: identify expected source and test files.'];
65
73
  }
66
74
  function renderBehaviorContract(criteria) {
67
75
  return criteria.length > 0
@@ -76,11 +84,18 @@ function renderVerificationRow(criterion, index, testFiles, commands) {
76
84
  ? `- AC${String(index)}: ${criterion} -> unit test \`${test}\` plus \`${command}\`.`
77
85
  : `- AC${String(index)}: ${criterion} -> unit test \`${test}\`.`;
78
86
  }
79
- return `- AC${String(index)}: ${criterion} -> Needs decision: choose unit test, integration test, CLI/tool result, snapshot/golden fixture, or exact manual verification.`;
87
+ return `- AC${String(index)}: ${criterion} -> verify the exact observable result declared by this criterion.`;
80
88
  }
81
89
  function renderNonGoals(outOfScope) {
82
90
  return outOfScope.length > 0
83
91
  ? outOfScope.map((item) => `- ${item}`)
84
- : ['- Needs decision: provide explicit non-goals or confirm that none were supplied.'];
92
+ : ['- No explicit non-goals were supplied.'];
93
+ }
94
+ function renderFailureModes(criteria) {
95
+ return criteria.length > 0
96
+ ? criteria.map((criterion, index) => `- AC${String(index + 1)} failure: reject partial behavior that violates "${criterion.text}" and preserve the last valid observable state.`)
97
+ : [
98
+ '- Needs decision: identify criterion-specific failure modes from user input or project evidence.',
99
+ ];
85
100
  }
86
101
  //# sourceMappingURL=renderer.js.map
@@ -0,0 +1,11 @@
1
+ import type { ReconciliationReceiptV1 } from '../types/handoff-artifacts.js';
2
+ export declare function reconciliationDigest(value: string | Buffer): string;
3
+ export declare function safeReceiptPath(projectId: string, specId: string, requestId: string): Promise<string>;
4
+ export declare function readReconciliationReceipt(path: string): Promise<ReconciliationReceiptV1 | null>;
5
+ export declare function writeReconciliationReceipt(path: string, receipt: ReconciliationReceiptV1): Promise<void>;
6
+ export declare function collectSupersededReconciliationArtifacts(projectId: string, specId: string): Promise<{
7
+ artifactId: string;
8
+ sha256?: string;
9
+ }[]>;
10
+ export declare function readCommittedReconciliationReceipts(projectId: string, specId: string): Promise<ReconciliationReceiptV1[]>;
11
+ //# sourceMappingURL=lifecycle-reconciliation-io.d.ts.map