@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,6 +1,6 @@
1
1
  // engine/readiness-checker.ts — Spec readiness evaluation for implementation gate (SPEC-039)
2
2
  import { readFile } from 'node:fs/promises';
3
- import { readSpecTechnicalSection } from './spec-format/read-technical-section.js';
3
+ import { extractSectionBody, readSpecTechnicalSection, } from './spec-format/read-technical-section.js';
4
4
  import { stripFrontmatter } from './frontmatter-parser.js';
5
5
  import { loadReadinessConfig } from './readiness-config-loader.js';
6
6
  import { runEarsGate } from './ears-gate.js';
@@ -233,7 +233,7 @@ export function detectTechnicalPlaceholder(body) {
233
233
  /**
234
234
  * SPEC-784: Returns true when the ## Technical body is too shallow:
235
235
  * fewer than TECHNICAL_MIN_CHARS characters AND contains zero file
236
- * paths under src/ or tests/.
236
+ * safe repository-relative file paths.
237
237
  */
238
238
  export function detectTechnicalTooShallow(body) {
239
239
  const section = extractTechnicalSection(body);
@@ -244,9 +244,7 @@ export function detectTechnicalTooShallow(body) {
244
244
  if (section.length >= TECHNICAL_MIN_CHARS) {
245
245
  return false;
246
246
  }
247
- // Has at least one file path under src/ or tests/ → not too shallow
248
- const hasFilePaths = /\b(?:src|tests)\/[a-zA-Z0-9/_.-]+\.[a-z]+\b/.test(section);
249
- return !hasFilePaths;
247
+ return extractFilePaths(section).size === 0;
250
248
  }
251
249
  // ── SPEC-629 / SPEC-777: Specificity gate helpers ────────────────────────────
252
250
  /**
@@ -260,18 +258,27 @@ export function detectTechnicalTooShallow(body) {
260
258
  */
261
259
  export function extractFilePaths(text) {
262
260
  const found = new Set();
263
- // Match paths that look like <dir>/<rest>.<ext> where dir is a valid identifier
264
- // Works inside backticks, after commas/spaces, after FILES: markers
265
- const RE = /(?:[`\s,]|^|FILES:\s*)([a-zA-Z][a-zA-Z0-9_-]*(?:\/[a-zA-Z0-9_.-]+)+\.[a-zA-Z]{1,6})(?=[`\s,\n)]|$)/g;
261
+ const RE = /(?<![a-zA-Z0-9_./\\-])([a-zA-Z0-9_.-]+(?:\/[a-zA-Z0-9_.-]+)*\.[a-zA-Z][a-zA-Z0-9]*)(?=[`"'\s,):;.!?]|$)/g;
266
262
  let m;
267
263
  while ((m = RE.exec(text)) !== null) {
268
264
  const p = m[1];
269
- if (p !== undefined) {
265
+ if (p !== undefined && isSafeRepositoryFilePath(p)) {
270
266
  found.add(p);
271
267
  }
272
268
  }
273
269
  return found;
274
270
  }
271
+ function isSafeRepositoryFilePath(path) {
272
+ const segments = path.split('/');
273
+ const filename = segments.at(-1) ?? '';
274
+ const extensionIndex = filename.lastIndexOf('.');
275
+ return (path.length > 0 &&
276
+ !path.startsWith('/') &&
277
+ !/^[a-zA-Z]:/u.test(path) &&
278
+ segments.every((segment) => segment.length > 0 && segment !== '.' && segment !== '..') &&
279
+ extensionIndex > 0 &&
280
+ extensionIndex < filename.length - 1);
281
+ }
275
282
  /**
276
283
  * Extract function/method names from text.
277
284
  * Recognises:
@@ -294,27 +301,21 @@ export function extractFunctionNames(text) {
294
301
  // ── SPEC-629: Specificity gate (difficulty >= 3) ────────────────────────────
295
302
  /**
296
303
  * For specs with difficulty >= 3, enforces that criteria contain:
297
- * - 3+ concrete file paths (src/ or tests/)
304
+ * - 3+ concrete repository-relative file paths
298
305
  * - 1+ criterion with exact function/type name
299
306
  * - 1+ anticipated test break (file + line number)
300
307
  * Returns blocker strings; empty array = gate passed.
301
308
  */
302
- function checkSpecificityGate(spec, criteriaLines, fichaContent) {
309
+ function checkSpecificityGate(spec, criteriaLines, fichaContent, anticipatedTestBreaksContent) {
303
310
  if (spec.difficulty < 3) {
304
311
  return [];
305
312
  }
306
313
  const allText = [...criteriaLines, fichaContent].join('\n');
307
314
  const blockers = [];
308
- // Count distinct file paths in src/ or tests/ — use enhanced extractor (SPEC-777)
309
315
  const uniquePaths = extractFilePaths(allText);
310
- // Also keep the legacy word-boundary regex for backward compat with bare paths not in backticks
311
- const legacyMatches = allText.match(/\b(?:src|tests)\/[a-zA-Z0-9/_.-]+\.[a-z]+\b/g) ?? [];
312
- for (const p of legacyMatches) {
313
- uniquePaths.add(p);
314
- }
315
316
  if (uniquePaths.size < 3) {
316
- blockers.push(`Difficulty ${String(spec.difficulty)} spec requires 3+ concrete file paths in criteria (src/ or tests/) — found ${String(uniquePaths.size)}. ` +
317
- `Add exact paths like 'src/engine/foo/bar.ts'.`);
317
+ blockers.push(`Difficulty ${String(spec.difficulty)} spec requires 3+ concrete repository-relative file paths in criteria — found ${String(uniquePaths.size)}. ` +
318
+ `Add exact paths like 'scripts/check-contract.mjs'.`);
318
319
  }
319
320
  // Detect function calls via enhanced extractor + legacy regex (SPEC-777)
320
321
  const functionNames = extractFunctionNames(allText);
@@ -325,7 +326,8 @@ function checkSpecificityGate(spec, criteriaLines, fichaContent) {
325
326
  }
326
327
  // Detect anticipated test breaks: a test file path + "line N" (with optional ~) or "change ... from ... to"
327
328
  const hasTestBreak = /\btests?\/[a-zA-Z0-9/_.-]+\.test\.[a-z]+.*\bline\s+~?\d+/i.test(allText) ||
328
- /\bchange\b.*\bfrom\b.*\bto\b/i.test(allText);
329
+ /\bchange\b.*\bfrom\b.*\bto\b/i.test(allText) ||
330
+ /\btests\/[a-zA-Z0-9/_.-]+\.test\.[a-z0-9]+(?![a-zA-Z0-9_.\\/-])[^\n]*\bline\s+~?\d+/i.test(anticipatedTestBreaksContent);
329
331
  if (!hasTestBreak) {
330
332
  blockers.push(`Difficulty ${String(spec.difficulty)} spec requires at least 1 anticipated test break ` +
331
333
  `(e.g. 'tests/api/foo.test.ts line 47: change count from 477 to 478').`);
@@ -333,76 +335,12 @@ function checkSpecificityGate(spec, criteriaLines, fichaContent) {
333
335
  return blockers;
334
336
  }
335
337
  // ── Public API ───────────────────────────────────────────────────────────────
336
- /**
337
- * SPEC-769: Pure in-memory readiness check — no file I/O.
338
- * Accepts the raw spec.md content (including frontmatter) and returns a quick
339
- * score + warnings without loading technical.md or any additional file.
340
- *
341
- * Scoring (max 100):
342
- * - Base (title/metadata present): 20
343
- * - Criteria: 0 | 20 | 35 | 50 (0 / 1-2 / 3-4 / 5+)
344
- * - Technical files (src/*.ts paths found in body): 30
345
- */
346
- export function checkReadinessInternal(body) {
347
- const bodyContent = stripFrontmatter(body);
348
- const normalizedCriteria = extractNormalizedAcceptanceCriteria(body);
349
- const criteriaLines = normalizedCriteria.map((criterion) => criterion.text);
350
- const scenarioCount = criteriaLines.length === 0 ? countFrontmatterScenarios(body) : 0;
351
- const criteriaCount = criteriaLines.length > 0 ? criteriaLines.length : scenarioCount;
352
- const config = loadReadinessConfig();
353
- const vagueWords = config.vagueWords.map((v) => v.word);
354
- const warnings = [];
355
- // Score based on criteria count
356
- let criteriaScore;
357
- if (criteriaCount === 0) {
358
- criteriaScore = 0;
359
- warnings.push('No acceptance criteria found — add at least 3 testable criteria');
360
- }
361
- else if (criteriaCount >= 5) {
362
- criteriaScore = 50;
363
- }
364
- else if (criteriaCount >= 3) {
365
- criteriaScore = 35;
366
- }
367
- else {
368
- criteriaScore = 20;
369
- warnings.push('Add more acceptance criteria (need at least 3 for adequate readiness)');
370
- }
371
- // Vague criteria detection (re-uses existing logic)
372
- const criteriaResult = scoreCriteria(criteriaLines.length > 0 ? criteriaLines : [], vagueWords);
373
- warnings.push(...criteriaResult.warnings);
374
- // Technical files presence (proxy for inline ## Technical — check src/ paths in body)
375
- const hasTechnicalFiles = /\bsrc\/[^\s]+\.[jt]s\b/.test(bodyContent);
376
- const technicalScore = hasTechnicalFiles ? 30 : 0;
377
- if (!hasTechnicalFiles && criteriaCount > 0) {
378
- warnings.push('No source file paths (e.g. src/engine/foo.ts) found — add file entries in ## Technical section');
379
- }
380
- // SPEC-784: Technical section quality gates
381
- // Run both detectors against the raw body (includes ## Technical heading)
382
- if (detectTechnicalPlaceholder(bodyContent)) {
383
- warnings.push('TECHNICAL_PLACEHOLDER_DETECTED: ## Technical section contains a placeholder pointer ' +
384
- '(e.g. "See technical.md") — inline the content instead of deferring to another file');
385
- }
386
- if (detectTechnicalTooShallow(bodyContent)) {
387
- warnings.push('TECHNICAL_TOO_SHALLOW: ## Technical section is too short (< 500 chars) and has no ' +
388
- 'src/ or tests/ file paths — add concrete file paths and implementation details');
389
- }
390
- // Base points (title present, valid structure)
391
- const baseScore = 20;
392
- // When any SPEC-784 technical blocker is present, cap the score at 0 so the
393
- // approval gate hard-blocks (score < 70 with no-forceApprove path).
394
- const technicalBlockerCount = warnings.filter((w) => w.startsWith('TECHNICAL_PLACEHOLDER_DETECTED') || w.startsWith('TECHNICAL_TOO_SHALLOW')).length;
395
- if (technicalBlockerCount > 0) {
396
- return { score: 0, warnings, criteriaCount };
397
- }
398
- const score = Math.min(100, baseScore + criteriaScore + technicalScore);
399
- return { score, warnings, criteriaCount };
400
- }
401
338
  export async function checkSpecReadiness(spec, mode, projectHash) {
402
339
  const config = loadReadinessConfig(projectHash);
403
340
  const vagueWords = config.vagueWords.map((v) => v.word);
404
341
  const huRaw = await readHuRaw(spec);
405
342
  const huContent = stripFrontmatter(huRaw);
343
+ const anticipatedTestBreaksContent = extractSectionBody(huRaw, 'Anticipated Test Breaks');
406
344
  const fichaContent = await readFichaContent(spec);
407
345
  const normalizedCriteria = extractNormalizedAcceptanceCriteria(huRaw);
408
346
  const canonicalCriteriaLines = normalizedCriteria.map((criterion) => criterion.text);
@@ -414,6 +352,7 @@ export async function checkSpecReadiness(spec, mode, projectHash) {
414
352
  // evidence model so specificity gates still see exact test paths and line refs.
415
353
  const scenarioCriteria = usesFrontmatterAsCanonical ? frontmatterScenarioCriteria(huRaw) : [];
416
354
  const effectiveCriteriaLines = scenarioCriteria.length > 0 ? scenarioCriteria : canonicalCriteriaLines;
355
+ const specificityEvidenceLines = [...scenarioCriteria, ...extractCriteriaLines(huContent)];
417
356
  const hu = scoreHuCompleteness(spec);
418
357
  const criteria = scoreCriteria(effectiveCriteriaLines, vagueWords);
419
358
  const files = scoreFilesIdentified(spec, fichaContent);
@@ -450,11 +389,11 @@ export async function checkSpecReadiness(spec, mode, projectHash) {
450
389
  }
451
390
  if (detectTechnicalTooShallow(huContent)) {
452
391
  allBlockers.push('TECHNICAL_TOO_SHALLOW: ## Technical section is too short (< 500 chars) and has no ' +
453
- 'src/ or tests/ file paths — add concrete file paths and implementation details');
392
+ 'repository-relative file paths — add concrete file paths and implementation details');
454
393
  }
455
394
  // SPEC-629: Specificity gate caps score at 60 for difficulty >= 3 specs that lack
456
395
  // concrete file paths, function names, or anticipated test breaks.
457
- const specificityBlockers = checkSpecificityGate(spec, effectiveCriteriaLines, fichaContent);
396
+ const specificityBlockers = checkSpecificityGate(spec, specificityEvidenceLines, fichaContent, anticipatedTestBreaksContent);
458
397
  allBlockers.push(...specificityBlockers);
459
398
  const effectiveScore = specificityBlockers.length > 0 && spec.difficulty >= 3 ? Math.min(totalScore, 60) : totalScore;
460
399
  const breakdown = {
@@ -481,7 +420,7 @@ export async function checkSpecReadiness(spec, mode, projectHash) {
481
420
  const isReady = effectiveScore >= cautionThreshold && allBlockers.length === 0;
482
421
  const recommendations = buildRecommendations(effectiveScore, hu.points, criteria.points, files.points, deps.points);
483
422
  if (specificityBlockers.length > 0) {
484
- recommendations.push('Add exact file paths (src/ or tests/), function names (e.g. createFoo()), and anticipated test breaks to unlock implementation for this difficulty spec.');
423
+ recommendations.push('Add exact repository-relative file paths, function names (e.g. createFoo()), and anticipated test breaks to unlock implementation for this difficulty spec.');
485
424
  }
486
425
  return {
487
426
  specId: spec.id,
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
+ import { shouldIgnoreDir } from './walk-ignore.js';
3
4
  const ROUTE_PATTERNS = [
4
5
  // Express/Koa/Hono: app.get('/path', handler) or router.post(...)
5
6
  {
@@ -69,18 +70,6 @@ const SOURCE_EXTENSIONS = new Set([
69
70
  '.kt',
70
71
  '.rb',
71
72
  ]);
72
- const IGNORE_DIRS = new Set([
73
- 'node_modules',
74
- '.git',
75
- 'dist',
76
- 'build',
77
- 'out',
78
- '.next',
79
- '.nuxt',
80
- 'coverage',
81
- 'vendor',
82
- '__pycache__',
83
- ]);
84
73
  function collectSourceFiles(dir) {
85
74
  const results = [];
86
75
  const queue = [dir];
@@ -97,7 +86,7 @@ function collectSourceFiles(dir) {
97
86
  continue;
98
87
  }
99
88
  for (const entry of entries) {
100
- if (IGNORE_DIRS.has(entry.name)) {
89
+ if (shouldIgnoreDir(entry.name)) {
101
90
  continue;
102
91
  }
103
92
  const full = path.join(current, entry.name);
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
+ import { shouldIgnoreDir } from './walk-ignore.js';
3
4
  const SOURCE_EXTENSIONS = new Set([
4
5
  '.ts',
5
6
  '.tsx',
@@ -14,18 +15,6 @@ const SOURCE_EXTENSIONS = new Set([
14
15
  '.rs',
15
16
  '.rb',
16
17
  ]);
17
- const IGNORE_DIRS = new Set([
18
- 'node_modules',
19
- '.git',
20
- 'dist',
21
- 'build',
22
- 'out',
23
- '.next',
24
- '.nuxt',
25
- 'coverage',
26
- 'vendor',
27
- '__pycache__',
28
- ]);
29
18
  // Patterns that increase cyclomatic complexity
30
19
  const BRANCH_PATTERNS = [
31
20
  /\bif\s*\(/g,
@@ -73,7 +62,7 @@ function collectSourceFiles(dir) {
73
62
  continue;
74
63
  }
75
64
  for (const entry of entries) {
76
- if (IGNORE_DIRS.has(entry.name)) {
65
+ if (shouldIgnoreDir(entry.name)) {
77
66
  continue;
78
67
  }
79
68
  const full = path.join(current, entry.name);
@@ -1,6 +1,7 @@
1
1
  import { technologyValue } from '../technology-registry.js';
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
+ import { shouldIgnoreDir } from './walk-ignore.js';
4
5
  const ENV_VAR_PATTERNS = [
5
6
  // JS/TS: process.env.VAR_NAME
6
7
  /process\.env\.([A-Z_][A-Z0-9_]*)/g,
@@ -55,18 +56,6 @@ const INFRA_INDICATORS = {
55
56
  'azure-pipelines.yml': 'Azure Pipelines',
56
57
  'cloudbuild.yaml': 'Google Cloud Build',
57
58
  };
58
- const IGNORE_DIRS = new Set([
59
- 'node_modules',
60
- '.git',
61
- 'dist',
62
- 'build',
63
- 'out',
64
- '.next',
65
- '.nuxt',
66
- 'coverage',
67
- 'vendor',
68
- '__pycache__',
69
- ]);
70
59
  const SOURCE_EXTENSIONS = new Set([
71
60
  '.ts',
72
61
  '.tsx',
@@ -97,7 +86,7 @@ function collectAllFiles(dir) {
97
86
  continue;
98
87
  }
99
88
  for (const entry of entries) {
100
- if (IGNORE_DIRS.has(entry.name)) {
89
+ if (shouldIgnoreDir(entry.name)) {
101
90
  continue;
102
91
  }
103
92
  const full = path.join(current, entry.name);
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
+ import { shouldIgnoreDir } from './walk-ignore.js';
3
4
  const IMPORT_PATTERNS = [
4
5
  // ES import: import ... from './foo'
5
6
  /(?:import\s+(?:[\s\S]*?)\s+from\s+['"]([^'"]+)['"])/g,
@@ -22,18 +23,6 @@ const SOURCE_EXTENSIONS = new Set([
22
23
  '.rs',
23
24
  '.rb',
24
25
  ]);
25
- const IGNORE_DIRS = new Set([
26
- 'node_modules',
27
- '.git',
28
- 'dist',
29
- 'build',
30
- 'out',
31
- '.next',
32
- '.nuxt',
33
- 'coverage',
34
- 'vendor',
35
- '__pycache__',
36
- ]);
37
26
  const HUB_THRESHOLD = 10;
38
27
  function collectSourceFiles(dir) {
39
28
  const results = [];
@@ -51,7 +40,7 @@ function collectSourceFiles(dir) {
51
40
  continue;
52
41
  }
53
42
  for (const entry of entries) {
54
- if (IGNORE_DIRS.has(entry.name)) {
43
+ if (shouldIgnoreDir(entry.name)) {
55
44
  continue;
56
45
  }
57
46
  const full = path.join(current, entry.name);
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
+ import { shouldIgnoreDir } from './walk-ignore.js';
3
4
  const TEST_PATTERNS = [
4
5
  /\.test\.\w+$/,
5
6
  /\.spec\.\w+$/,
@@ -25,18 +26,6 @@ const SOURCE_EXTENSIONS = new Set([
25
26
  '.c',
26
27
  '.swift',
27
28
  ]);
28
- const IGNORE_DIRS = new Set([
29
- 'node_modules',
30
- '.git',
31
- 'dist',
32
- 'build',
33
- 'out',
34
- '.next',
35
- '.nuxt',
36
- 'coverage',
37
- 'vendor',
38
- '__pycache__',
39
- ]);
40
29
  export function isTestFile(filePath) {
41
30
  const basename = path.basename(filePath);
42
31
  if (TEST_PATTERNS.some((p) => p.test(basename))) {
@@ -61,7 +50,7 @@ function collectFiles(dir) {
61
50
  continue;
62
51
  }
63
52
  for (const entry of entries) {
64
- if (IGNORE_DIRS.has(entry.name)) {
53
+ if (shouldIgnoreDir(entry.name)) {
65
54
  continue;
66
55
  }
67
56
  const full = path.join(current, entry.name);
@@ -0,0 +1,3 @@
1
+ export declare const WALK_IGNORE_DIRS: ReadonlySet<string>;
2
+ export declare function shouldIgnoreDir(name: string): boolean;
3
+ //# sourceMappingURL=walk-ignore.d.ts.map
@@ -0,0 +1,26 @@
1
+ // engine/reverse-engineer/walk-ignore.ts — shared directory-walk ignore list
2
+ // Consumed by all reverse-engineer analyzers (dependency-graph, test-analyzer,
3
+ // api-detector, config-analyzer, complexity-analyzer) so the ignore rules stay
4
+ // in one place instead of five duplicated copies.
5
+ export const WALK_IGNORE_DIRS = new Set([
6
+ 'node_modules',
7
+ '.git',
8
+ 'dist',
9
+ 'build',
10
+ 'out',
11
+ '.next',
12
+ '.nuxt',
13
+ 'coverage',
14
+ 'vendor',
15
+ '__pycache__',
16
+ '.worktrees',
17
+ '.claude',
18
+ 'planu',
19
+ 'website',
20
+ 'data',
21
+ 'benchmarks',
22
+ ]);
23
+ export function shouldIgnoreDir(name) {
24
+ return WALK_IGNORE_DIRS.has(name);
25
+ }
26
+ //# sourceMappingURL=walk-ignore.js.map
@@ -1,4 +1,6 @@
1
1
  import type { BoundedDurationPolicy, RuntimePolicy } from '../types/runtime-policy.js';
2
+ /** Validate an in-memory policy fixture without mutating the process cache. */
3
+ export declare function parseRuntimePolicyForTests(raw: unknown): RuntimePolicy;
2
4
  /** Load the validated bundled runtime authority once per process. */
3
5
  export declare function getRuntimePolicy(): RuntimePolicy;
4
6
  /** Resolve a numeric environment override without duplicating policy bounds. */
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { createRequire } from 'node:module';
3
+ import { PROCESS_TERMINATION_GRACE_MS } from './abortable-process-runner.js';
3
4
  const boundedDurationSchema = z
4
5
  .object({
5
6
  defaultTimeoutMs: z.number().int().positive(),
@@ -45,11 +46,22 @@ const runtimePolicySchema = z
45
46
  validation: z
46
47
  .object({
47
48
  defaultDeadlineMs: z.number().int().positive(),
49
+ durableLintTimeoutMs: z.number().int().positive(),
50
+ complianceCommandTimeoutMs: z.number().int().positive(),
51
+ noProgressTimeoutMs: z.number().int().positive(),
48
52
  submissionLockWaitMs: z.number().int().positive(),
49
53
  submissionLockPollMs: z.number().int().positive(),
50
54
  workerLeaseMs: z.number().int().positive(),
51
55
  workerHeartbeatMs: z.number().int().positive(),
52
56
  workerConcurrency: z.number().int().positive(),
57
+ heartbeatStartupTimeoutMs: z.number().int().positive(),
58
+ heartbeatShutdownTimeoutMs: z.number().int().positive(),
59
+ heartbeatDatabaseBusyTimeoutMs: z.number().int().positive(),
60
+ freshnessLeaseTtlMs: z.number().int().positive(),
61
+ freshnessInvalidationCoalesceMs: z.number().int().positive(),
62
+ receiptPublicationDeadlineMs: z.number().int().positive(),
63
+ receiptCheckpointLogMaxBytes: z.number().int().positive(),
64
+ receiptCheckpointResultMaxBytes: z.number().int().positive(),
53
65
  })
54
66
  .strict()
55
67
  .refine((value) => value.submissionLockPollMs < value.submissionLockWaitMs, {
@@ -57,6 +69,27 @@ const runtimePolicySchema = z
57
69
  })
58
70
  .refine((value) => value.workerHeartbeatMs < value.workerLeaseMs, {
59
71
  message: 'workerHeartbeatMs must be below workerLeaseMs',
72
+ })
73
+ .refine((value) => value.durableLintTimeoutMs < value.complianceCommandTimeoutMs, {
74
+ message: 'durableLintTimeoutMs must be below complianceCommandTimeoutMs',
75
+ })
76
+ .refine((value) => value.complianceCommandTimeoutMs + PROCESS_TERMINATION_GRACE_MS <
77
+ value.noProgressTimeoutMs, {
78
+ message: 'complianceCommandTimeoutMs plus termination grace must be below noProgressTimeoutMs',
79
+ })
80
+ .refine((value) => value.complianceCommandTimeoutMs < value.defaultDeadlineMs, {
81
+ message: 'complianceCommandTimeoutMs must be below defaultDeadlineMs',
82
+ })
83
+ .refine((value) => value.noProgressTimeoutMs < value.defaultDeadlineMs, {
84
+ message: 'noProgressTimeoutMs must be below defaultDeadlineMs',
85
+ })
86
+ .refine((value) => value.heartbeatDatabaseBusyTimeoutMs < value.workerLeaseMs - value.workerHeartbeatMs, { message: 'heartbeatDatabaseBusyTimeoutMs must fit within the worker lease' })
87
+ .refine((value) => value.freshnessInvalidationCoalesceMs < value.freshnessLeaseTtlMs, {
88
+ message: 'freshnessInvalidationCoalesceMs must be below freshnessLeaseTtlMs',
89
+ })
90
+ .refine((value) => value.receiptPublicationDeadlineMs <= value.workerLeaseMs - value.workerHeartbeatMs, { message: 'receiptPublicationDeadlineMs must fit within the worker lease' })
91
+ .refine((value) => value.receiptCheckpointLogMaxBytes <= value.receiptCheckpointResultMaxBytes, {
92
+ message: 'receiptCheckpointLogMaxBytes must not exceed receiptCheckpointResultMaxBytes',
60
93
  }),
61
94
  postCommit: z
62
95
  .object({
@@ -71,15 +104,19 @@ const runtimePolicySchema = z
71
104
  .strict();
72
105
  const require = createRequire(import.meta.url);
73
106
  let cachedPolicy;
107
+ /** Validate an in-memory policy fixture without mutating the process cache. */
108
+ export function parseRuntimePolicyForTests(raw) {
109
+ const parsed = runtimePolicySchema.safeParse(raw);
110
+ if (!parsed.success) {
111
+ throw new Error(`Invalid bundled runtime-policy config: ${parsed.error.message}`);
112
+ }
113
+ return parsed.data;
114
+ }
74
115
  /** Load the validated bundled runtime authority once per process. */
75
116
  export function getRuntimePolicy() {
76
117
  if (cachedPolicy === undefined) {
77
118
  const raw = require('../config/runtime-policy.json');
78
- const parsed = runtimePolicySchema.safeParse(raw);
79
- if (!parsed.success) {
80
- throw new Error(`Invalid bundled runtime-policy config: ${parsed.error.message}`);
81
- }
82
- cachedPolicy = parsed.data;
119
+ cachedPolicy = parseRuntimePolicyForTests(raw);
83
120
  }
84
121
  return cachedPolicy;
85
122
  }
@@ -10,7 +10,6 @@ const READ_TOOLS = new Set([
10
10
  'estimate',
11
11
  'semantic_search',
12
12
  'list_groups',
13
- 'license_status',
14
13
  'usage_stats',
15
14
  'usage_report',
16
15
  'spec_history',
@@ -0,0 +1,3 @@
1
+ /** Resolve a currently existing regular file whose physical path is contained by a project root. */
2
+ export declare function resolveContainedProjectFile(projectPath: string, candidatePath: string): Promise<string>;
3
+ //# sourceMappingURL=contained-project-file.d.ts.map
@@ -0,0 +1,23 @@
1
+ import { lstat, realpath } from 'node:fs/promises';
2
+ import { isAbsolute, relative, resolve, sep } from 'node:path';
3
+ function isOutside(root, candidate) {
4
+ const pathFromRoot = relative(root, candidate);
5
+ return pathFromRoot === '..' || pathFromRoot.startsWith(`..${sep}`) || isAbsolute(pathFromRoot);
6
+ }
7
+ /** Resolve a currently existing regular file whose physical path is contained by a project root. */
8
+ export async function resolveContainedProjectFile(projectPath, candidatePath) {
9
+ const lexicalRoot = resolve(projectPath);
10
+ const lexicalCandidate = resolve(candidatePath);
11
+ const [projectRealPath, candidateRealPath, candidateStatus] = await Promise.all([
12
+ realpath(lexicalRoot),
13
+ realpath(lexicalCandidate),
14
+ lstat(lexicalCandidate),
15
+ ]);
16
+ if (candidateStatus.isSymbolicLink() ||
17
+ !candidateStatus.isFile() ||
18
+ isOutside(projectRealPath, candidateRealPath)) {
19
+ throw new Error('CONTAINED_PROJECT_FILE_REJECTED: candidate is not a contained regular file');
20
+ }
21
+ return candidateRealPath;
22
+ }
23
+ //# sourceMappingURL=contained-project-file.js.map
@@ -43,6 +43,58 @@ function keywords(phrase) {
43
43
  .split(' ')
44
44
  .filter((w) => w.length > 3 && !STOP_WORDS.has(w));
45
45
  }
46
+ /** Return true only for explicit language that preserves an existing boundary. */
47
+ function preservesBoundary(text) {
48
+ const normalized = normalize(text);
49
+ return [
50
+ /\bremains? unchanged\b/,
51
+ /\bkeeps?\b.{0,80}\bunchanged\b/,
52
+ /\bpreserves?\b.{0,80}\b(?:behavior|contract|boundary|semantics|state)\b/,
53
+ /\bwithout (?:any )?(?:changing|modifying|altering|adding|introducing)\b/,
54
+ /\b(?:does|do|must|will|should) not (?:change|modify|alter|add|introduce|implement|enable)\b/,
55
+ /\bno changes? to\b/,
56
+ ].some((pattern) => pattern.test(normalized));
57
+ }
58
+ function splitClauses(text) {
59
+ return text
60
+ .split(/\b(?:but|while|although|however)\b|[,;.]/i)
61
+ .map((clause) => clause.trim())
62
+ .filter(Boolean);
63
+ }
64
+ function hasAffirmativeDrift(text, outOfScopeItem) {
65
+ const action = /\b(?:changes?|modif(?:y|ies)|alters?|adds?|introduces?|implements?|enables?)\b/g;
66
+ const actionSegments = text.split(/\band\b/i).map(normalize);
67
+ for (const [index, segment] of actionSegments.entries()) {
68
+ const inheritsRelevantSubject = index > 0 &&
69
+ /^(?:changes?|modif(?:y|ies)|alters?|adds?|introduces?|implements?|enables?)\b/.test(segment) &&
70
+ clauseMatchesScope(actionSegments[index - 1] ?? '', outOfScopeItem);
71
+ for (const match of segment.matchAll(action)) {
72
+ const before = segment.slice(Math.max(0, match.index - 24), match.index);
73
+ const after = segment.slice(match.index + match[0].length);
74
+ if (/\b(?:not|without|no)\s*$/.test(before)) {
75
+ continue;
76
+ }
77
+ if (/^\s+remains? unchanged\b/.test(after)) {
78
+ continue;
79
+ }
80
+ if (inheritsRelevantSubject || clauseMatchesScope(segment, outOfScopeItem)) {
81
+ return true;
82
+ }
83
+ }
84
+ }
85
+ return false;
86
+ }
87
+ function clauseMatchesScope(clause, outOfScopeItem) {
88
+ const normalizedClause = normalize(clause);
89
+ const normalizedScope = normalize(outOfScopeItem);
90
+ if (normalizedClause.includes(normalizedScope) || normalizedScope.includes(normalizedClause)) {
91
+ return true;
92
+ }
93
+ const scopeKeywords = keywords(outOfScopeItem);
94
+ const matchCount = scopeKeywords.filter((keyword) => normalizedClause.includes(keyword)).length;
95
+ const threshold = scopeKeywords.length <= 2 ? scopeKeywords.length : 2;
96
+ return scopeKeywords.length > 0 && matchCount >= threshold;
97
+ }
46
98
  /**
47
99
  * Determine whether a criterion text contradicts an out-of-scope item.
48
100
  * Uses substring match first, then keyword overlap as fuzzy fallback.
@@ -50,6 +102,13 @@ function keywords(phrase) {
50
102
  function contradicts(criterionText, outOfScopeItem) {
51
103
  const normCriterion = normalize(criterionText);
52
104
  const normScope = normalize(outOfScopeItem);
105
+ const relevantClauses = splitClauses(criterionText).filter((clause) => clauseMatchesScope(clause, outOfScopeItem));
106
+ const hasConditionalException = /\b(?:unless|except)\b/i.test(criterionText);
107
+ if (!hasConditionalException &&
108
+ relevantClauses.length > 0 &&
109
+ relevantClauses.every((clause) => preservesBoundary(clause) && !hasAffirmativeDrift(clause, outOfScopeItem))) {
110
+ return false;
111
+ }
53
112
  // 1. Direct substring match
54
113
  if (normCriterion.includes(normScope)) {
55
114
  return true;
@@ -74,9 +133,12 @@ function contradicts(criterionText, outOfScopeItem) {
74
133
  */
75
134
  export function checkContradictions(outOfScope, criteria) {
76
135
  const contradictions = [];
136
+ const seenPairs = new Set();
77
137
  for (const criterion of criteria) {
78
138
  for (const scopeItem of outOfScope) {
79
- if (contradicts(criterion, scopeItem)) {
139
+ const pairKey = `${normalize(criterion)}\u0000${normalize(scopeItem)}`;
140
+ if (!seenPairs.has(pairKey) && contradicts(criterion, scopeItem)) {
141
+ seenPairs.add(pairKey);
80
142
  contradictions.push({ criterion, contradicts: scopeItem });
81
143
  }
82
144
  }