@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
@@ -1,55 +1,96 @@
1
1
  // tools/challenge-spec-helpers.ts — Concurrency, risk, and spec-reader helpers for challenge-spec
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { readSpecTechnicalSection } from '../engine/spec-format/read-technical-section.js';
4
- // --- Concurrency analysis ---
4
+ import { hasAffirmedMatch, stripMetaAnalysisText, stripNonContractText, } from '../engine/text-signal-boundaries.js';
5
+ // Bare keyword matches (counter, status, draft, ...) are common in unrelated
6
+ // prose (variable names, file paths, section headers, bug narratives). They
7
+ // only ground a race-condition/shared-state finding when the spec content
8
+ // also affirms an explicit concurrency context — otherwise they are boilerplate.
9
+ const CONCURRENCY_CONTEXT_PATTERN = /\b(?:concurrent(?:ly)?|simultaneous(?:ly)?|in\s+parallel|parallel\s+writes?|race\s+condition|multiple\s+users?|at\s+the\s+same\s+time|two\s+users|shared\s+state|atomic(?:ally)?|thread-safe|synchroniz(?:e|es|ed|ing|ation)|multiple\s+(?:tabs|devices|requests|clients))\b/i;
10
+ const AUTH_PATTERN = /\b(?:login|auth)\b/i;
11
+ const LIST_SEARCH_PATTERN = /\b(?:list|search|feed)\b/i;
12
+ const WRITE_PATTERN = /\b(?:submit|create|update)\b/i;
13
+ const COUNTER_PATTERN = /\b(?:counter|increment|balance|stock|quantity|vote)\b/i;
14
+ const STATUS_PATTERN = /\bstatus\b/i;
15
+ const TRANSITION_PATTERN = /\b(?:update|transition)\b/i;
16
+ const FILE_PATTERN = /\b(?:file|upload|resource)\b/i;
17
+ const SESSION_PATTERN = /\b(?:session|cart|draft)\b/i;
18
+ const CACHE_PATTERN = /\b(?:cache|global|config)\b/i;
19
+ /** Grounded, boundary-aware, negation-aware match against contract prose only. */
20
+ function affirms(content, pattern) {
21
+ return hasAffirmedMatch(content, pattern);
22
+ }
5
23
  export function generateConcurrencyAnalysis(_spec, content, _knowledge) {
6
- const lower = content.toLowerCase();
24
+ // Drop frontmatter, code fences, and quoted/backticked examples before
25
+ // keyword inference — mirrors detectChallengeCapabilities so this generator
26
+ // reads the same "contract prose" the capability gate already reads.
27
+ const contract = stripMetaAnalysisText(stripNonContractText(content));
7
28
  const hotPaths = [];
8
29
  const raceConditions = [];
9
30
  const sharedState = [];
10
31
  const recommendations = [];
11
- // Detect hot paths
12
- if (lower.includes('login') || lower.includes('auth')) {
32
+ let suppressedCount = 0;
33
+ // Hot paths are informational only (they do not feed overallRisk), so a
34
+ // plain boundary-aware match is sufficient here — no context gate needed.
35
+ if (affirms(contract, AUTH_PATTERN)) {
13
36
  hotPaths.push('Authentication endpoint (high-frequency, shared session state)');
14
37
  }
15
- if (lower.includes('list') || lower.includes('search') || lower.includes('feed')) {
38
+ if (affirms(contract, LIST_SEARCH_PATTERN)) {
16
39
  hotPaths.push('List/search endpoints (high read frequency)');
17
40
  }
18
- if (lower.includes('submit') || lower.includes('create') || lower.includes('update')) {
41
+ if (affirms(contract, WRITE_PATTERN)) {
19
42
  hotPaths.push('Write endpoints (mutation-heavy, lock-prone)');
20
43
  }
21
- // Detect race conditions
22
- if (lower.includes('counter') ||
23
- lower.includes('increment') ||
24
- lower.includes('balance') ||
25
- lower.includes('stock') ||
26
- lower.includes('quantity') ||
27
- lower.includes('vote')) {
44
+ const hasConcurrencyContext = affirms(contract, CONCURRENCY_CONTEXT_PATTERN);
45
+ const counterMatched = affirms(contract, COUNTER_PATTERN);
46
+ if (counterMatched && hasConcurrencyContext) {
28
47
  raceConditions.push('Counter/balance updates may lose increments under concurrent writes');
29
48
  recommendations.push('Use database-level atomic increments (UPDATE SET count = count + 1) instead of read-modify-write');
30
49
  }
31
- if (lower.includes('status') && (lower.includes('update') || lower.includes('transition'))) {
50
+ else if (counterMatched) {
51
+ suppressedCount += 1;
52
+ }
53
+ const statusMatched = affirms(contract, STATUS_PATTERN) && affirms(contract, TRANSITION_PATTERN);
54
+ if (statusMatched && hasConcurrencyContext) {
32
55
  raceConditions.push('Status transitions may conflict when two users update simultaneously');
33
56
  recommendations.push('Use optimistic locking (version column) or pessimistic locking (SELECT FOR UPDATE)');
34
57
  }
35
- if (lower.includes('file') || lower.includes('upload') || lower.includes('resource')) {
58
+ else if (statusMatched) {
59
+ suppressedCount += 1;
60
+ }
61
+ const fileMatched = affirms(contract, FILE_PATTERN);
62
+ if (fileMatched && hasConcurrencyContext) {
36
63
  raceConditions.push('Concurrent file writes to same resource may corrupt data');
37
64
  recommendations.push('Use advisory locks or rename-and-swap pattern for file operations');
38
65
  }
39
- // Detect shared state
40
- if (lower.includes('session') || lower.includes('cart') || lower.includes('draft')) {
66
+ else if (fileMatched) {
67
+ suppressedCount += 1;
68
+ }
69
+ const sessionMatched = affirms(contract, SESSION_PATTERN);
70
+ if (sessionMatched && hasConcurrencyContext) {
41
71
  sharedState.push('User session state (may be accessed from multiple tabs/devices)');
42
72
  }
43
- if (lower.includes('cache') || lower.includes('global') || lower.includes('config')) {
73
+ else if (sessionMatched) {
74
+ suppressedCount += 1;
75
+ }
76
+ const cacheMatched = affirms(contract, CACHE_PATTERN);
77
+ if (cacheMatched && hasConcurrencyContext) {
44
78
  sharedState.push('Global cache or configuration (requires synchronized access)');
45
79
  }
46
- // General recommendations
80
+ else if (cacheMatched) {
81
+ suppressedCount += 1;
82
+ }
83
+ // General recommendations — only emitted once a race condition is actually
84
+ // grounded, otherwise a formatting-only spec would still surface generic
85
+ // "use database transactions" boilerplate (SPEC-1350 AC1).
47
86
  if (raceConditions.length === 0) {
48
87
  recommendations.push('No obvious race conditions detected, but test concurrent scenarios in integration tests');
49
88
  }
50
- recommendations.push('Use database transactions for multi-step operations');
51
- recommendations.push('Implement idempotency keys for all mutation endpoints');
52
- return { hotPaths, raceConditions, sharedState, recommendations };
89
+ else {
90
+ recommendations.push('Use database transactions for multi-step operations');
91
+ recommendations.push('Implement idempotency keys for all mutation endpoints');
92
+ }
93
+ return { hotPaths, raceConditions, sharedState, recommendations, suppressedCount };
53
94
  }
54
95
  // --- Scalability and risk ---
55
96
  export function buildScalabilityAssessment(spec, knowledge, scenarios) {
@@ -19,6 +19,7 @@ import { analyzeMinimalImplementation, loadMinimalImplementationPolicy, } from '
19
19
  import { detectChallengeCapabilities, } from './challenge-spec/scenarios-utils.js';
20
20
  import { collectCapabilityScenarios } from './challenge-spec/scenario-collector.js';
21
21
  import { buildChallengeReport, parseChallengeResolutionEvidence, } from './challenge-spec/challenge-report.js';
22
+ import { extractListItems, findMarkdownSectionRange, } from '../engine/spec-format/markdown-sections.js';
22
23
  const ALL_FOCUS_AREAS = [
23
24
  'failures',
24
25
  'concurrency',
@@ -150,11 +151,10 @@ export async function handleChallengeSpec(args, server) {
150
151
  failureScenarios.push(...collectCapabilityScenarios({ spec, specContent, knowledge, focusAreas, capabilities }));
151
152
  // SPEC-612: Check for contradictions between outOfScope and acceptance criteria
152
153
  if (spec.outOfScope !== undefined && spec.outOfScope.length > 0) {
153
- const criteriaTexts = specContent
154
- .split('\n')
155
- .filter((line) => line.trim().startsWith('-') || line.trim().startsWith('*'))
156
- .map((line) => line.replace(/^[\s\-*]+/, '').trim())
157
- .filter((line) => line.length > 0);
154
+ const criteriaRange = findMarkdownSectionRange(specContent, 'Acceptance Criteria');
155
+ const criteriaTexts = criteriaRange === null
156
+ ? []
157
+ : extractListItems(specContent.slice(criteriaRange.contentStart, criteriaRange.end));
158
158
  const contradictionResult = checkScopeContradictions(spec.outOfScope, criteriaTexts);
159
159
  for (const c of contradictionResult.contradictions) {
160
160
  failureScenarios.push({
@@ -171,9 +171,24 @@ export async function handleChallengeSpec(args, server) {
171
171
  // SPEC-615 AC3: Check criteria against prior decisions for technology contradictions
172
172
  await runPriorDecisionContradictions(projectId, spec.title, spec.tags, specContent, failureScenarios);
173
173
  // 6. Generate concurrency analysis
174
- const concurrencyAnalysis = focusAreas.includes('concurrency') && capabilities.concurrency
174
+ const concurrencyResult = focusAreas.includes('concurrency') && capabilities.concurrency
175
175
  ? generateConcurrencyAnalysis(spec, specContent, knowledge)
176
- : { hotPaths: [], raceConditions: [], sharedState: [], recommendations: [] };
176
+ : {
177
+ hotPaths: [],
178
+ raceConditions: [],
179
+ sharedState: [],
180
+ recommendations: [],
181
+ suppressedCount: 0,
182
+ };
183
+ // SPEC-1350: concurrency candidates that matched a domain keyword but lacked
184
+ // a corroborating concurrency context are suppressed before risk/summary math.
185
+ const concurrencySuppressedCount = concurrencyResult.suppressedCount;
186
+ const concurrencyAnalysis = {
187
+ hotPaths: concurrencyResult.hotPaths,
188
+ raceConditions: concurrencyResult.raceConditions,
189
+ sharedState: concurrencyResult.sharedState,
190
+ recommendations: concurrencyResult.recommendations,
191
+ };
177
192
  // Unsupported domain templates are removed before prioritization and risk calculation.
178
193
  const actionableFailureScenarios = failureScenarios.filter((scenario) => isScenarioSupportedByCapabilities(scenario, capabilities));
179
194
  const suppressedScenarioCount = failureScenarios.length - actionableFailureScenarios.length;
@@ -219,7 +234,7 @@ export async function handleChallengeSpec(args, server) {
219
234
  summary: {
220
235
  totalScenarios: failureScenarios.length,
221
236
  actionableScenarios: failureScenariosScored.length,
222
- suppressedLowRelevanceScenarios: suppressedScenarioCount,
237
+ suppressedLowRelevanceScenarios: suppressedScenarioCount + concurrencySuppressedCount,
223
238
  shownByDefault: 3,
224
239
  mustAddressBeforeCoding: prioritizedSummary,
225
240
  criticalImpact: actionableFailureScenarios.filter((s) => s.impact === 'critical').length,
@@ -1,7 +1,5 @@
1
1
  // tools/check-readiness.ts — Completeness checkpoint tool (SPEC-039, SPEC-314, SPEC-716)
2
2
  import { specStore } from '../storage/index.js';
3
- import { checkSpecReadiness } from '../engine/readiness-checker.js';
4
- import { scoreSpecQuality } from '../engine/spec-quality-scorer.js';
5
3
  import { buildCheckReadinessSummary } from '../engine/human-summary.js';
6
4
  import { validateSpecFormat } from '../core/spec-validator.js';
7
5
  import { resolveProjectId } from './resolve-project-id.js';
@@ -9,6 +7,7 @@ import { resolveProjectId } from './resolve-project-id.js';
9
7
  const MAX_VISIBLE_BLOCKERS = 8;
10
8
  const MAX_VISIBLE_WARNINGS = 8;
11
9
  const MAX_VISIBLE_RECOMMENDATIONS = 5;
10
+ const CANONICAL_CRITERIA_MISSING = 'CANONICAL_CRITERIA_MISSING';
12
11
  function formatScore(score) {
13
12
  if (score >= 90) {
14
13
  return `${score}/100 (Excellent)`;
@@ -21,6 +20,23 @@ function formatScore(score) {
21
20
  }
22
21
  return `${score}/100 (Not Ready)`;
23
22
  }
23
+ function canonicalReadinessFailure(validationResult) {
24
+ const metrics = validationResult.metrics;
25
+ if (metrics === undefined || metrics.criteriaCount === 0) {
26
+ return CANONICAL_CRITERIA_MISSING;
27
+ }
28
+ return null;
29
+ }
30
+ function createFailClosedReport(specId, mode) {
31
+ return {
32
+ specId,
33
+ score: 0,
34
+ ready: false,
35
+ mode,
36
+ issues: { score: 0, breakdown: {}, blockers: [], warnings: [] },
37
+ recommendations: [],
38
+ };
39
+ }
24
40
  function formatReport(report) {
25
41
  const lines = [];
26
42
  lines.push(`# Readiness Report — ${report.specId}`);
@@ -109,20 +125,15 @@ export async function handleCheckReadiness(args) {
109
125
  isError: true,
110
126
  };
111
127
  }
112
- // SPEC-716: Ground yes/no decision in validateSpecFormat.
113
- // The existing checkSpecReadiness call and formatReport are preserved for
114
- // the rich human-readable output. validateSpecFormat drives the yes/no gate
115
- // and its errors/warnings are surfaced in structuredContent.validationResult.
116
- const [report, qualityReport, validationResult] = await Promise.all([
117
- checkSpecReadiness(spec, mode),
118
- scoreSpecQuality(spec),
119
- validateSpecFormat(spec, { readinessMode: mode, skipQuality: true }),
120
- ]);
121
- // SPEC-716: Ground ready flag in unified ValidationResult.
128
+ // validateSpecFormat owns the readiness and quality evaluation so the response
129
+ // cannot combine separately computed evidence from different reads of spec.md.
130
+ const validationResult = await validateSpecFormat(spec, { readinessMode: mode });
131
+ // SPEC-716: Ground ready flag in unified SpecValidationResult.
122
132
  // Only non-file-access errors from validateSpecFormat are surfaced in the
123
133
  // report — MISSING_FRONTMATTER due to file-not-found is best-effort since
124
134
  // the readiness checker already handles missing files gracefully.
125
135
  const vr = validationResult;
136
+ const report = vr.readinessReport ?? createFailClosedReport(spec.id, mode);
126
137
  const hardFormatErrors = vr.errors.filter((e) => e.code !== 'MISSING_FRONTMATTER' && !(e.code === 'READINESS_CHECK_FAILED'));
127
138
  const hardFormatMessages = hardFormatErrors.map((e) => e.message);
128
139
  const formatWarnings = vr.warnings
@@ -142,11 +153,24 @@ export async function handleCheckReadiness(args) {
142
153
  // Ground ready: only false if BOTH readiness report and format gate agree
143
154
  // (or format has hard non-file errors)
144
155
  report.ready = report.ready && hardFormatErrors.length === 0;
156
+ const canonicalFailure = canonicalReadinessFailure(vr);
157
+ if (canonicalFailure !== null) {
158
+ const target = mode === 'strict' ? report.issues.blockers : report.issues.warnings;
159
+ if (!target.includes(canonicalFailure)) {
160
+ target.push(canonicalFailure);
161
+ }
162
+ if (!report.recommendations.includes(`Resolve ${canonicalFailure} before implementation.`)) {
163
+ report.recommendations.push(`Resolve ${canonicalFailure} before implementation.`);
164
+ }
165
+ // Lenient mode is advisory, but it must not present a contradictory
166
+ // canonical validation result as an implementation-ready pass.
167
+ report.ready = false;
168
+ }
145
169
  // SPEC-612: recommend adding outOfScope items when none are declared
146
170
  if (spec.outOfScope === undefined || spec.outOfScope.length === 0) {
147
171
  report.recommendations.push('Add outOfScope items to the spec frontmatter to declare explicit scope boundaries (SPEC-612). This reduces scope creep during implementation.');
148
172
  }
149
- const qualityScore = qualityReport.score;
173
+ const qualityScore = vr.qualityReport?.score;
150
174
  const formatted = formatReport(report);
151
175
  const humanSummary = buildCheckReadinessSummary(report.score, report.issues.blockers.length);
152
176
  return {
@@ -161,7 +185,7 @@ export async function handleCheckReadiness(args) {
161
185
  mode: report.mode,
162
186
  issues: report.issues,
163
187
  recommendations: report.recommendations,
164
- qualityScore,
188
+ ...(qualityScore === undefined ? {} : { qualityScore }),
165
189
  humanSummary,
166
190
  validationResult: vr,
167
191
  },
@@ -1,9 +1,30 @@
1
1
  import { readTelemetryConfig, writeTelemetryConfig, TELEMETRY_CONSENT_VERSION, } from '../engine/telemetry/index.js';
2
2
  import { compactResult, compactError, formatKeyValue } from './output-formatter.js';
3
+ function isLoopbackHost(hostname) {
4
+ return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]';
5
+ }
6
+ function isTelemetryConfigured() {
7
+ const endpoint = process.env.PLANU_TELEMETRY_ENDPOINT?.trim();
8
+ const token = process.env.PLANU_TELEMETRY_TOKEN?.trim();
9
+ if (!endpoint || !token) {
10
+ return false;
11
+ }
12
+ try {
13
+ const parsed = new URL(endpoint);
14
+ return (parsed.username === '' &&
15
+ parsed.password === '' &&
16
+ (parsed.protocol === 'https:' ||
17
+ (parsed.protocol === 'http:' && isLoopbackHost(parsed.hostname))));
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ }
3
23
  export async function handleConfigureTelemetry(input) {
4
24
  try {
5
25
  const existing = await readTelemetryConfig();
6
26
  const enabled = existing?.enabled === true && existing.consentVersion === TELEMETRY_CONSENT_VERSION;
27
+ const configured = isTelemetryConfigured();
7
28
  if (input.action === 'status') {
8
29
  const observatoryStatus = existing?.enableObservatory === true
9
30
  ? ' Observatory: ENABLED (cross-project insights active).'
@@ -11,9 +32,12 @@ export async function handleConfigureTelemetry(input) {
11
32
  const result = {
12
33
  action: 'status',
13
34
  enabled,
35
+ configured,
14
36
  consentVersion: existing?.consentVersion,
15
37
  message: (enabled
16
- ? 'Telemetry is ENABLED. Anonymous usage events are being sent to help improve Planu.'
38
+ ? configured
39
+ ? 'Telemetry is ENABLED and configured. Anonymous usage events may be sent to help improve Planu.'
40
+ : 'Telemetry consent is ENABLED, but delivery is inactive: configure valid PLANU_TELEMETRY_ENDPOINT and PLANU_TELEMETRY_TOKEN values.'
17
41
  : 'Telemetry is DISABLED. No data is being collected.') + observatoryStatus,
18
42
  };
19
43
  return compactResult(formatKeyValue(result));
@@ -31,8 +55,11 @@ export async function handleConfigureTelemetry(input) {
31
55
  const result = {
32
56
  action: 'enable',
33
57
  enabled: true,
58
+ configured,
34
59
  consentVersion: TELEMETRY_CONSENT_VERSION,
35
- message: 'Telemetry ENABLED. Thank you! Only anonymous usage data is collected — ' +
60
+ message: (configured
61
+ ? 'Telemetry ENABLED and configured. Only anonymous usage data is collected — '
62
+ : 'Telemetry consent ENABLED, but delivery is inactive until valid PLANU_TELEMETRY_ENDPOINT and PLANU_TELEMETRY_TOKEN values are configured. ') +
36
63
  'no paths, emails, identifiers, source content, or raw errors. ' +
37
64
  'Run configure_telemetry with action=disable to opt out anytime.' +
38
65
  observatoryNote,
@@ -49,6 +76,7 @@ export async function handleConfigureTelemetry(input) {
49
76
  const result = {
50
77
  action: 'disable',
51
78
  enabled: false,
79
+ configured,
52
80
  consentVersion: existing?.consentVersion,
53
81
  message: 'Telemetry DISABLED. No usage data will be sent.',
54
82
  };
@@ -13,4 +13,11 @@ export declare function buildSpecContext(params: CreateSpecInput): Promise<{
13
13
  export declare function buildSplitResult(splitSuggestion: ReturnType<typeof analyzeSplit>, experienceLevel: string | undefined): Record<string, unknown> | undefined;
14
14
  /** Infer meaningful tags from title and description when no tags were provided. */
15
15
  export declare function inferTagsFromContent(title: string, description: string, type?: string): string[];
16
+ /**
17
+ * SPEC-1351: Recompute the next spec id from a fresh store + filesystem scan.
18
+ * Called once (unlocked) during prepare to pick a candidate id, and again
19
+ * inside the exclusive create-spec write lock immediately before persisting
20
+ * so the id actually written can never collide under concurrency.
21
+ */
22
+ export declare function computeNextSpecId(projectPath: string, projectId: string): Promise<string>;
16
23
  //# sourceMappingURL=spec-builder.d.ts.map
@@ -2,8 +2,6 @@
2
2
  // tools/create-spec/spec-builder.ts — Builds the Spec object and estimation (SPEC-461: lean format).
3
3
  // Extracted from create-spec.ts to keep file sizes within limits.
4
4
  import { hashProjectPath, knowledgeStore, specStore, globalStore } from '../../storage/index.js';
5
- import { getCurrentTier } from '../license-gate.js';
6
- import { checkLimits } from '../../engine/license-validator.js';
7
5
  import { inferDifficulty, calculateEstimation } from '../../engine/estimator.js';
8
6
  import { analyzeSplit, formatSplitSuggestion } from '../../engine/spec-splitter.js';
9
7
  import { isLegacyLocation, getSpecFileNames } from '../../engine/planu-config-writer.js';
@@ -25,19 +23,13 @@ export async function buildSpecContext(params) {
25
23
  const projectId = hashProjectPath(projectPath);
26
24
  const knowledge = await knowledgeStore.getKnowledge(projectId);
27
25
  const existingSpecs = await specStore.listSpecs(projectId);
28
- // License: check active spec limit (exclude completed specs)
29
- const activeSpecs = existingSpecs.filter((s) => s.status !== 'done' && s.status !== 'discarded');
30
- const tier = await getCurrentTier();
31
- const specLimit = checkLimits(tier, activeSpecs.length, 'maxActiveSpecs');
32
- /* v8 ignore start -- license limit requires paid tier test env */
33
- if (!specLimit.allowed) {
34
- return { ok: false, errorMessage: specLimit.message };
35
- }
36
- /* v8 ignore stop */
37
- // Generate spec ID: combine store IDs + filesystem IDs for global max
38
- const fsSpecIds = await scanFilesystemSpecIds(projectPath);
39
- const allSpecs = [...existingSpecs, ...fsSpecIds.map((id) => ({ id }))];
40
- const specId = generateSpecId(allSpecs);
26
+ // Generate spec ID: combine store IDs + filesystem IDs for global max.
27
+ // SPEC-1351: this snapshot read is NOT locked under concurrency two callers
28
+ // can compute the same "next" id here. create-spec.ts re-derives the id via
29
+ // computeNextSpecId() again inside its exclusive per-project write lock right
30
+ // before persisting, so a stale id computed here is only ever a starting
31
+ // candidate, never the value that actually gets written to disk.
32
+ const specId = await computeNextSpecId(projectPath, projectId);
41
33
  const slug = slugify(title);
42
34
  // Check for duplicate title
43
35
  const duplicate = existingSpecs.find((s) => slugify(s.title) === slug);
@@ -220,6 +212,18 @@ function buildTags(tags, feature, _title, _description, _type) {
220
212
  const result = feature ? [...new Set([...explicitTags, slugify(feature)])] : explicitTags;
221
213
  return [...new Set(result)];
222
214
  }
215
+ /**
216
+ * SPEC-1351: Recompute the next spec id from a fresh store + filesystem scan.
217
+ * Called once (unlocked) during prepare to pick a candidate id, and again
218
+ * inside the exclusive create-spec write lock immediately before persisting
219
+ * so the id actually written can never collide under concurrency.
220
+ */
221
+ export async function computeNextSpecId(projectPath, projectId) {
222
+ const existingSpecs = await specStore.listSpecs(projectId);
223
+ const fsSpecIds = await scanFilesystemSpecIds(projectPath);
224
+ const allSpecs = [...existingSpecs, ...fsSpecIds.map((id) => ({ id }))];
225
+ return generateSpecId(allSpecs);
226
+ }
223
227
  /* v8 ignore start -- filesystem scanning is best-effort, tested via integration */
224
228
  /** Scan filesystem for SPEC-XXX directories to find max ID globally. */
225
229
  async function scanFilesystemSpecIds(projectPath) {
@@ -1,4 +1,5 @@
1
1
  import type { CreateSpecInput, ToolResult } from '../types/index.js';
2
2
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ export declare function resolveGroundedVerificationCommands(projectPath: string, testPaths: string[]): Promise<string[]>;
3
4
  export declare function handleCreateSpec(inputParams: CreateSpecInput, server?: McpServer): Promise<ToolResult>;
4
5
  //# sourceMappingURL=create-spec.d.ts.map