@planu/cli 4.14.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (424) hide show
  1. package/CHANGELOG.md +35 -1
  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 +2 -2
  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 +1 -1
  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 +10 -1
  46. package/dist/engine/evidence-gates/artifact-reader.js +115 -2
  47. package/dist/engine/evidence-gates/lifecycle-gate.js +4 -3
  48. package/dist/engine/evidence-gates/reconciliation-freshness.d.ts +11 -0
  49. package/dist/engine/evidence-gates/reconciliation-freshness.js +72 -0
  50. package/dist/engine/evidence-index/done-drift.d.ts +1 -1
  51. package/dist/engine/evidence-index/done-drift.js +40 -18
  52. package/dist/engine/execution/context.js +3 -0
  53. package/dist/engine/execution/durable-job-heartbeat-runtime.d.ts +4 -0
  54. package/dist/engine/execution/durable-job-heartbeat-runtime.js +400 -0
  55. package/dist/engine/execution/job-runtime.d.ts +30 -0
  56. package/dist/engine/execution/job-runtime.js +114 -6
  57. package/dist/engine/execution/public-job-sanitizer.d.ts +4 -0
  58. package/dist/engine/execution/public-job-sanitizer.js +31 -0
  59. package/dist/engine/execution/validate-job-executor.d.ts +12 -1
  60. package/dist/engine/execution/validate-job-executor.js +549 -86
  61. package/dist/engine/execution/validate-job-payload.js +107 -50
  62. package/dist/engine/execution/validate-job-recovery.js +1 -1
  63. package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
  64. package/dist/engine/execution/validate-worker-runtime.js +90 -2
  65. package/dist/engine/execution/validate-worker-thread.js +17 -24
  66. package/dist/engine/handoff-artifacts/schemas.d.ts +2 -1
  67. package/dist/engine/handoff-artifacts/schemas.js +33 -0
  68. package/dist/engine/handoff-packager.d.ts +19 -0
  69. package/dist/engine/handoff-packager.js +415 -13
  70. package/dist/engine/hooks/effort-configurator.js +1 -1
  71. package/dist/engine/impact-detector/test-break-predictor.js +3 -3
  72. package/dist/engine/impact-detector/tool-registration.js +1 -1
  73. package/dist/engine/implementation-contract/renderer.js +23 -8
  74. package/dist/engine/lifecycle-reconciliation-io.d.ts +11 -0
  75. package/dist/engine/lifecycle-reconciliation-io.js +180 -0
  76. package/dist/engine/lifecycle-reconciliation.d.ts +16 -0
  77. package/dist/engine/lifecycle-reconciliation.js +406 -0
  78. package/dist/engine/local-first/tool-classification.js +2 -0
  79. package/dist/engine/macos-keychain-native-port.d.ts +5 -0
  80. package/dist/engine/macos-keychain-native-port.js +19 -7
  81. package/dist/engine/migrations/remove-commercial-state.d.ts +3 -0
  82. package/dist/engine/migrations/remove-commercial-state.js +343 -0
  83. package/dist/engine/network-policy.js +1 -0
  84. package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
  85. package/dist/engine/planu-core.darwin-arm64.node.sbom.json +10 -10
  86. package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
  87. package/dist/engine/planu-core.darwin-x64.node.sbom.json +10 -10
  88. package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
  89. package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +10 -10
  90. package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
  91. package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +10 -10
  92. package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
  93. package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +10 -10
  94. package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
  95. package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +10 -10
  96. package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
  97. package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +10 -10
  98. package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
  99. package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +10 -10
  100. package/dist/engine/readiness-checker.d.ts +1 -16
  101. package/dist/engine/readiness-checker.js +27 -88
  102. package/dist/engine/runtime-policy.d.ts +2 -0
  103. package/dist/engine/runtime-policy.js +42 -5
  104. package/dist/engine/runtime-security/rate-limiter.js +0 -1
  105. package/dist/engine/safety/contained-project-file.d.ts +3 -0
  106. package/dist/engine/safety/contained-project-file.js +23 -0
  107. package/dist/engine/scope-boundaries/contradiction-checker.js +63 -1
  108. package/dist/engine/scope-boundaries/scope-validator.js +45 -7
  109. package/dist/engine/session/checkpoint-writer.js +0 -9
  110. package/dist/engine/spec-format/acceptance-criteria.d.ts +6 -2
  111. package/dist/engine/spec-format/acceptance-criteria.js +77 -18
  112. package/dist/engine/spec-format/markdown-sections.d.ts +14 -0
  113. package/dist/engine/spec-format/markdown-sections.js +105 -0
  114. package/dist/engine/spec-format/read-technical-section.js +33 -5
  115. package/dist/engine/spec-format/technical-md-populator.js +3 -2
  116. package/dist/engine/spec-format/unified-spec-builder.d.ts +7 -0
  117. package/dist/engine/spec-format/unified-spec-builder.js +202 -0
  118. package/dist/engine/spec-migrator/canonical-deduplicator.d.ts +18 -0
  119. package/dist/engine/spec-migrator/canonical-deduplicator.js +479 -0
  120. package/dist/engine/spec-migrator/filesystem-import.d.ts +4 -8
  121. package/dist/engine/spec-migrator/filesystem-import.js +121 -14
  122. package/dist/engine/spec-migrator/frontmatter-parser.js +32 -15
  123. package/dist/engine/spec-migrator/index.d.ts +1 -0
  124. package/dist/engine/spec-migrator/index.js +1 -0
  125. package/dist/engine/spec-state-machine/transition-spec.d.ts +6 -1
  126. package/dist/engine/spec-state-machine/transition-spec.js +10 -1
  127. package/dist/engine/technical-enricher/index.js +16 -8
  128. package/dist/engine/technical-enricher/render-enriched.d.ts +1 -0
  129. package/dist/engine/technical-enricher/render-enriched.js +42 -14
  130. package/dist/engine/telemetry/health-checker.js +53 -17
  131. package/dist/engine/telemetry/telemetry-client.js +26 -8
  132. package/dist/engine/text-signal-boundaries.d.ts +2 -0
  133. package/dist/engine/text-signal-boundaries.js +25 -2
  134. package/dist/engine/time/relative-date.d.ts +3 -0
  135. package/dist/engine/time/relative-date.js +16 -0
  136. package/dist/engine/timing/budget.d.ts +11 -0
  137. package/dist/engine/timing/budget.js +27 -9
  138. package/dist/engine/token-optimizer/analytics.d.ts +1 -1
  139. package/dist/engine/token-optimizer/analytics.js +5 -6
  140. package/dist/engine/usage-tracker/core.d.ts +2 -2
  141. package/dist/engine/usage-tracker/core.js +1 -2
  142. package/dist/engine/usage-tracker/index.d.ts +0 -3
  143. package/dist/engine/usage-tracker/index.js +0 -3
  144. package/dist/engine/usage-tracker/stats.d.ts +2 -2
  145. package/dist/engine/usage-tracker/stats.js +1 -28
  146. package/dist/engine/validation/durable-validation.d.ts +1 -1
  147. package/dist/engine/validation/durable-validation.js +3 -82
  148. package/dist/engine/validation/validation-freshness.d.ts +11 -1
  149. package/dist/engine/validation/validation-freshness.js +231 -91
  150. package/dist/engine/validation/validation-receipt.d.ts +9 -6
  151. package/dist/engine/validation/validation-receipt.js +84 -24
  152. package/dist/engine/validation/validation-source-digest.d.ts +2 -0
  153. package/dist/engine/validation/validation-source-digest.js +86 -0
  154. package/dist/engine/validation/validation-submission.d.ts +5 -4
  155. package/dist/engine/validation/validation-submission.js +25 -11
  156. package/dist/engine/validation/validation-worktree.d.ts +21 -0
  157. package/dist/engine/validation/validation-worktree.js +260 -0
  158. package/dist/engine/validation-impact-planner.d.ts +14 -2
  159. package/dist/engine/validation-impact-planner.js +0 -3
  160. package/dist/engine/validator/dor-dod.d.ts +1 -0
  161. package/dist/engine/validator/dor-dod.js +5 -3
  162. package/dist/engine/validator/extractors.d.ts +1 -5
  163. package/dist/engine/validator/extractors.js +24 -69
  164. package/dist/engine/validator/spec-compliance-runner.d.ts +12 -24
  165. package/dist/engine/validator/spec-compliance-runner.js +429 -211
  166. package/dist/engine/validator.js +35 -22
  167. package/dist/index.js +4 -16
  168. package/dist/resources/usage-stats-resource.js +2 -18
  169. package/dist/security/adapters/linux-secret-service.js +7 -3
  170. package/dist/security/adapters/windows-credential-manager.js +6 -4
  171. package/dist/server/routes/specs.js +10 -0
  172. package/dist/storage/base-store.d.ts +1 -1
  173. package/dist/storage/base-store.js +1 -1
  174. package/dist/storage/feedback-remote.d.ts +2 -3
  175. package/dist/storage/feedback-remote.js +45 -31
  176. package/dist/storage/global-store.d.ts +1 -17
  177. package/dist/storage/global-store.js +1 -42
  178. package/dist/storage/index.d.ts +0 -2
  179. package/dist/storage/index.js +0 -2
  180. package/dist/storage/migrations/canonical-storage.js +124 -11
  181. package/dist/storage/runtime-db.d.ts +9 -0
  182. package/dist/storage/runtime-db.js +64 -8
  183. package/dist/storage/spec-store.d.ts +14 -2
  184. package/dist/storage/spec-store.js +104 -14
  185. package/dist/storage/status-store/atomic-status-write.d.ts +5 -0
  186. package/dist/storage/status-store/atomic-status-write.js +57 -0
  187. package/dist/storage/status-store/file-lock.js +30 -11
  188. package/dist/storage/status-store/self-healing.js +3 -3
  189. package/dist/storage/status-store/version-sync.d.ts +2 -1
  190. package/dist/storage/status-store/version-sync.js +35 -40
  191. package/dist/storage/usage-store.d.ts +1 -5
  192. package/dist/storage/usage-store.js +0 -35
  193. package/dist/tools/auto-update-handler.d.ts +3 -3
  194. package/dist/tools/auto-update-handler.js +3 -3
  195. package/dist/tools/challenge-spec/resilience-challenge-scenarios.d.ts +2 -1
  196. package/dist/tools/challenge-spec/resilience-challenge-scenarios.js +10 -7
  197. package/dist/tools/challenge-spec/scenario-collector.js +1 -1
  198. package/dist/tools/challenge-spec/scenarios-data.js +1 -1
  199. package/dist/tools/challenge-spec/scenarios-utils.d.ts +1 -1
  200. package/dist/tools/challenge-spec/scenarios-utils.js +35 -11
  201. package/dist/tools/challenge-spec.js +5 -5
  202. package/dist/tools/check-readiness.js +1 -1
  203. package/dist/tools/configure-telemetry.js +30 -2
  204. package/dist/tools/create-spec/spec-builder.js +0 -11
  205. package/dist/tools/create-spec.d.ts +1 -0
  206. package/dist/tools/create-spec.js +444 -239
  207. package/dist/tools/git/branch-ops.d.ts +1 -1
  208. package/dist/tools/git/branch-ops.js +3 -2
  209. package/dist/tools/init-project/handler.js +10 -12
  210. package/dist/tools/init-project/host-assets-writer.js +26 -1
  211. package/dist/tools/init-project/lint-scaffolder.d.ts +3 -3
  212. package/dist/tools/init-project/migration-runner.d.ts +2 -4
  213. package/dist/tools/init-project/migration-runner.js +3 -2
  214. package/dist/tools/init-project/portable-index-reconciler.d.ts +4 -0
  215. package/dist/tools/init-project/portable-index-reconciler.js +14 -0
  216. package/dist/tools/init-project/result-builder.js +1 -3
  217. package/dist/tools/jobs/handlers.js +38 -6
  218. package/dist/tools/list-specs.js +5 -26
  219. package/dist/tools/merge-risk-handler.js +2 -2
  220. package/dist/tools/package-handoff.js +2 -0
  221. package/dist/tools/reconcile-spec.js +0 -27
  222. package/dist/tools/register-agent-squad-tools.js +2 -2
  223. package/dist/tools/register-platform-tools/design-stack-tools.js +11 -11
  224. package/dist/tools/register-platform-tools/lifecycle-infra-tools.js +7 -7
  225. package/dist/tools/register-sdd-tools.d.ts +1 -1
  226. package/dist/tools/register-sdd-tools.js +2 -29
  227. package/dist/tools/register-spec-tools/analysis-tools.js +8 -8
  228. package/dist/tools/register-spec-tools/core-spec-tools.js +17 -8
  229. package/dist/tools/safe-handler.d.ts +5 -13
  230. package/dist/tools/safe-handler.js +7 -23
  231. package/dist/tools/schemas/index.d.ts +1 -1
  232. package/dist/tools/schemas/index.js +1 -1
  233. package/dist/tools/schemas/output-schemas.d.ts +0 -23
  234. package/dist/tools/schemas/output-schemas.js +0 -28
  235. package/dist/tools/schemas/spec.d.ts +4 -0
  236. package/dist/tools/schemas/spec.js +3 -0
  237. package/dist/tools/schemas/validate-output-schema.d.ts +11 -0
  238. package/dist/tools/schemas/validate-output-schema.js +7 -0
  239. package/dist/tools/spec-prompt-handler.js +3 -3
  240. package/dist/tools/sync-spec-state-handler.d.ts +1 -1
  241. package/dist/tools/sync-spec-state-handler.js +1 -1
  242. package/dist/tools/tool-entry.d.ts +4 -4
  243. package/dist/tools/tool-entry.js +3 -3
  244. package/dist/tools/tool-registry/core-tools.js +31 -15
  245. package/dist/tools/tool-registry/group-infra.js +27 -110
  246. package/dist/tools/tool-registry/group-quality-compliance.js +26 -26
  247. package/dist/tools/tool-registry/inventory.d.ts +2 -0
  248. package/dist/tools/tool-registry/inventory.js +2 -0
  249. package/dist/tools/tool-registry-helpers.d.ts +3 -3
  250. package/dist/tools/tool-registry-helpers.js +3 -3
  251. package/dist/tools/tool-usage-report/registered-tools.d.ts +1 -1
  252. package/dist/tools/tool-usage-report/registered-tools.js +3 -15
  253. package/dist/tools/update-status/approval-gates.js +3 -0
  254. package/dist/tools/update-status/done-receipt-verifier.js +40 -27
  255. package/dist/tools/update-status/evidence-gate.js +36 -1
  256. package/dist/tools/update-status/file-sync.d.ts +2 -1
  257. package/dist/tools/update-status/file-sync.js +57 -6
  258. package/dist/tools/update-status/index.d.ts +2 -0
  259. package/dist/tools/update-status/index.js +95 -58
  260. package/dist/tools/update-status/response-builder.js +3 -3
  261. package/dist/tools/update-status/side-effects.d.ts +2 -0
  262. package/dist/tools/update-status/side-effects.js +2 -2
  263. package/dist/tools/update-status/transition-guard.js +32 -15
  264. package/dist/tools/update-status-actions.d.ts +4 -2
  265. package/dist/tools/update-status-actions.js +16 -14
  266. package/dist/tools/usage-report.js +1 -16
  267. package/dist/tools/usage-stats.js +1 -18
  268. package/dist/tools/usage-tracking.d.ts +4 -0
  269. package/dist/tools/usage-tracking.js +20 -0
  270. package/dist/tools/validate-lint.d.ts +1 -0
  271. package/dist/tools/validate-lint.js +1 -1
  272. package/dist/tools/validate.d.ts +2 -1
  273. package/dist/tools/validate.js +114 -34
  274. package/dist/transports/http-transport.js +6 -8
  275. package/dist/transports/mcp-types.d.ts +0 -2
  276. package/dist/transports/session-context.js +1 -1
  277. package/dist/types/cascade-hooks.d.ts +1 -1
  278. package/dist/types/ci.d.ts +0 -4
  279. package/dist/types/clarification-token.d.ts +1 -1
  280. package/dist/types/claude-code-runtime.d.ts +0 -27
  281. package/dist/types/commercial-migration.d.ts +17 -0
  282. package/dist/types/commercial-migration.js +2 -0
  283. package/dist/types/common/primitives.d.ts +0 -2
  284. package/dist/types/core-bridge.d.ts +4 -10
  285. package/dist/types/dashboard.d.ts +3 -7
  286. package/dist/types/docs.d.ts +0 -1
  287. package/dist/types/durable-job.d.ts +4 -4
  288. package/dist/types/durable-validation.d.ts +100 -2
  289. package/dist/types/durable-validation.js +165 -1
  290. package/dist/types/errors/structured-error.d.ts +3 -3
  291. package/dist/types/estimation.d.ts +2 -0
  292. package/dist/types/evidence-gates.d.ts +9 -1
  293. package/dist/types/execution.d.ts +2 -0
  294. package/dist/types/gemini-integration.d.ts +0 -11
  295. package/dist/types/handoff-artifacts.d.ts +41 -0
  296. package/dist/types/hooks-advanced.d.ts +0 -13
  297. package/dist/types/impact-detection.d.ts +2 -2
  298. package/dist/types/index.d.ts +2 -6
  299. package/dist/types/index.js +1 -5
  300. package/dist/types/kiro-integration.d.ts +0 -6
  301. package/dist/types/network-policy.d.ts +1 -1
  302. package/dist/types/project/lint-scaffolder.d.ts +1 -1
  303. package/dist/types/runtime-policy.d.ts +11 -0
  304. package/dist/types/session-safeguard.d.ts +0 -31
  305. package/dist/types/spec/canonical-repair.d.ts +81 -0
  306. package/dist/types/spec/canonical-repair.js +2 -0
  307. package/dist/types/spec/core.d.ts +14 -0
  308. package/dist/types/spec/index.d.ts +1 -0
  309. package/dist/types/spec/index.js +1 -0
  310. package/dist/types/spec/inputs.d.ts +29 -0
  311. package/dist/types/spec-format.d.ts +24 -0
  312. package/dist/types/telemetry.d.ts +4 -1
  313. package/dist/types/transport.d.ts +0 -2
  314. package/dist/types/usage.d.ts +1 -36
  315. package/dist/types/usage.js +1 -1
  316. package/dist/types/validate-worker.d.ts +6 -0
  317. package/dist/types/validation-receipt.d.ts +1 -1
  318. package/dist/types/validation.d.ts +2 -2
  319. package/package.json +16 -12
  320. package/planu-native.json +1 -1
  321. package/planu-plugin.json +23 -40
  322. package/scripts/lib/pending-release-file.mjs +93 -0
  323. package/src/i18n/messages/en.json +0 -41
  324. package/src/i18n/messages/es.json +0 -41
  325. package/src/i18n/messages/pt.json +0 -41
  326. package/dist/cli/commands/activate.d.ts +0 -14
  327. package/dist/cli/commands/activate.js +0 -174
  328. package/dist/config/license-plans.json +0 -251
  329. package/dist/config/product-public.ts +0 -148
  330. package/dist/config/server-instructions.ts +0 -121
  331. package/dist/config/version-defaults.ts +0 -76
  332. package/dist/config/version.ts +0 -21
  333. package/dist/engine/ai-integration/gemini/settings-generator.d.ts +0 -4
  334. package/dist/engine/ai-integration/gemini/settings-generator.js +0 -195
  335. package/dist/engine/ai-integration/kiro/hooks-generator.d.ts +0 -6
  336. package/dist/engine/ai-integration/kiro/hooks-generator.js +0 -75
  337. package/dist/engine/hooks/full-spectrum-generator.d.ts +0 -32
  338. package/dist/engine/hooks/full-spectrum-generator.js +0 -117
  339. package/dist/engine/license-validator/config-loader.d.ts +0 -5
  340. package/dist/engine/license-validator/config-loader.js +0 -16
  341. package/dist/engine/license-validator/core.d.ts +0 -15
  342. package/dist/engine/license-validator/core.js +0 -151
  343. package/dist/engine/license-validator/fingerprint.d.ts +0 -3
  344. package/dist/engine/license-validator/fingerprint.js +0 -17
  345. package/dist/engine/license-validator/lemon-squeezy.d.ts +0 -5
  346. package/dist/engine/license-validator/lemon-squeezy.js +0 -55
  347. package/dist/engine/license-validator.d.ts +0 -5
  348. package/dist/engine/license-validator.js +0 -6
  349. package/dist/engine/product-intelligence/index.d.ts +0 -7
  350. package/dist/engine/product-intelligence/index.js +0 -211
  351. package/dist/engine/session/auto-save.d.ts +0 -18
  352. package/dist/engine/session/auto-save.js +0 -98
  353. package/dist/engine/session/context-snapshot.d.ts +0 -8
  354. package/dist/engine/session/context-snapshot.js +0 -49
  355. package/dist/engine/session/memory-sync.d.ts +0 -12
  356. package/dist/engine/session/memory-sync.js +0 -34
  357. package/dist/engine/session/session-diff.d.ts +0 -11
  358. package/dist/engine/session/session-diff.js +0 -42
  359. package/dist/engine/session/session-merge.d.ts +0 -12
  360. package/dist/engine/session/session-merge.js +0 -55
  361. package/dist/engine/session-safeguard/checkpoint-runner.d.ts +0 -4
  362. package/dist/engine/session-safeguard/checkpoint-runner.js +0 -70
  363. package/dist/engine/session-safeguard/learnings-buffer.d.ts +0 -15
  364. package/dist/engine/session-safeguard/learnings-buffer.js +0 -91
  365. package/dist/engine/session-safeguard/precompaction-drain.d.ts +0 -10
  366. package/dist/engine/session-safeguard/precompaction-drain.js +0 -82
  367. package/dist/engine/session-safeguard/unpushed-detector.d.ts +0 -7
  368. package/dist/engine/session-safeguard/unpushed-detector.js +0 -59
  369. package/dist/engine/spec-changelog/core.d.ts +0 -16
  370. package/dist/engine/spec-changelog/core.js +0 -176
  371. package/dist/engine/spec-changelog/diff.d.ts +0 -18
  372. package/dist/engine/spec-changelog/diff.js +0 -121
  373. package/dist/engine/spec-changelog/index.d.ts +0 -3
  374. package/dist/engine/spec-changelog/index.js +0 -4
  375. package/dist/engine/trial-engine.d.ts +0 -5
  376. package/dist/engine/trial-engine.js +0 -14
  377. package/dist/engine/usage-tracker/rate-check.d.ts +0 -7
  378. package/dist/engine/usage-tracker/rate-check.js +0 -18
  379. package/dist/engine/usage-tracker/rate-limiter.d.ts +0 -14
  380. package/dist/engine/usage-tracker/rate-limiter.js +0 -73
  381. package/dist/engine/usage-tracker/trial.d.ts +0 -27
  382. package/dist/engine/usage-tracker/trial.js +0 -49
  383. package/dist/engine/webhook/event-handlers.d.ts +0 -25
  384. package/dist/engine/webhook/event-handlers.js +0 -89
  385. package/dist/engine/webhook/index.d.ts +0 -4
  386. package/dist/engine/webhook/index.js +0 -5
  387. package/dist/engine/webhook/server.d.ts +0 -12
  388. package/dist/engine/webhook/server.js +0 -249
  389. package/dist/engine/webhook/signature.d.ts +0 -16
  390. package/dist/engine/webhook/signature.js +0 -49
  391. package/dist/storage/license-store.d.ts +0 -6
  392. package/dist/storage/license-store.js +0 -63
  393. package/dist/storage/session-store.d.ts +0 -20
  394. package/dist/storage/session-store.js +0 -136
  395. package/dist/tools/activate-license.d.ts +0 -6
  396. package/dist/tools/activate-license.js +0 -132
  397. package/dist/tools/checkpoint-handler.d.ts +0 -3
  398. package/dist/tools/checkpoint-handler.js +0 -130
  399. package/dist/tools/export-session.d.ts +0 -3
  400. package/dist/tools/export-session.js +0 -90
  401. package/dist/tools/license-gate.d.ts +0 -18
  402. package/dist/tools/license-gate.js +0 -222
  403. package/dist/tools/license-status.d.ts +0 -3
  404. package/dist/tools/license-status.js +0 -93
  405. package/dist/tools/list-sessions.d.ts +0 -3
  406. package/dist/tools/list-sessions.js +0 -46
  407. package/dist/tools/planu-session-checkpoint.d.ts +0 -6
  408. package/dist/tools/planu-session-checkpoint.js +0 -42
  409. package/dist/tools/restore-session.d.ts +0 -3
  410. package/dist/tools/restore-session.js +0 -71
  411. package/dist/tools/spec-history.d.ts +0 -3
  412. package/dist/tools/spec-history.js +0 -59
  413. package/dist/tools/webhook.d.ts +0 -6
  414. package/dist/tools/webhook.js +0 -150
  415. package/dist/types/changelog.d.ts +0 -49
  416. package/dist/types/changelog.js +0 -3
  417. package/dist/types/licensing.d.ts +0 -109
  418. package/dist/types/licensing.js +0 -4
  419. package/dist/types/product-intelligence.d.ts +0 -60
  420. package/dist/types/product-intelligence.js +0 -3
  421. package/dist/types/session.d.ts +0 -84
  422. package/dist/types/session.js +0 -3
  423. package/dist/types/webhook.d.ts +0 -62
  424. package/dist/types/webhook.js +0 -4
@@ -0,0 +1,86 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import { lstat, readFile, readlink } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ import { isValidationSourcePath } from './validation-source-policy.js';
7
+ const execFileAsync = promisify(execFile);
8
+ const SOURCE_DIGEST_MAX_CONCURRENCY = 8;
9
+ async function mapWithConcurrency(values, concurrency, worker) {
10
+ const results = new Array(values.length);
11
+ let cursor = 0;
12
+ const runners = Array.from({ length: Math.min(concurrency, values.length) }, async () => {
13
+ for (;;) {
14
+ const index = cursor;
15
+ cursor += 1;
16
+ if (index >= values.length) {
17
+ return;
18
+ }
19
+ results[index] = await worker(values[index]);
20
+ }
21
+ });
22
+ await Promise.all(runners);
23
+ return results;
24
+ }
25
+ export async function gitSourceTreeDigest(projectPath) {
26
+ try {
27
+ const gitOptions = { cwd: projectPath, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 };
28
+ const [trackedResult, untrackedResult] = await Promise.all([
29
+ execFileAsync('git', ['ls-files', '--cached', '-z'], gitOptions),
30
+ execFileAsync('git', ['ls-files', '--others', '--exclude-standard', '-z'], gitOptions),
31
+ ]);
32
+ const sourceEntries = (stdout) => stdout
33
+ .split('\0')
34
+ .filter(Boolean)
35
+ .map((sourcePath) => ({ sourcePath, canonicalPath: sourcePath.normalize('NFC') }))
36
+ .filter(({ canonicalPath }) => isValidationSourcePath(canonicalPath));
37
+ const entriesToRead = [
38
+ ...sourceEntries(trackedResult.stdout),
39
+ ...sourceEntries(untrackedResult.stdout),
40
+ ].sort((left, right) => Buffer.compare(Buffer.from(left.canonicalPath), Buffer.from(right.canonicalPath)));
41
+ if (new Set(entriesToRead.map(({ canonicalPath }) => canonicalPath)).size !== entriesToRead.length) {
42
+ throw new Error('source paths collide after Unicode normalization');
43
+ }
44
+ const entries = await mapWithConcurrency(entriesToRead, SOURCE_DIGEST_MAX_CONCURRENCY, async (entry) => {
45
+ const { canonicalPath: path, sourcePath } = entry;
46
+ const absolutePath = join(projectPath, sourcePath);
47
+ try {
48
+ const stats = await lstat(absolutePath);
49
+ if (stats.isSymbolicLink()) {
50
+ const target = (await readlink(absolutePath)).normalize('NFC');
51
+ return { path, content: Buffer.from(`symlink\0${target}`, 'utf8') };
52
+ }
53
+ if (!stats.isFile()) {
54
+ throw new Error(`unsupported source entry type: ${path}`);
55
+ }
56
+ return {
57
+ path,
58
+ content: Buffer.concat([Buffer.from('file\0'), await readFile(absolutePath)]),
59
+ };
60
+ }
61
+ catch (error) {
62
+ if (error.code === 'ENOENT') {
63
+ return undefined;
64
+ }
65
+ throw error;
66
+ }
67
+ });
68
+ const hash = createHash('sha256');
69
+ hash.update('planu-source-v1\0');
70
+ for (const entry of entries) {
71
+ if (!entry) {
72
+ continue;
73
+ }
74
+ const pathBytes = Buffer.from(entry.path, 'utf8');
75
+ hash.update(`${pathBytes.length}:`);
76
+ hash.update(pathBytes);
77
+ hash.update(`${entry.content.length}:`);
78
+ hash.update(entry.content);
79
+ }
80
+ return `sha256:${hash.digest('hex')}`;
81
+ }
82
+ catch (error) {
83
+ throw new Error('[Planu] Unable to bind validation to the source tree', { cause: error });
84
+ }
85
+ }
86
+ //# sourceMappingURL=validation-source-digest.js.map
@@ -1,12 +1,11 @@
1
1
  import type { DurableJobRuntime } from '../execution/job-runtime.js';
2
2
  import type { DurableJobRecord } from '../../storage/runtime-db.js';
3
3
  import type { DurableValidationBindings } from '../../types/durable-validation.js';
4
- import type { ValidationArtifactDigests } from '../../types/validation-receipt.js';
5
- import type { ValidationFreshnessLease } from './validation-freshness.js';
4
+ import type { ValidationArtifactDigests, ValidationFreshnessLease } from '../../types/validation-receipt.js';
6
5
  /** Stable identity for exactly one immutable validation input tuple. */
7
- export declare function validationOperationId(bindings: DurableValidationBindings): string;
6
+ export declare function validationOperationId(bindings: DurableValidationBindings, validationRootId: string): string;
8
7
  /** Stable identity used to acknowledge before repository-wide bindings are computed. */
9
- export declare function validationSubmissionOperationId(projectId: string, specId: string): string;
8
+ export declare function validationSubmissionOperationId(projectId: string, specId: string, validationRootId: string): string;
10
9
  /** Accept one pre-bound durable validation for internal and compatibility callers. */
11
10
  export declare function createValidationSubmission(input: {
12
11
  readonly runtime: DurableJobRuntime;
@@ -16,6 +15,7 @@ export declare function createValidationSubmission(input: {
16
15
  readonly projectId?: string;
17
16
  readonly specPath?: string;
18
17
  readonly projectPath?: string;
18
+ readonly validationRootId: string;
19
19
  };
20
20
  readonly bindings: DurableValidationBindings;
21
21
  readonly artifactDigests?: ValidationArtifactDigests;
@@ -30,6 +30,7 @@ export declare function createPendingValidationSubmission(input: {
30
30
  readonly id: string;
31
31
  readonly specPath: string;
32
32
  readonly projectPath: string;
33
+ readonly validationRootId: string;
33
34
  };
34
35
  readonly deadlineAt: number;
35
36
  }): DurableJobRecord;
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { DIGEST, PROJECT_ID as CANONICAL_PROJECT_ID, SPEC_ID as CANONICAL_SPEC_ID, } from './validation-receipt-codec.js';
3
+ import { isValidationRootId } from './validation-worktree.js';
3
4
  function assertBindings(bindings) {
4
5
  if (!CANONICAL_PROJECT_ID.test(bindings.projectId)) {
5
6
  throw new Error('[Planu] Durable validation requires a canonical projectId');
@@ -17,11 +18,15 @@ function assertBindings(bindings) {
17
18
  }
18
19
  }
19
20
  /** Stable identity for exactly one immutable validation input tuple. */
20
- export function validationOperationId(bindings) {
21
+ export function validationOperationId(bindings, validationRootId) {
21
22
  assertBindings(bindings);
23
+ if (!isValidationRootId(validationRootId)) {
24
+ throw new Error('[Planu] Durable validation requires a valid validationRootId');
25
+ }
22
26
  const operationDigest = createHash('sha256')
23
27
  .update(JSON.stringify([
24
- 'planu-validation-v1',
28
+ 'planu-validation-v2',
29
+ validationRootId,
25
30
  bindings.projectId,
26
31
  bindings.specId,
27
32
  bindings.sourceTreeHash,
@@ -33,12 +38,14 @@ export function validationOperationId(bindings) {
33
38
  return `validation-${operationDigest}`;
34
39
  }
35
40
  /** Stable identity used to acknowledge before repository-wide bindings are computed. */
36
- export function validationSubmissionOperationId(projectId, specId) {
37
- if (!CANONICAL_PROJECT_ID.test(projectId) || !CANONICAL_SPEC_ID.test(specId)) {
41
+ export function validationSubmissionOperationId(projectId, specId, validationRootId) {
42
+ if (!CANONICAL_PROJECT_ID.test(projectId) ||
43
+ !CANONICAL_SPEC_ID.test(specId) ||
44
+ !isValidationRootId(validationRootId)) {
38
45
  throw new Error('[Planu] Invalid durable validation submission identity');
39
46
  }
40
47
  const operationDigest = createHash('sha256')
41
- .update(JSON.stringify(['planu-validation-submission-v1', projectId, specId]))
48
+ .update(JSON.stringify(['planu-validation-submission-v2', projectId, specId, validationRootId]))
42
49
  .digest('hex');
43
50
  return `validation-${operationDigest}`;
44
51
  }
@@ -70,6 +77,9 @@ function existingOrAccept(input) {
70
77
  /** Accept one pre-bound durable validation for internal and compatibility callers. */
71
78
  export function createValidationSubmission(input) {
72
79
  assertBindings(input.bindings);
80
+ if (!isValidationRootId(input.spec.validationRootId) || !input.spec.specPath) {
81
+ throw new Error('[Planu] Durable validation requires a verified validation root and spec path');
82
+ }
73
83
  if (input.canonicalProjectId !== input.bindings.projectId ||
74
84
  input.spec.id !== input.bindings.specId) {
75
85
  throw new Error('[Planu] Durable validation binding identity mismatch');
@@ -79,7 +89,8 @@ export function createValidationSubmission(input) {
79
89
  }
80
90
  const payload = {
81
91
  kind: 'validate',
82
- schemaVersion: 1,
92
+ schemaVersion: 2,
93
+ validationRootId: input.spec.validationRootId,
83
94
  input: {
84
95
  specId: input.spec.id,
85
96
  projectId: input.canonicalProjectId,
@@ -88,20 +99,22 @@ export function createValidationSubmission(input) {
88
99
  bindings: input.bindings,
89
100
  ...(input.artifactDigests === undefined ? {} : { artifactDigests: input.artifactDigests }),
90
101
  ...(input.freshnessLease === undefined ? {} : { freshnessLease: input.freshnessLease }),
91
- ...(input.spec.specPath === undefined ? {} : { specPath: input.spec.specPath }),
102
+ specPath: input.spec.specPath ?? '',
92
103
  deadlineAt: input.deadlineAt,
93
104
  };
94
105
  return existingOrAccept({
95
106
  runtime: input.runtime,
96
107
  projectId: input.canonicalProjectId,
97
- operationId: validationOperationId(input.bindings),
108
+ operationId: validationOperationId(input.bindings, input.spec.validationRootId),
98
109
  payload,
99
110
  });
100
111
  }
101
112
  /** Persist validation immediately; the worker computes and binds the source snapshot. */
102
113
  export function createPendingValidationSubmission(input) {
103
114
  if (!CANONICAL_PROJECT_ID.test(input.canonicalProjectId) ||
104
- !CANONICAL_SPEC_ID.test(input.spec.id)) {
115
+ !CANONICAL_SPEC_ID.test(input.spec.id) ||
116
+ !isValidationRootId(input.spec.validationRootId) ||
117
+ !input.spec.specPath) {
105
118
  throw new Error('[Planu] Invalid durable validation submission identity');
106
119
  }
107
120
  if (!Number.isSafeInteger(input.deadlineAt) || input.deadlineAt <= Date.now()) {
@@ -109,7 +122,8 @@ export function createPendingValidationSubmission(input) {
109
122
  }
110
123
  const payload = {
111
124
  kind: 'validate',
112
- schemaVersion: 1,
125
+ schemaVersion: 2,
126
+ validationRootId: input.spec.validationRootId,
113
127
  input: {
114
128
  specId: input.spec.id,
115
129
  projectId: input.canonicalProjectId,
@@ -121,7 +135,7 @@ export function createPendingValidationSubmission(input) {
121
135
  return existingOrAccept({
122
136
  runtime: input.runtime,
123
137
  projectId: input.canonicalProjectId,
124
- operationId: validationSubmissionOperationId(input.canonicalProjectId, input.spec.id),
138
+ operationId: validationSubmissionOperationId(input.canonicalProjectId, input.spec.id, input.spec.validationRootId),
125
139
  payload,
126
140
  });
127
141
  }
@@ -0,0 +1,21 @@
1
+ import type { ResolvedValidationWorktree, ValidationWorktreeErrorCode } from '../../types/durable-validation.js';
2
+ export declare class ValidationWorktreeError extends Error {
3
+ readonly code: ValidationWorktreeErrorCode;
4
+ readonly specId: string;
5
+ readonly relativeSpecPath?: string;
6
+ constructor(code: ValidationWorktreeErrorCode, specId: string, relativeSpecPath?: string);
7
+ }
8
+ export declare function resolveValidationWorktree(input: {
9
+ requestedProjectPath: string;
10
+ canonicalProjectPath: string;
11
+ canonicalSpecPath: string;
12
+ specId: string;
13
+ }): Promise<ResolvedValidationWorktree>;
14
+ export declare function revalidateValidationWorktree(input: {
15
+ projectPath: string;
16
+ specPath: string;
17
+ specId: string;
18
+ validationRootId: string;
19
+ }): Promise<ResolvedValidationWorktree>;
20
+ export declare function isValidationRootId(value: unknown): value is string;
21
+ //# sourceMappingURL=validation-worktree.d.ts.map
@@ -0,0 +1,260 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import { lstat, readFile, realpath } from 'node:fs/promises';
4
+ import { basename, dirname, isAbsolute, relative, resolve, sep } from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ import { reportClassifiedDegradation } from '../../errors/classified-degradation.js';
7
+ import { parseFrontmatter } from '../frontmatter-parser.js';
8
+ const runFile = promisify(execFile);
9
+ const ROOT_ID = /^[a-f0-9]{64}$/u;
10
+ const SAFE_SPEC_ID = /^SPEC-[1-9]\d*$/u;
11
+ const PORTABLE_SPEC = /^planu\/specs\/(SPEC-\d{3,}(?:-[^/]+)?)\/spec\.md$/u;
12
+ export class ValidationWorktreeError extends Error {
13
+ code;
14
+ specId;
15
+ relativeSpecPath;
16
+ constructor(code, specId, relativeSpecPath) {
17
+ const safeSpecId = SAFE_SPEC_ID.test(specId) ? specId : 'SPEC-unknown';
18
+ const safeRelativeSpecPath = relativeSpecPath !== undefined && PORTABLE_SPEC.test(relativeSpecPath)
19
+ ? relativeSpecPath
20
+ : undefined;
21
+ super(`[Planu] ${code} spec=${safeSpecId}${safeRelativeSpecPath ? ` path=${safeRelativeSpecPath}` : ''}`);
22
+ this.code = code;
23
+ this.name = 'ValidationWorktreeError';
24
+ this.specId = safeSpecId;
25
+ this.relativeSpecPath = safeRelativeSpecPath;
26
+ }
27
+ }
28
+ function fail(code, specId, relativeSpecPath) {
29
+ throw new ValidationWorktreeError(code, specId, relativeSpecPath);
30
+ }
31
+ function isEnoent(error) {
32
+ return error.code === 'ENOENT';
33
+ }
34
+ async function gitPath(projectPath, argument) {
35
+ try {
36
+ const result = await runFile('git', ['-C', projectPath, 'rev-parse', argument], {
37
+ encoding: 'utf8',
38
+ timeout: 10_000,
39
+ maxBuffer: 64 * 1024,
40
+ });
41
+ const output = result.stdout.trim();
42
+ return await realpath(isAbsolute(output) ? output : resolve(projectPath, output));
43
+ }
44
+ catch (error) {
45
+ reportClassifiedDegradation('VALIDATION_GIT_PATH_PROBE', error);
46
+ return null;
47
+ }
48
+ }
49
+ async function resolveGitMembership(projectPath, specId) {
50
+ let requestedRoot;
51
+ try {
52
+ requestedRoot = await realpath(projectPath);
53
+ }
54
+ catch (error) {
55
+ reportClassifiedDegradation('VALIDATION_ROOT_REALPATH', error);
56
+ }
57
+ if (requestedRoot === undefined) {
58
+ fail('VALIDATION_ROOT_NOT_GIT_WORKTREE', specId);
59
+ }
60
+ const [topLevel, commonDir] = await Promise.all([
61
+ gitPath(requestedRoot, '--show-toplevel'),
62
+ gitPath(requestedRoot, '--git-common-dir'),
63
+ ]);
64
+ if (topLevel === null || commonDir === null) {
65
+ fail('VALIDATION_ROOT_NOT_GIT_WORKTREE', specId);
66
+ }
67
+ return { projectPath: topLevel, gitCommonDir: commonDir };
68
+ }
69
+ async function resolveGitRoot(projectPath, specId) {
70
+ let requestedRoot;
71
+ try {
72
+ requestedRoot = await realpath(projectPath);
73
+ }
74
+ catch (error) {
75
+ reportClassifiedDegradation('VALIDATION_ROOT_REALPATH', error);
76
+ }
77
+ if (requestedRoot === undefined) {
78
+ fail('VALIDATION_ROOT_NOT_GIT_WORKTREE', specId);
79
+ }
80
+ const membership = await resolveGitMembership(requestedRoot, specId);
81
+ if (membership.projectPath !== requestedRoot) {
82
+ fail('VALIDATION_ROOT_NOT_GIT_WORKTREE', specId);
83
+ }
84
+ return membership;
85
+ }
86
+ async function resolveSpecSourceRoot(input) {
87
+ const specPath = isAbsolute(input.canonicalSpecPath)
88
+ ? input.canonicalSpecPath
89
+ : resolve(input.canonical.projectPath, input.canonicalSpecPath);
90
+ let source;
91
+ try {
92
+ source = await resolveGitMembership(dirname(specPath), input.specId);
93
+ }
94
+ catch {
95
+ throw new ValidationWorktreeError('VALIDATION_SPEC_PATH_TRAVERSAL', input.specId);
96
+ }
97
+ if (source.gitCommonDir !== input.canonical.gitCommonDir) {
98
+ fail('VALIDATION_COMMON_DIR_MISMATCH', input.specId);
99
+ }
100
+ return { projectPath: source.projectPath, specPath };
101
+ }
102
+ async function portableSpecPath(projectPath, submittedSpecPath, specId) {
103
+ const candidate = isAbsolute(submittedSpecPath)
104
+ ? submittedSpecPath
105
+ : resolve(projectPath, submittedSpecPath);
106
+ let stats;
107
+ try {
108
+ stats = await lstat(candidate);
109
+ }
110
+ catch (error) {
111
+ if (!isEnoent(error)) {
112
+ reportClassifiedDegradation('VALIDATION_SPEC_STAT_FAILED', error);
113
+ }
114
+ }
115
+ if (stats === undefined) {
116
+ const normalizedMissingPath = await resolveFromExistingAncestor(candidate);
117
+ if (!contained(projectPath, normalizedMissingPath)) {
118
+ fail('VALIDATION_SPEC_PATH_TRAVERSAL', specId);
119
+ }
120
+ fail('VALIDATION_SPEC_NOT_FOUND', specId);
121
+ }
122
+ if (stats.isSymbolicLink()) {
123
+ fail('VALIDATION_SPEC_PATH_SYMLINK', specId);
124
+ }
125
+ let canonicalPath;
126
+ try {
127
+ canonicalPath = await realpath(candidate);
128
+ }
129
+ catch (error) {
130
+ reportClassifiedDegradation('VALIDATION_SPEC_REALPATH_FAILED', error);
131
+ }
132
+ if (canonicalPath === undefined || !contained(projectPath, canonicalPath)) {
133
+ fail('VALIDATION_SPEC_PATH_TRAVERSAL', specId);
134
+ }
135
+ const portablePath = relative(projectPath, canonicalPath).replaceAll('\\', '/');
136
+ const match = PORTABLE_SPEC.exec(portablePath);
137
+ if (!match?.[1] || (match[1] !== specId && !match[1].startsWith(`${specId}-`))) {
138
+ fail('VALIDATION_SPEC_PATH_TRAVERSAL', specId);
139
+ }
140
+ return portablePath;
141
+ }
142
+ function contained(root, candidate) {
143
+ const path = relative(root, candidate);
144
+ return path.length > 0 && path !== '..' && !path.startsWith(`..${sep}`) && !isAbsolute(path);
145
+ }
146
+ async function resolveFromExistingAncestor(candidate) {
147
+ const suffix = [];
148
+ let cursor = candidate;
149
+ for (;;) {
150
+ let resolvedAncestor;
151
+ try {
152
+ resolvedAncestor = await realpath(cursor);
153
+ }
154
+ catch (error) {
155
+ if (!isEnoent(error)) {
156
+ reportClassifiedDegradation('VALIDATION_ANCESTOR_REALPATH_FAILED', error);
157
+ }
158
+ }
159
+ if (resolvedAncestor !== undefined) {
160
+ return resolve(resolvedAncestor, ...suffix.reverse());
161
+ }
162
+ const parent = dirname(cursor);
163
+ if (parent === cursor) {
164
+ return candidate;
165
+ }
166
+ suffix.push(basename(cursor));
167
+ cursor = parent;
168
+ }
169
+ }
170
+ async function resolveSpec(projectPath, relativeSpecPath, specId) {
171
+ const candidate = resolve(projectPath, relativeSpecPath);
172
+ if (!contained(projectPath, candidate)) {
173
+ fail('VALIDATION_SPEC_PATH_TRAVERSAL', specId, relativeSpecPath);
174
+ }
175
+ let stats;
176
+ try {
177
+ stats = await lstat(candidate);
178
+ }
179
+ catch (error) {
180
+ if (!isEnoent(error)) {
181
+ reportClassifiedDegradation('VALIDATION_SPEC_STAT_FAILED', error);
182
+ }
183
+ }
184
+ if (stats === undefined) {
185
+ fail('VALIDATION_SPEC_NOT_FOUND', specId, relativeSpecPath);
186
+ }
187
+ if (stats.isSymbolicLink()) {
188
+ fail('VALIDATION_SPEC_PATH_SYMLINK', specId, relativeSpecPath);
189
+ }
190
+ if (!stats.isFile()) {
191
+ fail('VALIDATION_SPEC_NOT_FOUND', specId, relativeSpecPath);
192
+ }
193
+ let specPath;
194
+ try {
195
+ specPath = await realpath(candidate);
196
+ }
197
+ catch (error) {
198
+ reportClassifiedDegradation('VALIDATION_SPEC_REALPATH_FAILED', error);
199
+ }
200
+ if (specPath === undefined || !contained(projectPath, specPath)) {
201
+ fail('VALIDATION_SPEC_PATH_TRAVERSAL', specId, relativeSpecPath);
202
+ }
203
+ let content;
204
+ try {
205
+ content = await readFile(specPath, 'utf8');
206
+ }
207
+ catch (error) {
208
+ if (!isEnoent(error)) {
209
+ reportClassifiedDegradation('VALIDATION_SPEC_READ_FAILED', error);
210
+ }
211
+ }
212
+ const parsedId = content === undefined ? undefined : parseFrontmatter(content).metadata.id;
213
+ if (parsedId !== specId) {
214
+ fail('VALIDATION_SPEC_ID_MISMATCH', specId, relativeSpecPath);
215
+ }
216
+ return { specPath, relativeSpecPath };
217
+ }
218
+ function buildValidationRootId(projectPath, gitCommonDir) {
219
+ return createHash('sha256')
220
+ .update(`validation-root/v1\0${projectPath}\0${gitCommonDir}`)
221
+ .digest('hex');
222
+ }
223
+ export async function resolveValidationWorktree(input) {
224
+ const [requested, canonical] = await Promise.all([
225
+ resolveGitRoot(input.requestedProjectPath, input.specId),
226
+ resolveGitRoot(input.canonicalProjectPath, input.specId),
227
+ ]);
228
+ if (requested.gitCommonDir !== canonical.gitCommonDir) {
229
+ fail('VALIDATION_COMMON_DIR_MISMATCH', input.specId);
230
+ }
231
+ const source = await resolveSpecSourceRoot({
232
+ canonical,
233
+ canonicalSpecPath: input.canonicalSpecPath,
234
+ specId: input.specId,
235
+ });
236
+ const relativeSpecPath = await portableSpecPath(source.projectPath, source.specPath, input.specId);
237
+ const spec = await resolveSpec(requested.projectPath, relativeSpecPath, input.specId);
238
+ return {
239
+ ...requested,
240
+ ...spec,
241
+ validationRootId: buildValidationRootId(requested.projectPath, requested.gitCommonDir),
242
+ };
243
+ }
244
+ export async function revalidateValidationWorktree(input) {
245
+ if (!ROOT_ID.test(input.validationRootId)) {
246
+ fail('VALIDATION_ROOT_ID_MALFORMED', input.specId);
247
+ }
248
+ const root = await resolveGitRoot(input.projectPath, input.specId);
249
+ const relativeSpecPath = await portableSpecPath(root.projectPath, input.specPath, input.specId);
250
+ const spec = await resolveSpec(root.projectPath, relativeSpecPath, input.specId);
251
+ const observedRootId = buildValidationRootId(root.projectPath, root.gitCommonDir);
252
+ if (observedRootId !== input.validationRootId) {
253
+ fail('VALIDATION_ROOT_ID_MISMATCH', input.specId, spec.relativeSpecPath);
254
+ }
255
+ return { ...root, ...spec, validationRootId: observedRootId };
256
+ }
257
+ export function isValidationRootId(value) {
258
+ return typeof value === 'string' && ROOT_ID.test(value);
259
+ }
260
+ //# sourceMappingURL=validation-worktree.js.map
@@ -1,4 +1,16 @@
1
- import type { ValidationGateCapability, ValidationImpactPlan } from '../types/validation-evidence.js';
2
- export declare const VALIDATION_COMMANDS: Readonly<Record<ValidationGateCapability, string>>;
1
+ import type { ValidationImpactPlan } from '../types/validation-evidence.js';
2
+ export declare const VALIDATION_COMMANDS: {
3
+ readonly typecheck: 'pnpm typecheck';
4
+ readonly lint: 'pnpm lint';
5
+ readonly 'test-related': 'pnpm test --run --changed';
6
+ readonly 'test-full': 'pnpm test';
7
+ readonly contract: 'pnpm test:contracts';
8
+ readonly coverage: 'pnpm test:coverage';
9
+ readonly migration: 'pnpm test:migrations';
10
+ readonly 'fault-injection': 'pnpm test:fault-injection';
11
+ readonly security: 'pnpm check:deps:fresh';
12
+ readonly native: 'pnpm native:project-graph:e2e';
13
+ readonly website: 'pnpm --dir website build';
14
+ };
3
15
  export declare function planValidationImpact(paths: readonly string[]): ValidationImpactPlan;
4
16
  //# sourceMappingURL=validation-impact-planner.d.ts.map
@@ -10,7 +10,6 @@ export const VALIDATION_COMMANDS = {
10
10
  security: 'pnpm check:deps:fresh',
11
11
  native: 'pnpm native:project-graph:e2e',
12
12
  website: 'pnpm --dir website build',
13
- reproducibility: 'bash scripts/check-reproducibility.sh',
14
13
  };
15
14
  const LIFECYCLE_RE = /^(?:planu\/|docs\/|README(?:\.|$)|CHANGELOG\.md$|[^/]+\.md$)/;
16
15
  const SOURCE_RE = /^(?:src\/|tests\/)/;
@@ -44,7 +43,6 @@ export function planValidationImpact(paths) {
44
43
  else if (NATIVE_RE.test(path)) {
45
44
  kind = 'native';
46
45
  gates.add('native');
47
- gates.add('reproducibility');
48
46
  gates.add('test-full');
49
47
  }
50
48
  else if (DEPENDENCY_RE.test(path)) {
@@ -71,7 +69,6 @@ function fullPlan(reason, changedPaths) {
71
69
  'migration',
72
70
  'fault-injection',
73
71
  'native',
74
- 'reproducibility',
75
72
  ];
76
73
  if (changedPaths.some((path) => path.startsWith('website/'))) {
77
74
  gates.push('website');
@@ -1,4 +1,5 @@
1
1
  import type { Spec, ValidateResult, DefinitionOfReady, DefinitionOfDone, CodeState } from '../../types/index.js';
2
+ export declare function isBlockingQualitySeverity(severity: unknown): boolean;
2
3
  /**
3
4
  * Generate a Definition of Ready checklist for a spec.
4
5
  */
@@ -5,6 +5,9 @@ import { runAllGates } from './gates/index.js';
5
5
  /** Minimum test file count that auto-passes test gates (batch-implementation heuristic). */
6
6
  const BATCH_TEST_THRESHOLD = 5;
7
7
  import { parseProgressActuals } from '../actuals/progress-parser.js';
8
+ export function isBlockingQualitySeverity(severity) {
9
+ return severity !== 'info' && severity !== 'warning';
10
+ }
8
11
  function buildDoRSpecItems(spec) {
9
12
  // Adapt description to actual file name (modern: spec.md, legacy: HU.md)
10
13
  const specFileName = spec.specPath ? basename(spec.specPath) : 'spec.md';
@@ -320,9 +323,8 @@ function gateCategory(gate) {
320
323
  */
321
324
  export async function generateDoD(spec, validationResult, codeState, projectPath) {
322
325
  const score = validationResult?.score ?? 0;
323
- // Only errors and critical issues block DoD — warnings and info are non-blocking
324
- const blockingSeverities = ['error', 'critical'];
325
- const hasBlockingQualityIssues = validationResult?.qualityIssues.some((i) => blockingSeverities.includes(i.severity)) ?? false;
326
+ const hasBlockingQualityIssues = validationResult?.qualityIssues.some((issue) => isBlockingQualitySeverity(issue.severity)) ??
327
+ false;
326
328
  const hasTestFiles = await detectTestFiles(spec, codeState);
327
329
  const items = buildDoDItems(spec, score, hasBlockingQualityIssues, hasTestFiles);
328
330
  // Override actuals check with progress.md parsing
@@ -1,4 +1,5 @@
1
1
  import type { Spec, VerifyBlock } from '../../types/index.js';
2
+ export { extractListItems, extractSection } from '../spec-format/markdown-sections.js';
2
3
  /**
3
4
  * Extract all acceptance criteria from a spec's source files.
4
5
  */
@@ -13,9 +14,4 @@ export declare function extractVerifyBlocks(content: string): Map<string, Verify
13
14
  /**
14
15
  * Extract the text content under a markdown heading that matches any of the given keywords.
15
16
  */
16
- export declare function extractSection(content: string, ...headingKeywords: string[]): string | null;
17
- /**
18
- * Extract bullet/numbered list items from a markdown text block.
19
- */
20
- export declare function extractListItems(content: string): string[];
21
17
  //# sourceMappingURL=extractors.d.ts.map