@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
@@ -0,0 +1,400 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { isAbsolute, resolve as resolvePath } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { isMainThread, parentPort, Worker, workerData } from 'node:worker_threads';
5
+ import { RuntimeDatabase } from '../../storage/runtime-db.js';
6
+ import { reportClassifiedDegradation } from '../../errors/classified-degradation.js';
7
+ function heartbeatWorkerUrl() {
8
+ const sibling = new URL('./durable-job-heartbeat-runtime.js', import.meta.url);
9
+ if (existsSync(sibling)) {
10
+ return sibling;
11
+ }
12
+ const built = resolvePath(process.cwd(), 'dist/engine/execution/durable-job-heartbeat-runtime.js');
13
+ if (existsSync(built)) {
14
+ return pathToFileURL(built);
15
+ }
16
+ throw new Error('[Planu] Durable heartbeat worker artifact is missing; run the production build');
17
+ }
18
+ function positiveSafeInteger(value) {
19
+ return Number.isSafeInteger(value) && Number(value) > 0;
20
+ }
21
+ function heartbeatIdentifier(value) {
22
+ return typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u.test(value);
23
+ }
24
+ function heartbeatTimingIsValid(candidate) {
25
+ return (positiveSafeInteger(candidate.fencingToken) &&
26
+ positiveSafeInteger(candidate.leaseMs) &&
27
+ positiveSafeInteger(candidate.heartbeatMs) &&
28
+ Number(candidate.heartbeatMs) < Number(candidate.leaseMs) &&
29
+ positiveSafeInteger(candidate.databaseBusyTimeoutMs) &&
30
+ Number(candidate.databaseBusyTimeoutMs) <
31
+ Number(candidate.leaseMs) - Number(candidate.heartbeatMs));
32
+ }
33
+ function workerDataIsValid(value) {
34
+ if (!value || typeof value !== 'object') {
35
+ return false;
36
+ }
37
+ const candidate = value;
38
+ return (candidate.kind === 'planu-durable-job-heartbeat' &&
39
+ candidate.schemaVersion === 1 &&
40
+ typeof candidate.databasePath === 'string' &&
41
+ isAbsolute(candidate.databasePath) &&
42
+ candidate.databasePath !== ':memory:' &&
43
+ typeof candidate.projectId === 'string' &&
44
+ /^[a-f0-9]{32}$/u.test(candidate.projectId) &&
45
+ heartbeatIdentifier(candidate.workspaceId) &&
46
+ heartbeatIdentifier(candidate.operationId) &&
47
+ heartbeatIdentifier(candidate.workerId) &&
48
+ heartbeatTimingIsValid(candidate));
49
+ }
50
+ function sameIdentity(message, input) {
51
+ return (message.schemaVersion === 1 &&
52
+ message.projectId === input.projectId &&
53
+ message.workspaceId === input.workspaceId &&
54
+ message.operationId === input.operationId &&
55
+ message.workerId === input.workerId &&
56
+ message.fencingToken === input.fencingToken);
57
+ }
58
+ function asError(error, fallback) {
59
+ return error instanceof Error ? error : new Error(fallback);
60
+ }
61
+ async function terminateWithinBudget(worker, timeoutMs) {
62
+ worker.unref();
63
+ let timeout;
64
+ const expired = new Promise((resolveTimeout) => {
65
+ timeout = setTimeout(() => {
66
+ resolveTimeout('timeout');
67
+ }, timeoutMs);
68
+ timeout.unref();
69
+ });
70
+ const termination = worker.terminate().then(() => 'terminated', (error) => {
71
+ throw asError(error, '[Planu] Durable heartbeat Worker termination failed');
72
+ });
73
+ try {
74
+ if ((await Promise.race([termination, expired])) === 'timeout') {
75
+ throw new Error('[Planu] Durable heartbeat Worker termination timed out');
76
+ }
77
+ }
78
+ finally {
79
+ if (timeout) {
80
+ clearTimeout(timeout);
81
+ }
82
+ }
83
+ }
84
+ function heartbeatAuthorityReason(value) {
85
+ return (value === 'cancelled-or-stale' || value === 'database-failure' || value === 'worker-failure');
86
+ }
87
+ /** Start one autonomous, fenced heartbeat and wait for its typed ready acknowledgement. */
88
+ // eslint-disable-next-line max-lines-per-function -- all controller settlement guards surround one Worker
89
+ export async function createDurableJobHeartbeat(input, options = {}) {
90
+ const data = {
91
+ kind: 'planu-durable-job-heartbeat',
92
+ schemaVersion: 1,
93
+ databasePath: input.databasePath,
94
+ projectId: input.projectId,
95
+ workspaceId: input.workspaceId,
96
+ operationId: input.operationId,
97
+ workerId: input.workerId,
98
+ fencingToken: input.fencingToken,
99
+ leaseMs: input.leaseMs,
100
+ heartbeatMs: input.heartbeatMs,
101
+ databaseBusyTimeoutMs: input.databaseBusyTimeoutMs,
102
+ };
103
+ if (!workerDataIsValid(data)) {
104
+ throw new Error('[Planu] Durable heartbeat configuration is invalid');
105
+ }
106
+ if (!Number.isSafeInteger(input.startupTimeoutMs) ||
107
+ input.startupTimeoutMs <= 0 ||
108
+ !Number.isSafeInteger(input.shutdownTimeoutMs) ||
109
+ input.shutdownTimeoutMs <= 0) {
110
+ throw new Error('[Planu] Durable heartbeat lifecycle budgets are invalid');
111
+ }
112
+ const worker = options.workerFactory
113
+ ? options.workerFactory(new URL('./durable-job-heartbeat-runtime.js', import.meta.url), data)
114
+ : new Worker(heartbeatWorkerUrl(), {
115
+ workerData: data,
116
+ execArgv: process.execArgv.filter((argument) => !argument.startsWith('--input-type')),
117
+ });
118
+ let ready = false;
119
+ let stopping = false;
120
+ let lost = false;
121
+ let exited = false;
122
+ let startFailed = false;
123
+ let lastSequence = 0;
124
+ let stopPromise;
125
+ let resolveReady;
126
+ let rejectReady;
127
+ let resolveStopped;
128
+ let resolveExited;
129
+ const readyPromise = new Promise((resolveReadyPromise, rejectReadyPromise) => {
130
+ resolveReady = resolveReadyPromise;
131
+ rejectReady = rejectReadyPromise;
132
+ });
133
+ const stoppedPromise = new Promise((settleStopped) => {
134
+ resolveStopped = settleStopped;
135
+ });
136
+ const exitedPromise = new Promise((settleExited) => {
137
+ resolveExited = settleExited;
138
+ });
139
+ const authorityLost = (error) => {
140
+ if (lost || stopping) {
141
+ return;
142
+ }
143
+ lost = true;
144
+ try {
145
+ input.onAuthorityLost(error);
146
+ }
147
+ catch (callbackError) {
148
+ reportClassifiedDegradation('VALIDATE_JOB_HEARTBEAT_FAILURE', callbackError);
149
+ }
150
+ };
151
+ const settleLocally = () => {
152
+ worker.removeAllListeners();
153
+ };
154
+ const failStart = (error) => {
155
+ if (ready) {
156
+ authorityLost(error);
157
+ return;
158
+ }
159
+ if (startFailed) {
160
+ return;
161
+ }
162
+ startFailed = true;
163
+ authorityLost(error);
164
+ clearTimeout(startupTimer);
165
+ void (async () => {
166
+ try {
167
+ if (!exited) {
168
+ await terminateWithinBudget(worker, input.shutdownTimeoutMs);
169
+ }
170
+ }
171
+ catch (cleanupError) {
172
+ reportClassifiedDegradation('VALIDATE_JOB_HEARTBEAT_FAILURE', cleanupError);
173
+ }
174
+ finally {
175
+ settleLocally();
176
+ rejectReady(error);
177
+ }
178
+ })();
179
+ };
180
+ const startupTimer = setTimeout(() => {
181
+ const error = new Error('[Planu] Durable heartbeat Worker startup timed out');
182
+ failStart(error);
183
+ }, input.startupTimeoutMs);
184
+ startupTimer.unref();
185
+ worker.on('message', (value) => {
186
+ const message = value;
187
+ if (!sameIdentity(message, input)) {
188
+ failStart(new Error('[Planu] Durable heartbeat message identity mismatch'));
189
+ return;
190
+ }
191
+ if (message.type === 'ready') {
192
+ if (!ready) {
193
+ ready = true;
194
+ clearTimeout(startupTimer);
195
+ resolveReady();
196
+ }
197
+ return;
198
+ }
199
+ if (message.type === 'renewed' && ready && Number.isSafeInteger(message.sequence)) {
200
+ const sequence = Number(message.sequence);
201
+ if (sequence <= 0) {
202
+ authorityLost(new Error('[Planu] Durable heartbeat sequence is invalid'));
203
+ return;
204
+ }
205
+ if (sequence <= lastSequence) {
206
+ return;
207
+ }
208
+ if (sequence !== lastSequence + 1) {
209
+ authorityLost(new Error('[Planu] Durable heartbeat sequence gap'));
210
+ return;
211
+ }
212
+ lastSequence = sequence;
213
+ return;
214
+ }
215
+ if (message.type === 'authorityLost' &&
216
+ Number.isSafeInteger(message.sequence) &&
217
+ heartbeatAuthorityReason(message.reason) &&
218
+ Number(message.sequence) === lastSequence + 1) {
219
+ const error = new Error(`[Planu] Durable heartbeat authority lost (${message.reason})`);
220
+ lastSequence = Number(message.sequence);
221
+ if (ready) {
222
+ authorityLost(error);
223
+ }
224
+ else {
225
+ failStart(error);
226
+ }
227
+ return;
228
+ }
229
+ if (message.type === 'stopped' && stopping) {
230
+ resolveStopped();
231
+ return;
232
+ }
233
+ const error = new Error('[Planu] Durable heartbeat protocol violation');
234
+ if (ready) {
235
+ authorityLost(error);
236
+ }
237
+ else {
238
+ failStart(error);
239
+ }
240
+ });
241
+ worker.once('error', (error) => {
242
+ failStart(asError(error, '[Planu] Durable heartbeat Worker failed'));
243
+ });
244
+ worker.once('exit', (code) => {
245
+ exited = true;
246
+ resolveExited();
247
+ if (!stopping) {
248
+ failStart(new Error(`[Planu] Durable heartbeat Worker exited ${String(code)}`));
249
+ }
250
+ });
251
+ await readyPromise;
252
+ return {
253
+ stop() {
254
+ stopPromise ??= (async () => {
255
+ stopping = true;
256
+ if (exited) {
257
+ settleLocally();
258
+ return;
259
+ }
260
+ try {
261
+ worker.postMessage({ ...data, type: 'stop' });
262
+ }
263
+ catch (postError) {
264
+ reportClassifiedDegradation('VALIDATE_JOB_HEARTBEAT_FAILURE', postError);
265
+ try {
266
+ await terminateWithinBudget(worker, input.shutdownTimeoutMs);
267
+ }
268
+ finally {
269
+ settleLocally();
270
+ }
271
+ return;
272
+ }
273
+ let shutdownTimer;
274
+ const shutdownExpired = new Promise((resolveShutdown) => {
275
+ shutdownTimer = setTimeout(() => {
276
+ resolveShutdown('timeout');
277
+ }, input.shutdownTimeoutMs);
278
+ shutdownTimer.unref();
279
+ });
280
+ const outcome = await Promise.race([
281
+ stoppedPromise.then(() => 'stopped'),
282
+ exitedPromise.then(() => 'exited'),
283
+ shutdownExpired,
284
+ ]);
285
+ try {
286
+ if (outcome === 'stopped') {
287
+ const exitOutcome = await Promise.race([
288
+ exitedPromise.then(() => 'exited'),
289
+ shutdownExpired,
290
+ ]);
291
+ if (exitOutcome === 'timeout') {
292
+ await terminateWithinBudget(worker, input.shutdownTimeoutMs);
293
+ }
294
+ }
295
+ if (outcome === 'timeout') {
296
+ await terminateWithinBudget(worker, input.shutdownTimeoutMs);
297
+ }
298
+ }
299
+ finally {
300
+ if (shutdownTimer) {
301
+ clearTimeout(shutdownTimer);
302
+ }
303
+ settleLocally();
304
+ }
305
+ })();
306
+ return stopPromise;
307
+ },
308
+ };
309
+ }
310
+ // eslint-disable-next-line max-lines-per-function -- one Worker owns one contained database lifecycle
311
+ function runHeartbeatWorker(data) {
312
+ const port = parentPort;
313
+ if (!port || !workerDataIsValid(data)) {
314
+ throw new Error('[Planu] Durable heartbeat Worker data is invalid');
315
+ }
316
+ const identity = {
317
+ schemaVersion: 1,
318
+ projectId: data.projectId,
319
+ workspaceId: data.workspaceId,
320
+ operationId: data.operationId,
321
+ workerId: data.workerId,
322
+ fencingToken: data.fencingToken,
323
+ };
324
+ const database = new RuntimeDatabase({
325
+ path: data.databasePath,
326
+ busyTimeoutMs: data.databaseBusyTimeoutMs,
327
+ checkIntegrity: false,
328
+ maxConnections: 1,
329
+ });
330
+ let sequence = 0;
331
+ let settled = false;
332
+ const stop = (notify) => {
333
+ if (settled) {
334
+ return;
335
+ }
336
+ settled = true;
337
+ clearInterval(timer);
338
+ try {
339
+ database.close();
340
+ }
341
+ finally {
342
+ if (notify) {
343
+ port.postMessage({ ...identity, type: 'stopped' });
344
+ }
345
+ port.close();
346
+ }
347
+ };
348
+ const lose = (reason) => {
349
+ if (settled) {
350
+ return;
351
+ }
352
+ sequence += 1;
353
+ port.postMessage({ ...identity, type: 'authorityLost', sequence, reason });
354
+ stop(false);
355
+ };
356
+ const renew = (notify) => {
357
+ try {
358
+ const renewed = database.renewJobLease({
359
+ id: data.operationId,
360
+ projectId: data.projectId,
361
+ workspaceId: data.workspaceId,
362
+ workerId: data.workerId,
363
+ fencingToken: data.fencingToken,
364
+ leaseMs: data.leaseMs,
365
+ });
366
+ if (!renewed) {
367
+ lose('cancelled-or-stale');
368
+ return false;
369
+ }
370
+ if (notify) {
371
+ sequence += 1;
372
+ port.postMessage({ ...identity, type: 'renewed', sequence });
373
+ }
374
+ return true;
375
+ }
376
+ catch (databaseError) {
377
+ reportClassifiedDegradation('VALIDATE_JOB_HEARTBEAT_FAILURE', databaseError);
378
+ lose('database-failure');
379
+ return false;
380
+ }
381
+ };
382
+ const timer = setInterval(() => {
383
+ renew(true);
384
+ }, data.heartbeatMs);
385
+ timer.unref();
386
+ port.on('message', (message) => {
387
+ const command = message;
388
+ if (command.type === 'stop' && sameIdentity(command, data)) {
389
+ stop(true);
390
+ }
391
+ });
392
+ if (renew(false)) {
393
+ port.postMessage({ ...identity, type: 'ready' });
394
+ }
395
+ }
396
+ if (!isMainThread &&
397
+ workerData?.kind === 'planu-durable-job-heartbeat') {
398
+ runHeartbeatWorker(workerData);
399
+ }
400
+ //# sourceMappingURL=durable-job-heartbeat-runtime.js.map
@@ -9,6 +9,8 @@ export declare class DurableJobRuntime implements Disposable {
9
9
  private readonly database;
10
10
  private readonly ownsDatabase;
11
11
  constructor(options?: DurableJobRuntimeOptions);
12
+ /** Runtime database path for contained infrastructure workers. */
13
+ runtimeDatabasePath(): string;
12
14
  accept(input: {
13
15
  readonly projectId: string;
14
16
  readonly workspaceId?: string;
@@ -27,6 +29,8 @@ export declare class DurableJobRuntime implements Disposable {
27
29
  readonly maxAttempts?: number;
28
30
  }): DurableJobRecord;
29
31
  get(input: DurableJobIdentity): DurableJobRecord;
32
+ /** Return the allowlisted public projection for one job and its current queue scope. */
33
+ observe(input: DurableJobIdentity | DurableJobRecord): ReturnType<typeof publicJobObservation>;
30
34
  list(projectId: string, workspaceId?: string): readonly DurableJobRecord[];
31
35
  listRunnableScopes(): readonly {
32
36
  projectId: string;
@@ -43,6 +47,7 @@ export declare class DurableJobRuntime implements Disposable {
43
47
  }): boolean;
44
48
  recordProgress(input: DurableJobIdentity & {
45
49
  readonly workerId: string;
50
+ readonly leaseMs: number;
46
51
  readonly fencingToken: number;
47
52
  readonly checkpoint: unknown;
48
53
  }): DurableJobRecord;
@@ -63,6 +68,7 @@ export declare class DurableJobRuntime implements Disposable {
63
68
  }): DurableJobRecord;
64
69
  retry(input: DurableJobIdentity): DurableJobRecord;
65
70
  restart(input: DurableJobIdentity): DurableJobRecord;
71
+ restartReceiptPublication(input: DurableJobIdentity): DurableJobRecord;
66
72
  restartWithPayload(input: DurableJobIdentity & {
67
73
  readonly payload: unknown;
68
74
  }): DurableJobRecord;
@@ -75,4 +81,28 @@ export declare class DurableJobRuntime implements Disposable {
75
81
  }
76
82
  /** Stable watcher cursor that detects state changes even within one clock millisecond. */
77
83
  export declare function durableJobCursor(job: DurableJobRecord): string;
84
+ /** Build a privacy-safe job projection from existing durable records. */
85
+ export declare function publicJobObservation(job: DurableJobRecord, scopeJobs: readonly DurableJobRecord[], now?: number): {
86
+ id: string;
87
+ projectId: string;
88
+ workspaceId: string;
89
+ state: DurableJobRecord['state'];
90
+ checkpoint?: unknown;
91
+ result?: unknown;
92
+ error?: string;
93
+ attempts: number;
94
+ maxAttempts: number;
95
+ cancelRequested: boolean;
96
+ createdAt: string;
97
+ updatedAt: string;
98
+ queue: {
99
+ status: 'active' | 'queued' | 'terminal';
100
+ position: number | null;
101
+ aheadCount: number;
102
+ capacity: number;
103
+ remainingBudgetMs: number;
104
+ };
105
+ };
106
+ /** Stable public cursor: queue movement and semantic progress count, leases and time do not. */
107
+ export declare function publicJobCursor(job: ReturnType<typeof publicJobObservation>): string;
78
108
  //# sourceMappingURL=job-runtime.d.ts.map
@@ -1,11 +1,14 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { RuntimeDatabase, } from '../../storage/runtime-db.js';
3
3
  import { resolveStorageLayout } from '../../storage/storage-layout.js';
4
+ import { getRuntimePolicy } from '../runtime-policy.js';
4
5
  import { isNativeWorkerOperation } from './native-worker-protocol.js';
5
6
  import { getExecutionContext } from './context.js';
7
+ import { sanitizePublicJobValue } from './public-job-sanitizer.js';
6
8
  const DEFAULT_WORKSPACE_ID = 'global';
7
9
  const MAX_WATCH_MS = 30_000;
8
10
  const TERMINAL_STATES = new Set(['cancelled', 'failed', 'dead-letter', 'completed']);
11
+ const DURATION_ONLY_CHECKPOINT_KEYS = new Set(['durationMs', 'elapsedMs']);
9
12
  export class DurableJobNotFoundError extends Error {
10
13
  constructor(operationId) {
11
14
  super(`[Planu] Job ${operationId} was not found`);
@@ -23,6 +26,10 @@ export class DurableJobRuntime {
23
26
  this.ownsDatabase = true;
24
27
  this.database.recoverExpiredJobs();
25
28
  }
29
+ /** Runtime database path for contained infrastructure workers. */
30
+ runtimeDatabasePath() {
31
+ return this.database.path;
32
+ }
26
33
  accept(input) {
27
34
  const operationId = input.operationId ?? randomUUID();
28
35
  const workspaceId = input.workspaceId ?? DEFAULT_WORKSPACE_ID;
@@ -60,6 +67,11 @@ export class DurableJobRuntime {
60
67
  get(input) {
61
68
  return this.requireJob(input);
62
69
  }
70
+ /** Return the allowlisted public projection for one job and its current queue scope. */
71
+ observe(input) {
72
+ const job = 'id' in input ? input : this.requireJob(input);
73
+ return publicJobObservation(job, this.list(job.projectId, job.workspaceId));
74
+ }
63
75
  list(projectId, workspaceId = DEFAULT_WORKSPACE_ID) {
64
76
  return this.database.listJobs(projectId, workspaceId);
65
77
  }
@@ -74,7 +86,7 @@ export class DurableJobRuntime {
74
86
  }
75
87
  recordProgress(input) {
76
88
  return this.database.recordJobProgress({
77
- ...this.leaseInput({ ...input, leaseMs: 100 }),
89
+ ...this.leaseInput(input),
78
90
  checkpoint: input.checkpoint,
79
91
  });
80
92
  }
@@ -102,6 +114,12 @@ export class DurableJobRuntime {
102
114
  restart(input) {
103
115
  return this.database.restartJob(input.projectId, input.workspaceId ?? DEFAULT_WORKSPACE_ID, input.operationId);
104
116
  }
117
+ restartReceiptPublication(input) {
118
+ return this.database.restartReceiptPublication(input.projectId, input.workspaceId ?? DEFAULT_WORKSPACE_ID, input.operationId, {
119
+ logMaxBytes: getRuntimePolicy().validation.receiptCheckpointLogMaxBytes,
120
+ resultMaxBytes: getRuntimePolicy().validation.receiptCheckpointResultMaxBytes,
121
+ });
122
+ }
105
123
  restartWithPayload(input) {
106
124
  return this.database.restartJobWithPayload(input.projectId, input.workspaceId ?? DEFAULT_WORKSPACE_ID, input.operationId, input.payload);
107
125
  }
@@ -132,9 +150,10 @@ export class DurableJobRuntime {
132
150
  const deadline = Date.now() + timeoutMs;
133
151
  for (;;) {
134
152
  const job = this.requireJob(input);
153
+ const cursor = publicJobCursor(this.observe(job));
135
154
  if (TERMINAL_STATES.has(job.state) ||
136
155
  input.afterCursor === undefined ||
137
- durableJobCursor(job) !== input.afterCursor ||
156
+ cursor !== input.afterCursor ||
138
157
  Date.now() >= deadline) {
139
158
  return job;
140
159
  }
@@ -172,20 +191,109 @@ export class DurableJobRuntime {
172
191
  }
173
192
  /** Stable watcher cursor that detects state changes even within one clock millisecond. */
174
193
  export function durableJobCursor(job) {
194
+ const capacity = getRuntimePolicy().validation.workerConcurrency;
195
+ const status = queueStatus(job);
196
+ return publicJobCursor({
197
+ ...publicJobFields(job),
198
+ queue: {
199
+ status,
200
+ position: status === 'terminal' ? null : 1,
201
+ aheadCount: 0,
202
+ capacity,
203
+ remainingBudgetMs: remainingBudgetMs(job),
204
+ },
205
+ });
206
+ }
207
+ /** Build a privacy-safe job projection from existing durable records. */
208
+ export function publicJobObservation(job, scopeJobs, now = Date.now()) {
209
+ const status = queueStatus(job);
210
+ const queueJobs = scopeJobs.filter(isQueueRelevant).filter((candidate) => !isTerminal(candidate));
211
+ const positionIndex = queueJobs.findIndex((candidate) => candidate.id === job.id);
212
+ const position = status === 'terminal' ? null : Math.max(0, positionIndex) + 1;
213
+ return {
214
+ ...publicJobFields(job),
215
+ queue: {
216
+ status,
217
+ position,
218
+ aheadCount: position === null ? 0 : position - 1,
219
+ capacity: getRuntimePolicy().validation.workerConcurrency,
220
+ remainingBudgetMs: status === 'terminal' ? 0 : remainingBudgetMs(job, now),
221
+ },
222
+ };
223
+ }
224
+ /** Stable public cursor: queue movement and semantic progress count, leases and time do not. */
225
+ export function publicJobCursor(job) {
175
226
  return createHash('sha256')
176
227
  .update(JSON.stringify({
177
228
  state: job.state,
178
- checkpoint: job.checkpoint,
229
+ checkpoint: omitDurationOnlyFields(job.checkpoint),
179
230
  result: job.result,
180
231
  error: job.error,
181
232
  attempts: job.attempts,
182
233
  cancelRequested: job.cancelRequested,
183
- leaseOwner: job.leaseOwner,
184
- leaseExpiresAt: job.leaseExpiresAt,
185
- updatedAt: job.updatedAt,
234
+ queue: {
235
+ status: job.queue.status,
236
+ position: job.queue.position,
237
+ aheadCount: job.queue.aheadCount,
238
+ capacity: job.queue.capacity,
239
+ },
186
240
  }))
187
241
  .digest('hex');
188
242
  }
243
+ function publicJobFields(job) {
244
+ return {
245
+ id: job.id,
246
+ projectId: job.projectId,
247
+ workspaceId: job.workspaceId,
248
+ state: job.state,
249
+ ...(job.checkpoint === undefined ? {} : { checkpoint: sanitizePublicJobValue(job.checkpoint) }),
250
+ ...(job.result === undefined ? {} : { result: sanitizePublicJobValue(job.result) }),
251
+ ...(job.error === undefined ? {} : { error: sanitizePublicJobValue(job.error) }),
252
+ attempts: job.attempts,
253
+ maxAttempts: job.maxAttempts,
254
+ cancelRequested: job.cancelRequested,
255
+ createdAt: job.createdAt,
256
+ updatedAt: job.updatedAt,
257
+ };
258
+ }
259
+ function queueStatus(job) {
260
+ if (isTerminal(job)) {
261
+ return 'terminal';
262
+ }
263
+ return job.state === 'running' ? 'active' : 'queued';
264
+ }
265
+ function isTerminal(job) {
266
+ return TERMINAL_STATES.has(job.state);
267
+ }
268
+ function isQueueRelevant(job) {
269
+ if (!job.payload || typeof job.payload !== 'object') {
270
+ return true;
271
+ }
272
+ const kind = job.payload.kind;
273
+ return kind === undefined || kind === 'validate';
274
+ }
275
+ function remainingBudgetMs(job, now = Date.now()) {
276
+ const payload = job.payload && typeof job.payload === 'object'
277
+ ? job.payload
278
+ : undefined;
279
+ const explicitDeadline = payload?.deadlineAt;
280
+ const fallbackDeadline = Date.parse(job.createdAt) + getRuntimePolicy().validation.defaultDeadlineMs;
281
+ const deadline = typeof explicitDeadline === 'number' && Number.isFinite(explicitDeadline)
282
+ ? explicitDeadline
283
+ : fallbackDeadline;
284
+ return Math.max(0, Math.floor(deadline - now));
285
+ }
286
+ function omitDurationOnlyFields(value) {
287
+ if (Array.isArray(value)) {
288
+ return value.map(omitDurationOnlyFields);
289
+ }
290
+ if (value && typeof value === 'object') {
291
+ return Object.fromEntries(Object.entries(value)
292
+ .filter(([key]) => !DURATION_ONLY_CHECKPOINT_KEYS.has(key))
293
+ .map(([key, nested]) => [key, omitDurationOnlyFields(nested)]));
294
+ }
295
+ return value;
296
+ }
189
297
  function abortableDelay(delayMs, signals) {
190
298
  const activeSignals = signals.filter((signal) => signal !== undefined);
191
299
  const aborted = activeSignals.find((signal) => signal.aborted);
@@ -54,9 +54,15 @@ export class OperationJournal {
54
54
  const existing = this.get(operation, idempotencyKey);
55
55
  if (existing) {
56
56
  if (existing.requestDigest !== requestDigest) {
57
- throw new BoundaryFailure('Conflict', 'operation begin', 'Use a new idempotency key for a different request.');
57
+ // SPEC-1348: a rolled-back attempt produced no durable effects, so the
58
+ // key is re-claimable even when the retry payload differs byte-wise.
59
+ if (existing.state !== 'rolled-back') {
60
+ throw new BoundaryFailure('Conflict', 'operation begin', 'Use a new idempotency key for a different request.');
61
+ }
62
+ }
63
+ else {
64
+ return existing;
58
65
  }
59
- return existing;
60
66
  }
61
67
  const now = new Date().toISOString();
62
68
  const entry = {
@@ -66,8 +72,8 @@ export class OperationJournal {
66
72
  requestDigest,
67
73
  state: 'intent',
68
74
  ...(recovery ?? {}),
69
- recoveryAttempts: 0,
70
- createdAt: now,
75
+ recoveryAttempts: existing?.recoveryAttempts ?? 0,
76
+ createdAt: existing?.createdAt ?? now,
71
77
  updatedAt: now,
72
78
  };
73
79
  this.put(entry);
@@ -0,0 +1,4 @@
1
+ /** Recursively remove secrets and absolute paths from public durable-job values. */
2
+ export declare function sanitizePublicJobValue(value: string): string;
3
+ export declare function sanitizePublicJobValue(value: unknown): unknown;
4
+ //# sourceMappingURL=public-job-sanitizer.d.ts.map