@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
@@ -24,10 +24,44 @@ const GENERIC_SCOPE_TOKENS = new Set([
24
24
  'tool',
25
25
  'tools',
26
26
  ]);
27
+ const GENERIC_SEMANTIC_TOKENS = new Set([
28
+ 'change',
29
+ 'validation',
30
+ 'evidence',
31
+ 'format',
32
+ 'semantic',
33
+ 'schema',
34
+ 'receipt',
35
+ ]);
36
+ function inflectionCandidates(token) {
37
+ const candidates = [token];
38
+ if (token.endsWith('s')) {
39
+ candidates.push(token.slice(0, -1));
40
+ }
41
+ for (const suffix of ['ed', 'ing']) {
42
+ if (token.endsWith(suffix)) {
43
+ const stem = token.slice(0, -suffix.length);
44
+ candidates.push(stem, `${stem}e`);
45
+ }
46
+ }
47
+ return [...new Set(candidates.filter((candidate) => candidate.length >= 4))];
48
+ }
49
+ function semanticToken(token) {
50
+ const candidates = inflectionCandidates(token);
51
+ const generic = candidates.find((candidate) => GENERIC_SEMANTIC_TOKENS.has(candidate));
52
+ if (generic) {
53
+ return generic;
54
+ }
55
+ const singular = token.endsWith('s') ? token.slice(0, -1) : token;
56
+ return singular.length >= 4 ? singular : token;
57
+ }
27
58
  function keywords(phrase) {
28
- return normalize(phrase)
29
- .split(' ')
30
- .filter((w) => w.length > 2 && !STOP_WORDS.has(w) && !GENERIC_SCOPE_TOKENS.has(w));
59
+ return [
60
+ ...new Set(normalize(phrase)
61
+ .split(' ')
62
+ .filter((word) => word.length > 2 && !STOP_WORDS.has(word) && !GENERIC_SCOPE_TOKENS.has(word))
63
+ .map(semanticToken)),
64
+ ];
31
65
  }
32
66
  /**
33
67
  * Determine whether a file path matches an out-of-scope item.
@@ -39,9 +73,12 @@ function fileMatchesScopeItem(filePath, scopeItem) {
39
73
  if (scopeKws.length === 0) {
40
74
  return false;
41
75
  }
42
- const matchCount = scopeKws.filter((kw) => normPath.includes(kw)).length;
43
- // Require at least 1 keyword match for a warning
44
- return matchCount >= 1;
76
+ const pathKeywords = new Set(keywords(normPath));
77
+ const specific = scopeKws.filter((token) => !GENERIC_SEMANTIC_TOKENS.has(token));
78
+ const matched = scopeKws.filter((token) => pathKeywords.has(token));
79
+ return specific.length > 0
80
+ ? specific.some((token) => pathKeywords.has(token))
81
+ : new Set(matched).size >= 2;
45
82
  }
46
83
  /**
47
84
  * Validate implementation file paths against the spec's outOfScope declarations.
@@ -52,8 +89,9 @@ export function validateScopeCompliance(outOfScope, filePaths) {
52
89
  for (const filePath of filePaths) {
53
90
  for (const scopeItem of outOfScope) {
54
91
  if (fileMatchesScopeItem(filePath, scopeItem)) {
92
+ const pathKeywords = new Set(keywords(filePath));
55
93
  const matchedKws = keywords(scopeItem)
56
- .filter((kw) => normalize(filePath).includes(kw))
94
+ .filter((keyword) => pathKeywords.has(keyword))
57
95
  .join(', ');
58
96
  warnings.push({
59
97
  filePath,
@@ -74,15 +74,6 @@ export async function writeCheckpoint(projectPath, snapshot) {
74
74
  const updated = replaceLatestCheckpoint(existing, newBlock);
75
75
  await mkdir(planuDir, { recursive: true });
76
76
  await writeFile(filePath, updated, 'utf8');
77
- void (async () => {
78
- try {
79
- const { planuAutoCommit } = await import('../git/planu-autocommit.js');
80
- await planuAutoCommit({ projectPath, reason: 'session-checkpoint' });
81
- }
82
- catch {
83
- /* best-effort — never blocks checkpoint writer */
84
- }
85
- })();
86
77
  }
87
78
  /**
88
79
  * Fire-and-forget helper: records the tool call, then writes a checkpoint if
@@ -1,5 +1,9 @@
1
1
  import type { NormalizedAcceptanceCriterion } from '../../types/spec-format.js';
2
- export declare function extractNormalizedAcceptanceCriteria(raw: string): NormalizedAcceptanceCriterion[];
3
- export declare function extractAcceptanceCriteriaTexts(raw: string): string[];
2
+ export declare function extractNormalizedAcceptanceCriteria(raw: string, options?: {
3
+ allowLegacyBodyFallback?: boolean;
4
+ }): NormalizedAcceptanceCriterion[];
5
+ export declare function extractAcceptanceCriteriaTexts(raw: string, options?: {
6
+ allowLegacyBodyFallback?: boolean;
7
+ }): string[];
4
8
  export declare function normalizeAcceptanceCriterionToken(value: string): string;
5
9
  //# sourceMappingURL=acceptance-criteria.d.ts.map
@@ -1,12 +1,13 @@
1
1
  import { parseFrontmatterScenarios } from '../validator/spec-compliance-runner.js';
2
2
  import { stripFrontmatter } from '../frontmatter-parser.js';
3
- import { extractListItems, extractSection } from '../validator/extractors.js';
3
+ import { extractListItems, extractSection } from './markdown-sections.js';
4
+ import { stripFencedBlocks } from './text-fences.js';
4
5
  import { createCriterionIdentity, normalizeCriterionText } from '../criterion-identity.js';
5
- function extractSectionCriteria(section) {
6
- const listItems = extractListItems(section);
7
- if (listItems.length > 0) {
8
- return listItems;
9
- }
6
+ const BDD_STEP = /^(GIVEN|WHEN|THEN|AND|DADO|CUANDO|ENTONCES|Y)\b/i;
7
+ const BDD_START = /^(GIVEN|DADO)\b/i;
8
+ const TECHNICAL_MARKER = /^(FILES|FUNCTIONS|TEST|OWNER):/i;
9
+ const EXPLICIT_CRITERION_HEADING = /^#{3,6}\s+((?:AC|AB)\s*-?\s*\d+)\b/i;
10
+ function extractBddBlocks(section) {
10
11
  const lines = section.split('\n').map((line) => line.trim());
11
12
  if (lines.length === 0) {
12
13
  return [];
@@ -21,16 +22,21 @@ function extractSectionCriteria(section) {
21
22
  }
22
23
  continue;
23
24
  }
24
- if (/^(GIVEN|WHEN|THEN|AND|DADO|CUANDO|ENTONCES|Y)\b/i.test(line)) {
25
- if (/^(GIVEN|DADO)\b/i.test(line) && current.length > 0) {
25
+ const withoutListMarker = line.replace(/^(?:[-*+]\s+(?:\[[ xX]\]\s*)?|\d+[.)]\s+)/, '');
26
+ if (TECHNICAL_MARKER.test(withoutListMarker) || /^#{1,6}\s+/.test(withoutListMarker)) {
27
+ if (current.length > 0) {
26
28
  bddBlocks.push(current.join(' '));
27
29
  current = [];
28
30
  }
29
- current.push(line.replace(/^[-*+]\s*/, ''));
30
31
  continue;
31
32
  }
32
- if (current.length > 0) {
33
- current.push(line);
33
+ if (BDD_STEP.test(withoutListMarker)) {
34
+ if (BDD_START.test(withoutListMarker) && current.length > 0) {
35
+ bddBlocks.push(current.join(' '));
36
+ current = [];
37
+ }
38
+ current.push(withoutListMarker);
39
+ continue;
34
40
  }
35
41
  }
36
42
  if (current.length > 0) {
@@ -38,8 +44,55 @@ function extractSectionCriteria(section) {
38
44
  }
39
45
  return bddBlocks;
40
46
  }
41
- function extractBodyCriteria(raw) {
42
- const body = stripFrontmatter(raw);
47
+ function extractExplicitCriterionBodies(section) {
48
+ const lines = section.split('\n');
49
+ const bodies = [];
50
+ let current = null;
51
+ for (const line of lines) {
52
+ const heading = EXPLICIT_CRITERION_HEADING.exec(line.trim());
53
+ if (heading?.[1]) {
54
+ if (current !== null) {
55
+ bodies.push(current);
56
+ }
57
+ current = { id: heading[1].replace(/[\s-]/g, ''), body: '' };
58
+ continue;
59
+ }
60
+ if (current !== null) {
61
+ current.body += `${current.body.length > 0 ? '\n' : ''}${line}`;
62
+ }
63
+ }
64
+ if (current !== null) {
65
+ bodies.push(current);
66
+ }
67
+ return bodies;
68
+ }
69
+ function extractOneCriterion(body) {
70
+ const bddBlocks = extractBddBlocks(body);
71
+ if (bddBlocks.length > 0) {
72
+ return bddBlocks.reduce((selected, candidate) => candidate.length > selected.length ? candidate : selected);
73
+ }
74
+ const listItem = extractListItems(body).find((item) => !TECHNICAL_MARKER.test(item));
75
+ return listItem ?? null;
76
+ }
77
+ function extractSectionCriteria(section) {
78
+ const explicitBodies = extractExplicitCriterionBodies(section);
79
+ if (explicitBodies.length > 0) {
80
+ return explicitBodies
81
+ .map(({ id, body }) => {
82
+ const criterion = extractOneCriterion(body);
83
+ return criterion === null ? null : `${id}: ${criterion}`;
84
+ })
85
+ .filter((criterion) => criterion !== null);
86
+ }
87
+ const listItems = extractListItems(section).filter((item) => !TECHNICAL_MARKER.test(item));
88
+ if (listItems.length > 0) {
89
+ const nonStepItems = listItems.filter((item) => !BDD_STEP.test(item));
90
+ return nonStepItems.length > 0 ? nonStepItems : extractBddBlocks(section);
91
+ }
92
+ return extractBddBlocks(section);
93
+ }
94
+ function extractBodyCriteria(raw, options) {
95
+ const body = stripFencedBlocks(stripFrontmatter(raw));
43
96
  const acceptanceCriteria = extractSection(body, 'acceptance criteria', 'criterios de aceptaci');
44
97
  if (acceptanceCriteria) {
45
98
  const sectionCriteria = extractSectionCriteria(acceptanceCriteria);
@@ -47,11 +100,18 @@ function extractBodyCriteria(raw) {
47
100
  return sectionCriteria;
48
101
  }
49
102
  }
50
- return body
51
- .split('\n')
52
- .map((line) => line.trim())
53
- .filter((line) => /^-\s*\[[ x]\]/i.test(line) || /^- .*\bgiven\b.*\bwhen\b.*\bthen\b/i.test(line))
54
- .map((line) => line.replace(/^-\s*\[[ x]\]\s*/i, '').trim());
103
+ if (options.allowLegacyBodyFallback !== false) {
104
+ const checkboxCriteria = body
105
+ .split('\n')
106
+ .map((line) => line.trim())
107
+ .filter((line) => /^-\s*\[[ x]\]/i.test(line))
108
+ .map((line) => line.replace(/^-\s*\[[ x]\]\s*/i, '').trim());
109
+ if (checkboxCriteria.length > 0) {
110
+ return checkboxCriteria;
111
+ }
112
+ return extractBddBlocks(body);
113
+ }
114
+ return [];
55
115
  }
56
116
  function buildCriterion(text, source, index) {
57
117
  const trimmed = text.trim();
@@ -68,8 +128,8 @@ function buildCriterion(text, source, index) {
68
128
  aliases: identity.aliases,
69
129
  };
70
130
  }
71
- export function extractNormalizedAcceptanceCriteria(raw) {
72
- const bodyCriteria = extractBodyCriteria(raw)
131
+ export function extractNormalizedAcceptanceCriteria(raw, options = {}) {
132
+ const bodyCriteria = extractBodyCriteria(raw, options)
73
133
  .map((criterion, index) => buildCriterion(criterion, 'body', index))
74
134
  .filter((criterion) => criterion !== null);
75
135
  if (bodyCriteria.length > 0) {
@@ -79,8 +139,8 @@ export function extractNormalizedAcceptanceCriteria(raw) {
79
139
  .map((scenario, index) => buildCriterion(scenario.title, 'frontmatter', index))
80
140
  .filter((criterion) => criterion !== null);
81
141
  }
82
- export function extractAcceptanceCriteriaTexts(raw) {
83
- return extractNormalizedAcceptanceCriteria(raw).map((criterion) => criterion.text);
142
+ export function extractAcceptanceCriteriaTexts(raw, options = {}) {
143
+ return extractNormalizedAcceptanceCriteria(raw, options).map((criterion) => criterion.text);
84
144
  }
85
145
  export function normalizeAcceptanceCriterionToken(value) {
86
146
  return normalizeCriterionText(value);
@@ -0,0 +1,14 @@
1
+ /** Locate one exact markdown section without normalizing or copying source bytes. */
2
+ export declare function findMarkdownSectionRange(content: string, headingName: string): {
3
+ headingStart: number;
4
+ contentStart: number;
5
+ end: number;
6
+ level: number;
7
+ } | null;
8
+ /**
9
+ * Extract the text content under a markdown heading that matches any keyword.
10
+ */
11
+ export declare function extractSection(content: string, ...headingKeywords: string[]): string | null;
12
+ /** Extract bullet and numbered-list item text from a markdown block. */
13
+ export declare function extractListItems(content: string): string[];
14
+ //# sourceMappingURL=markdown-sections.d.ts.map
@@ -0,0 +1,105 @@
1
+ function markdownLines(content) {
2
+ const lines = [];
3
+ let start = 0;
4
+ while (start < content.length) {
5
+ const newline = content.indexOf('\n', start);
6
+ const end = newline === -1 ? content.length : newline + 1;
7
+ const contentEnd = newline === -1
8
+ ? end
9
+ : newline > start && content[newline - 1] === '\r'
10
+ ? newline - 1
11
+ : newline;
12
+ lines.push({ start, contentEnd, end });
13
+ start = end;
14
+ }
15
+ return lines;
16
+ }
17
+ /** Locate one exact markdown section without normalizing or copying source bytes. */
18
+ export function findMarkdownSectionRange(content, headingName) {
19
+ let selected = null;
20
+ let fence = null;
21
+ for (const line of markdownLines(content)) {
22
+ const text = content.slice(line.start, line.contentEnd);
23
+ const fenceMatch = /^[ \t]{0,3}(`{3,}|~{3,})/.exec(text);
24
+ if (fenceMatch?.[1]) {
25
+ const marker = fenceMatch[1][0];
26
+ if (fence === null) {
27
+ fence = { marker, length: fenceMatch[1].length };
28
+ }
29
+ else if (fence.marker === marker && fenceMatch[1].length >= fence.length) {
30
+ fence = null;
31
+ }
32
+ continue;
33
+ }
34
+ if (fence !== null) {
35
+ continue;
36
+ }
37
+ const heading = /^(#{1,6})[ \t]+(.+?)[ \t]*#*[ \t]*$/.exec(text);
38
+ if (!heading?.[1] || heading[2] === undefined) {
39
+ continue;
40
+ }
41
+ const level = heading[1].length;
42
+ if (selected !== null && level <= selected.level) {
43
+ return { ...selected, end: line.start };
44
+ }
45
+ if (selected === null && heading[2].trim().toLowerCase() === headingName.trim().toLowerCase()) {
46
+ selected = {
47
+ headingStart: line.start,
48
+ contentStart: line.end,
49
+ end: content.length,
50
+ level,
51
+ };
52
+ }
53
+ }
54
+ return selected;
55
+ }
56
+ /**
57
+ * Extract the text content under a markdown heading that matches any keyword.
58
+ */
59
+ export function extractSection(content, ...headingKeywords) {
60
+ const lines = content.split('\n');
61
+ let capturing = false;
62
+ let capturedLevel = 0;
63
+ const captured = [];
64
+ for (const line of lines) {
65
+ const headingMatch = /^(#{1,6})\s+(.+)/.exec(line);
66
+ if (headingMatch?.[1] !== undefined && headingMatch[2] !== undefined) {
67
+ const level = headingMatch[1].length;
68
+ const title = headingMatch[2].toLowerCase();
69
+ if (capturing && level <= capturedLevel) {
70
+ break;
71
+ }
72
+ if (!capturing && headingKeywords.some((keyword) => title.includes(keyword))) {
73
+ capturing = true;
74
+ capturedLevel = level;
75
+ continue;
76
+ }
77
+ }
78
+ if (capturing) {
79
+ captured.push(line);
80
+ }
81
+ }
82
+ return captured.length > 0 ? captured.join('\n') : null;
83
+ }
84
+ /** Extract bullet and numbered-list item text from a markdown block. */
85
+ export function extractListItems(content) {
86
+ const items = [];
87
+ for (const line of content.split('\n')) {
88
+ const listMatch = /^\s*[-*+]\s+\[?\s*[xX ]?\s*\]?\s*(.+)/.exec(line);
89
+ if (listMatch?.[1]) {
90
+ const item = listMatch[1].trim();
91
+ if (item.length > 5) {
92
+ items.push(item);
93
+ }
94
+ }
95
+ const numberedMatch = /^\s*\d+[.)]\s+(.+)/.exec(line);
96
+ if (numberedMatch?.[1]) {
97
+ const item = numberedMatch[1].trim();
98
+ if (item.length > 5) {
99
+ items.push(item);
100
+ }
101
+ }
102
+ }
103
+ return items;
104
+ }
105
+ //# sourceMappingURL=markdown-sections.js.map
@@ -60,11 +60,39 @@ export function extractSectionBody(body, sectionName) {
60
60
  * against the masked variant.
61
61
  */
62
62
  function maskFencedBlocks(body) {
63
- return body.replace(/(```|~~~)[\s\S]*?\1/g, (block) => {
64
- // Replace every non-newline char with a space so offsets (and line
65
- // numbers) are preserved exactly. Keep newlines intact.
66
- return block.replace(/[^\n]/g, ' ');
67
- });
63
+ const masked = body.split('');
64
+ let activeMarker = null;
65
+ let minimumClosingLength = 0;
66
+ let lineStart = 0;
67
+ while (lineStart < body.length) {
68
+ const newlineIndex = body.indexOf('\n', lineStart);
69
+ const lineEnd = newlineIndex === -1 ? body.length : newlineIndex;
70
+ const line = body.slice(lineStart, lineEnd);
71
+ if (activeMarker === null) {
72
+ const opening = /^ {0,3}(`{3,}|~{3,})/.exec(line)?.[1];
73
+ if (opening !== undefined) {
74
+ activeMarker = opening[0];
75
+ minimumClosingLength = opening.length;
76
+ }
77
+ }
78
+ else {
79
+ const closing = /^ {0,3}(`+|~+)[ \t]*$/.exec(line)?.[1];
80
+ if (closing?.startsWith(activeMarker) === true && closing.length >= minimumClosingLength) {
81
+ activeMarker = null;
82
+ minimumClosingLength = 0;
83
+ }
84
+ }
85
+ if (activeMarker !== null || minimumClosingLength === 0) {
86
+ const isFenceBoundary = /^ {0,3}(`{3,}|~{3,})/.test(line) || /^ {0,3}(`+|~+)[ \t]*$/.test(line);
87
+ if (activeMarker !== null || isFenceBoundary) {
88
+ for (let index = lineStart; index < lineEnd; index += 1) {
89
+ masked[index] = ' ';
90
+ }
91
+ }
92
+ }
93
+ lineStart = newlineIndex === -1 ? body.length : newlineIndex + 1;
94
+ }
95
+ return masked.join('');
68
96
  }
69
97
  function escapeRegex(input) {
70
98
  return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@@ -18,7 +18,7 @@ function extractPathsFromSection(sectionText) {
18
18
  return paths;
19
19
  }
20
20
  function parseSectionedFileLists(body) {
21
- const filesSection = /##\s+Files\s+likely\s+to\s+change[\s\S]*?(?=\n##\s|$)/.exec(body);
21
+ const filesSection = /##\s+Files(?:\s+likely\s+to\s+change)?\s*[\s\S]*?(?=\n##\s|$)/.exec(body);
22
22
  const scopedBody = filesSection?.[0] ?? body;
23
23
  const createSection = /###\s+Create[\s\S]*?(?=\n###|\n##\s|$)/.exec(scopedBody);
24
24
  const modifySection = /###\s+Modify[\s\S]*?(?=\n###|\n##\s|$)/.exec(scopedBody);
@@ -67,7 +67,8 @@ async function categorizeByExistence(paths, projectPath) {
67
67
  */
68
68
  export async function extractFilesFromSpecBody(specBody, projectPath) {
69
69
  const structured = parseSectionedFileLists(specBody);
70
- if (structured !== null && (structured.create.length > 0 || structured.modify.length > 0)) {
70
+ if (structured !== null &&
71
+ (structured.create.length > 0 || structured.modify.length > 0 || structured.test.length > 0)) {
71
72
  return structured;
72
73
  }
73
74
  const allPaths = [...new Set(Array.from(specBody.matchAll(FILE_PATH_RE), (m) => m[0]))];
@@ -4,7 +4,25 @@
4
4
  * Returns the remaining prose only, preserving line structure.
5
5
  */
6
6
  export function stripFencedBlocks(md) {
7
- // Match ``` or ~~~ fences (with optional language specifier) spanning multiple lines
8
- return md.replace(/^(`{3,}|~{3,})[^\n]*\n[\s\S]*?^\1\s*$/gm, '');
7
+ const lines = md.split('\n');
8
+ let openFence;
9
+ return lines
10
+ .map((line) => {
11
+ if (openFence !== undefined) {
12
+ const close = new RegExp(`^ {0,3}${openFence.marker}{${String(openFence.length)},}[ \\t]*\\r?$`);
13
+ if (close.test(line)) {
14
+ openFence = undefined;
15
+ }
16
+ return '';
17
+ }
18
+ const opening = /^ {0,3}(`{3,}|~{3,})[^\r\n]*\r?$/.exec(line);
19
+ if (opening?.[1]) {
20
+ const marker = opening[1][0];
21
+ openFence = { marker, length: opening[1].length };
22
+ return '';
23
+ }
24
+ return line;
25
+ })
26
+ .join('\n');
9
27
  }
10
28
  //# sourceMappingURL=text-fences.js.map
@@ -1,3 +1,6 @@
1
+ import type { CanonicalUnifiedSpecInput, UnifiedSpecCandidateValidation } from '../../types/index.js';
2
+ /** Compose the one canonical persisted spec document from already-grounded inputs. */
3
+ export declare function buildCanonicalUnifiedSpecContent(input: CanonicalUnifiedSpecInput): string;
1
4
  /**
2
5
  * Combine a generated lean spec.md body and a generated lean technical.md body
3
6
  * into a single unified spec.md content. The technical body's YAML frontmatter
@@ -10,4 +13,8 @@
10
13
  * inject sections the user did not author themselves.
11
14
  */
12
15
  export declare function buildUnifiedSpecContent(leanSpecBody: string, leanTechnicalBody: string): string;
16
+ /** Pure pre-persistence validation for the complete unified spec candidate. */
17
+ export declare function validateUnifiedSpecCandidate(candidate: string, options?: {
18
+ groundedFilePaths?: Iterable<string>;
19
+ }): UnifiedSpecCandidateValidation;
13
20
  //# sourceMappingURL=unified-spec-builder.d.ts.map