@planu/cli 4.12.3 → 4.14.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 (787) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +29 -25
  3. package/dist/cli/commands/inspect.d.ts +4 -0
  4. package/dist/cli/commands/inspect.js +144 -0
  5. package/dist/cli/commands/install.d.ts +19 -1
  6. package/dist/cli/commands/install.js +145 -43
  7. package/dist/cli/commands/job.d.ts +3 -0
  8. package/dist/cli/commands/job.js +119 -0
  9. package/dist/cli/commands/offline.d.ts +15 -0
  10. package/dist/cli/commands/offline.js +132 -0
  11. package/dist/cli/commands/serve.js +4 -0
  12. package/dist/cli/commands/spec.js +1 -1
  13. package/dist/cli/commands/storage.d.ts +3 -0
  14. package/dist/cli/commands/storage.js +102 -0
  15. package/dist/cli/commands/uninstall.d.ts +10 -0
  16. package/dist/cli/commands/uninstall.js +93 -7
  17. package/dist/cli/commands/validate.js +1 -1
  18. package/dist/cli/index.js +2 -0
  19. package/dist/cli/router.js +9 -1
  20. package/dist/config/crash-shield-framework-rules.json +93 -0
  21. package/dist/config/environment-schema.json +149 -0
  22. package/dist/config/hardcode-exceptions.json +4 -0
  23. package/dist/config/license-plans.json +7 -0
  24. package/dist/config/native-release-public-key.pem +3 -0
  25. package/dist/config/native-targets.json +87 -0
  26. package/dist/config/product-public.d.ts +89 -0
  27. package/dist/config/product-public.js +140 -0
  28. package/dist/config/product-public.json +312 -0
  29. package/dist/config/product-public.ts +148 -0
  30. package/dist/config/release-compatibility.json +13 -0
  31. package/dist/config/release-policy.json +26 -0
  32. package/dist/config/runtime-policy.json +44 -0
  33. package/dist/config/skill-templates/planu-validate.md +7 -4
  34. package/dist/config/subagent-templates/planu-spec-implementer.md +7 -3
  35. package/dist/config/subagent-templates/planu-validator.md +10 -5
  36. package/dist/config/technology-registry.json +120 -0
  37. package/dist/config/version.js +7 -8
  38. package/dist/config/version.ts +10 -7
  39. package/dist/engine/abortable-process-runner.js +40 -9
  40. package/dist/engine/advanced-testing/accessibility-checker.js +12 -14
  41. package/dist/engine/advanced-testing/mutation-advisor.js +3 -4
  42. package/dist/engine/advanced-testing/property-based.js +2 -3
  43. package/dist/engine/advanced-testing/test-data-advisor.js +2 -3
  44. package/dist/engine/agent-generator.js +2 -1
  45. package/dist/engine/agent-handoff-store.js +2 -1
  46. package/dist/engine/agent-prompt-generator.js +7 -5
  47. package/dist/engine/agent-telemetry.js +2 -1
  48. package/dist/engine/ai-integration/gemini/extensions-advisor.js +41 -9
  49. package/dist/engine/ambiguity-detector.js +12 -11
  50. package/dist/engine/analyzer/db-engine.js +2 -3
  51. package/dist/engine/analyzer/detectors.js +13 -14
  52. package/dist/engine/analyzer/env-setup.js +9 -10
  53. package/dist/engine/analyzer-env-scanner/env-example.js +7 -8
  54. package/dist/engine/api-spec-generator/graphql-parser.js +2 -2
  55. package/dist/engine/api-validation/graphql-schema-validator.js +2 -1
  56. package/dist/engine/api-validation/openapi-impl-validator.js +6 -7
  57. package/dist/engine/architecture-detector.js +10 -8
  58. package/dist/engine/auth/config.d.ts +1 -1
  59. package/dist/engine/auth/config.js +4 -3
  60. package/dist/engine/auto-updater/atomic-upgrade.d.ts +8 -0
  61. package/dist/engine/auto-updater/atomic-upgrade.js +381 -0
  62. package/dist/engine/auto-updater/config-detector.js +9 -3
  63. package/dist/engine/auto-updater/config-patcher.d.ts +0 -4
  64. package/dist/engine/auto-updater/config-patcher.js +10 -15
  65. package/dist/engine/auto-updater/index.d.ts +3 -1
  66. package/dist/engine/auto-updater/index.js +44 -30
  67. package/dist/engine/auto-updater/npm-registry.js +10 -2
  68. package/dist/engine/auto-updater/release-verifier.d.ts +3 -0
  69. package/dist/engine/auto-updater/release-verifier.js +112 -0
  70. package/dist/engine/auto-updater/upgrade-lock.d.ts +6 -0
  71. package/dist/engine/auto-updater/upgrade-lock.js +28 -0
  72. package/dist/engine/auto-updater/upgrade-trust-state.d.ts +7 -0
  73. package/dist/engine/auto-updater/upgrade-trust-state.js +59 -0
  74. package/dist/engine/autopilot/audit-logger.js +2 -5
  75. package/dist/engine/best-practices-library.js +2 -1
  76. package/dist/engine/browser-validator.js +2 -1
  77. package/dist/engine/build-tool-detector.js +3 -2
  78. package/dist/engine/ci-generator/context-builders.js +7 -5
  79. package/dist/engine/ci-generator/stack-detector.js +0 -2
  80. package/dist/engine/ci-generator/yaml-builder.js +0 -2
  81. package/dist/engine/claude-config-auditor/rules-auditor.js +4 -3
  82. package/dist/engine/code-transforms/typescript/ast-utils.js +2 -3
  83. package/dist/engine/complexity-budget/trivial-detector.js +2 -1
  84. package/dist/engine/compliance-test-generator/index.js +7 -2
  85. package/dist/engine/compliance-test-generator/test-formatter.js +2 -2
  86. package/dist/engine/config-health/mcp-config-checker.js +2 -1
  87. package/dist/engine/config-health/ts-checker-scripts.js +4 -3
  88. package/dist/engine/config-health/ts-checker.js +3 -2
  89. package/dist/engine/convention-injector.js +5 -7
  90. package/dist/engine/convention-scanner/convention-parser.js +3 -2
  91. package/dist/engine/core-bridge-duplicate-blocks.d.ts +3 -0
  92. package/dist/engine/core-bridge-duplicate-blocks.js +57 -0
  93. package/dist/engine/core-bridge-gaps.d.ts +4 -0
  94. package/dist/engine/core-bridge-gaps.js +75 -0
  95. package/dist/engine/core-bridge.d.ts +9 -9
  96. package/dist/engine/core-bridge.js +196 -283
  97. package/dist/engine/cost-tracking/ledger.js +2 -5
  98. package/dist/engine/coverage-gap-analyzer.js +10 -1
  99. package/dist/engine/crash-shield/detectors/framework-detector.d.ts +2 -0
  100. package/dist/engine/crash-shield/detectors/framework-detector.js +110 -192
  101. package/dist/engine/crash-shield/detectors/typescript-detector.js +2 -1
  102. package/dist/engine/dashboard/data-loader.js +2 -1
  103. package/dist/engine/data-projects-gc/gc-runner.d.ts +7 -0
  104. package/dist/engine/data-projects-gc/gc-runner.js +113 -3
  105. package/dist/engine/data-projects-gc/scanner.js +5 -1
  106. package/dist/engine/decision-store.js +11 -14
  107. package/dist/engine/deleter/core.js +5 -5
  108. package/dist/engine/dep-auditor/abandonment-data.js +2 -1
  109. package/dist/engine/dep-auditor/abandonment-registry.js +3 -1
  110. package/dist/engine/dep-auditor/cve-fetcher.js +3 -0
  111. package/dist/engine/dep-auditor/dep-duplicates-detector.js +36 -4
  112. package/dist/engine/dep-auditor/license-registry.js +2 -0
  113. package/dist/engine/dependency-evaluator.d.ts +14 -0
  114. package/dist/engine/dependency-evaluator.js +81 -0
  115. package/dist/engine/deploy/providers/fly.js +7 -7
  116. package/dist/engine/deploy/providers/netlify.js +7 -7
  117. package/dist/engine/deploy/providers/railway.js +10 -12
  118. package/dist/engine/deploy/providers/vercel.js +7 -9
  119. package/dist/engine/deprecation-scanner/pattern-loader.js +0 -2
  120. package/dist/engine/desktop-detector.js +2 -3
  121. package/dist/engine/detect-duplication.js +2 -1
  122. package/dist/engine/detectors/advanced-framework-detector/css-state-detector.js +2 -1
  123. package/dist/engine/detectors/advanced-framework-detector/legacy-detector.js +2 -3
  124. package/dist/engine/detectors/advanced-framework-detector/modern-detector.js +3 -4
  125. package/dist/engine/detectors/agent-framework-detector.js +3 -2
  126. package/dist/engine/detectors/ai-native-detector.js +4 -6
  127. package/dist/engine/detectors/cache-db-detector.js +4 -3
  128. package/dist/engine/detectors/cicd-detector.js +4 -3
  129. package/dist/engine/detectors/deployment-detector.js +11 -12
  130. package/dist/engine/detectors/frontend-perf-detector.js +14 -9
  131. package/dist/engine/detectors/library-detector-multilang-a.js +16 -3
  132. package/dist/engine/detectors/library-detector-node.js +14 -4
  133. package/dist/engine/detectors/library-detector-python.js +7 -1
  134. package/dist/engine/detectors/library-detector.js +0 -2
  135. package/dist/engine/detectors/llm-detector/provider-maps.js +3 -2
  136. package/dist/engine/detectors/mcp-candidate-detector.js +12 -16
  137. package/dist/engine/detectors/mfe-detector.js +6 -7
  138. package/dist/engine/detectors/monitoring-detector.js +4 -3
  139. package/dist/engine/detectors/otel-detector.js +3 -2
  140. package/dist/engine/detectors/otel-ecosystem-detectors.d.ts +2 -2
  141. package/dist/engine/detectors/otel-ecosystem-detectors.js +4 -3
  142. package/dist/engine/detectors/platform-specialty-detector.js +3 -5
  143. package/dist/engine/detectors/template-engine-detector.js +3 -4
  144. package/dist/engine/doc-generator/builders.js +2 -3
  145. package/dist/engine/doc-generator/mobile-distribution-guide.js +13 -17
  146. package/dist/engine/doc-generator/portal/dirty-flag-map.d.ts +2 -2
  147. package/dist/engine/doc-generator/portal/portal-regenerator.js +3 -47
  148. package/dist/engine/domain-detector.js +3 -6
  149. package/dist/engine/dynamic-knowledge/knowledge-cache.js +3 -4
  150. package/dist/engine/dynamic-knowledge/knowledge-merger.js +17 -2
  151. package/dist/engine/dynamic-knowledge/web-researcher.js +15 -14
  152. package/dist/engine/dynamic-migration-detector/manifest-readers-extended.js +0 -2
  153. package/dist/engine/e2e-test-generator.js +4 -3
  154. package/dist/engine/ecosystem-absorber/knowledge-cache.js +2 -1
  155. package/dist/engine/ecosystem-absorber/platform-crawler.js +2 -2
  156. package/dist/engine/escalator/retry-counter.js +2 -1
  157. package/dist/engine/evidence-gates/artifact-reader.d.ts +6 -0
  158. package/dist/engine/evidence-gates/artifact-reader.js +105 -21
  159. package/dist/engine/evidence-gates/lifecycle-gate.d.ts +2 -1
  160. package/dist/engine/evidence-gates/lifecycle-gate.js +54 -0
  161. package/dist/engine/execution/context.d.ts +19 -0
  162. package/dist/engine/execution/context.js +127 -0
  163. package/dist/engine/execution/deadline-io.d.ts +21 -0
  164. package/dist/engine/execution/deadline-io.js +45 -0
  165. package/dist/engine/execution/job-executor.d.ts +16 -0
  166. package/dist/engine/execution/job-executor.js +140 -0
  167. package/dist/engine/execution/job-runtime.d.ts +78 -0
  168. package/dist/engine/execution/job-runtime.js +220 -0
  169. package/dist/engine/execution/native-relevance-scorer.d.ts +6 -0
  170. package/dist/engine/execution/native-relevance-scorer.js +64 -0
  171. package/dist/engine/execution/native-worker-dispatch.d.ts +3 -0
  172. package/dist/engine/execution/native-worker-dispatch.js +46 -0
  173. package/dist/engine/execution/native-worker-protocol.d.ts +6 -0
  174. package/dist/engine/execution/native-worker-protocol.js +33 -0
  175. package/dist/engine/execution/native-worker-runtime.d.ts +4 -0
  176. package/dist/engine/execution/native-worker-runtime.js +177 -0
  177. package/dist/engine/execution/native-worker-thread.d.ts +2 -0
  178. package/dist/engine/execution/native-worker-thread.js +66 -0
  179. package/dist/engine/execution/operation-journal.d.ts +66 -0
  180. package/dist/engine/execution/operation-journal.js +260 -0
  181. package/dist/engine/execution/outbox-worker.d.ts +31 -0
  182. package/dist/engine/execution/outbox-worker.js +192 -0
  183. package/dist/engine/execution/validate-job-executor.d.ts +24 -0
  184. package/dist/engine/execution/validate-job-executor.js +342 -0
  185. package/dist/engine/execution/validate-job-payload.d.ts +5 -0
  186. package/dist/engine/execution/validate-job-payload.js +87 -0
  187. package/dist/engine/execution/validate-job-recovery.d.ts +4 -0
  188. package/dist/engine/execution/validate-job-recovery.js +47 -0
  189. package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
  190. package/dist/engine/execution/validate-worker-runtime.js +100 -0
  191. package/dist/engine/execution/validate-worker-thread.d.ts +2 -0
  192. package/dist/engine/execution/validate-worker-thread.js +71 -0
  193. package/dist/engine/execution-plan/desktop-distribution.js +3 -7
  194. package/dist/engine/execution-plan/mobile-distribution.js +4 -9
  195. package/dist/engine/execution-plan/phases.js +4 -5
  196. package/dist/engine/execution-plan/plan-utils.js +8 -5
  197. package/dist/engine/facilitate/context-loader.js +3 -9
  198. package/dist/engine/figma/code-connect-fetcher.js +9 -8
  199. package/dist/engine/filesystem-watcher/index.d.ts +3 -3
  200. package/dist/engine/filesystem-watcher/index.js +5 -5
  201. package/dist/engine/framework-detector.js +14 -15
  202. package/dist/engine/git/planu-autocommit.js +8 -7
  203. package/dist/engine/git/repository-probe.d.ts +3 -0
  204. package/dist/engine/git/repository-probe.js +13 -0
  205. package/dist/engine/global-rules-manager.js +2 -2
  206. package/dist/engine/handoff-artifacts/io.js +2 -3
  207. package/dist/engine/handoff-artifacts/schemas/red-tests-handoff.js +8 -1
  208. package/dist/engine/handoff-artifacts/schemas.d.ts +4 -0
  209. package/dist/engine/handoff-artifacts/schemas.js +5 -0
  210. package/dist/engine/hook-generator/stack-hook-templates.js +4 -4
  211. package/dist/engine/hooks/config-loader.js +1 -1
  212. package/dist/engine/hooks/context-injector.js +4 -7
  213. package/dist/engine/hooks/file-watcher.js +1 -14
  214. package/dist/engine/hooks-reconciler.js +6 -4
  215. package/dist/engine/infrastructure/component-mapper.js +5 -7
  216. package/dist/engine/infrastructure/docker-compose-generator.js +8 -10
  217. package/dist/engine/infrastructure/index.js +6 -3
  218. package/dist/engine/infrastructure/kubernetes-generator.js +2 -2
  219. package/dist/engine/infrastructure/railway-generator.js +10 -8
  220. package/dist/engine/infrastructure/signal-detector.js +6 -8
  221. package/dist/engine/infrastructure/terraform-generator.js +6 -8
  222. package/dist/engine/legal-compliance/detector.js +3 -2
  223. package/dist/engine/local-first/storage-advisor.js +5 -6
  224. package/dist/engine/macos-keychain-native-port.d.ts +5 -0
  225. package/dist/engine/macos-keychain-native-port.js +26 -0
  226. package/dist/engine/marketplace-fetcher/cache.js +3 -1
  227. package/dist/engine/mcp-config/mcp-config-writer.d.ts +2 -2
  228. package/dist/engine/mcp-config/mcp-config-writer.js +10 -8
  229. package/dist/engine/migration/db-migrator.js +2 -5
  230. package/dist/engine/migration/equivalence-mapper.js +12 -13
  231. package/dist/engine/migration/service-catalogs.js +6 -7
  232. package/dist/engine/migration/service-migrator-catalogs.js +6 -7
  233. package/dist/engine/mobile-detector-ios.js +2 -3
  234. package/dist/engine/mobile-detector.js +16 -4
  235. package/dist/engine/model-router/complexity-analyzer.js +4 -7
  236. package/dist/engine/multi-agent-review/security-analyzer.js +3 -1
  237. package/dist/engine/multi-app-detector/app-type.js +26 -21
  238. package/dist/engine/multi-app-detector/core.js +3 -2
  239. package/dist/engine/multi-teammate-review/disagreement-counter.js +2 -1
  240. package/dist/engine/multi-teammate-review/panel-orchestrator.js +0 -2
  241. package/dist/engine/mutation-config-generator.js +10 -7
  242. package/dist/engine/native-capability-policy.d.ts +4 -0
  243. package/dist/engine/native-capability-policy.js +24 -0
  244. package/dist/engine/native-platform.d.ts +3 -0
  245. package/dist/engine/native-platform.js +44 -0
  246. package/dist/engine/native-runtime-handshake.d.ts +20 -0
  247. package/dist/engine/native-runtime-handshake.js +230 -0
  248. package/dist/engine/network-policy.d.ts +27 -0
  249. package/dist/engine/network-policy.js +174 -0
  250. package/dist/engine/next-spec-resolver/dependency-filter.js +2 -22
  251. package/dist/engine/nfr-profile-detector.js +12 -16
  252. package/dist/engine/nli-keywords.js +8 -9
  253. package/dist/engine/oauth/config-guard.js +4 -5
  254. package/dist/engine/observability/local-execution-spans.d.ts +15 -0
  255. package/dist/engine/observability/local-execution-spans.js +63 -0
  256. package/dist/engine/orchestrator/runtime.js +0 -1
  257. package/dist/engine/package-registry.js +2 -6
  258. package/dist/engine/performance-analyzer.js +2 -5
  259. package/dist/engine/permissions-merger/stack-detectors.js +5 -5
  260. package/dist/engine/planu-core.darwin-arm64.node.manifest.json +39 -0
  261. package/dist/engine/planu-core.darwin-arm64.node.sbom.json +1310 -0
  262. package/dist/engine/planu-core.darwin-x64.node.manifest.json +39 -0
  263. package/dist/engine/planu-core.darwin-x64.node.sbom.json +1310 -0
  264. package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +38 -0
  265. package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +1310 -0
  266. package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +38 -0
  267. package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +1310 -0
  268. package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +38 -0
  269. package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +1310 -0
  270. package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +38 -0
  271. package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +1310 -0
  272. package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +38 -0
  273. package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +1310 -0
  274. package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +38 -0
  275. package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +1310 -0
  276. package/dist/engine/platform-detector/desktop.js +15 -2
  277. package/dist/engine/platform-detector/extensions.js +2 -1
  278. package/dist/engine/platform-detector/games.js +2 -1
  279. package/dist/engine/platform-detector.js +3 -2
  280. package/dist/engine/platform-engineering/idp-detector.js +2 -1
  281. package/dist/engine/plugin-installer/stack-matcher.js +9 -17
  282. package/dist/engine/plugins/lifecycle.js +6 -2
  283. package/dist/engine/prior-decisions/contradiction-detector.js +60 -30
  284. package/dist/engine/project-dna/stack-detector.js +15 -17
  285. package/dist/engine/project-graph/builder.js +11 -0
  286. package/dist/engine/project-graph/cache.js +1 -1
  287. package/dist/engine/project-graph/freshness-projection.d.ts +16 -0
  288. package/dist/engine/project-graph/freshness-projection.js +95 -0
  289. package/dist/engine/project-graph/index.d.ts +1 -0
  290. package/dist/engine/project-graph/index.js +1 -0
  291. package/dist/engine/project-graph/query.js +15 -25
  292. package/dist/engine/project-health-checker.js +3 -4
  293. package/dist/engine/project-scanner/stack-detector.js +17 -17
  294. package/dist/engine/property-test-generator.js +2 -3
  295. package/dist/engine/qa-gate.d.ts +1 -0
  296. package/dist/engine/qa-gate.js +6 -4
  297. package/dist/engine/quality-gates/gate-catalog.js +47 -46
  298. package/dist/engine/quality-gates/gate-injector.js +9 -4
  299. package/dist/engine/registry/core.js +0 -2
  300. package/dist/engine/registry/loader.js +9 -12
  301. package/dist/engine/registry/matcher.js +129 -24
  302. package/dist/engine/resilience-detector/concurrency-detector.js +4 -4
  303. package/dist/engine/resilience-detector/middleware-detector.js +11 -13
  304. package/dist/engine/resilience-detector/validation-detector.js +17 -4
  305. package/dist/engine/reverse-engineer/config-analyzer.js +9 -8
  306. package/dist/engine/reverse-engineer/orchestrator.js +5 -9
  307. package/dist/engine/reverse-engineer/test-file-parser.js +6 -3
  308. package/dist/engine/rules-generator/index.js +6 -5
  309. package/dist/engine/runtime-policy.d.ts +7 -0
  310. package/dist/engine/runtime-policy.js +101 -0
  311. package/dist/engine/runtime-security/checkers/content-security.js +21 -6
  312. package/dist/engine/runtime-security/checkers/file-permissions.js +0 -2
  313. package/dist/engine/safety/atomic-write-file.js +20 -9
  314. package/dist/engine/safety/atomic-writer.js +10 -3
  315. package/dist/engine/safety/cross-process-lock.d.ts +3 -40
  316. package/dist/engine/safety/cross-process-lock.js +268 -272
  317. package/dist/engine/safety/file-mutex.d.ts +2 -9
  318. package/dist/engine/safety/file-mutex.js +155 -87
  319. package/dist/engine/safety/health-monitor.js +15 -6
  320. package/dist/engine/safety/lock-lease-store.d.ts +79 -0
  321. package/dist/engine/safety/lock-lease-store.js +372 -0
  322. package/dist/engine/safety/lock-scavenger.d.ts +2 -5
  323. package/dist/engine/safety/lock-scavenger.js +158 -76
  324. package/dist/engine/safety/lock-staleness.js +4 -1
  325. package/dist/engine/safety/obsolete-lock-guard.d.ts +8 -0
  326. package/dist/engine/safety/obsolete-lock-guard.js +31 -0
  327. package/dist/engine/safety/transaction.js +3 -3
  328. package/dist/engine/sandbox/index.js +2 -1
  329. package/dist/engine/sandbox/runner-detect.js +3 -2
  330. package/dist/engine/sandbox/runner-docker.js +4 -3
  331. package/dist/engine/scan-project/module-discoverer.js +3 -2
  332. package/dist/engine/schema-generator.js +16 -9
  333. package/dist/engine/security-analyzer/criteria-generator.js +2 -3
  334. package/dist/engine/self-healing/healer.js +4 -4
  335. package/dist/engine/session-safeguard/learnings-buffer.d.ts +1 -2
  336. package/dist/engine/session-safeguard/learnings-buffer.js +42 -65
  337. package/dist/engine/shared-agent-memory.js +66 -74
  338. package/dist/engine/skill-adapter/command-rewriter.js +3 -2
  339. package/dist/engine/skill-adapter/index.js +3 -3
  340. package/dist/engine/skill-adapter/placeholder-map.js +3 -2
  341. package/dist/engine/skill-bootstrap/stack-matcher.js +47 -48
  342. package/dist/engine/skill-generation/stack-content-generator.js +0 -2
  343. package/dist/engine/skill-generator/workflow-skill-generator.js +2 -1
  344. package/dist/engine/skill-registry/ttl-refresh.js +3 -1
  345. package/dist/engine/skills/skills-fetcher.js +3 -6
  346. package/dist/engine/skills-reconciler.js +19 -39
  347. package/dist/engine/spec-coverage/test-finder.js +7 -6
  348. package/dist/engine/spec-diff-engine.js +3 -3
  349. package/dist/engine/spec-generator/api-key-resolver.d.ts +1 -1
  350. package/dist/engine/spec-generator/api-key-resolver.js +3 -24
  351. package/dist/engine/spec-generators/issue-extractor.js +9 -3
  352. package/dist/engine/spec-migrator/drift-detector.js +5 -13
  353. package/dist/engine/spec-migrator/filesystem-import.js +14 -10
  354. package/dist/engine/spec-migrator/planu-canonical-policy.js +10 -1
  355. package/dist/engine/spec-migrator/strict-planu-cleanup.js +24 -25
  356. package/dist/engine/spec-registry/adapter.d.ts +0 -5
  357. package/dist/engine/spec-registry/adapter.js +45 -46
  358. package/dist/engine/spec-registry/client.js +2 -0
  359. package/dist/engine/spec-source-sync.js +3 -2
  360. package/dist/engine/spec-templates/custom-loader.js +2 -3
  361. package/dist/engine/spec-templates/templates-domain-specific.js +8 -5
  362. package/dist/engine/spec-templates/templates-perf-integration.js +2 -3
  363. package/dist/engine/stack-auditor/manifest-reader.js +0 -2
  364. package/dist/engine/staleness/stale-implementing.js +7 -7
  365. package/dist/engine/tdd-scaffold-generator.js +24 -11
  366. package/dist/engine/teammate-router/green-phase-verifier.js +2 -1
  367. package/dist/engine/teammate-router/red-phase-verifier.js +2 -1
  368. package/dist/engine/technology-registry.d.ts +11 -0
  369. package/dist/engine/technology-registry.js +142 -0
  370. package/dist/engine/telemetry/error-reporter.d.ts +1 -2
  371. package/dist/engine/telemetry/error-reporter.js +11 -18
  372. package/dist/engine/telemetry/health-checker.js +5 -14
  373. package/dist/engine/telemetry/index.d.ts +0 -1
  374. package/dist/engine/telemetry/index.js +0 -1
  375. package/dist/engine/telemetry/stance.js +3 -2
  376. package/dist/engine/telemetry/telemetry-client.d.ts +1 -5
  377. package/dist/engine/telemetry/telemetry-client.js +45 -29
  378. package/dist/engine/telemetry/telemetry-store.d.ts +3 -3
  379. package/dist/engine/telemetry/telemetry-store.js +30 -23
  380. package/dist/engine/test-framework-detector/detectors.js +8 -8
  381. package/dist/engine/test-framework-detector/strategy.js +8 -9
  382. package/dist/engine/test-generators/agent-test-templates.js +2 -3
  383. package/dist/engine/test-generators/contract-test-generator.d.ts +1 -1
  384. package/dist/engine/test-generators/contract-test-generator.js +9 -202
  385. package/dist/engine/test-generators/platform-test-templates-b.js +2 -3
  386. package/dist/engine/test-generators/platform-test-templates.js +2 -5
  387. package/dist/engine/test-mocks-generator.js +4 -3
  388. package/dist/engine/test-plan-generator.js +30 -12
  389. package/dist/engine/test-scaffold-generator/advanced-scaffold.js +4 -5
  390. package/dist/engine/test-scaffold-generator/unit-scaffold.js +5 -6
  391. package/dist/engine/timing/budget.d.ts +6 -17
  392. package/dist/engine/timing/budget.js +80 -64
  393. package/dist/engine/tool-groups/group-manager.js +3 -3
  394. package/dist/engine/universal-rules/installer.js +1 -1
  395. package/dist/engine/universal-rules/rules/planu-modes.js +2 -0
  396. package/dist/engine/universal-rules/rules/planu-release-policy.js +1 -0
  397. package/dist/engine/update-notifier.js +8 -5
  398. package/dist/engine/validation/approved-spec-portability.d.ts +12 -0
  399. package/dist/engine/validation/approved-spec-portability.js +107 -0
  400. package/dist/engine/validation/durable-validation.d.ts +36 -0
  401. package/dist/engine/validation/durable-validation.js +335 -0
  402. package/dist/engine/validation/validation-freshness.d.ts +36 -0
  403. package/dist/engine/validation/validation-freshness.js +427 -0
  404. package/dist/engine/validation/validation-receipt-codec.d.ts +13 -0
  405. package/dist/engine/validation/validation-receipt-codec.js +182 -0
  406. package/dist/engine/validation/validation-receipt.d.ts +59 -0
  407. package/dist/engine/validation/validation-receipt.js +282 -0
  408. package/dist/engine/validation/validation-source-policy.d.ts +4 -0
  409. package/dist/engine/validation/validation-source-policy.js +16 -0
  410. package/dist/engine/validation/validation-submission.d.ts +36 -0
  411. package/dist/engine/validation/validation-submission.js +128 -0
  412. package/dist/engine/validation-evidence-ledger.js +41 -0
  413. package/dist/engine/validation-impact-planner.js +25 -9
  414. package/dist/engine/validator/spec-compliance-runner.d.ts +1 -1
  415. package/dist/engine/validator/spec-compliance-runner.js +17 -8
  416. package/dist/engine/validator/validation-report-writer.js +1 -1
  417. package/dist/engine/validator.js +2 -1
  418. package/dist/engine/verify-integrations/index.js +1 -1
  419. package/dist/engine/version-resolver.js +5 -6
  420. package/dist/engine/web-fetcher/stack-advisor.js +156 -92
  421. package/dist/engine/web-fetcher/stack-detector.js +114 -54
  422. package/dist/engine/workspace-manager.js +3 -2
  423. package/dist/errors/classified-degradation.d.ts +3 -0
  424. package/dist/errors/classified-degradation.js +10 -0
  425. package/dist/errors/degradation-sink.d.ts +3 -0
  426. package/dist/errors/degradation-sink.js +5 -0
  427. package/dist/errors/error-taxonomy.d.ts +12 -0
  428. package/dist/errors/error-taxonomy.js +62 -0
  429. package/dist/hosts/claude-code/ux/mcp-prompts.js +10 -4
  430. package/dist/hosts/claude-code/ux/mcp-resources.js +4 -2
  431. package/dist/hosts/codex/config-scaffold.js +4 -3
  432. package/dist/hosts/gemini/config-scaffold.js +2 -1
  433. package/dist/hosts/gemini/multimodal-spec-flow.js +7 -4
  434. package/dist/index.js +21 -6
  435. package/dist/resources/patterns.js +3 -1
  436. package/dist/resources/specs.js +3 -1
  437. package/dist/resources/templates.js +3 -1
  438. package/dist/security/adapters/environment.d.ts +12 -0
  439. package/dist/security/adapters/environment.js +25 -0
  440. package/dist/security/adapters/linux-secret-service.d.ts +8 -0
  441. package/dist/security/adapters/linux-secret-service.js +60 -0
  442. package/dist/security/adapters/macos-keychain.d.ts +18 -0
  443. package/dist/security/adapters/macos-keychain.js +90 -0
  444. package/dist/security/adapters/windows-credential-manager.d.ts +8 -0
  445. package/dist/security/adapters/windows-credential-manager.js +58 -0
  446. package/dist/security/redactor.d.ts +5 -0
  447. package/dist/security/redactor.js +58 -0
  448. package/dist/security/secret-field.d.ts +5 -0
  449. package/dist/security/secret-field.js +17 -0
  450. package/dist/security/secret-migration.d.ts +3 -0
  451. package/dist/security/secret-migration.js +123 -0
  452. package/dist/security/secret-provider.d.ts +23 -0
  453. package/dist/security/secret-provider.js +145 -0
  454. package/dist/security/secure-json.d.ts +3 -0
  455. package/dist/security/secure-json.js +29 -0
  456. package/dist/storage/api-surfaces-store.js +2 -2
  457. package/dist/storage/approval-operation-lock.d.ts +1 -1
  458. package/dist/storage/approval-operation-lock.js +5 -3
  459. package/dist/storage/audit-trail-store.d.ts +1 -1
  460. package/dist/storage/audit-trail-store.js +48 -62
  461. package/dist/storage/autopilot-log-store.js +12 -5
  462. package/dist/storage/base-store.d.ts +8 -8
  463. package/dist/storage/base-store.js +57 -20
  464. package/dist/storage/checkpoint-store.js +5 -2
  465. package/dist/storage/comments-store.js +2 -2
  466. package/dist/storage/compliance-audit-store.js +5 -2
  467. package/dist/storage/compliance-gate-config-store.js +7 -4
  468. package/dist/storage/compliance-store.js +2 -2
  469. package/dist/storage/context-profile-store.js +2 -2
  470. package/dist/storage/crash-shield-store.js +8 -4
  471. package/dist/storage/feedback-store.js +10 -6
  472. package/dist/storage/figma-store.js +8 -4
  473. package/dist/storage/file-mutex.js +9 -1
  474. package/dist/storage/gaps-log.js +7 -4
  475. package/dist/storage/global-projects-store.js +4 -2
  476. package/dist/storage/ideas-store.js +2 -2
  477. package/dist/storage/index.d.ts +5 -0
  478. package/dist/storage/index.js +5 -0
  479. package/dist/storage/knowledge-store/knowledge.js +27 -33
  480. package/dist/storage/lessons-store.js +2 -2
  481. package/dist/storage/license-store.js +13 -41
  482. package/dist/storage/migrations/canonical-storage.d.ts +15 -0
  483. package/dist/storage/migrations/canonical-storage.js +599 -0
  484. package/dist/storage/oauth-store.js +36 -8
  485. package/dist/storage/path-resolver.js +16 -3
  486. package/dist/storage/pr-store.js +2 -2
  487. package/dist/storage/project-drift-store.js +20 -8
  488. package/dist/storage/project-identity.d.ts +32 -0
  489. package/dist/storage/project-identity.js +194 -0
  490. package/dist/storage/project-resolver.js +14 -7
  491. package/dist/storage/release-notes-store.js +2 -6
  492. package/dist/storage/runtime-db.d.ts +186 -0
  493. package/dist/storage/runtime-db.js +1054 -0
  494. package/dist/storage/schema-registry.d.ts +5 -0
  495. package/dist/storage/schema-registry.js +74 -0
  496. package/dist/storage/sentry-store.js +20 -9
  497. package/dist/storage/session-state-store.js +12 -5
  498. package/dist/storage/session-store.js +12 -4
  499. package/dist/storage/skill-registry-storage.d.ts +1 -1
  500. package/dist/storage/skill-registry-storage.js +13 -11
  501. package/dist/storage/slack-store.js +10 -5
  502. package/dist/storage/spec-store.js +31 -24
  503. package/dist/storage/status-store/file-lock.js +31 -9
  504. package/dist/storage/status-store/self-healing.js +10 -5
  505. package/dist/storage/status-store/version-sync.js +8 -6
  506. package/dist/storage/steering-store.js +2 -2
  507. package/dist/storage/storage-bundle.d.ts +5 -0
  508. package/dist/storage/storage-bundle.js +117 -0
  509. package/dist/storage/storage-catalog-validation.d.ts +3 -0
  510. package/dist/storage/storage-catalog-validation.js +20 -0
  511. package/dist/storage/storage-catalog.d.ts +25 -0
  512. package/dist/storage/storage-catalog.js +390 -0
  513. package/dist/storage/storage-layout.d.ts +24 -0
  514. package/dist/storage/storage-layout.js +101 -0
  515. package/dist/storage/storybook-store.js +2 -2
  516. package/dist/storage/supabase-store.js +24 -6
  517. package/dist/storage/tdd-policy-store.js +8 -6
  518. package/dist/storage/tech-debt-store.js +3 -3
  519. package/dist/storage/technology-selection-store.d.ts +1 -1
  520. package/dist/storage/technology-selection-store.js +6 -3
  521. package/dist/storage/token-cache-store.js +3 -3
  522. package/dist/storage/token-ledger-store.js +13 -8
  523. package/dist/storage/transition-log.js +7 -4
  524. package/dist/storage/trash-store.js +15 -6
  525. package/dist/storage/vector-store/migrator.js +7 -2
  526. package/dist/storage/vector-store/sqlite-adapter.js +4 -1
  527. package/dist/storage/webhook-server-store.js +2 -2
  528. package/dist/tools/api-spec-generator-handler.js +3 -2
  529. package/dist/tools/auto-update-handler.d.ts +1 -1
  530. package/dist/tools/auto-update-handler.js +1 -1
  531. package/dist/tools/browser-validate-handler.js +2 -1
  532. package/dist/tools/challenge-spec/platform-challenge-scenarios-b.js +8 -5
  533. package/dist/tools/challenge-spec/scenarios-desktop.js +8 -3
  534. package/dist/tools/challenge-spec/scenarios-failure.js +7 -2
  535. package/dist/tools/challenge-spec/security-challenge-scenarios.js +3 -3
  536. package/dist/tools/clarify-requirements/multiple-choice.js +53 -41
  537. package/dist/tools/comments-handler.js +2 -3
  538. package/dist/tools/compliance-test-handler.js +2 -2
  539. package/dist/tools/configure-telemetry.js +11 -11
  540. package/dist/tools/create-spec/auto-pipeline.js +13 -1
  541. package/dist/tools/create-spec/autopilot-analyzer.d.ts +1 -1
  542. package/dist/tools/create-spec/autopilot-analyzer.js +2 -4
  543. package/dist/tools/create-spec/mcp-tool-contract.d.ts +10 -4
  544. package/dist/tools/create-spec/mcp-tool-contract.js +7 -36
  545. package/dist/tools/create-spec/post-creation.d.ts +2 -1
  546. package/dist/tools/create-spec/post-creation.js +56 -54
  547. package/dist/tools/create-spec/relevance-scorer.d.ts +1 -1
  548. package/dist/tools/create-spec/relevance-scorer.js +17 -1
  549. package/dist/tools/create-spec/spec-builder.js +2 -12
  550. package/dist/tools/create-spec/spec-created-outbox-consumer.d.ts +14 -0
  551. package/dist/tools/create-spec/spec-created-outbox-consumer.js +176 -0
  552. package/dist/tools/create-spec.js +385 -520
  553. package/dist/tools/define-ui-contract/agent-interaction-contract.js +2 -4
  554. package/dist/tools/define-ui-contract-desktop/desktop-contract.js +12 -4
  555. package/dist/tools/define-ui-contract-desktop/native-contract.js +7 -3
  556. package/dist/tools/define-ui-contract-extensions.js +2 -3
  557. package/dist/tools/define-ui-contract-mobile.js +5 -9
  558. package/dist/tools/define-ui-contract-web/component-tree.js +4 -3
  559. package/dist/tools/define-ui-contract.js +7 -4
  560. package/dist/tools/deploy/deploy-spec.js +2 -4
  561. package/dist/tools/deploy/deploy-status.js +2 -4
  562. package/dist/tools/design-schema/nosql-category-schemas.js +2 -3
  563. package/dist/tools/design-schema-sql/migrations.js +3 -2
  564. package/dist/tools/design-schema-sql/tables.js +4 -1
  565. package/dist/tools/design-schema.js +4 -3
  566. package/dist/tools/feedback-handler.js +2 -4
  567. package/dist/tools/gc-data-projects.js +5 -5
  568. package/dist/tools/generate-execution-plan.js +3 -4
  569. package/dist/tools/generate-sub-agent.js +2 -1
  570. package/dist/tools/generate-tests/generators/a11y-tests-generator.js +5 -4
  571. package/dist/tools/generate-tests/generators/advanced-testing-generator.js +5 -4
  572. package/dist/tools/generate-tests/generators/concurrency-test-generator/js-templates.js +9 -4
  573. package/dist/tools/generate-tests/generators/concurrency-test-generator.js +8 -4
  574. package/dist/tools/generate-tests/generators/database/detectors.js +9 -3
  575. package/dist/tools/generate-tests/generators/database/index.js +2 -4
  576. package/dist/tools/generate-tests/generators/event-test-generator.js +5 -4
  577. package/dist/tools/generate-tests/generators/game-tests-generator.js +2 -1
  578. package/dist/tools/generate-tests/generators/graphql-test-generator.js +11 -5
  579. package/dist/tools/generate-tests/generators/grpc-test-generator.js +2 -3
  580. package/dist/tools/generate-tests/generators/llm-security-test-generator.js +4 -3
  581. package/dist/tools/generate-tests/generators/local-first-test-generator.js +4 -3
  582. package/dist/tools/generate-tests/generators/mcp-tests-generator.js +11 -9
  583. package/dist/tools/generate-tests/generators/microservices/index.js +2 -3
  584. package/dist/tools/generate-tests/generators/otel-test-generator.js +6 -3
  585. package/dist/tools/generate-tests/generators/security/detectors.js +2 -5
  586. package/dist/tools/generate-tests/generators/security/index.js +2 -4
  587. package/dist/tools/generate-tests/generators/supply-chain-test-generator.js +2 -3
  588. package/dist/tools/generate-tests/generators/visual-regression-generator.js +14 -17
  589. package/dist/tools/generate-tests/generators/websocket-test-generator.js +2 -3
  590. package/dist/tools/generate-tests/test-helpers.js +11 -12
  591. package/dist/tools/generate-tests-content.js +4 -3
  592. package/dist/tools/generate-tests.js +7 -4
  593. package/dist/tools/git/git-helpers.d.ts +0 -2
  594. package/dist/tools/git/git-helpers.js +7 -7
  595. package/dist/tools/github-pr-handler.js +10 -3
  596. package/dist/tools/heal-spec-docs.js +6 -53
  597. package/dist/tools/hook-generator-handler.js +6 -6
  598. package/dist/tools/init-constitution/platform-principles.js +4 -2
  599. package/dist/tools/init-project/agents-md-writer.js +14 -5
  600. package/dist/tools/init-project/claude-md-generator.js +19 -12
  601. package/dist/tools/init-project/handler.js +165 -73
  602. package/dist/tools/init-project/host-assets-writer.d.ts +1 -1
  603. package/dist/tools/init-project/host-assets-writer.js +4 -2
  604. package/dist/tools/init-project/lifecycle-helpers.js +3 -5
  605. package/dist/tools/init-project/lint-scaffolder.js +6 -2
  606. package/dist/tools/init-project/migration-runner.d.ts +10 -1
  607. package/dist/tools/init-project/migration-runner.js +68 -3
  608. package/dist/tools/init-project/per-client-files-writer.js +14 -4
  609. package/dist/tools/init-project/rules-generator.js +10 -2
  610. package/dist/tools/init-project/scaffold-writer.d.ts +1 -1
  611. package/dist/tools/init-project/scaffold-writer.js +17 -15
  612. package/dist/tools/jobs/handlers.d.ts +15 -0
  613. package/dist/tools/jobs/handlers.js +126 -0
  614. package/dist/tools/list-specs.js +35 -34
  615. package/dist/tools/manage-plugins-handler.js +17 -9
  616. package/dist/tools/migrate-tech/advanced-handlers.js +3 -2
  617. package/dist/tools/migrate-tech/build-tool-handlers.js +3 -2
  618. package/dist/tools/migrate-tech/core-handlers.js +5 -2
  619. package/dist/tools/migrate-tech/data-handlers.js +6 -3
  620. package/dist/tools/migrate-tech-advanced/rollback-handlers.js +3 -2
  621. package/dist/tools/migrate-tech-advanced/service-handlers.js +5 -2
  622. package/dist/tools/oauth-handler.js +7 -1
  623. package/dist/tools/register-sdd-tools.d.ts +1 -1
  624. package/dist/tools/register-sdd-tools.js +5 -0
  625. package/dist/tools/register-spec-tools/core-spec-tools.js +31 -0
  626. package/dist/tools/registry/auth.js +13 -5
  627. package/dist/tools/registry/publish.js +7 -4
  628. package/dist/tools/resolve-project-path.d.ts +2 -2
  629. package/dist/tools/resolve-project-path.js +7 -7
  630. package/dist/tools/reverse-engineer/analyzer.js +14 -14
  631. package/dist/tools/rollback-release.js +3 -2
  632. package/dist/tools/safe-handler.js +295 -171
  633. package/dist/tools/schema-generator-handler.js +2 -1
  634. package/dist/tools/schemas/output-schemas.d.ts +88 -82
  635. package/dist/tools/schemas/output-schemas.js +12 -94
  636. package/dist/tools/schemas/plugins-schemas.js +0 -2
  637. package/dist/tools/schemas/registry.js +0 -2
  638. package/dist/tools/schemas/skill-registry-schemas.js +0 -2
  639. package/dist/tools/schemas/validate-output-schema.d.ts +256 -0
  640. package/dist/tools/schemas/validate-output-schema.js +212 -0
  641. package/dist/tools/sentry-handler.js +6 -1
  642. package/dist/tools/skill-bootstrap-handler.js +7 -4
  643. package/dist/tools/status-handler.js +4 -0
  644. package/dist/tools/storage-bundle-handler.d.ts +9 -0
  645. package/dist/tools/storage-bundle-handler.js +29 -0
  646. package/dist/tools/storage-paths-handler.d.ts +9 -0
  647. package/dist/tools/storage-paths-handler.js +17 -0
  648. package/dist/tools/suggest-mcp-server.js +11 -5
  649. package/dist/tools/suggest-mcps.js +29 -9
  650. package/dist/tools/suggest-tooling/advanced-testing-catalog.js +4 -5
  651. package/dist/tools/suggest-tooling/build-tool-catalog.js +2 -1
  652. package/dist/tools/suggest-tooling/css-framework-catalog.js +13 -7
  653. package/dist/tools/suggest-tooling/framework-catalog.js +3 -5
  654. package/dist/tools/suggest-tooling/frontend-perf-catalog.js +2 -6
  655. package/dist/tools/suggest-tooling/handler.js +10 -4
  656. package/dist/tools/suggest-tooling/hypermedia-catalog.js +11 -3
  657. package/dist/tools/suggest-tooling/linting-catalog.js +4 -7
  658. package/dist/tools/suggest-tooling/llm-security-catalog.js +2 -1
  659. package/dist/tools/suggest-tooling/local-first-catalog.js +7 -5
  660. package/dist/tools/suggest-tooling/observability-catalog.js +3 -4
  661. package/dist/tools/suggest-tooling/otel-catalog.js +4 -1
  662. package/dist/tools/suggest-tooling/resilience-catalog.js +16 -5
  663. package/dist/tools/suggest-tooling/skills-catalog.js +10 -9
  664. package/dist/tools/suggest-tooling/supply-chain-catalog.js +2 -3
  665. package/dist/tools/supabase-handler.js +2 -1
  666. package/dist/tools/token-intelligence-handler.js +2 -2
  667. package/dist/tools/token-recording.js +2 -2
  668. package/dist/tools/token-savings-handler.js +2 -2
  669. package/dist/tools/tool-registry/core-tools.js +131 -0
  670. package/dist/tools/tool-registry/group-infra.js +10 -12
  671. package/dist/tools/tool-registry/group-quality-compliance.js +5 -12
  672. package/dist/tools/update-status/approval-gates.d.ts +13 -0
  673. package/dist/tools/update-status/approval-gates.js +81 -0
  674. package/dist/tools/update-status/batch.js +4 -2
  675. package/dist/tools/update-status/dod-gates.d.ts +6 -24
  676. package/dist/tools/update-status/dod-gates.js +60 -135
  677. package/dist/tools/update-status/done-receipt-verifier.d.ts +15 -0
  678. package/dist/tools/update-status/done-receipt-verifier.js +145 -0
  679. package/dist/tools/update-status/evidence-gate.js +154 -2
  680. package/dist/tools/update-status/file-sync.js +23 -12
  681. package/dist/tools/update-status/gate-harness.d.ts +7 -0
  682. package/dist/tools/update-status/gate-harness.js +8 -0
  683. package/dist/tools/update-status/index.js +228 -325
  684. package/dist/tools/update-status/qa-gate.d.ts +1 -1
  685. package/dist/tools/update-status/qa-gate.js +2 -2
  686. package/dist/tools/update-status/side-effects.js +30 -37
  687. package/dist/tools/update-status/transition-guard.d.ts +4 -2
  688. package/dist/tools/update-status/transition-guard.js +57 -10
  689. package/dist/tools/update-status-convention-gate.js +24 -23
  690. package/dist/tools/update-status-reconcile.js +2 -2
  691. package/dist/tools/validate-api-contract-handler.js +3 -3
  692. package/dist/tools/validate-lint.js +20 -13
  693. package/dist/tools/validate.d.ts +3 -1
  694. package/dist/tools/validate.js +213 -5
  695. package/dist/transports/http-transport.js +84 -61
  696. package/dist/transports/middleware/with-telemetry.js +3 -2
  697. package/dist/types/abortable-process.d.ts +2 -0
  698. package/dist/types/advanced-framework.js +0 -2
  699. package/dist/types/atomic-upgrade.d.ts +71 -0
  700. package/dist/types/atomic-upgrade.js +2 -0
  701. package/dist/types/ci.js +0 -2
  702. package/dist/types/core-bridge.d.ts +78 -1
  703. package/dist/types/crash-shield-framework-rules.d.ts +24 -0
  704. package/dist/types/crash-shield-framework-rules.js +2 -0
  705. package/dist/types/data-gc.d.ts +16 -0
  706. package/dist/types/deploy.js +0 -2
  707. package/dist/types/durable-job.d.ts +78 -0
  708. package/dist/types/durable-job.js +2 -0
  709. package/dist/types/durable-validation.d.ts +60 -0
  710. package/dist/types/durable-validation.js +2 -0
  711. package/dist/types/estimation.d.ts +2 -0
  712. package/dist/types/evidence-gates.d.ts +9 -1
  713. package/dist/types/execution.d.ts +43 -0
  714. package/dist/types/handoff-artifacts.d.ts +2 -0
  715. package/dist/types/index.d.ts +2 -0
  716. package/dist/types/index.js +2 -0
  717. package/dist/types/infrastructure.js +0 -2
  718. package/dist/types/lifecycle.js +0 -2
  719. package/dist/types/migration/canonical-storage.d.ts +37 -0
  720. package/dist/types/migration/canonical-storage.js +2 -0
  721. package/dist/types/migration/index.d.ts +1 -1
  722. package/dist/types/native-worker.d.ts +48 -0
  723. package/dist/types/native-worker.js +2 -0
  724. package/dist/types/network-policy.d.ts +12 -0
  725. package/dist/types/network-policy.js +2 -0
  726. package/dist/types/oauth.js +0 -2
  727. package/dist/types/observability.d.ts +32 -0
  728. package/dist/types/outbox-worker.d.ts +35 -0
  729. package/dist/types/outbox-worker.js +11 -0
  730. package/dist/types/permissions-config.d.ts +0 -27
  731. package/dist/types/permissions-config.js +0 -2
  732. package/dist/types/plugin-install.d.ts +0 -11
  733. package/dist/types/plugin-install.js +0 -2
  734. package/dist/types/portal.d.ts +1 -0
  735. package/dist/types/product-public.d.ts +75 -0
  736. package/dist/types/product-public.js +2 -0
  737. package/dist/types/project/inputs.d.ts +2 -0
  738. package/dist/types/project/mfe-detection.js +0 -2
  739. package/dist/types/project/platform-mobile.js +0 -2
  740. package/dist/types/project/platform-specialty.js +0 -2
  741. package/dist/types/project-knowledge-graph.d.ts +7 -0
  742. package/dist/types/runtime-database.d.ts +10 -0
  743. package/dist/types/runtime-database.js +2 -0
  744. package/dist/types/runtime-policy.d.ts +40 -0
  745. package/dist/types/runtime-policy.js +2 -0
  746. package/dist/types/safety.d.ts +4 -5
  747. package/dist/types/schema-registry.d.ts +12 -0
  748. package/dist/types/schema-registry.js +2 -0
  749. package/dist/types/security.d.ts +52 -0
  750. package/dist/types/skill-registry.js +0 -2
  751. package/dist/types/spec/inputs.d.ts +2 -0
  752. package/dist/types/spec-lock-v2.d.ts +13 -7
  753. package/dist/types/spec-lock-v2.js +1 -1
  754. package/dist/types/spec-registry.js +0 -2
  755. package/dist/types/storage-bundle.d.ts +13 -0
  756. package/dist/types/storage-bundle.js +2 -0
  757. package/dist/types/storage-catalog.d.ts +18 -0
  758. package/dist/types/storage-catalog.js +2 -0
  759. package/dist/types/team-planner.js +0 -2
  760. package/dist/types/technology-registry.d.ts +35 -0
  761. package/dist/types/technology-registry.js +2 -0
  762. package/dist/types/technology-symbols.generated.d.ts +117 -0
  763. package/dist/types/technology-symbols.generated.js +2 -0
  764. package/dist/types/telemetry.d.ts +3 -3
  765. package/dist/types/transport.d.ts +2 -0
  766. package/dist/types/validate-worker.d.ts +44 -0
  767. package/dist/types/validate-worker.js +2 -0
  768. package/dist/types/validation-evidence.d.ts +1 -1
  769. package/dist/types/validation-receipt.d.ts +104 -0
  770. package/dist/types/validation-receipt.js +2 -0
  771. package/package.json +31 -20
  772. package/planu-native.json +1 -1
  773. package/planu-plugin.json +1 -1
  774. package/dist/engine/telemetry/geo-resolver.d.ts +0 -9
  775. package/dist/engine/telemetry/geo-resolver.js +0 -43
  776. package/dist/storage/data-dir-discovery.d.ts +0 -31
  777. package/dist/storage/data-dir-discovery.js +0 -140
  778. package/dist/storage/migrations/cwd-to-absolute.d.ts +0 -25
  779. package/dist/storage/migrations/cwd-to-absolute.js +0 -281
  780. package/dist/tools/create-spec/adapters/prior-decisions-hint.d.ts +0 -14
  781. package/dist/tools/create-spec/adapters/prior-decisions-hint.js +0 -30
  782. package/dist/tools/init-project/ancestor-data-detector.d.ts +0 -22
  783. package/dist/tools/init-project/ancestor-data-detector.js +0 -81
  784. package/dist/tools/update-status/force-done-audit.d.ts +0 -2
  785. package/dist/tools/update-status/force-done-audit.js +0 -23
  786. package/dist/types/migration/cwd-to-absolute.d.ts +0 -8
  787. package/dist/types/migration/cwd-to-absolute.js +0 -3
@@ -3,17 +3,13 @@ import { upsertToken, hashQuestions } from '../engine/clarification-gate/token-s
3
3
  import { ti } from '../i18n/index.js';
4
4
  import { knowledgeStore, specStore } from '../storage/index.js';
5
5
  import { readTechnologySelectionContract } from '../storage/technology-selection-store.js';
6
- import { formatSuccess, addNextSteps, toolResult, interactiveResult } from './response-helpers.js';
7
- import { writeFile, mkdir, rm, readFile, stat as fsStat, rename, link as hardLink, } from 'node:fs/promises';
6
+ import { toolResult, interactiveResult } from './response-helpers.js';
7
+ import { readFile, stat as fsStat } from 'node:fs/promises';
8
8
  import { createHash, randomUUID } from 'node:crypto';
9
9
  import { dirname as pathDirname, isAbsolute as pathIsAbsolute, join as pathJoin, relative as pathRelative, sep as pathSeparator, } from 'node:path';
10
- import { checkSpecReadiness } from '../engine/readiness-checker.js';
11
10
  import { buildSpecContext, buildSplitResult } from './create-spec/spec-builder.js';
12
11
  import { validateConstitution } from './create-spec/constitution-validator.js';
13
- import { setupGitBranch, checkContradictions, fireSpecCreatedHook, generatePostCreationSuggestions, formatPostCreationSuggestion, runAutopilotAsync, getAsyncAnalysisPath, } from './create-spec/post-creation.js';
14
- import { notifyStoreChange } from '../engine/doc-generator/portal/regen-hook.js';
15
- import { compactObj } from '../engine/compact-obj.js';
16
- import { runAutoPostCreatePipeline } from './create-spec/auto-pipeline.js';
12
+ import { getAsyncAnalysisPath } from './create-spec/post-creation.js';
17
13
  import { extractCriteria, generateLeanSpecContent, } from '../engine/spec-format/lean-spec-generator.js';
18
14
  import { generateLeanTechnicalContent, } from '../engine/spec-format/lean-technical-generator.js';
19
15
  import { extractFilesFromSpecBody } from '../engine/spec-format/technical-md-populator.js';
@@ -22,22 +18,25 @@ import { appendImplementationContractIfMissing } from '../engine/implementation-
22
18
  import { validateEnglishOnlySpecText } from '../engine/spec-language/english-only.js';
23
19
  import { FallbackGenerator } from '../engine/spec-generator/index.js';
24
20
  import { analyzeProjectForSpec, getEmptyAutopilotResult, } from './create-spec/autopilot-analyzer.js';
25
- import { AutopilotSummaryCollector } from '../engine/autopilot/summary-collector.js';
26
21
  import { trackCost } from '../engine/cost-tracking/operation-tracker.js';
27
22
  import { analyzeSimplicity } from '../engine/simplicity-detector.js';
28
23
  import { withBudget, unwrapBudget, withTotalBudget } from '../engine/timing/budget.js';
29
24
  import { measureStep } from '../engine/timing/structured-log.js';
30
25
  import { resolveProjectIdOrAutoDetect } from './resolve-project-id.js';
31
26
  import { hashProjectPath } from '../storage/base-store.js';
32
- import { findSimilarSpecs } from '../engine/spec-searcher.js';
33
- import { scoreSpecQuality } from '../engine/spec-quality-scorer.js';
34
- import { runPriorDecisionsHint } from './create-spec/adapters/prior-decisions-hint.js';
35
- import { adviseSimilarSpecs } from '../engine/complexity-budget/index.js';
36
27
  import { issuePlannerToken } from '../engine/reviewer-tokens/issuer.js';
28
+ import { getRuntimePolicy } from '../engine/runtime-policy.js';
37
29
  import { generateInteractiveQuestions } from './create-spec/question-generator.js';
38
30
  import { buildCriterionGroundingRecords, filterGroundedCriteria, getAdvisoryCriteria, getContractCriteria, } from '../engine/spec-grounding/contract.js';
39
31
  import { checkGenericSpecOutput } from '../engine/spec-quality/generic-output-gate.js';
40
32
  import { calculateActionableSpecMetrics, shouldExposeMetric, } from '../engine/spec-metrics/actionable-metrics.js';
33
+ import { RuntimeDatabase } from '../storage/runtime-db.js';
34
+ import { SPEC_CREATED_POST_COMMIT_TASKS } from '../types/outbox-worker.js';
35
+ import { resolveStorageLayout } from '../storage/storage-layout.js';
36
+ import { OperationJournal, recoverOperationJournal, } from '../engine/execution/operation-journal.js';
37
+ import { assertExecutionCanCommit } from '../engine/execution/context.js';
38
+ import { cleanupExecutionArtifact, executionLink, executionMkdir, executionRemove, executionRename, executionWriteFileExclusive, } from '../engine/execution/deadline-io.js';
39
+ import { atomicWriteFile } from '../engine/safety/atomic-write-file.js';
41
40
  /** SPEC-584: Persist a clarification token when interactive questions are emitted. Best-effort. */
42
41
  async function persistClarificationToken(earlyReturn, projectId, toolName) {
43
42
  try {
@@ -88,31 +87,13 @@ function handleClarification(_server, description, knowledge, autopilot, params)
88
87
  function hasFileEntries(files) {
89
88
  return files.create.length + files.modify.length + files.test.length > 0;
90
89
  }
91
- function mergeTechnicalFiles(primary, fallback) {
92
- return {
93
- create: mergeFileEntries(primary.create, fallback.create),
94
- modify: mergeFileEntries(primary.modify, fallback.modify),
95
- test: mergeFileEntries(primary.test, fallback.test),
96
- };
97
- }
98
- function mergeFileEntries(primary, fallback) {
99
- const byPath = new Map();
100
- for (const file of [...primary, ...fallback]) {
101
- if (!byPath.has(file.path)) {
102
- byPath.set(file.path, file);
103
- }
104
- }
105
- return [...byPath.values()];
106
- }
107
90
  async function resolveTechnicalFiles(input) {
108
91
  const generatedSource = [input.generatedTechnicalSection, input.generatedSpecBody]
109
92
  .filter((part) => part.trim().length > 0)
110
93
  .join('\n\n');
111
94
  const extracted = await extractFilesFromSpecBody(generatedSource, input.projectPath);
112
95
  if (extracted !== null && hasFileEntries(extracted)) {
113
- return input.fallbackReason === undefined
114
- ? mergeTechnicalFiles(extracted, input.autopilot.suggestedFiles)
115
- : extracted;
96
+ return extracted;
116
97
  }
117
98
  return { create: [], modify: [], test: [] };
118
99
  }
@@ -185,23 +166,6 @@ const HIGH_RISK_WARNING = 'High-risk spec — consider: ' +
185
166
  '1) Is the approach technically feasible within the project constraints? ' +
186
167
  '2) What edge cases (network failure, concurrent writes, empty state) could break this? ' +
187
168
  '3) Which existing specs or external services does this depend on?';
188
- async function runQualityScore(spec) {
189
- try {
190
- const report = await scoreSpecQuality(spec);
191
- return {
192
- total: report.score.total,
193
- grade: report.score.grade,
194
- completeness: report.score.completeness,
195
- testability: report.score.testability,
196
- ambiguity: report.score.ambiguity,
197
- risk: report.score.risk,
198
- };
199
- }
200
- catch {
201
- /* best-effort — never block spec creation */
202
- return null;
203
- }
204
- }
205
169
  function runSimplicityCheck(text, hours) {
206
170
  try {
207
171
  return analyzeSimplicity(text, hours);
@@ -224,35 +188,6 @@ function buildAdvisoryCompat() {
224
188
  function resolveOutOfScope(provided) {
225
189
  return provided?.filter((item) => item.trim().length > 0) ?? [];
226
190
  }
227
- /** SPEC-614 AC4: suggest complexity category based on similar historical specs (best-effort). */
228
- async function runComplexityAdvice(projectId, currentSpecId, tags, targetCriteriaCount) {
229
- try {
230
- const allSpecs = await specStore.listSpecs(projectId);
231
- const historicals = allSpecs
232
- .filter((s) => s.id !== currentSpecId)
233
- .slice(-200)
234
- .map((s) => ({
235
- specId: s.id,
236
- criteriaCount: s.reviewNotes?.length ?? 0,
237
- filesCount: s.impactAnalysis?.affectedFiles.length ?? 0,
238
- estimatedHours: s.estimation.devHours,
239
- actualHours: s.actuals?.devHours,
240
- tags: s.tags,
241
- }));
242
- const advice = adviseSimilarSpecs(targetCriteriaCount, tags, historicals);
243
- if (advice.similarSpecsCount === 0) {
244
- return null;
245
- }
246
- return {
247
- suggestedCategory: advice.suggestedCategory,
248
- reasoning: advice.reasoning,
249
- similarSpecsCount: advice.similarSpecsCount,
250
- };
251
- }
252
- catch {
253
- return null;
254
- }
255
- }
256
191
  /** SPEC-783: Synthesize agent team findings into unified spec.md ## Technical section. */
257
192
  async function handleAgentTeamSynthesis(specId, projectPath, findings) {
258
193
  try {
@@ -296,7 +231,7 @@ async function handleAgentTeamSynthesis(specId, projectPath, findings) {
296
231
  const synthesized = synthesizeFindings('', findings);
297
232
  updatedContent = `${specContent.trimEnd()}\n\n## Technical\n\n${synthesized}\n`;
298
233
  }
299
- await writeFile(specPath, updatedContent, 'utf8');
234
+ await atomicWriteFile(specPath, updatedContent, { encoding: 'utf8' });
300
235
  return {
301
236
  content: [
302
237
  {
@@ -311,14 +246,136 @@ async function handleAgentTeamSynthesis(specId, projectPath, findings) {
311
246
  return { content: [{ type: 'text', text: `Synthesis failed: ${msg}` }], isError: true };
312
247
  }
313
248
  }
314
- /** SPEC-770: Derive idempotency key from title and projectPath. */
315
- function computeIdempotencyKey(title, projectPath) {
316
- return createHash('sha256').update(`${title}::${projectPath}`).digest('hex');
249
+ /** Derive a bounded storage key from an explicit caller key or the legacy request identity. */
250
+ function computeIdempotencyKey(title, projectPath, explicitKey) {
251
+ const identity = explicitKey ? `explicit::${explicitKey}` : `${title}::${projectPath}`;
252
+ return createHash('sha256').update(identity).digest('hex');
253
+ }
254
+ function createSpecRequestDigest(params, projectPath) {
255
+ return createHash('sha256')
256
+ .update(JSON.stringify({ ...params, projectPath, idempotencyKey: undefined }))
257
+ .digest('hex');
258
+ }
259
+ function computeOperationKey(params, projectPath, dedupeKey) {
260
+ const identity = params.idempotencyKey
261
+ ? `explicit::${params.idempotencyKey}`
262
+ : `implicit::${dedupeKey}::${params.description}::${randomUUID()}`;
263
+ return createHash('sha256').update(`${identity}::${projectPath}`).digest('hex');
264
+ }
265
+ function finishRecoveredOperation(journal, key, result) {
266
+ let entry = journal.get('create_spec', key);
267
+ if (entry?.state === 'intent') {
268
+ entry = journal.prepared('create_spec', key);
269
+ }
270
+ if (entry?.state === 'prepared') {
271
+ entry = journal.committed('create_spec', key, result);
272
+ }
273
+ if (entry?.state === 'committed') {
274
+ entry = journal.acknowledged('create_spec', key);
275
+ }
276
+ return entry?.result ?? result;
277
+ }
278
+ function buildCommittedCreateResult(input) {
279
+ const advisorySignals = [];
280
+ if (input.advisoryCriteria.length > 0) {
281
+ advisorySignals.push(makeAdvisorySignal({
282
+ key: 'ungrounded-contract-items',
283
+ kind: 'quality',
284
+ message: `${String(input.advisoryCriteria.length)} ungrounded contract item(s) kept advisory-only.`,
285
+ source: 'validator',
286
+ evidence: input.advisoryCriteria.slice(0, 10),
287
+ confidence: 0.8,
288
+ surface: 'structuredContent',
289
+ value: input.advisoryCriteria,
290
+ }));
291
+ }
292
+ const splitResult = buildSplitResult(input.splitSuggestion, input.experienceLevel);
293
+ if (splitResult) {
294
+ advisorySignals.push(makeAdvisorySignal({
295
+ key: 'split-suggestion',
296
+ kind: 'complexity',
297
+ message: 'Spec may benefit from splitting.',
298
+ source: 'heuristic',
299
+ evidence: ['spec-splitter heuristic'],
300
+ confidence: 0.5,
301
+ surface: 'structuredContent',
302
+ value: splitResult,
303
+ }));
304
+ }
305
+ if (input.simplicityResult) {
306
+ advisorySignals.push(makeAdvisorySignal({
307
+ key: 'simplicity-check',
308
+ kind: 'simplicity',
309
+ message: `Simplicity recommendation: ${input.simplicityResult.recommendation}.`,
310
+ source: 'heuristic',
311
+ evidence: input.simplicityResult.signals.map((signal) => signal.type),
312
+ confidence: 0.55,
313
+ surface: 'structuredContent',
314
+ value: input.simplicityResult,
315
+ deprecatedAlias: 'simplicityCheck',
316
+ }));
317
+ }
318
+ const spec = input.spec;
319
+ const riskWarning = spec.risk === 'high' || spec.difficulty >= 4 ? HIGH_RISK_WARNING : undefined;
320
+ if (riskWarning) {
321
+ advisorySignals.push(makeAdvisorySignal({
322
+ key: 'risk-warning',
323
+ kind: 'challenge',
324
+ message: 'High-risk heuristic warning generated.',
325
+ source: 'heuristic',
326
+ evidence: [`risk:${spec.risk}`, `difficulty:${String(spec.difficulty)}`],
327
+ confidence: 0.6,
328
+ surface: 'structuredContent',
329
+ value: riskWarning,
330
+ deprecatedAlias: 'riskWarning',
331
+ }));
332
+ }
333
+ return toolResult(`Spec ${spec.id} created and committed.`, {
334
+ operationId: input.operationId,
335
+ committed: true,
336
+ pendingAnalysis: true,
337
+ specId: spec.id,
338
+ title: spec.title,
339
+ slug: spec.slug,
340
+ type: spec.type,
341
+ scope: spec.scope,
342
+ difficulty: spec.difficulty,
343
+ risk: spec.risk,
344
+ tags: spec.tags,
345
+ target: spec.target,
346
+ status: spec.status,
347
+ gitBranch: spec.gitBranch,
348
+ specPath: spec.specPath,
349
+ ...(input.duplicate
350
+ ? { duplicateWarning: ti('spec.duplicateTitle', { title: spec.title, slug: spec.slug }) }
351
+ : {}),
352
+ ...(input.constitutionWarnings.length > 0
353
+ ? { constitutionWarnings: input.constitutionWarnings }
354
+ : {}),
355
+ ...(input.clarificationSession
356
+ ? {
357
+ linkedClarificationSession: input.clarificationSession.id,
358
+ clarificationTopic: input.clarificationSession.topic,
359
+ clarificationAnswersUsed: Object.keys(input.clarificationSession.answers).length,
360
+ }
361
+ : {
362
+ clarificationNote: 'Spec created directly from the supplied description; no clarification session was linked.',
363
+ }),
364
+ ...(input.contradictionHint ? { contradictionHint: input.contradictionHint } : {}),
365
+ ...(input.actionableMetrics.length > 0 ? { actionableMetrics: input.actionableMetrics } : {}),
366
+ ...(input.simplicityResult ? { simplicityCheck: input.simplicityResult } : {}),
367
+ ...(riskWarning ? { riskWarning } : {}),
368
+ ...(input.plannerToken ? { plannerToken: input.plannerToken } : {}),
369
+ ...(advisorySignals.length > 0 ? { advisorySignals } : {}),
370
+ compat: buildAdvisoryCompat(),
371
+ message: ti('tools.create_spec.success', { id: spec.id, title: spec.title }),
372
+ });
317
373
  }
318
- const IDEMPOTENCY_CLAIM_STALE_MS = 60_000;
319
- const IDEMPOTENCY_CLAIM_WAIT_MS = 25_000;
320
- const IDEMPOTENCY_CLAIM_POLL_MS = 20;
321
- const IDEMPOTENCY_MATCH_WINDOW_MS = 10 * 60 * 1000;
374
+ const CREATE_SPEC_POLICY = getRuntimePolicy().createSpec;
375
+ const IDEMPOTENCY_CLAIM_STALE_MS = CREATE_SPEC_POLICY.idempotencyClaimStaleMs;
376
+ const IDEMPOTENCY_CLAIM_WAIT_MS = CREATE_SPEC_POLICY.idempotencyClaimWaitMs;
377
+ const IDEMPOTENCY_CLAIM_POLL_MS = CREATE_SPEC_POLICY.idempotencyClaimPollMs;
378
+ const IDEMPOTENCY_MATCH_WINDOW_MS = CREATE_SPEC_POLICY.idempotencyMatchWindowMs;
322
379
  function getIdempotencyEvidencePath(projectPath, key) {
323
380
  const analysisPath = getAsyncAnalysisPath(projectPath, 'SPEC-000');
324
381
  const projectDataPath = pathDirname(pathDirname(analysisPath));
@@ -438,9 +495,8 @@ async function commitIdempotencyEvidence(projectPath, key, claim, spec, specPath
438
495
  committedAt,
439
496
  };
440
497
  try {
441
- await writeFile(evidencePath, JSON.stringify(evidence, null, 2), {
498
+ await executionWriteFileExclusive(evidencePath, JSON.stringify(evidence, null, 2), {
442
499
  encoding: 'utf-8',
443
- flag: 'wx',
444
500
  });
445
501
  }
446
502
  catch (error) {
@@ -464,10 +520,66 @@ async function releaseIdempotencyClaim(projectPath, key, ownerId) {
464
520
  await quarantineAndDeleteIdempotencyClaim(claimPath, raw);
465
521
  }
466
522
  }
523
+ async function decideCreateSpecRecovery(entry) {
524
+ const payload = entry.payload;
525
+ if (entry.payloadVersion !== 1 || payload?.operationVersion !== 1) {
526
+ return { action: 'quarantine', reason: 'Unsupported create_spec recovery payload' };
527
+ }
528
+ if (entry.state === 'intent') {
529
+ if (payload.ownerId) {
530
+ await releaseIdempotencyClaim(payload.projectPath, payload.idempotencyKey, payload.ownerId);
531
+ }
532
+ return { action: 'rollback', reason: 'Intent has no prepared durable side effects' };
533
+ }
534
+ if (!payload.projectId ||
535
+ !payload.specId ||
536
+ !payload.specPath ||
537
+ !payload.specContentDigest ||
538
+ !payload.result) {
539
+ return { action: 'quarantine', reason: 'Prepared payload is incomplete' };
540
+ }
541
+ const [content, storedSpec, evidenceRaw] = await Promise.all([
542
+ readFile(payload.specPath, 'utf8').catch(() => ''),
543
+ specStore.getSpec(payload.projectId, payload.specId).catch(() => null),
544
+ readFile(getIdempotencyEvidencePath(payload.projectPath, payload.idempotencyKey), 'utf8').catch(() => ''),
545
+ ]);
546
+ const evidence = parseIdempotencyEvidence(evidenceRaw);
547
+ const isCommitted = createHash('sha256').update(content).digest('hex') === payload.specContentDigest &&
548
+ storedSpec?.id === payload.specId &&
549
+ evidence?.specId === payload.specId &&
550
+ (!payload.ownerId || !evidence.ownerId || evidence.ownerId === payload.ownerId);
551
+ if (isCommitted) {
552
+ return {
553
+ action: 'commit',
554
+ result: payload.result,
555
+ outbox: {
556
+ topic: 'spec.created',
557
+ payload: {
558
+ schemaVersion: 1,
559
+ specId: payload.specId,
560
+ projectId: payload.projectId,
561
+ projectPath: payload.projectPath,
562
+ postCommitTasks: SPEC_CREATED_POST_COMMIT_TASKS,
563
+ },
564
+ },
565
+ };
566
+ }
567
+ const noDurableArtifacts = content.length === 0 && storedSpec === null && evidence === undefined;
568
+ if (noDurableArtifacts) {
569
+ if (payload.ownerId) {
570
+ await releaseIdempotencyClaim(payload.projectPath, payload.idempotencyKey, payload.ownerId);
571
+ }
572
+ return { action: 'rollback', reason: 'Prepared mutation has no durable artifacts' };
573
+ }
574
+ return {
575
+ action: 'quarantine',
576
+ reason: 'Prepared create_spec artifacts are partial or inconsistent',
577
+ };
578
+ }
467
579
  async function quarantineAndDeleteIdempotencyClaim(claimPath, expectedRaw) {
468
580
  const quarantinePath = `${claimPath}.${randomUUID()}.quarantine`;
469
581
  try {
470
- await rename(claimPath, quarantinePath);
582
+ await executionRename(claimPath, quarantinePath);
471
583
  }
472
584
  catch (error) {
473
585
  if (error.code === 'ENOENT') {
@@ -477,18 +589,18 @@ async function quarantineAndDeleteIdempotencyClaim(claimPath, expectedRaw) {
477
589
  }
478
590
  const quarantinedRaw = await readFile(quarantinePath, 'utf-8').catch(() => '');
479
591
  if (quarantinedRaw === expectedRaw) {
480
- await rm(quarantinePath, { force: true });
592
+ await executionRemove(quarantinePath, { force: true });
481
593
  return true;
482
594
  }
483
595
  try {
484
- await hardLink(quarantinePath, claimPath);
596
+ await executionLink(quarantinePath, claimPath);
485
597
  }
486
598
  catch (error) {
487
599
  if (error.code !== 'EEXIST') {
488
600
  throw error;
489
601
  }
490
602
  }
491
- await rm(quarantinePath, { force: true });
603
+ await executionRemove(quarantinePath, { force: true });
492
604
  return false;
493
605
  }
494
606
  async function waitForIdempotencyOwner(projectPath, key, claim) {
@@ -514,7 +626,7 @@ async function waitForIdempotencyOwner(projectPath, key, claim) {
514
626
  }
515
627
  async function acquireIdempotencyClaim(projectPath, key, title) {
516
628
  const claimPath = getIdempotencyClaimPath(projectPath, key);
517
- await mkdir(pathDirname(claimPath), { recursive: true });
629
+ await executionMkdir(pathDirname(claimPath), { recursive: true });
518
630
  for (let attempt = 0; attempt < 4; attempt += 1) {
519
631
  const claim = {
520
632
  version: 2,
@@ -525,9 +637,8 @@ async function acquireIdempotencyClaim(projectPath, key, title) {
525
637
  claimedAt: new Date().toISOString(),
526
638
  };
527
639
  try {
528
- await writeFile(claimPath, JSON.stringify(claim, null, 2), {
640
+ await executionWriteFileExclusive(claimPath, JSON.stringify(claim, null, 2), {
529
641
  encoding: 'utf-8',
530
- flag: 'wx',
531
642
  });
532
643
  const racedCommit = await findByIdempotencyEvidence(projectPath, key, Date.now() - IDEMPOTENCY_MATCH_WINDOW_MS);
533
644
  if (racedCommit !== undefined) {
@@ -536,7 +647,7 @@ async function acquireIdempotencyClaim(projectPath, key, title) {
536
647
  }
537
648
  const expiredEvidencePath = getIdempotencyEvidencePath(projectPath, key);
538
649
  if ((await fsStat(expiredEvidencePath).catch(() => null)) !== null) {
539
- await rm(expiredEvidencePath, { force: true });
650
+ await executionRemove(expiredEvidencePath, { force: true });
540
651
  }
541
652
  return { kind: 'owner', claim };
542
653
  }
@@ -702,6 +813,19 @@ function checkEnglishOnlyInput(params) {
702
813
  }
703
814
  // eslint-disable-next-line max-lines-per-function
704
815
  export async function handleCreateSpec(inputParams, server) {
816
+ if (inputParams.idempotencyKey !== undefined &&
817
+ !/^[A-Za-z0-9._:-]{8,128}$/.test(inputParams.idempotencyKey)) {
818
+ return {
819
+ content: [
820
+ {
821
+ type: 'text',
822
+ text: 'idempotencyKey must contain 8-128 letters, digits, dots, underscores, colons or hyphens.',
823
+ },
824
+ ],
825
+ isError: true,
826
+ structuredContent: { error: 'INVALID_IDEMPOTENCY_KEY', code: 422 },
827
+ };
828
+ }
705
829
  // SPEC-781: Friendly error for description exceeding 10000 chars (replaces cryptic Zod error)
706
830
  if (inputParams.description && inputParams.description.length > DESCRIPTION_MAX_CHARS) {
707
831
  return {
@@ -758,16 +882,85 @@ export async function handleCreateSpec(inputParams, server) {
758
882
  return gateError;
759
883
  }
760
884
  // SPEC-770: Idempotency check — return existing spec if same title+projectPath within 10 minutes
761
- const idempotencyKey = computeIdempotencyKey(inputParams.title, resolvedPath);
885
+ const idempotencyKey = computeIdempotencyKey(inputParams.title, resolvedPath, inputParams.idempotencyKey);
886
+ const operationKey = computeOperationKey(resolvedInputParams, resolvedPath, idempotencyKey);
887
+ const runtimeDatabase = new RuntimeDatabase({ path: resolveStorageLayout().runtimeDatabase });
888
+ const operationJournal = new OperationJournal(runtimeDatabase, createHash('sha256').update(hashProjectPath(resolvedPath)).digest('hex').slice(0, 32));
889
+ let journalEntry;
890
+ try {
891
+ await recoverOperationJournal({
892
+ journal: operationJournal,
893
+ operation: 'create_spec',
894
+ staleBefore: new Date(Date.now() - IDEMPOTENCY_CLAIM_STALE_MS).toISOString(),
895
+ decide: decideCreateSpecRecovery,
896
+ });
897
+ journalEntry = operationJournal.begin('create_spec', operationKey, inputParams.idempotencyKey
898
+ ? createSpecRequestDigest(resolvedInputParams, resolvedPath)
899
+ : operationKey, {
900
+ payloadVersion: 1,
901
+ payload: {
902
+ operationVersion: 1,
903
+ projectPath: resolvedPath,
904
+ idempotencyKey,
905
+ },
906
+ });
907
+ if (journalEntry.state === 'rolled-back') {
908
+ journalEntry = operationJournal.restartRolledBack('create_spec', operationKey);
909
+ journalEntry = operationJournal.setRecoveryPayload('create_spec', operationKey, 1, {
910
+ operationVersion: 1,
911
+ projectPath: resolvedPath,
912
+ idempotencyKey,
913
+ });
914
+ }
915
+ }
916
+ catch (error) {
917
+ runtimeDatabase.close();
918
+ throw error;
919
+ }
920
+ if ((journalEntry.state === 'committed' || journalEntry.state === 'acknowledged') &&
921
+ journalEntry.result) {
922
+ if (journalEntry.state === 'committed') {
923
+ operationJournal.acknowledged('create_spec', operationKey);
924
+ }
925
+ runtimeDatabase.close();
926
+ return journalEntry.result;
927
+ }
928
+ if (journalEntry.state === 'quarantined') {
929
+ runtimeDatabase.close();
930
+ return {
931
+ content: [
932
+ {
933
+ type: 'text',
934
+ text: `The previous create_spec attempt is quarantined: ${journalEntry.recoveryReason ?? 'artifact mismatch'}.`,
935
+ },
936
+ ],
937
+ isError: true,
938
+ structuredContent: { recoveryQuarantined: true, operationId: operationKey },
939
+ };
940
+ }
762
941
  const existingByKey = await findByIdempotencyKey(resolvedPath, idempotencyKey, hashProjectPath(resolvedPath));
763
942
  if (existingByKey) {
764
- return buildIdempotencyMatchResult(resolvedPath, existingByKey);
943
+ const result = await buildIdempotencyMatchResult(resolvedPath, existingByKey);
944
+ finishRecoveredOperation(operationJournal, operationKey, result);
945
+ runtimeDatabase.close();
946
+ return result;
947
+ }
948
+ let claimResolution;
949
+ try {
950
+ claimResolution = await acquireIdempotencyClaim(resolvedPath, idempotencyKey, inputParams.title);
951
+ }
952
+ catch (error) {
953
+ runtimeDatabase.close();
954
+ throw error;
765
955
  }
766
- const claimResolution = await acquireIdempotencyClaim(resolvedPath, idempotencyKey, inputParams.title);
767
956
  if (claimResolution.kind === 'existing') {
768
- return buildIdempotencyMatchResult(resolvedPath, claimResolution.spec);
957
+ const result = await buildIdempotencyMatchResult(resolvedPath, claimResolution.spec);
958
+ finishRecoveredOperation(operationJournal, operationKey, result);
959
+ runtimeDatabase.close();
960
+ return result;
769
961
  }
770
962
  if (claimResolution.kind === 'pending') {
963
+ runtimeDatabase.close();
771
964
  return {
772
965
  content: [
773
966
  {
@@ -785,7 +978,13 @@ export async function handleCreateSpec(inputParams, server) {
785
978
  retainForInFlightWork: false,
786
979
  };
787
980
  try {
788
- // eslint-disable-next-line max-lines-per-function, complexity -- orchestrator: one sequential gate + response-build block per lifecycle step; splitting requires threading 15+ shared variables
981
+ operationJournal.setRecoveryPayload('create_spec', operationKey, 1, {
982
+ operationVersion: 1,
983
+ projectPath: resolvedPath,
984
+ idempotencyKey,
985
+ ownerId: idempotencyClaim.ownerId,
986
+ });
987
+ // eslint-disable-next-line max-lines-per-function -- cohesive transactional create boundary
789
988
  return await trackCost(resolvedInputParams.projectPath ?? '', 'create_spec', async () => {
790
989
  // Allow internal re-enrichment without mutating function parameter
791
990
  let params = resolvedInputParams;
@@ -793,8 +992,8 @@ export async function handleCreateSpec(inputParams, server) {
793
992
  try {
794
993
  // SPEC-713: Phase 1 — Critical path: build + persist spec within 25s hard ceiling.
795
994
  // Only the steps required to produce spec.md on disk are inside this budget.
796
- // Post-creation enrichment (git, contradictions, quality scores, etc.) runs outside.
797
- const criticalResult = await withTotalBudget('create_spec-critical', 25_000, async () => {
995
+ // Durable post-commit work is delegated to the spec.created outbox consumer.
996
+ const criticalResult = await withTotalBudget('create_spec-critical', getRuntimePolicy().createSpec.criticalTimeoutMs, async (criticalSignal) => {
798
997
  // Build spec context (ID, estimation, diagrams, scope filters)
799
998
  const buildResult = await measureStep('buildSpecContext', () => buildSpecContext(params));
800
999
  if (!buildResult.ok) {
@@ -806,7 +1005,7 @@ export async function handleCreateSpec(inputParams, server) {
806
1005
  },
807
1006
  };
808
1007
  }
809
- const { spec, specDir, specPath, technicalPath, estimation, splitSuggestion, duplicate, projectId, agentTeamPlan, } = buildResult.context;
1008
+ const { spec, specDir, specPath, estimation, splitSuggestion, duplicate, projectId } = buildResult.context;
810
1009
  // Kept in external store/evidence for retries; the value-only serializer omits it.
811
1010
  spec.idempotencyKey = idempotencyKey;
812
1011
  // Load project knowledge and clarification session
@@ -819,11 +1018,11 @@ export async function handleCreateSpec(inputParams, server) {
819
1018
  if (constitutionCheck.blocked && constitutionCheck.errorResult) {
820
1019
  return { ok: false, earlyReturn: constitutionCheck.errorResult };
821
1020
  }
822
- // SPEC-461 Phase 3: Autopilot analyze project to enrich spec (best-effort)
823
- // SPEC-560: Wrapped with 5s timeout to prevent hangs on large projects (2000+ files)
824
- // SPEC-713: measureStep for Phase 0 diagnostic; withBudget enforces 5s ceiling
825
- const autopilotResult = await withBudget('autopilot-analyzer', 5_000, () => measureStep('autopilot-analyzer', () => analyzeProjectForSpec(params.projectPath ?? '', description, spec.title, knowledge)));
826
- const autopilot = unwrapBudget(autopilotResult, getEmptyAutopilotResult());
1021
+ // Full project-wide analysis is delivered by the durable spec.created outbox consumer.
1022
+ // A tiny inline budget preserves deterministic idea/clarification behavior when the
1023
+ // answer is immediately available without allowing repository scans to delay ACK.
1024
+ const inlineAnalysis = await withBudget('create-spec-inline-analysis', getRuntimePolicy().createSpec.inlineAnalysisBudgetMs, (signal) => analyzeProjectForSpec(params.projectPath ?? '', description, spec.title, knowledge, signal));
1025
+ const autopilot = unwrapBudget(inlineAnalysis, getEmptyAutopilotResult());
827
1026
  // If very vague (<10 words), capture as idea instead of spec
828
1027
  if (autopilot.isIdea) {
829
1028
  return {
@@ -923,8 +1122,6 @@ export async function handleCreateSpec(inputParams, server) {
923
1122
  generatedSpecBody: generatedSpec.specBody,
924
1123
  generatedTechnicalSection: generatedSpec.technicalSection,
925
1124
  projectPath: params.projectPath ?? '',
926
- autopilot,
927
- fallbackReason: generatedSpec.fallbackReason,
928
1125
  }));
929
1126
  const groundedTechnical = await measureStep('groundTechnicalFiles', () => groundTechnicalFiles({
930
1127
  files: technicalFiles,
@@ -990,49 +1187,87 @@ export async function handleCreateSpec(inputParams, server) {
990
1187
  },
991
1188
  };
992
1189
  }
1190
+ // Contradiction analysis is durable post-commit work. Its synchronous scanners can
1191
+ // block the event loop, so it must never run on the persistence acknowledgement path.
1192
+ const contradictionHint = undefined;
1193
+ const committedSimplicity = runSimplicityCheck([params.description, ...filteredCriteria].join('\n'), estimation.devHours);
1194
+ if (outOfScope.length > 0) {
1195
+ spec.outOfScope = outOfScope;
1196
+ }
1197
+ let committedPlannerToken;
1198
+ try {
1199
+ committedPlannerToken = await issuePlannerToken(resolvedPath, spec.id, params.sessionId ?? 'unknown-session', params.modelId ?? 'unknown-model', params.host ?? 'unknown-host');
1200
+ }
1201
+ catch {
1202
+ // Best-effort evidence must not block durable spec creation.
1203
+ }
1204
+ const committedResult = buildCommittedCreateResult({
1205
+ spec,
1206
+ operationId: operationKey,
1207
+ duplicate,
1208
+ constitutionWarnings: constitutionCheck.warnings,
1209
+ clarificationSession,
1210
+ advisoryCriteria,
1211
+ actionableMetrics,
1212
+ splitSuggestion,
1213
+ experienceLevel: knowledge?.experienceLevel,
1214
+ contradictionHint,
1215
+ simplicityResult: committedSimplicity,
1216
+ plannerToken: committedPlannerToken,
1217
+ });
1218
+ let storeCreated = false;
993
1219
  try {
994
- await measureStep('mkdir-specDir', () => mkdir(specDir, { recursive: true }));
1220
+ assertExecutionCanCommit(criticalSignal);
1221
+ operationJournal.setRecoveryPayload('create_spec', operationKey, 1, {
1222
+ operationVersion: 1,
1223
+ projectPath: resolvedPath,
1224
+ idempotencyKey,
1225
+ ownerId: idempotencyClaim.ownerId,
1226
+ projectId,
1227
+ specId: spec.id,
1228
+ specPath,
1229
+ specContentDigest: createHash('sha256').update(unifiedSpec).digest('hex'),
1230
+ result: committedResult,
1231
+ });
1232
+ operationJournal.prepared('create_spec', operationKey);
1233
+ await measureStep('mkdir-specDir', () => executionMkdir(specDir, { recursive: true }));
995
1234
  // SPEC-713: measure file write — this is the critical persistence step.
996
- await measureStep('writeFile-specPath', () => writeFile(specPath, unifiedSpec, 'utf-8'));
1235
+ assertExecutionCanCommit(criticalSignal);
1236
+ await measureStep('writeFile-specPath', () => atomicWriteFile(specPath, unifiedSpec, { encoding: 'utf-8' }));
1237
+ assertExecutionCanCommit(criticalSignal);
1238
+ await measureStep('specStore-createSpec', () => specStore.createSpec(projectId, spec));
1239
+ storeCreated = true;
1240
+ assertExecutionCanCommit(criticalSignal);
997
1241
  await measureStep('commit-idempotency-evidence', () => commitIdempotencyEvidence(resolvedPath, idempotencyKey, idempotencyClaim, spec, specPath));
1242
+ operationJournal.commitWithOutbox('create_spec', operationKey, committedResult, {
1243
+ topic: 'spec.created',
1244
+ payload: {
1245
+ schemaVersion: 1,
1246
+ specId: spec.id,
1247
+ projectId,
1248
+ projectPath: resolvedPath,
1249
+ postCommitTasks: SPEC_CREATED_POST_COMMIT_TASKS,
1250
+ },
1251
+ });
998
1252
  claimLifecycle.committed = true;
999
- // SPEC-709: technical.md no longer written content lives inside spec.md.
1000
- // SPEC-461: No progress.md, no HTML reports.
1253
+ // SPEC-709/SPEC-461: unified spec.md; no progress or HTML artifacts.
1001
1254
  }
1002
1255
  catch (writeErr) {
1003
- // Clean up partial files to avoid orphaned spec directories
1004
- await rm(specDir, { recursive: true, force: true });
1256
+ const storeRolledBack = storeCreated
1257
+ ? await specStore.deleteSpec(projectId, spec.id).catch(() => false)
1258
+ : true;
1259
+ if (storeRolledBack) {
1260
+ await cleanupExecutionArtifact(getIdempotencyEvidencePath(resolvedPath, idempotencyKey), {
1261
+ force: true,
1262
+ });
1263
+ await cleanupExecutionArtifact(specDir, { recursive: true, force: true });
1264
+ }
1005
1265
  throw writeErr;
1006
1266
  }
1007
- // Persist only explicit out-of-scope input.
1008
- if (outOfScope.length > 0) {
1009
- spec.outOfScope = outOfScope;
1010
- }
1011
- // Persist spec in storage
1012
- // SPEC-713: measure specStore.createSpec — file lock + JSON rewrite
1013
- await measureStep('specStore-createSpec', () => specStore.createSpec(projectId, spec));
1014
1267
  return {
1015
1268
  ok: true,
1016
1269
  data: {
1017
- spec,
1018
- specDir,
1019
- specPath,
1020
- technicalPath,
1021
- estimation,
1022
- splitSuggestion,
1023
- duplicate,
1024
- projectId,
1025
- agentTeamPlan,
1026
- knowledge,
1027
- clarificationSession,
1028
- constitutionCheck,
1029
- autopilot,
1030
- filteredCriteria,
1031
- advisoryCriteria: [
1032
- ...advisoryCriteria,
1033
- ...groundedTechnical.advisoryFiles.map((file) => file.path),
1034
- ],
1035
- actionableMetrics,
1270
+ committedResult,
1036
1271
  },
1037
1272
  };
1038
1273
  }); // end withTotalBudget critical path
@@ -1060,391 +1295,20 @@ export async function handleCreateSpec(inputParams, server) {
1060
1295
  if (!criticalResult.value.ok) {
1061
1296
  return criticalResult.value.earlyReturn;
1062
1297
  }
1063
- // Destructure critical path results for use in post-creation enrichment
1064
- const { spec, specDir: _specDir, specPath,
1065
- // SPEC-1010 Bug A: no longer surfaced in the response payload (SSR back-migration).
1066
- technicalPath: _technicalPath, estimation, splitSuggestion, duplicate, projectId, agentTeamPlan, knowledge, clarificationSession, constitutionCheck, autopilot, filteredCriteria, advisoryCriteria, actionableMetrics, } = criticalResult.value.data;
1067
- // -----------------------------------------------------------------------
1068
- // Post-creation enrichment (outside 25s ceiling — best-effort, budgeted)
1069
- // -----------------------------------------------------------------------
1070
- // Auto-setup git branch (non-blocking)
1071
- // SPEC-713: withBudget 3s — git subprocess can be slow on large repos
1072
- const gitBudgetResult = await withBudget('setupGitBranch', 3_000, () => measureStep('setupGitBranch', () => setupGitBranch(projectId, spec.id)));
1073
- const gitSetupResult = unwrapBudget(gitBudgetResult, undefined);
1074
- /* v8 ignore start -- requires real git repo */
1075
- if (gitSetupResult) {
1076
- spec.gitBranch = gitSetupResult.branch;
1077
- }
1078
- /* v8 ignore stop */
1079
- // Brief contradiction check (non-blocking)
1080
- // SPEC-713: withBudget 2s — scans all specs for contradiction keywords
1081
- const contradictionResult = await withBudget('checkContradictions', 2_000, () => measureStep('checkContradictions', () => checkContradictions(projectId, spec.id, description)));
1082
- const contradictionHint = unwrapBudget(contradictionResult, undefined);
1083
- // Build result (SPEC-461: lean — no progress, HTML, diagrams, scope filters)
1084
- const result = {
1085
- // SPEC-781: async analysis running in background (external project data)
1086
- pendingAnalysis: true,
1087
- specId: spec.id,
1088
- title: spec.title,
1089
- slug: spec.slug,
1090
- type: spec.type,
1091
- scope: spec.scope,
1092
- difficulty: spec.difficulty,
1093
- risk: spec.risk,
1094
- tags: spec.tags,
1095
- target: spec.target,
1096
- status: spec.status,
1097
- gitBranch: spec.gitBranch,
1098
- specPath,
1099
- // SPEC-1010 Bug A — `technicalPath` no longer leaked in the response.
1100
- // SSR back-migration (SPEC-752) folded technical.md into spec.md as
1101
- // ## Technical; the file is never written and the field would point to
1102
- // a non-existent path. Internal Spec record still carries it for
1103
- // backwards-compat with stored data — that field is removed in PR-C.
1104
- duplicateWarning: duplicate
1105
- ? ti('spec.duplicateTitle', { title: spec.title, slug: spec.slug })
1106
- : undefined,
1107
- ...(constitutionCheck.warnings.length > 0
1108
- ? { constitutionWarnings: constitutionCheck.warnings }
1109
- : {}),
1110
- ...(clarificationSession
1111
- ? {
1112
- linkedClarificationSession: clarificationSession.id,
1113
- clarificationTopic: clarificationSession.topic,
1114
- clarificationAnswersUsed: Object.keys(clarificationSession.answers).length,
1115
- }
1116
- : {
1117
- clarificationNote: 'Spec created directly from the supplied description; no clarification session was linked.',
1118
- }),
1119
- message: ti('tools.create_spec.success', { id: spec.id, title: spec.title }),
1120
- ...(contradictionHint ? { contradictionHint } : {}),
1121
- /* v8 ignore next -- requires real git repo */
1122
- ...(gitSetupResult ? { gitAutoSetup: gitSetupResult.data } : {}),
1123
- };
1124
- const advisorySignals = [];
1125
- if (actionableMetrics.length > 0) {
1126
- result.actionableMetrics = actionableMetrics;
1127
- }
1128
- if (advisoryCriteria.length > 0) {
1129
- advisorySignals.push(makeAdvisorySignal({
1130
- key: 'ungrounded-contract-items',
1131
- kind: 'quality',
1132
- message: `${String(advisoryCriteria.length)} ungrounded contract item(s) kept advisory-only.`,
1133
- source: 'validator',
1134
- evidence: advisoryCriteria.slice(0, 10),
1135
- confidence: 0.8,
1136
- surface: 'structuredContent',
1137
- value: advisoryCriteria,
1138
- }));
1139
- }
1140
- const splitResult = buildSplitResult(splitSuggestion, knowledge?.experienceLevel);
1141
- if (splitResult) {
1142
- advisorySignals.push(makeAdvisorySignal({
1143
- key: 'split-suggestion',
1144
- kind: 'complexity',
1145
- message: 'Spec may benefit from splitting.',
1146
- source: 'heuristic',
1147
- evidence: ['spec-splitter heuristic'],
1148
- confidence: 0.5,
1149
- surface: 'structuredContent',
1150
- value: splitResult,
1151
- }));
1152
- }
1153
- // Dispatch hook event (fire-and-forget)
1154
- fireSpecCreatedHook(projectId, spec, params.projectPath ?? '');
1155
- // SPEC-781: Fire-and-forget async analysis (external project data)
1156
- runAutopilotAsync(spec.id, params.projectPath ?? '', description);
1157
- // SPEC-713: Track warnings from budgeted post-creation steps
1158
- const budgetWarnings = [];
1159
- // SPEC-461: No per-spec HTML reports — lean format
1160
- // SPEC-713: Run post-creation checks in parallel to reduce total wall-clock time.
1161
- // Each has an individual budget; results are merged into `result` after settlement.
1162
- const [readinessResult, qualityResult, duplicatesResult, complexityResult, priorLinksResult, nextStepsResult,] = await Promise.all([
1163
- // Auto-readiness check (best-effort) — SPEC-713: 3s budget
1164
- withBudget('auto-readiness', 3_000, () => measureStep('auto-readiness', () => checkSpecReadiness(spec, 'lenient'))),
1165
- // SPEC-492: Spec quality score (0-100) — SPEC-713: 2s budget
1166
- withBudget('quality-score', 2_000, () => measureStep('quality-score', () => runQualityScore(spec).then((r) => r ?? null))),
1167
- // SPEC-514: Semantic duplicate detection — SPEC-713: 2s budget
1168
- withBudget('duplicate-detection', 2_000, () => measureStep('duplicate-detection', async () => {
1169
- const allSpecs = await specStore.listSpecs(projectId);
1170
- const recentSpecs = allSpecs.slice(-200).filter((s) => s.id !== spec.id);
1171
- return findSimilarSpecs(spec.title, recentSpecs, { threshold: 0.3, topN: 3 });
1172
- })),
1173
- // SPEC-614 AC4: complexity-category hint — SPEC-713: 2s budget
1174
- withBudget('complexity-advice', 2_000, () => measureStep('complexity-advice', () => runComplexityAdvice(projectId, spec.id, spec.tags, filteredCriteria.length))),
1175
- // SPEC-615: prior-decision links — SPEC-713: 2s budget
1176
- withBudget('prior-decisions', 2_000, () => measureStep('prior-decisions', () => runPriorDecisionsHint(projectId, description, spec.tags))),
1177
- // Post-creation suggestions — SPEC-713: 3s budget
1178
- withBudget('post-creation-suggestions', 3_000, () => measureStep('post-creation-suggestions', () => generatePostCreationSuggestions(params.projectPath ?? '', description, knowledge ?? undefined))),
1179
- ]);
1180
- // Merge parallel results into `result`
1181
- if (!readinessResult.exceeded) {
1182
- const readiness = readinessResult.value;
1183
- result.autoReadiness = { score: readiness.score, isReady: readiness.ready };
1184
- }
1185
- else {
1186
- budgetWarnings.push(readinessResult.warning);
1187
- }
1188
- const qualityValue = unwrapBudget(qualityResult, null, budgetWarnings);
1189
- if (qualityValue !== null) {
1190
- result.qualityScore = qualityValue;
1191
- }
1192
- // SPEC-485: Simplicity autopilot — detect over-engineering signals (best-effort, sync)
1193
- const simplicityResult = runSimplicityCheck([params.description, ...filteredCriteria].join('\n'), estimation.devHours);
1194
- if (simplicityResult) {
1195
- result.simplicityCheck = simplicityResult;
1196
- advisorySignals.push(makeAdvisorySignal({
1197
- key: 'simplicity-check',
1198
- kind: 'simplicity',
1199
- message: `Simplicity recommendation: ${simplicityResult.recommendation}.`,
1200
- source: 'heuristic',
1201
- evidence: simplicityResult.signals.map((signal) => signal.type),
1202
- confidence: 0.55,
1203
- surface: 'structuredContent',
1204
- value: simplicityResult,
1205
- deprecatedAlias: 'simplicityCheck',
1206
- }));
1207
- }
1208
- // SPEC-514: duplicate results
1209
- const possibleDuplicates = unwrapBudget(duplicatesResult, [], budgetWarnings);
1210
- if (possibleDuplicates.length > 0) {
1211
- result.possibleDuplicates = possibleDuplicates;
1212
- advisorySignals.push(makeAdvisorySignal({
1213
- key: 'possible-duplicates',
1214
- kind: 'duplicate',
1215
- message: `${String(possibleDuplicates.length)} possible duplicate spec(s) detected.`,
1216
- source: 'heuristic',
1217
- evidence: possibleDuplicates.map((dup) => dup.specId),
1218
- confidence: 0.5,
1219
- surface: 'structuredContent',
1220
- value: possibleDuplicates,
1221
- deprecatedAlias: 'possibleDuplicates',
1222
- }));
1223
- }
1224
- // SPEC-222 Trigger 2: Auto-challenge hint for high-risk specs
1225
- if (spec.risk === 'high' || spec.difficulty >= 4) {
1226
- result.riskWarning = HIGH_RISK_WARNING;
1227
- advisorySignals.push(makeAdvisorySignal({
1228
- key: 'risk-warning',
1229
- kind: 'challenge',
1230
- message: 'High-risk heuristic warning generated.',
1231
- source: 'heuristic',
1232
- evidence: [`risk:${spec.risk}`, `difficulty:${String(spec.difficulty)}`],
1233
- confidence: 0.6,
1234
- surface: 'structuredContent',
1235
- value: HIGH_RISK_WARNING,
1236
- deprecatedAlias: 'riskWarning',
1237
- }));
1238
- }
1239
- // SPEC-614 AC4: complexity advice
1240
- const cAdvice = unwrapBudget(complexityResult, null, budgetWarnings);
1241
- if (cAdvice) {
1242
- result.complexityAdvice = cAdvice;
1243
- advisorySignals.push(makeAdvisorySignal({
1244
- key: 'complexity-advice',
1245
- kind: 'complexity',
1246
- message: cAdvice.reasoning,
1247
- source: 'history',
1248
- evidence: [`similarSpecs:${String(cAdvice.similarSpecsCount)}`],
1249
- confidence: 0.6,
1250
- surface: 'structuredContent',
1251
- value: cAdvice,
1252
- deprecatedAlias: 'complexityAdvice',
1253
- }));
1254
- }
1255
- // SPEC-615: prior decisions
1256
- const priorLinks = unwrapBudget(priorLinksResult, [], budgetWarnings);
1257
- if (priorLinks.length > 0) {
1258
- result.priorDecisions = priorLinks.map((l) => l.decisionId);
1259
- spec.priorDecisions = result.priorDecisions;
1260
- advisorySignals.push(makeAdvisorySignal({
1261
- key: 'prior-decisions',
1262
- kind: 'prior-decision',
1263
- message: `${String(priorLinks.length)} prior decision link(s) found.`,
1264
- source: 'history',
1265
- evidence: priorLinks.map((link) => link.decisionId),
1266
- confidence: 0.65,
1267
- surface: 'structuredContent',
1268
- value: result.priorDecisions,
1269
- deprecatedAlias: 'priorDecisions',
1270
- }));
1271
- }
1272
- // Post-creation suggestions
1273
- const nextSteps = unwrapBudget(nextStepsResult, [], budgetWarnings);
1274
- if (nextSteps.length > 0) {
1275
- result.nextSteps = nextSteps;
1276
- }
1277
- // SPEC-713: Surface budget warnings in result when steps exceeded their budget
1278
- if (budgetWarnings.length > 0) {
1279
- result.budgetWarnings = budgetWarnings;
1280
- }
1281
- // SPEC-1017: No auto-regeneration of project-tree dashboard HTML.
1282
- if (params.projectPath) {
1283
- notifyStoreChange(params.projectPath, 'specs');
1284
- }
1285
- // SPEC-644: Refresh model mapping TTL in background (fire-and-forget)
1286
- void import('../engine/model-tier-resolver.js')
1287
- .then(({ triggerModelMappingRefresh }) => {
1288
- triggerModelMappingRefresh(knowledge?.projectPath ?? params.projectPath ?? '');
1289
- })
1290
- .catch(() => {
1291
- /* best-effort */
1292
- });
1293
- // Auto post-creation pipeline: challenge + readiness (SPEC-445).
1294
- // Keep it observable and bounded so users see the actual result instead of
1295
- // background work that may finish invisibly after the tool already returned.
1296
- const pipelineResult = await runAutoPostCreatePipeline(spec.id, projectId, knowledge?.projectPath ?? params.projectPath ?? '');
1297
- // Build markdown response
1298
- const lines = [
1299
- `**SPEC-${spec.id}** — ${spec.title}`,
1300
- '',
1301
- `| Field | Value |`,
1302
- `|-------|-------|`,
1303
- `| Type | ${spec.type} |`,
1304
- `| Scope | ${spec.scope} |`,
1305
- `| Difficulty | ${String(spec.difficulty)}/5 |`,
1306
- `| Risk | ${spec.risk} |`,
1307
- `| Target | ${spec.target} |`,
1308
- `| Status | ${spec.status} |`,
1309
- `| Tags | ${spec.tags.join(', ')} |`,
1310
- ];
1311
- if (spec.gitBranch) {
1312
- lines.push(`| Branch | \`${spec.gitBranch}\` |`);
1313
- }
1314
- if (duplicate) {
1315
- lines.push('', `⚠️ ${ti('spec.duplicateTitle', { title: spec.title, slug: spec.slug })}`);
1316
- }
1317
- if (constitutionCheck.warnings.length > 0) {
1318
- lines.push('', '⚠️ **Constitution Warnings**');
1319
- constitutionCheck.warnings.forEach((w) => lines.push(`- ${w.description}`));
1298
+ if (!claimLifecycle.committed) {
1299
+ throw new Error('create_spec critical path completed without a durable commit');
1320
1300
  }
1321
- if (contradictionHint) {
1322
- lines.push('', `⚠️ ${contradictionHint}`);
1323
- }
1324
- if (possibleDuplicates.length > 0 ||
1325
- result.riskWarning ||
1326
- splitResult ||
1327
- result.qualityScore ||
1328
- simplicityResult) {
1329
- lines.push('', 'Advisory signals were computed and are available in structuredContent.advisorySignals.');
1330
- }
1331
- const allNextSteps = (result.nextSteps ?? []).map((step) => (typeof step === 'string' ? step : formatPostCreationSuggestion(step)));
1332
- const markdownText = allNextSteps.length > 0
1333
- ? addNextSteps(formatSuccess(ti('tools.create_spec.success', { id: spec.id, title: spec.title }), lines.join('\n')), allNextSteps)
1334
- : formatSuccess(ti('tools.create_spec.success', { id: spec.id, title: spec.title }), lines.join('\n'));
1335
- // SPEC-469: Build autopilot summary from analyzer results
1336
- const collector = new AutopilotSummaryCollector();
1337
- if (autopilot.detectedPatterns.length > 0) {
1338
- collector.pushOk('pattern-detection', `Detected patterns: ${autopilot.detectedPatterns.join(', ')}`);
1339
- advisorySignals.push(makeAdvisorySignal({
1340
- key: 'detected-patterns',
1341
- kind: 'domain',
1342
- message: `Detected patterns: ${autopilot.detectedPatterns.join(', ')}`,
1343
- source: 'heuristic',
1344
- evidence: autopilot.detectedPatterns,
1345
- confidence: 0.5,
1346
- surface: 'structuredContent',
1347
- value: autopilot.detectedPatterns,
1348
- }));
1349
- }
1350
- const totalSuggestedFiles = autopilot.suggestedFiles.create.length +
1351
- autopilot.suggestedFiles.modify.length +
1352
- autopilot.suggestedFiles.test.length;
1353
- if (totalSuggestedFiles > 0) {
1354
- collector.pushOk('file-analysis', `Suggested ${String(totalSuggestedFiles)} files (${String(autopilot.suggestedFiles.create.length)} create, ${String(autopilot.suggestedFiles.modify.length)} modify, ${String(autopilot.suggestedFiles.test.length)} test)`);
1355
- advisorySignals.push(makeAdvisorySignal({
1356
- key: 'suggested-files',
1357
- kind: 'file',
1358
- message: `${String(totalSuggestedFiles)} possible related file(s) detected.`,
1359
- source: 'heuristic',
1360
- evidence: [
1361
- ...autopilot.suggestedFiles.create.map((f) => f.path),
1362
- ...autopilot.suggestedFiles.modify.map((f) => f.path),
1363
- ...autopilot.suggestedFiles.test.map((f) => f.path),
1364
- ],
1365
- confidence: 0.45,
1366
- surface: 'structuredContent',
1367
- value: {
1368
- create: autopilot.suggestedFiles.create.map((f) => f.path),
1369
- modify: autopilot.suggestedFiles.modify.map((f) => f.path),
1370
- test: autopilot.suggestedFiles.test.map((f) => f.path),
1371
- },
1372
- deprecatedAlias: 'autopilotSummary.suggestedFiles',
1373
- }));
1374
- }
1375
- if (filteredCriteria.length > 0) {
1376
- collector.pushOk('criteria-enrichment', `Evaluated ${String(filteredCriteria.length)} proposed criteria; only directly grounded items entered the contract`);
1377
- }
1378
- if (pipelineResult.challengeSummary) {
1379
- collector.pushOk('challenge', `Challenge analysis complete: ${pipelineResult.challengeSummary}`);
1380
- }
1381
- if (pipelineResult.readinessScore !== null) {
1382
- collector.pushOk('readiness', `Readiness score: ${String(pipelineResult.readinessScore)}/100`);
1383
- advisorySignals.push(makeAdvisorySignal({
1384
- key: 'readiness-score',
1385
- kind: 'readiness',
1386
- message: `Readiness score: ${String(pipelineResult.readinessScore)}/100.`,
1387
- source: 'validator',
1388
- evidence: ['auto post-creation pipeline'],
1389
- confidence: 0.6,
1390
- surface: 'structuredContent',
1391
- value: pipelineResult.readinessScore,
1392
- }));
1393
- }
1394
- const humanSummary = `Plan created for "${spec.title}". Review the grounded criteria before approval.`;
1395
- result.advisorySignals = advisorySignals;
1396
- result.compat = buildAdvisoryCompat();
1397
- const compactResult = compactObj(result);
1398
- // SPEC-722: Issue a planner token for this spec creation.
1399
- // Best-effort — token failure never blocks spec creation.
1400
- let plannerToken;
1401
- try {
1402
- const resolvedProjectPath = resolvedInputParams.projectPath ?? '';
1403
- if (resolvedProjectPath.length > 0) {
1404
- const sessionId = resolvedInputParams.sessionId ?? 'unknown-session';
1405
- const modelId = resolvedInputParams.modelId ?? 'unknown-model';
1406
- const host = resolvedInputParams.host ?? 'unknown-host';
1407
- plannerToken = await issuePlannerToken(resolvedProjectPath, spec.id, sessionId, modelId, host);
1408
- }
1409
- }
1410
- catch {
1411
- // best-effort — token issuance failure must not block spec creation
1412
- }
1413
- // SPEC-1011 Bug E / fallback hardening: surface local file analysis in the response payload.
1414
- // Those paths are also written into ## Files only when used as technical evidence.
1415
- const suggestedFilesPayload = autopilot.suggestedFiles.create.length +
1416
- autopilot.suggestedFiles.modify.length +
1417
- autopilot.suggestedFiles.test.length >
1418
- 0
1419
- ? {
1420
- create: autopilot.suggestedFiles.create.map((f) => f.path),
1421
- modify: autopilot.suggestedFiles.modify.map((f) => f.path),
1422
- test: autopilot.suggestedFiles.test.map((f) => f.path),
1423
- }
1424
- : undefined;
1425
- const baseResult = toolResult(markdownText, {
1426
- ...compactResult,
1427
- advisorySignals,
1428
- compat: buildAdvisoryCompat(),
1429
- humanSummary,
1430
- ...(collector.hasEntries() ? { autopilotSummary: collector.getMessages() } : {}),
1431
- ...(suggestedFilesPayload !== undefined
1432
- ? { 'autopilotSummary.suggestedFiles': suggestedFilesPayload }
1433
- : {}),
1434
- ...(agentTeamPlan && agentTeamPlan.roles.length > 0 ? { agentTeamPlan } : {}),
1435
- ...(plannerToken !== undefined ? { plannerToken } : {}),
1436
- });
1437
- return {
1438
- ...baseResult,
1439
- content: [...baseResult.content, { type: 'text', text: humanSummary }],
1440
- };
1301
+ return finishRecoveredOperation(operationJournal, operationKey, criticalResult.value.data.committedResult);
1441
1302
  }
1442
1303
  catch (error) {
1443
1304
  const message = error instanceof Error ? error.message : String(error);
1444
- return {
1305
+ const errorResult = {
1445
1306
  content: [{ type: 'text', text: ti('errors.internalError', { message }) }],
1446
1307
  isError: true,
1447
1308
  };
1309
+ return claimLifecycle.committed
1310
+ ? finishRecoveredOperation(operationJournal, operationKey, errorResult)
1311
+ : errorResult;
1448
1312
  }
1449
1313
  }); // end trackCost
1450
1314
  }
@@ -1452,6 +1316,7 @@ export async function handleCreateSpec(inputParams, server) {
1452
1316
  if (!claimLifecycle.committed && !claimLifecycle.retainForInFlightWork) {
1453
1317
  await releaseIdempotencyClaim(resolvedPath, idempotencyKey, idempotencyClaim.ownerId);
1454
1318
  }
1319
+ runtimeDatabase.close();
1455
1320
  }
1456
1321
  }
1457
1322
  //# sourceMappingURL=create-spec.js.map