@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
@@ -50,6 +50,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
50
50
  var e = new Error(message);
51
51
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
52
  });
53
+ /* eslint-disable max-lines, no-param-reassign -- watcher lifecycle remains co-located and owns one mutable state machine per epoch */
53
54
  import { createHash, randomUUID } from 'node:crypto';
54
55
  import { constants, watch } from 'node:fs';
55
56
  import { lstat, mkdir, open, readdir } from 'node:fs/promises';
@@ -59,32 +60,76 @@ import { resolveStorageLayout } from '../../storage/storage-layout.js';
59
60
  import { ValidationReceiptStore } from './validation-receipt.js';
60
61
  import { isValidationSourcePath } from './validation-source-policy.js';
61
62
  import { reportClassifiedDegradation } from '../../errors/classified-degradation.js';
62
- import { gitSourceTreeDigest } from './durable-validation.js';
63
- const LEASE_TTL_MS = 35 * 60 * 1_000;
63
+ import { gitSourceTreeDigest } from './validation-source-digest.js';
64
+ import { getRuntimePolicy } from '../runtime-policy.js';
64
65
  const MAX_EVIDENCE_FILE_BYTES = 2 * 1024 * 1024;
65
66
  const FINGERPRINT_CHUNK_BYTES = 64 * 1024;
66
67
  const EVIDENCE_FILE = /^(?:discovery|task-plan|traceability-matrix|contract-validation-(?:api|graphql|event|ui|mcp))\.json$/u;
67
68
  const active = new Map();
69
+ const beginQueues = new Map();
68
70
  function key(projectId, specId) {
69
71
  return `${projectId}:${specId}`;
70
72
  }
71
- function invalidateState(projectId, specId, state) {
72
- const invalidating = state.invalidating.then(async () => {
73
- const env_1 = { stack: [], error: void 0, hasError: false };
74
- try {
75
- const database = __addDisposableResource(env_1, new RuntimeDatabase({ path: resolveStorageLayout().runtimeDatabase }), false);
76
- const store = new ValidationReceiptStore({ database, workspaceId: 'global' });
77
- await store.invalidateCurrentBindings(projectId, specId);
78
- }
79
- catch (e_1) {
80
- env_1.error = e_1;
81
- env_1.hasError = true;
82
- }
83
- finally {
84
- __disposeResources(env_1);
73
+ async function invalidateDurably(projectId, specId) {
74
+ const env_1 = { stack: [], error: void 0, hasError: false };
75
+ try {
76
+ const database = __addDisposableResource(env_1, new RuntimeDatabase({
77
+ path: resolveStorageLayout().runtimeDatabase,
78
+ checkIntegrity: false,
79
+ }), false);
80
+ const store = new ValidationReceiptStore({ database, workspaceId: 'global' });
81
+ await store.invalidateCurrentBindings(projectId, specId);
82
+ }
83
+ catch (e_1) {
84
+ env_1.error = e_1;
85
+ env_1.hasError = true;
86
+ }
87
+ finally {
88
+ __disposeResources(env_1);
89
+ }
90
+ }
91
+ async function invalidateDurablyWithCanonicalIntegrity(projectId, specId) {
92
+ const env_2 = { stack: [], error: void 0, hasError: false };
93
+ try {
94
+ const database = __addDisposableResource(env_2, new RuntimeDatabase({ path: resolveStorageLayout().runtimeDatabase }), false);
95
+ const store = new ValidationReceiptStore({ database, workspaceId: 'global' });
96
+ await store.invalidateCurrentBindings(projectId, specId);
97
+ }
98
+ catch (e_2) {
99
+ env_2.error = e_2;
100
+ env_2.hasError = true;
101
+ }
102
+ finally {
103
+ __disposeResources(env_2);
104
+ }
105
+ }
106
+ function runInvalidationTurn(projectId, specId, state) {
107
+ if (state.running) {
108
+ return;
109
+ }
110
+ state.running = true;
111
+ state.dirty = false;
112
+ const turn = state.invalidating.then(async () => {
113
+ await invalidateDurably(projectId, specId);
114
+ });
115
+ state.invalidating = turn
116
+ .catch((error) => {
117
+ state.healthy = false;
118
+ reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
119
+ })
120
+ .finally(() => {
121
+ state.running = false;
122
+ if (state.dirty && state.accepting && !state.coalesceTimer) {
123
+ const delay = getRuntimePolicy().validation.freshnessInvalidationCoalesceMs;
124
+ state.coalesceTimer = setTimeout(() => {
125
+ state.coalesceTimer = undefined;
126
+ if (state.accepting && active.get(key(projectId, specId)) === state) {
127
+ runInvalidationTurn(projectId, specId, state);
128
+ }
129
+ }, delay);
130
+ state.coalesceTimer.unref();
85
131
  }
86
132
  });
87
- return { ...state, generation: state.generation + 1, bindings: undefined, invalidating };
88
133
  }
89
134
  /**
90
135
  * Invalidate the active validation lease for a spec.
@@ -95,10 +140,13 @@ function invalidateState(projectId, specId, state) {
95
140
  export function invalidateValidationFreshness(input) {
96
141
  const identity = key(input.projectId, input.specId);
97
142
  const state = active.get(identity);
98
- if (!state) {
143
+ if (!state?.accepting) {
99
144
  return false;
100
145
  }
101
- active.set(identity, invalidateState(input.projectId, input.specId, state));
146
+ state.generation += 1;
147
+ state.bindings = undefined;
148
+ state.dirty = true;
149
+ runInvalidationTurn(input.projectId, input.specId, state);
102
150
  return true;
103
151
  }
104
152
  function startWatch(path, relevant, onRelevantChange, onError) {
@@ -115,6 +163,7 @@ function startWatch(path, relevant, onRelevantChange, onError) {
115
163
  }
116
164
  });
117
165
  watcher.on('error', onError);
166
+ watcher.unref();
118
167
  return watcher;
119
168
  }
120
169
  catch (error) {
@@ -187,70 +236,145 @@ async function evidenceFingerprint(path) {
187
236
  return hash.digest('hex');
188
237
  }
189
238
  /** Start both watchers before snapshotting and invalidate any older receipt immediately. */
239
+ // eslint-disable-next-line max-lines-per-function -- serialized setup and rollback form one auditable ownership boundary
190
240
  export async function beginValidationFreshnessBarrier(input) {
191
241
  const identity = key(input.projectId, input.specId);
192
- await mkdir(input.handoffPath, { recursive: true, mode: 0o700 });
193
- const initialEvidenceFingerprint = await evidenceFingerprint(input.handoffPath);
194
- active.get(identity)?.watchers.forEach((watcher) => {
195
- watcher.close();
242
+ const predecessor = beginQueues.get(identity) ?? Promise.resolve();
243
+ let release;
244
+ const queued = new Promise((resolve) => {
245
+ release = resolve;
196
246
  });
197
- let state = {
198
- epoch: randomUUID(),
199
- expiresAt: Date.now() + LEASE_TTL_MS,
200
- generation: 0,
201
- healthy: true,
202
- projectPath: input.projectPath,
203
- handoffPath: input.handoffPath,
204
- evidenceFingerprint: initialEvidenceFingerprint,
205
- invalidating: Promise.resolve(),
206
- watchers: [],
207
- };
208
- const watchedEpoch = state.epoch;
209
- const changed = () => {
210
- if (active.get(identity)?.epoch !== watchedEpoch) {
211
- return;
247
+ const tail = predecessor.then(() => queued);
248
+ beginQueues.set(identity, tail);
249
+ await predecessor;
250
+ try {
251
+ const previous = active.get(identity);
252
+ if (previous) {
253
+ await closeValidationFreshnessLease({
254
+ projectId: input.projectId,
255
+ specId: input.specId,
256
+ epoch: previous.epoch,
257
+ });
212
258
  }
213
- invalidateValidationFreshness(input);
214
- state = active.get(identity) ?? state;
215
- };
216
- const failed = () => {
217
- if (active.get(identity)?.epoch !== watchedEpoch) {
218
- return;
259
+ await mkdir(input.handoffPath, { recursive: true, mode: 0o700 });
260
+ const initialEvidenceFingerprint = await evidenceFingerprint(input.handoffPath);
261
+ const policy = getRuntimePolicy().validation;
262
+ const state = {
263
+ epoch: randomUUID(),
264
+ expiresAt: Date.now() + policy.freshnessLeaseTtlMs,
265
+ generation: 0,
266
+ healthy: true,
267
+ accepting: true,
268
+ projectPath: input.projectPath,
269
+ handoffPath: input.handoffPath,
270
+ evidenceFingerprint: initialEvidenceFingerprint,
271
+ invalidating: Promise.resolve(),
272
+ watchers: [],
273
+ dirty: false,
274
+ running: false,
275
+ };
276
+ const watchedEpoch = state.epoch;
277
+ const changed = () => {
278
+ if (active.get(identity)?.epoch === watchedEpoch && state.accepting) {
279
+ invalidateValidationFreshness(input);
280
+ }
281
+ };
282
+ const failed = () => {
283
+ if (active.get(identity)?.epoch === watchedEpoch && state.accepting) {
284
+ state.healthy = false;
285
+ changed();
286
+ }
287
+ };
288
+ const projectWatcher = startWatch(input.projectPath, isValidationSourcePath, changed, failed);
289
+ const handoffWatcher = startWatch(input.handoffPath, (filename) => EVIDENCE_FILE.test(filename), changed, failed);
290
+ if (!projectWatcher || !handoffWatcher) {
291
+ projectWatcher?.close();
292
+ handoffWatcher?.close();
293
+ throw new Error('[Planu] Validation freshness watchers could not be established');
219
294
  }
220
- changed();
221
- state = { ...state, healthy: false };
295
+ state.watchers.push(projectWatcher, handoffWatcher);
222
296
  active.set(identity, state);
223
- };
224
- const projectWatcher = startWatch(input.projectPath, isValidationSourcePath, changed, failed);
225
- const handoffWatcher = startWatch(input.handoffPath, (filename) => EVIDENCE_FILE.test(filename), changed, failed);
226
- if (!projectWatcher || !handoffWatcher) {
227
- projectWatcher?.close();
228
- handoffWatcher?.close();
229
- throw new Error('[Planu] Validation freshness watchers could not be established');
230
- }
231
- state = { ...state, watchers: [projectWatcher, handoffWatcher] };
232
- active.set(identity, state);
233
- if (input.invalidateCurrentBindings !== false) {
234
- const env_2 = { stack: [], error: void 0, hasError: false };
235
- try {
236
- const database = __addDisposableResource(env_2, new RuntimeDatabase({ path: resolveStorageLayout().runtimeDatabase }), false);
237
- const store = new ValidationReceiptStore({ database, workspaceId: 'global' });
238
- await store.invalidateCurrentBindings(input.projectId, input.specId);
297
+ state.ttlTimer = setTimeout(() => {
298
+ if (!state.accepting || active.get(identity) !== state) {
299
+ return;
300
+ }
301
+ void closeValidationFreshnessLease({
302
+ projectId: input.projectId,
303
+ specId: input.specId,
304
+ epoch: state.epoch,
305
+ }).catch((error) => {
306
+ reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
307
+ });
308
+ }, policy.freshnessLeaseTtlMs);
309
+ state.ttlTimer.unref();
310
+ if (input.invalidateCurrentBindings !== false) {
311
+ try {
312
+ await invalidateDurablyWithCanonicalIntegrity(input.projectId, input.specId);
313
+ }
314
+ catch (error) {
315
+ await closeValidationFreshnessLease({
316
+ projectId: input.projectId,
317
+ specId: input.specId,
318
+ epoch: state.epoch,
319
+ });
320
+ throw error;
321
+ }
322
+ }
323
+ return {
324
+ projectId: input.projectId,
325
+ specId: input.specId,
326
+ epoch: state.epoch,
327
+ generation: state.generation,
328
+ };
329
+ }
330
+ catch (error) {
331
+ reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
332
+ throw error;
333
+ }
334
+ finally {
335
+ release();
336
+ if (beginQueues.get(identity) === tail) {
337
+ beginQueues.delete(identity);
338
+ }
339
+ }
340
+ }
341
+ /** Stop one exact epoch and drain all invalidations accepted before closure. */
342
+ export async function closeValidationFreshnessLease(lease) {
343
+ const identity = key(lease.projectId, lease.specId);
344
+ const state = active.get(identity);
345
+ if (state?.epoch !== lease.epoch) {
346
+ return;
347
+ }
348
+ state.closing ??= (async () => {
349
+ state.accepting = false;
350
+ state.watchers.splice(0).forEach((watcher) => {
351
+ watcher.close();
352
+ });
353
+ if (state.ttlTimer) {
354
+ clearTimeout(state.ttlTimer);
239
355
  }
240
- catch (e_2) {
241
- env_2.error = e_2;
242
- env_2.hasError = true;
356
+ state.ttlTimer = undefined;
357
+ if (state.coalesceTimer) {
358
+ clearTimeout(state.coalesceTimer);
359
+ }
360
+ state.coalesceTimer = undefined;
361
+ try {
362
+ if (state.dirty && !state.running) {
363
+ runInvalidationTurn(lease.projectId, lease.specId, state);
364
+ }
365
+ await state.invalidating;
366
+ if (state.dirty) {
367
+ state.dirty = false;
368
+ await invalidateDurably(lease.projectId, lease.specId);
369
+ }
243
370
  }
244
371
  finally {
245
- __disposeResources(env_2);
372
+ if (active.get(identity)?.epoch === lease.epoch) {
373
+ active.delete(identity);
374
+ }
246
375
  }
247
- }
248
- return {
249
- projectId: input.projectId,
250
- specId: input.specId,
251
- epoch: state.epoch,
252
- generation: state.generation,
253
- };
376
+ })();
377
+ await state.closing;
254
378
  }
255
379
  /** Bind the post-watch snapshot; an event before this call makes the lease unusable. */
256
380
  export async function bindValidationFreshnessLease(lease, bindings) {
@@ -285,10 +409,7 @@ export async function bindValidationFreshnessLease(lease, bindings) {
285
409
  confirmed.generation !== state.generation) {
286
410
  return false;
287
411
  }
288
- active.set(key(lease.projectId, lease.specId), {
289
- ...confirmed,
290
- bindings: structuredClone(bindings),
291
- });
412
+ confirmed.bindings = structuredClone(bindings);
292
413
  return true;
293
414
  }
294
415
  async function readStableState(lease, expectedGeneration) {
@@ -300,12 +421,15 @@ async function readStableState(lease, expectedGeneration) {
300
421
  (expectedGeneration !== undefined && before.generation !== expectedGeneration)) {
301
422
  return undefined;
302
423
  }
303
- await before.invalidating;
424
+ const generationBefore = before.generation;
425
+ const invalidatingBefore = before.invalidating;
426
+ await invalidatingBefore;
304
427
  const after = active.get(identity);
305
428
  if (after?.healthy &&
306
429
  after.epoch === before.epoch &&
307
- after.generation === before.generation &&
308
- after.invalidating === before.invalidating) {
430
+ after.generation === generationBefore &&
431
+ (expectedGeneration === undefined || after.generation === expectedGeneration) &&
432
+ after.invalidating === invalidatingBefore) {
309
433
  return after;
310
434
  }
311
435
  }
@@ -383,6 +507,7 @@ export async function rebaselineValidationFreshnessLeaseAfterRecompute(input) {
383
507
  if (!before || Date.now() >= before.expiresAt) {
384
508
  return undefined;
385
509
  }
510
+ const generationBefore = before.generation;
386
511
  let fingerprintBefore;
387
512
  let observedBindings;
388
513
  let fingerprintAfter;
@@ -397,7 +522,7 @@ export async function rebaselineValidationFreshnessLeaseAfterRecompute(input) {
397
522
  return undefined;
398
523
  }
399
524
  const after = await readStableState(input.lease);
400
- if (after?.generation !== before.generation || fingerprintBefore !== fingerprintAfter) {
525
+ if (after?.generation !== generationBefore || fingerprintBefore !== fingerprintAfter) {
401
526
  continue;
402
527
  }
403
528
  if (JSON.stringify(input.expectedBindings) !== JSON.stringify(observedBindings)) {
@@ -407,21 +532,36 @@ export async function rebaselineValidationFreshnessLeaseAfterRecompute(input) {
407
532
  if (confirmed?.generation !== after.generation) {
408
533
  continue;
409
534
  }
410
- active.set(key(input.lease.projectId, input.lease.specId), {
411
- ...confirmed,
412
- bindings: structuredClone(observedBindings),
413
- evidenceFingerprint: fingerprintAfter,
414
- });
535
+ confirmed.bindings = structuredClone(observedBindings);
536
+ confirmed.evidenceFingerprint = fingerprintAfter;
415
537
  return { ...input.lease, generation: confirmed.generation };
416
538
  }
417
539
  return undefined;
418
540
  }
419
- export function resetValidationFreshnessForTests() {
541
+ export async function resetValidationFreshnessForTests() {
542
+ const leases = [...active.entries()].map(([identity, state]) => {
543
+ const separator = identity.indexOf(':');
544
+ return {
545
+ projectId: identity.slice(0, separator),
546
+ specId: identity.slice(separator + 1),
547
+ epoch: state.epoch,
548
+ };
549
+ });
550
+ await Promise.all(leases.map((lease) => closeValidationFreshnessLease(lease)));
551
+ beginQueues.clear();
552
+ }
553
+ /** Count-only process diagnostic; intentionally absent from the package entrypoint. */
554
+ export function getValidationFreshnessDiagnosticsForTests() {
555
+ let watchers = 0;
556
+ let queuedInvalidations = 0;
557
+ let timers = 0;
558
+ let generationTotal = 0;
420
559
  for (const state of active.values()) {
421
- state.watchers.forEach((watcher) => {
422
- watcher.close();
423
- });
560
+ watchers += state.watchers.length;
561
+ queuedInvalidations += Number(state.running) + Number(state.dirty);
562
+ timers += Number(Boolean(state.ttlTimer)) + Number(Boolean(state.coalesceTimer));
563
+ generationTotal += state.generation;
424
564
  }
425
- active.clear();
565
+ return { activeLeases: active.size, watchers, queuedInvalidations, timers, generationTotal };
426
566
  }
427
567
  //# sourceMappingURL=validation-freshness.js.map
@@ -3,10 +3,6 @@ import type { RuntimeDatabase } from '../../storage/runtime-db.js';
3
3
  import { type StorageCatalogContext } from '../../storage/storage-catalog.js';
4
4
  export { normalizeValidationCommand } from './validation-receipt-codec.js';
5
5
  export declare const LOCAL_VALIDATION_RECEIPT_ISSUER = "planu-local-validator";
6
- export declare class ValidationIssuerKeyError extends Error {
7
- readonly code: 'VALIDATION_ISSUER_KEY_NOT_CONFIGURED';
8
- constructor();
9
- }
10
6
  export declare class ValidationReceiptStore implements ValidationReceiptPersistence {
11
7
  private readonly options;
12
8
  private readonly logDirectory;
@@ -14,6 +10,7 @@ export declare class ValidationReceiptStore implements ValidationReceiptPersiste
14
10
  readonly database: RuntimeDatabase;
15
11
  readonly workspaceId: string;
16
12
  readonly catalogContext?: StorageCatalogContext;
13
+ readonly authorizePersistence?: (database: RuntimeDatabase) => void;
17
14
  });
18
15
  logPath(logDigest: string): string;
19
16
  persist(receipt: ValidationReceipt, log: Buffer): Promise<void>;
@@ -21,7 +18,7 @@ export declare class ValidationReceiptStore implements ValidationReceiptPersiste
21
18
  readCurrent(projectId: string, specId: string): Promise<ValidationReceipt | undefined>;
22
19
  readCurrentBindings(projectId: string, specId: string): Promise<ValidationReceiptBindings | undefined>;
23
20
  projectCurrentBindings(bindings: ValidationReceiptBindings): Promise<void>;
24
- invalidateCurrentBindings(projectId: string, specId: string): Promise<void>;
21
+ invalidateCurrentBindings(projectId: string, specId: string, receiptId?: string): Promise<void>;
25
22
  readLog(logDigest: string): Promise<Buffer | undefined>;
26
23
  private writeLog;
27
24
  }
@@ -46,6 +43,7 @@ export declare function createValidationReceiptAuthority(options: {
46
43
  readonly projectId: string;
47
44
  readonly issuerId: string;
48
45
  readonly catalogContext?: StorageCatalogContext;
46
+ readonly authorizePersistence?: (database: RuntimeDatabase) => void;
49
47
  }): {
50
48
  readonly authority: ValidationReceiptAuthority;
51
49
  readonly store: ValidationReceiptStore;
@@ -55,5 +53,10 @@ export declare function createValidationReceiptAuthority(options: {
55
53
  export declare function ensureValidationIssuerKey(identity: {
56
54
  readonly projectId: string;
57
55
  readonly issuerId: string;
58
- }): Promise<string>;
56
+ }, platform?: NodeJS.Platform): Promise<string>;
57
+ /** Prove that this process can resolve or provision its canonical receipt-signing key. */
58
+ export declare function preflightValidationReceiptSigner(identity: {
59
+ readonly projectId: string;
60
+ readonly issuerId: string;
61
+ }, platform?: NodeJS.Platform): Promise<string>;
59
62
  //# sourceMappingURL=validation-receipt.d.ts.map
@@ -6,16 +6,11 @@ import { reportClassifiedDegradation } from '../../errors/classified-degradation
6
6
  import { resolvedStorageArtifactPath, } from '../../storage/storage-catalog.js';
7
7
  import { formatSecretReference, getSecretProvider, parseSecretReference, SecretProviderError, } from '../../security/secret-provider.js';
8
8
  import { redactText } from '../../security/redactor.js';
9
+ import { ValidationReceiptSignerUnavailableError } from '../macos-keychain-native-port.js';
10
+ import { acquireLock, releaseLock } from '../safety/file-mutex.js';
9
11
  import { canonicalize, DIGEST, ISSUER_ID, PROJECT_ID, receiptCore, safeProof, sha256, SPEC_ID, validBindings, validReceiptShape, } from './validation-receipt-codec.js';
10
12
  export { normalizeValidationCommand } from './validation-receipt-codec.js';
11
13
  export const LOCAL_VALIDATION_RECEIPT_ISSUER = 'planu-local-validator';
12
- export class ValidationIssuerKeyError extends Error {
13
- code = 'VALIDATION_ISSUER_KEY_NOT_CONFIGURED';
14
- constructor() {
15
- super('[Planu] Validation issuer key is not configured in the explicit environment adapter');
16
- this.name = 'ValidationIssuerKeyError';
17
- }
18
- }
19
14
  export class ValidationReceiptStore {
20
15
  options;
21
16
  logDirectory;
@@ -35,6 +30,7 @@ export class ValidationReceiptStore {
35
30
  }
36
31
  await this.writeLog(receipt.logDigest, log);
37
32
  this.options.database.transaction(() => {
33
+ this.options.authorizePersistence?.(this.options.database);
38
34
  this.options.database.putRecord({
39
35
  projectId: receipt.bindings.projectId,
40
36
  workspaceId: this.options.workspaceId,
@@ -96,16 +92,26 @@ export class ValidationReceiptStore {
96
92
  });
97
93
  return Promise.resolve();
98
94
  }
99
- invalidateCurrentBindings(projectId, specId) {
100
- if (!PROJECT_ID.test(projectId) || !SPEC_ID.test(specId)) {
95
+ invalidateCurrentBindings(projectId, specId, receiptId) {
96
+ if (!PROJECT_ID.test(projectId) ||
97
+ !SPEC_ID.test(specId) ||
98
+ (receiptId !== undefined && !DIGEST.test(receiptId))) {
101
99
  throw new Error('[Planu] Validation binding identity is invalid');
102
100
  }
103
- this.options.database.putRecord({
104
- projectId,
105
- workspaceId: this.options.workspaceId,
106
- kind: 'audit-state',
107
- key: `validation-bindings-current:${specId}`,
108
- value: { invalidatedAt: new Date().toISOString() },
101
+ this.options.database.transaction(() => {
102
+ if (receiptId !== undefined) {
103
+ const current = this.options.database.getRecord(projectId, this.options.workspaceId, 'audit-state', `validation-current:${specId}`);
104
+ if (!validReceiptShape(current?.value) || current.value.receiptId !== receiptId) {
105
+ return;
106
+ }
107
+ }
108
+ this.options.database.putRecord({
109
+ projectId,
110
+ workspaceId: this.options.workspaceId,
111
+ kind: 'audit-state',
112
+ key: `validation-bindings-current:${specId}`,
113
+ value: { invalidatedAt: new Date().toISOString() },
114
+ });
109
115
  });
110
116
  return Promise.resolve();
111
117
  }
@@ -261,22 +267,76 @@ export function createValidationReceiptAuthority(options) {
261
267
  };
262
268
  }
263
269
  /** Provision or resolve a machine-local issuer key without exposing raw key material. */
264
- export async function ensureValidationIssuerKey(identity) {
265
- const provider = getSecretProvider();
270
+ export async function ensureValidationIssuerKey(identity, platform = process.platform) {
271
+ const canonicalProvider = platform === 'darwin'
272
+ ? 'macos-keychain'
273
+ : platform === 'linux'
274
+ ? 'linux-secret-service'
275
+ : platform === 'win32'
276
+ ? 'windows-credential-manager'
277
+ : undefined;
278
+ if (canonicalProvider === undefined) {
279
+ throw new ValidationReceiptSignerUnavailableError('PLATFORM_UNSUPPORTED');
280
+ }
281
+ let provider;
282
+ try {
283
+ provider = getSecretProvider();
284
+ }
285
+ catch {
286
+ throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
287
+ }
288
+ if (provider.adapter.kind !== canonicalProvider) {
289
+ throw new ValidationReceiptSignerUnavailableError('PROVIDER_NONCANONICAL');
290
+ }
266
291
  const reference = parseSecretReference(validationIssuerReference(identity));
292
+ let lock;
267
293
  try {
268
- await provider.resolve(reference);
269
- return formatSecretReference(reference);
294
+ lock = await acquireLock(`validation-issuer:${identity.projectId}:${identity.issuerId}`);
295
+ }
296
+ catch {
297
+ throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
298
+ }
299
+ let result;
300
+ try {
301
+ try {
302
+ await provider.resolve(reference);
303
+ result = formatSecretReference(reference);
304
+ }
305
+ catch (error) {
306
+ if (!(error instanceof SecretProviderError) || error.code !== 'SECRET_NOT_FOUND') {
307
+ throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
308
+ }
309
+ try {
310
+ await provider.store(reference, randomBytes(32).toString('base64url'));
311
+ result = formatSecretReference(reference);
312
+ }
313
+ catch {
314
+ throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
315
+ }
316
+ }
270
317
  }
271
318
  catch (error) {
272
- if (!(error instanceof SecretProviderError) || error.code !== 'SECRET_NOT_FOUND') {
319
+ try {
320
+ await releaseLock(lock);
321
+ }
322
+ catch {
323
+ reportClassifiedDegradation('VALIDATION_ISSUER_LOCK_RELEASE_FAILURE', new Error('Validation issuer lock release failed'));
324
+ }
325
+ if (error instanceof ValidationReceiptSignerUnavailableError) {
273
326
  throw error;
274
327
  }
328
+ throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
275
329
  }
276
- if (provider.adapter.kind === 'environment') {
277
- throw new ValidationIssuerKeyError();
330
+ try {
331
+ await releaseLock(lock);
332
+ }
333
+ catch {
334
+ throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
278
335
  }
279
- await provider.store(reference, randomBytes(32).toString('base64url'));
280
- return formatSecretReference(reference);
336
+ return result;
337
+ }
338
+ /** Prove that this process can resolve or provision its canonical receipt-signing key. */
339
+ export function preflightValidationReceiptSigner(identity, platform = process.platform) {
340
+ return ensureValidationIssuerKey(identity, platform);
281
341
  }
282
342
  //# sourceMappingURL=validation-receipt.js.map
@@ -0,0 +1,2 @@
1
+ export declare function gitSourceTreeDigest(projectPath: string): Promise<string>;
2
+ //# sourceMappingURL=validation-source-digest.d.ts.map