@planu/cli 4.13.0 → 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.
- package/CHANGELOG.md +29 -0
- package/README.md +24 -24
- package/dist/cli/commands/inspect.d.ts +4 -0
- package/dist/cli/commands/inspect.js +144 -0
- package/dist/cli/commands/install.d.ts +19 -1
- package/dist/cli/commands/install.js +145 -43
- package/dist/cli/commands/job.d.ts +3 -0
- package/dist/cli/commands/job.js +119 -0
- package/dist/cli/commands/offline.d.ts +15 -0
- package/dist/cli/commands/offline.js +132 -0
- package/dist/cli/commands/serve.js +4 -0
- package/dist/cli/commands/spec.js +1 -1
- package/dist/cli/commands/storage.d.ts +3 -0
- package/dist/cli/commands/storage.js +102 -0
- package/dist/cli/commands/uninstall.d.ts +10 -0
- package/dist/cli/commands/uninstall.js +93 -7
- package/dist/cli/commands/validate.js +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/router.js +9 -1
- package/dist/config/crash-shield-framework-rules.json +93 -0
- package/dist/config/environment-schema.json +149 -0
- package/dist/config/hardcode-exceptions.json +4 -0
- package/dist/config/license-plans.json +7 -0
- package/dist/config/native-release-public-key.pem +3 -0
- package/dist/config/native-targets.json +87 -0
- package/dist/config/product-public.d.ts +89 -0
- package/dist/config/product-public.js +140 -0
- package/dist/config/product-public.json +312 -0
- package/dist/config/product-public.ts +148 -0
- package/dist/config/release-compatibility.json +13 -0
- package/dist/config/release-policy.json +26 -0
- package/dist/config/runtime-policy.json +44 -0
- package/dist/config/skill-templates/planu-validate.md +7 -4
- package/dist/config/subagent-templates/planu-spec-implementer.md +7 -3
- package/dist/config/subagent-templates/planu-validator.md +10 -5
- package/dist/config/technology-registry.json +120 -0
- package/dist/config/version.js +7 -8
- package/dist/config/version.ts +10 -7
- package/dist/engine/abortable-process-runner.js +40 -9
- package/dist/engine/advanced-testing/accessibility-checker.js +12 -14
- package/dist/engine/advanced-testing/mutation-advisor.js +3 -4
- package/dist/engine/advanced-testing/property-based.js +2 -3
- package/dist/engine/advanced-testing/test-data-advisor.js +2 -3
- package/dist/engine/agent-generator.js +2 -1
- package/dist/engine/agent-handoff-store.js +2 -1
- package/dist/engine/agent-prompt-generator.js +7 -5
- package/dist/engine/agent-telemetry.js +2 -1
- package/dist/engine/ai-integration/gemini/extensions-advisor.js +41 -9
- package/dist/engine/ambiguity-detector.js +12 -11
- package/dist/engine/analyzer/db-engine.js +2 -3
- package/dist/engine/analyzer/detectors.js +13 -14
- package/dist/engine/analyzer/env-setup.js +9 -10
- package/dist/engine/analyzer-env-scanner/env-example.js +7 -8
- package/dist/engine/api-spec-generator/graphql-parser.js +2 -2
- package/dist/engine/api-validation/graphql-schema-validator.js +2 -1
- package/dist/engine/api-validation/openapi-impl-validator.js +6 -7
- package/dist/engine/architecture-detector.js +10 -8
- package/dist/engine/auth/config.d.ts +1 -1
- package/dist/engine/auth/config.js +4 -3
- package/dist/engine/auto-updater/atomic-upgrade.d.ts +8 -0
- package/dist/engine/auto-updater/atomic-upgrade.js +381 -0
- package/dist/engine/auto-updater/config-detector.js +9 -3
- package/dist/engine/auto-updater/config-patcher.d.ts +0 -4
- package/dist/engine/auto-updater/config-patcher.js +10 -15
- package/dist/engine/auto-updater/index.d.ts +3 -1
- package/dist/engine/auto-updater/index.js +44 -30
- package/dist/engine/auto-updater/npm-registry.js +10 -2
- package/dist/engine/auto-updater/release-verifier.d.ts +3 -0
- package/dist/engine/auto-updater/release-verifier.js +112 -0
- package/dist/engine/auto-updater/upgrade-lock.d.ts +6 -0
- package/dist/engine/auto-updater/upgrade-lock.js +28 -0
- package/dist/engine/auto-updater/upgrade-trust-state.d.ts +7 -0
- package/dist/engine/auto-updater/upgrade-trust-state.js +59 -0
- package/dist/engine/autopilot/audit-logger.js +2 -5
- package/dist/engine/best-practices-library.js +2 -1
- package/dist/engine/browser-validator.js +2 -1
- package/dist/engine/build-tool-detector.js +3 -2
- package/dist/engine/ci-generator/context-builders.js +7 -5
- package/dist/engine/ci-generator/stack-detector.js +0 -2
- package/dist/engine/ci-generator/yaml-builder.js +0 -2
- package/dist/engine/claude-config-auditor/rules-auditor.js +4 -3
- package/dist/engine/code-transforms/typescript/ast-utils.js +2 -3
- package/dist/engine/complexity-budget/trivial-detector.js +2 -1
- package/dist/engine/compliance-test-generator/index.js +7 -2
- package/dist/engine/compliance-test-generator/test-formatter.js +2 -2
- package/dist/engine/config-health/mcp-config-checker.js +2 -1
- package/dist/engine/config-health/ts-checker-scripts.js +4 -3
- package/dist/engine/config-health/ts-checker.js +3 -2
- package/dist/engine/convention-injector.js +5 -7
- package/dist/engine/convention-scanner/convention-parser.js +3 -2
- package/dist/engine/core-bridge-duplicate-blocks.d.ts +3 -0
- package/dist/engine/core-bridge-duplicate-blocks.js +57 -0
- package/dist/engine/core-bridge-gaps.d.ts +4 -0
- package/dist/engine/core-bridge-gaps.js +75 -0
- package/dist/engine/core-bridge.d.ts +9 -9
- package/dist/engine/core-bridge.js +196 -283
- package/dist/engine/cost-tracking/ledger.js +2 -5
- package/dist/engine/coverage-gap-analyzer.js +10 -1
- package/dist/engine/crash-shield/detectors/framework-detector.d.ts +2 -0
- package/dist/engine/crash-shield/detectors/framework-detector.js +110 -192
- package/dist/engine/crash-shield/detectors/typescript-detector.js +2 -1
- package/dist/engine/dashboard/data-loader.js +2 -1
- package/dist/engine/data-projects-gc/gc-runner.d.ts +7 -0
- package/dist/engine/data-projects-gc/gc-runner.js +113 -3
- package/dist/engine/data-projects-gc/scanner.js +5 -1
- package/dist/engine/decision-store.js +11 -14
- package/dist/engine/deleter/core.js +5 -5
- package/dist/engine/dep-auditor/abandonment-data.js +2 -1
- package/dist/engine/dep-auditor/abandonment-registry.js +3 -1
- package/dist/engine/dep-auditor/cve-fetcher.js +3 -0
- package/dist/engine/dep-auditor/dep-duplicates-detector.js +36 -4
- package/dist/engine/dep-auditor/license-registry.js +2 -0
- package/dist/engine/dependency-evaluator.d.ts +14 -0
- package/dist/engine/dependency-evaluator.js +81 -0
- package/dist/engine/deploy/providers/fly.js +7 -7
- package/dist/engine/deploy/providers/netlify.js +7 -7
- package/dist/engine/deploy/providers/railway.js +10 -12
- package/dist/engine/deploy/providers/vercel.js +7 -9
- package/dist/engine/deprecation-scanner/pattern-loader.js +0 -2
- package/dist/engine/desktop-detector.js +2 -3
- package/dist/engine/detect-duplication.js +2 -1
- package/dist/engine/detectors/advanced-framework-detector/css-state-detector.js +2 -1
- package/dist/engine/detectors/advanced-framework-detector/legacy-detector.js +2 -3
- package/dist/engine/detectors/advanced-framework-detector/modern-detector.js +3 -4
- package/dist/engine/detectors/agent-framework-detector.js +3 -2
- package/dist/engine/detectors/ai-native-detector.js +4 -6
- package/dist/engine/detectors/cache-db-detector.js +4 -3
- package/dist/engine/detectors/cicd-detector.js +4 -3
- package/dist/engine/detectors/deployment-detector.js +11 -12
- package/dist/engine/detectors/frontend-perf-detector.js +14 -9
- package/dist/engine/detectors/library-detector-multilang-a.js +16 -3
- package/dist/engine/detectors/library-detector-node.js +14 -4
- package/dist/engine/detectors/library-detector-python.js +7 -1
- package/dist/engine/detectors/library-detector.js +0 -2
- package/dist/engine/detectors/llm-detector/provider-maps.js +3 -2
- package/dist/engine/detectors/mcp-candidate-detector.js +12 -16
- package/dist/engine/detectors/mfe-detector.js +6 -7
- package/dist/engine/detectors/monitoring-detector.js +4 -3
- package/dist/engine/detectors/otel-detector.js +3 -2
- package/dist/engine/detectors/otel-ecosystem-detectors.d.ts +2 -2
- package/dist/engine/detectors/otel-ecosystem-detectors.js +4 -3
- package/dist/engine/detectors/platform-specialty-detector.js +3 -5
- package/dist/engine/detectors/template-engine-detector.js +3 -4
- package/dist/engine/doc-generator/builders.js +2 -3
- package/dist/engine/doc-generator/mobile-distribution-guide.js +13 -17
- package/dist/engine/doc-generator/portal/dirty-flag-map.d.ts +2 -2
- package/dist/engine/doc-generator/portal/portal-regenerator.js +3 -47
- package/dist/engine/domain-detector.js +3 -6
- package/dist/engine/dynamic-knowledge/knowledge-cache.js +3 -4
- package/dist/engine/dynamic-knowledge/knowledge-merger.js +17 -2
- package/dist/engine/dynamic-knowledge/web-researcher.js +15 -14
- package/dist/engine/dynamic-migration-detector/manifest-readers-extended.js +0 -2
- package/dist/engine/e2e-test-generator.js +4 -3
- package/dist/engine/ecosystem-absorber/knowledge-cache.js +2 -1
- package/dist/engine/ecosystem-absorber/platform-crawler.js +2 -2
- package/dist/engine/escalator/retry-counter.js +2 -1
- package/dist/engine/evidence-gates/artifact-reader.d.ts +6 -0
- package/dist/engine/evidence-gates/artifact-reader.js +105 -21
- package/dist/engine/evidence-gates/lifecycle-gate.d.ts +2 -1
- package/dist/engine/evidence-gates/lifecycle-gate.js +54 -0
- package/dist/engine/execution/context.d.ts +19 -0
- package/dist/engine/execution/context.js +127 -0
- package/dist/engine/execution/deadline-io.d.ts +21 -0
- package/dist/engine/execution/deadline-io.js +45 -0
- package/dist/engine/execution/job-executor.d.ts +16 -0
- package/dist/engine/execution/job-executor.js +140 -0
- package/dist/engine/execution/job-runtime.d.ts +78 -0
- package/dist/engine/execution/job-runtime.js +220 -0
- package/dist/engine/execution/native-relevance-scorer.d.ts +6 -0
- package/dist/engine/execution/native-relevance-scorer.js +64 -0
- package/dist/engine/execution/native-worker-dispatch.d.ts +3 -0
- package/dist/engine/execution/native-worker-dispatch.js +46 -0
- package/dist/engine/execution/native-worker-protocol.d.ts +6 -0
- package/dist/engine/execution/native-worker-protocol.js +33 -0
- package/dist/engine/execution/native-worker-runtime.d.ts +4 -0
- package/dist/engine/execution/native-worker-runtime.js +177 -0
- package/dist/engine/execution/native-worker-thread.d.ts +2 -0
- package/dist/engine/execution/native-worker-thread.js +66 -0
- package/dist/engine/execution/operation-journal.d.ts +66 -0
- package/dist/engine/execution/operation-journal.js +260 -0
- package/dist/engine/execution/outbox-worker.d.ts +31 -0
- package/dist/engine/execution/outbox-worker.js +192 -0
- package/dist/engine/execution/validate-job-executor.d.ts +24 -0
- package/dist/engine/execution/validate-job-executor.js +342 -0
- package/dist/engine/execution/validate-job-payload.d.ts +5 -0
- package/dist/engine/execution/validate-job-payload.js +87 -0
- package/dist/engine/execution/validate-job-recovery.d.ts +4 -0
- package/dist/engine/execution/validate-job-recovery.js +47 -0
- package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
- package/dist/engine/execution/validate-worker-runtime.js +100 -0
- package/dist/engine/execution/validate-worker-thread.d.ts +2 -0
- package/dist/engine/execution/validate-worker-thread.js +71 -0
- package/dist/engine/execution-plan/desktop-distribution.js +3 -7
- package/dist/engine/execution-plan/mobile-distribution.js +4 -9
- package/dist/engine/execution-plan/phases.js +4 -5
- package/dist/engine/execution-plan/plan-utils.js +8 -5
- package/dist/engine/facilitate/context-loader.js +3 -9
- package/dist/engine/figma/code-connect-fetcher.js +9 -8
- package/dist/engine/filesystem-watcher/index.d.ts +3 -3
- package/dist/engine/filesystem-watcher/index.js +5 -5
- package/dist/engine/framework-detector.js +14 -15
- package/dist/engine/git/planu-autocommit.js +8 -7
- package/dist/engine/git/repository-probe.d.ts +3 -0
- package/dist/engine/git/repository-probe.js +13 -0
- package/dist/engine/global-rules-manager.js +2 -2
- package/dist/engine/handoff-artifacts/io.js +2 -3
- package/dist/engine/handoff-artifacts/schemas/red-tests-handoff.js +8 -1
- package/dist/engine/handoff-artifacts/schemas.d.ts +4 -0
- package/dist/engine/handoff-artifacts/schemas.js +5 -0
- package/dist/engine/hook-generator/stack-hook-templates.js +4 -4
- package/dist/engine/hooks/config-loader.js +1 -1
- package/dist/engine/hooks/context-injector.js +4 -7
- package/dist/engine/hooks/file-watcher.js +1 -14
- package/dist/engine/hooks-reconciler.js +6 -4
- package/dist/engine/infrastructure/component-mapper.js +5 -7
- package/dist/engine/infrastructure/docker-compose-generator.js +8 -10
- package/dist/engine/infrastructure/index.js +6 -3
- package/dist/engine/infrastructure/kubernetes-generator.js +2 -2
- package/dist/engine/infrastructure/railway-generator.js +10 -8
- package/dist/engine/infrastructure/signal-detector.js +6 -8
- package/dist/engine/infrastructure/terraform-generator.js +6 -8
- package/dist/engine/legal-compliance/detector.js +3 -2
- package/dist/engine/local-first/storage-advisor.js +5 -6
- package/dist/engine/macos-keychain-native-port.d.ts +5 -0
- package/dist/engine/macos-keychain-native-port.js +26 -0
- package/dist/engine/marketplace-fetcher/cache.js +3 -1
- package/dist/engine/mcp-config/mcp-config-writer.d.ts +2 -2
- package/dist/engine/mcp-config/mcp-config-writer.js +10 -8
- package/dist/engine/migration/db-migrator.js +2 -5
- package/dist/engine/migration/equivalence-mapper.js +12 -13
- package/dist/engine/migration/service-catalogs.js +6 -7
- package/dist/engine/migration/service-migrator-catalogs.js +6 -7
- package/dist/engine/mobile-detector-ios.js +2 -3
- package/dist/engine/mobile-detector.js +16 -4
- package/dist/engine/model-router/complexity-analyzer.js +4 -7
- package/dist/engine/multi-agent-review/security-analyzer.js +3 -1
- package/dist/engine/multi-app-detector/app-type.js +26 -21
- package/dist/engine/multi-app-detector/core.js +3 -2
- package/dist/engine/multi-teammate-review/disagreement-counter.js +2 -1
- package/dist/engine/multi-teammate-review/panel-orchestrator.js +0 -2
- package/dist/engine/mutation-config-generator.js +10 -7
- package/dist/engine/native-capability-policy.d.ts +4 -0
- package/dist/engine/native-capability-policy.js +24 -0
- package/dist/engine/native-platform.d.ts +3 -0
- package/dist/engine/native-platform.js +44 -0
- package/dist/engine/native-runtime-handshake.d.ts +20 -0
- package/dist/engine/native-runtime-handshake.js +230 -0
- package/dist/engine/network-policy.d.ts +27 -0
- package/dist/engine/network-policy.js +174 -0
- package/dist/engine/next-spec-resolver/dependency-filter.js +2 -22
- package/dist/engine/nfr-profile-detector.js +12 -16
- package/dist/engine/nli-keywords.js +8 -9
- package/dist/engine/oauth/config-guard.js +4 -5
- package/dist/engine/observability/local-execution-spans.d.ts +15 -0
- package/dist/engine/observability/local-execution-spans.js +63 -0
- package/dist/engine/orchestrator/runtime.js +0 -1
- package/dist/engine/package-registry.js +2 -6
- package/dist/engine/performance-analyzer.js +2 -5
- package/dist/engine/permissions-merger/stack-detectors.js +5 -5
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +39 -0
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +1310 -0
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +39 -0
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +1310 -0
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +38 -0
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +1310 -0
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +38 -0
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +1310 -0
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +38 -0
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +1310 -0
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +38 -0
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +1310 -0
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +38 -0
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +1310 -0
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +38 -0
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +1310 -0
- package/dist/engine/platform-detector/desktop.js +15 -2
- package/dist/engine/platform-detector/extensions.js +2 -1
- package/dist/engine/platform-detector/games.js +2 -1
- package/dist/engine/platform-detector.js +3 -2
- package/dist/engine/platform-engineering/idp-detector.js +2 -1
- package/dist/engine/plugin-installer/stack-matcher.js +9 -17
- package/dist/engine/plugins/lifecycle.js +6 -2
- package/dist/engine/prior-decisions/contradiction-detector.js +60 -30
- package/dist/engine/project-dna/stack-detector.js +15 -17
- package/dist/engine/project-graph/builder.js +11 -0
- package/dist/engine/project-graph/cache.js +1 -1
- package/dist/engine/project-graph/freshness-projection.d.ts +16 -0
- package/dist/engine/project-graph/freshness-projection.js +95 -0
- package/dist/engine/project-graph/index.d.ts +1 -0
- package/dist/engine/project-graph/index.js +1 -0
- package/dist/engine/project-graph/query.js +15 -25
- package/dist/engine/project-health-checker.js +3 -4
- package/dist/engine/project-scanner/stack-detector.js +17 -17
- package/dist/engine/property-test-generator.js +2 -3
- package/dist/engine/qa-gate.d.ts +1 -0
- package/dist/engine/qa-gate.js +6 -4
- package/dist/engine/quality-gates/gate-catalog.js +47 -46
- package/dist/engine/quality-gates/gate-injector.js +9 -4
- package/dist/engine/registry/core.js +0 -2
- package/dist/engine/registry/loader.js +9 -12
- package/dist/engine/registry/matcher.js +129 -24
- package/dist/engine/resilience-detector/concurrency-detector.js +4 -4
- package/dist/engine/resilience-detector/middleware-detector.js +11 -13
- package/dist/engine/resilience-detector/validation-detector.js +17 -4
- package/dist/engine/reverse-engineer/config-analyzer.js +9 -8
- package/dist/engine/reverse-engineer/orchestrator.js +5 -9
- package/dist/engine/reverse-engineer/test-file-parser.js +6 -3
- package/dist/engine/rules-generator/index.js +6 -5
- package/dist/engine/runtime-policy.d.ts +7 -0
- package/dist/engine/runtime-policy.js +101 -0
- package/dist/engine/runtime-security/checkers/content-security.js +21 -6
- package/dist/engine/runtime-security/checkers/file-permissions.js +0 -2
- package/dist/engine/safety/atomic-write-file.js +20 -9
- package/dist/engine/safety/atomic-writer.js +10 -3
- package/dist/engine/safety/cross-process-lock.d.ts +3 -40
- package/dist/engine/safety/cross-process-lock.js +268 -272
- package/dist/engine/safety/file-mutex.d.ts +2 -9
- package/dist/engine/safety/file-mutex.js +155 -87
- package/dist/engine/safety/health-monitor.js +15 -6
- package/dist/engine/safety/lock-lease-store.d.ts +79 -0
- package/dist/engine/safety/lock-lease-store.js +372 -0
- package/dist/engine/safety/lock-scavenger.d.ts +2 -5
- package/dist/engine/safety/lock-scavenger.js +158 -76
- package/dist/engine/safety/lock-staleness.js +4 -1
- package/dist/engine/safety/obsolete-lock-guard.d.ts +8 -0
- package/dist/engine/safety/obsolete-lock-guard.js +31 -0
- package/dist/engine/safety/transaction.js +3 -3
- package/dist/engine/sandbox/index.js +2 -1
- package/dist/engine/sandbox/runner-detect.js +3 -2
- package/dist/engine/sandbox/runner-docker.js +4 -3
- package/dist/engine/scan-project/module-discoverer.js +3 -2
- package/dist/engine/schema-generator.js +16 -9
- package/dist/engine/security-analyzer/criteria-generator.js +2 -3
- package/dist/engine/self-healing/healer.js +4 -4
- package/dist/engine/session-safeguard/learnings-buffer.d.ts +1 -2
- package/dist/engine/session-safeguard/learnings-buffer.js +42 -65
- package/dist/engine/shared-agent-memory.js +66 -74
- package/dist/engine/skill-adapter/command-rewriter.js +3 -2
- package/dist/engine/skill-adapter/index.js +3 -3
- package/dist/engine/skill-adapter/placeholder-map.js +3 -2
- package/dist/engine/skill-bootstrap/stack-matcher.js +47 -48
- package/dist/engine/skill-generation/stack-content-generator.js +0 -2
- package/dist/engine/skill-generator/workflow-skill-generator.js +2 -1
- package/dist/engine/skill-registry/ttl-refresh.js +3 -1
- package/dist/engine/skills/skills-fetcher.js +3 -6
- package/dist/engine/skills-reconciler.js +19 -39
- package/dist/engine/spec-coverage/test-finder.js +7 -6
- package/dist/engine/spec-diff-engine.js +3 -3
- package/dist/engine/spec-generator/api-key-resolver.d.ts +1 -1
- package/dist/engine/spec-generator/api-key-resolver.js +3 -24
- package/dist/engine/spec-generators/issue-extractor.js +9 -3
- package/dist/engine/spec-migrator/drift-detector.js +5 -13
- package/dist/engine/spec-migrator/filesystem-import.js +14 -10
- package/dist/engine/spec-migrator/planu-canonical-policy.js +10 -1
- package/dist/engine/spec-migrator/strict-planu-cleanup.js +24 -25
- package/dist/engine/spec-registry/adapter.d.ts +0 -5
- package/dist/engine/spec-registry/adapter.js +45 -46
- package/dist/engine/spec-registry/client.js +2 -0
- package/dist/engine/spec-source-sync.js +3 -2
- package/dist/engine/spec-templates/custom-loader.js +2 -3
- package/dist/engine/spec-templates/templates-domain-specific.js +8 -5
- package/dist/engine/spec-templates/templates-perf-integration.js +2 -3
- package/dist/engine/stack-auditor/manifest-reader.js +0 -2
- package/dist/engine/staleness/stale-implementing.js +7 -7
- package/dist/engine/tdd-scaffold-generator.js +24 -11
- package/dist/engine/teammate-router/green-phase-verifier.js +2 -1
- package/dist/engine/teammate-router/red-phase-verifier.js +2 -1
- package/dist/engine/technology-registry.d.ts +11 -0
- package/dist/engine/technology-registry.js +142 -0
- package/dist/engine/telemetry/error-reporter.d.ts +1 -2
- package/dist/engine/telemetry/error-reporter.js +11 -18
- package/dist/engine/telemetry/health-checker.js +5 -14
- package/dist/engine/telemetry/index.d.ts +0 -1
- package/dist/engine/telemetry/index.js +0 -1
- package/dist/engine/telemetry/stance.js +3 -2
- package/dist/engine/telemetry/telemetry-client.d.ts +1 -5
- package/dist/engine/telemetry/telemetry-client.js +45 -29
- package/dist/engine/telemetry/telemetry-store.d.ts +3 -3
- package/dist/engine/telemetry/telemetry-store.js +30 -23
- package/dist/engine/test-framework-detector/detectors.js +8 -8
- package/dist/engine/test-framework-detector/strategy.js +8 -9
- package/dist/engine/test-generators/agent-test-templates.js +2 -3
- package/dist/engine/test-generators/contract-test-generator.d.ts +1 -1
- package/dist/engine/test-generators/contract-test-generator.js +9 -202
- package/dist/engine/test-generators/platform-test-templates-b.js +2 -3
- package/dist/engine/test-generators/platform-test-templates.js +2 -5
- package/dist/engine/test-mocks-generator.js +4 -3
- package/dist/engine/test-plan-generator.js +30 -12
- package/dist/engine/test-scaffold-generator/advanced-scaffold.js +4 -5
- package/dist/engine/test-scaffold-generator/unit-scaffold.js +5 -6
- package/dist/engine/timing/budget.d.ts +6 -17
- package/dist/engine/timing/budget.js +80 -64
- package/dist/engine/tool-groups/group-manager.js +3 -3
- package/dist/engine/universal-rules/installer.js +1 -1
- package/dist/engine/universal-rules/rules/planu-modes.js +2 -0
- package/dist/engine/universal-rules/rules/planu-release-policy.js +1 -0
- package/dist/engine/update-notifier.js +8 -5
- package/dist/engine/validation/approved-spec-portability.d.ts +12 -0
- package/dist/engine/validation/approved-spec-portability.js +107 -0
- package/dist/engine/validation/durable-validation.d.ts +36 -0
- package/dist/engine/validation/durable-validation.js +335 -0
- package/dist/engine/validation/validation-freshness.d.ts +36 -0
- package/dist/engine/validation/validation-freshness.js +427 -0
- package/dist/engine/validation/validation-receipt-codec.d.ts +13 -0
- package/dist/engine/validation/validation-receipt-codec.js +182 -0
- package/dist/engine/validation/validation-receipt.d.ts +59 -0
- package/dist/engine/validation/validation-receipt.js +282 -0
- package/dist/engine/validation/validation-source-policy.d.ts +4 -0
- package/dist/engine/validation/validation-source-policy.js +16 -0
- package/dist/engine/validation/validation-submission.d.ts +36 -0
- package/dist/engine/validation/validation-submission.js +128 -0
- package/dist/engine/validation-evidence-ledger.js +41 -0
- package/dist/engine/validation-impact-planner.js +25 -9
- package/dist/engine/validator/spec-compliance-runner.d.ts +1 -1
- package/dist/engine/validator/spec-compliance-runner.js +17 -8
- package/dist/engine/validator/validation-report-writer.js +1 -1
- package/dist/engine/validator.js +2 -1
- package/dist/engine/verify-integrations/index.js +1 -1
- package/dist/engine/version-resolver.js +5 -6
- package/dist/engine/web-fetcher/stack-advisor.js +156 -92
- package/dist/engine/web-fetcher/stack-detector.js +114 -54
- package/dist/engine/workspace-manager.js +3 -2
- package/dist/errors/classified-degradation.d.ts +3 -0
- package/dist/errors/classified-degradation.js +10 -0
- package/dist/errors/degradation-sink.d.ts +3 -0
- package/dist/errors/degradation-sink.js +5 -0
- package/dist/errors/error-taxonomy.d.ts +12 -0
- package/dist/errors/error-taxonomy.js +62 -0
- package/dist/hosts/claude-code/ux/mcp-prompts.js +10 -4
- package/dist/hosts/claude-code/ux/mcp-resources.js +4 -2
- package/dist/hosts/codex/config-scaffold.js +4 -3
- package/dist/hosts/gemini/config-scaffold.js +2 -1
- package/dist/hosts/gemini/multimodal-spec-flow.js +7 -4
- package/dist/index.js +21 -6
- package/dist/resources/patterns.js +3 -1
- package/dist/resources/specs.js +3 -1
- package/dist/resources/templates.js +3 -1
- package/dist/security/adapters/environment.d.ts +12 -0
- package/dist/security/adapters/environment.js +25 -0
- package/dist/security/adapters/linux-secret-service.d.ts +8 -0
- package/dist/security/adapters/linux-secret-service.js +60 -0
- package/dist/security/adapters/macos-keychain.d.ts +18 -0
- package/dist/security/adapters/macos-keychain.js +90 -0
- package/dist/security/adapters/windows-credential-manager.d.ts +8 -0
- package/dist/security/adapters/windows-credential-manager.js +58 -0
- package/dist/security/redactor.d.ts +5 -0
- package/dist/security/redactor.js +58 -0
- package/dist/security/secret-field.d.ts +5 -0
- package/dist/security/secret-field.js +17 -0
- package/dist/security/secret-migration.d.ts +3 -0
- package/dist/security/secret-migration.js +123 -0
- package/dist/security/secret-provider.d.ts +23 -0
- package/dist/security/secret-provider.js +145 -0
- package/dist/security/secure-json.d.ts +3 -0
- package/dist/security/secure-json.js +29 -0
- package/dist/storage/api-surfaces-store.js +2 -2
- package/dist/storage/approval-operation-lock.d.ts +1 -1
- package/dist/storage/approval-operation-lock.js +5 -3
- package/dist/storage/audit-trail-store.d.ts +1 -1
- package/dist/storage/audit-trail-store.js +48 -62
- package/dist/storage/autopilot-log-store.js +12 -5
- package/dist/storage/base-store.d.ts +8 -8
- package/dist/storage/base-store.js +57 -20
- package/dist/storage/checkpoint-store.js +5 -2
- package/dist/storage/comments-store.js +2 -2
- package/dist/storage/compliance-audit-store.js +5 -2
- package/dist/storage/compliance-gate-config-store.js +7 -4
- package/dist/storage/compliance-store.js +2 -2
- package/dist/storage/context-profile-store.js +2 -2
- package/dist/storage/crash-shield-store.js +8 -4
- package/dist/storage/feedback-store.js +10 -6
- package/dist/storage/figma-store.js +8 -4
- package/dist/storage/file-mutex.js +9 -1
- package/dist/storage/gaps-log.js +7 -4
- package/dist/storage/global-projects-store.js +4 -2
- package/dist/storage/ideas-store.js +2 -2
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/knowledge-store/knowledge.js +27 -33
- package/dist/storage/lessons-store.js +2 -2
- package/dist/storage/license-store.js +13 -41
- package/dist/storage/migrations/canonical-storage.d.ts +15 -0
- package/dist/storage/migrations/canonical-storage.js +599 -0
- package/dist/storage/oauth-store.js +36 -8
- package/dist/storage/path-resolver.js +16 -3
- package/dist/storage/pr-store.js +2 -2
- package/dist/storage/project-drift-store.js +20 -8
- package/dist/storage/project-identity.d.ts +32 -0
- package/dist/storage/project-identity.js +194 -0
- package/dist/storage/project-resolver.js +14 -7
- package/dist/storage/release-notes-store.js +2 -6
- package/dist/storage/runtime-db.d.ts +186 -0
- package/dist/storage/runtime-db.js +1054 -0
- package/dist/storage/schema-registry.d.ts +5 -0
- package/dist/storage/schema-registry.js +74 -0
- package/dist/storage/sentry-store.js +20 -9
- package/dist/storage/session-state-store.js +12 -5
- package/dist/storage/session-store.js +12 -4
- package/dist/storage/skill-registry-storage.d.ts +1 -1
- package/dist/storage/skill-registry-storage.js +13 -11
- package/dist/storage/slack-store.js +10 -5
- package/dist/storage/spec-store.js +31 -24
- package/dist/storage/status-store/file-lock.js +31 -9
- package/dist/storage/status-store/self-healing.js +10 -5
- package/dist/storage/status-store/version-sync.js +8 -6
- package/dist/storage/steering-store.js +2 -2
- package/dist/storage/storage-bundle.d.ts +5 -0
- package/dist/storage/storage-bundle.js +117 -0
- package/dist/storage/storage-catalog-validation.d.ts +3 -0
- package/dist/storage/storage-catalog-validation.js +20 -0
- package/dist/storage/storage-catalog.d.ts +25 -0
- package/dist/storage/storage-catalog.js +390 -0
- package/dist/storage/storage-layout.d.ts +24 -0
- package/dist/storage/storage-layout.js +101 -0
- package/dist/storage/storybook-store.js +2 -2
- package/dist/storage/supabase-store.js +24 -6
- package/dist/storage/tdd-policy-store.js +8 -6
- package/dist/storage/tech-debt-store.js +3 -3
- package/dist/storage/technology-selection-store.d.ts +1 -1
- package/dist/storage/technology-selection-store.js +6 -3
- package/dist/storage/token-cache-store.js +3 -3
- package/dist/storage/token-ledger-store.js +13 -8
- package/dist/storage/transition-log.js +7 -4
- package/dist/storage/trash-store.js +15 -6
- package/dist/storage/vector-store/migrator.js +7 -2
- package/dist/storage/vector-store/sqlite-adapter.js +4 -1
- package/dist/storage/webhook-server-store.js +2 -2
- package/dist/tools/api-spec-generator-handler.js +3 -2
- package/dist/tools/auto-update-handler.d.ts +1 -1
- package/dist/tools/auto-update-handler.js +1 -1
- package/dist/tools/browser-validate-handler.js +2 -1
- package/dist/tools/challenge-spec/platform-challenge-scenarios-b.js +8 -5
- package/dist/tools/challenge-spec/scenarios-desktop.js +8 -3
- package/dist/tools/challenge-spec/scenarios-failure.js +7 -2
- package/dist/tools/challenge-spec/security-challenge-scenarios.js +3 -3
- package/dist/tools/clarify-requirements/multiple-choice.js +53 -41
- package/dist/tools/comments-handler.js +2 -3
- package/dist/tools/compliance-test-handler.js +2 -2
- package/dist/tools/configure-telemetry.js +11 -11
- package/dist/tools/create-spec/auto-pipeline.js +13 -1
- package/dist/tools/create-spec/autopilot-analyzer.d.ts +1 -1
- package/dist/tools/create-spec/autopilot-analyzer.js +2 -4
- package/dist/tools/create-spec/mcp-tool-contract.d.ts +10 -4
- package/dist/tools/create-spec/mcp-tool-contract.js +7 -36
- package/dist/tools/create-spec/post-creation.d.ts +2 -1
- package/dist/tools/create-spec/post-creation.js +56 -54
- package/dist/tools/create-spec/relevance-scorer.d.ts +1 -1
- package/dist/tools/create-spec/relevance-scorer.js +17 -1
- package/dist/tools/create-spec/spec-builder.js +2 -12
- package/dist/tools/create-spec/spec-created-outbox-consumer.d.ts +14 -0
- package/dist/tools/create-spec/spec-created-outbox-consumer.js +176 -0
- package/dist/tools/create-spec.js +385 -520
- package/dist/tools/define-ui-contract/agent-interaction-contract.js +2 -4
- package/dist/tools/define-ui-contract-desktop/desktop-contract.js +12 -4
- package/dist/tools/define-ui-contract-desktop/native-contract.js +7 -3
- package/dist/tools/define-ui-contract-extensions.js +2 -3
- package/dist/tools/define-ui-contract-mobile.js +5 -9
- package/dist/tools/define-ui-contract-web/component-tree.js +4 -3
- package/dist/tools/define-ui-contract.js +7 -4
- package/dist/tools/deploy/deploy-spec.js +2 -4
- package/dist/tools/deploy/deploy-status.js +2 -4
- package/dist/tools/design-schema/nosql-category-schemas.js +2 -3
- package/dist/tools/design-schema-sql/migrations.js +3 -2
- package/dist/tools/design-schema-sql/tables.js +4 -1
- package/dist/tools/design-schema.js +4 -3
- package/dist/tools/feedback-handler.js +2 -4
- package/dist/tools/gc-data-projects.js +5 -5
- package/dist/tools/generate-execution-plan.js +3 -4
- package/dist/tools/generate-sub-agent.js +2 -1
- package/dist/tools/generate-tests/generators/a11y-tests-generator.js +5 -4
- package/dist/tools/generate-tests/generators/advanced-testing-generator.js +5 -4
- package/dist/tools/generate-tests/generators/concurrency-test-generator/js-templates.js +9 -4
- package/dist/tools/generate-tests/generators/concurrency-test-generator.js +8 -4
- package/dist/tools/generate-tests/generators/database/detectors.js +9 -3
- package/dist/tools/generate-tests/generators/database/index.js +2 -4
- package/dist/tools/generate-tests/generators/event-test-generator.js +5 -4
- package/dist/tools/generate-tests/generators/game-tests-generator.js +2 -1
- package/dist/tools/generate-tests/generators/graphql-test-generator.js +11 -5
- package/dist/tools/generate-tests/generators/grpc-test-generator.js +2 -3
- package/dist/tools/generate-tests/generators/llm-security-test-generator.js +4 -3
- package/dist/tools/generate-tests/generators/local-first-test-generator.js +4 -3
- package/dist/tools/generate-tests/generators/mcp-tests-generator.js +11 -9
- package/dist/tools/generate-tests/generators/microservices/index.js +2 -3
- package/dist/tools/generate-tests/generators/otel-test-generator.js +6 -3
- package/dist/tools/generate-tests/generators/security/detectors.js +2 -5
- package/dist/tools/generate-tests/generators/security/index.js +2 -4
- package/dist/tools/generate-tests/generators/supply-chain-test-generator.js +2 -3
- package/dist/tools/generate-tests/generators/visual-regression-generator.js +14 -17
- package/dist/tools/generate-tests/generators/websocket-test-generator.js +2 -3
- package/dist/tools/generate-tests/test-helpers.js +11 -12
- package/dist/tools/generate-tests-content.js +4 -3
- package/dist/tools/generate-tests.js +7 -4
- package/dist/tools/git/git-helpers.d.ts +0 -2
- package/dist/tools/git/git-helpers.js +7 -7
- package/dist/tools/github-pr-handler.js +10 -3
- package/dist/tools/heal-spec-docs.js +6 -53
- package/dist/tools/hook-generator-handler.js +6 -6
- package/dist/tools/init-constitution/platform-principles.js +4 -2
- package/dist/tools/init-project/agents-md-writer.js +14 -5
- package/dist/tools/init-project/claude-md-generator.js +19 -12
- package/dist/tools/init-project/handler.js +165 -73
- package/dist/tools/init-project/host-assets-writer.d.ts +1 -1
- package/dist/tools/init-project/host-assets-writer.js +4 -2
- package/dist/tools/init-project/lifecycle-helpers.js +3 -5
- package/dist/tools/init-project/lint-scaffolder.js +6 -2
- package/dist/tools/init-project/migration-runner.d.ts +10 -1
- package/dist/tools/init-project/migration-runner.js +68 -3
- package/dist/tools/init-project/per-client-files-writer.js +14 -4
- package/dist/tools/init-project/rules-generator.js +10 -2
- package/dist/tools/init-project/scaffold-writer.d.ts +1 -1
- package/dist/tools/init-project/scaffold-writer.js +17 -15
- package/dist/tools/jobs/handlers.d.ts +15 -0
- package/dist/tools/jobs/handlers.js +126 -0
- package/dist/tools/list-specs.js +35 -34
- package/dist/tools/manage-plugins-handler.js +17 -9
- package/dist/tools/migrate-tech/advanced-handlers.js +3 -2
- package/dist/tools/migrate-tech/build-tool-handlers.js +3 -2
- package/dist/tools/migrate-tech/core-handlers.js +5 -2
- package/dist/tools/migrate-tech/data-handlers.js +6 -3
- package/dist/tools/migrate-tech-advanced/rollback-handlers.js +3 -2
- package/dist/tools/migrate-tech-advanced/service-handlers.js +5 -2
- package/dist/tools/oauth-handler.js +7 -1
- package/dist/tools/register-sdd-tools.d.ts +1 -1
- package/dist/tools/register-sdd-tools.js +5 -0
- package/dist/tools/register-spec-tools/core-spec-tools.js +31 -0
- package/dist/tools/registry/auth.js +13 -5
- package/dist/tools/registry/publish.js +7 -4
- package/dist/tools/resolve-project-path.d.ts +2 -2
- package/dist/tools/resolve-project-path.js +7 -7
- package/dist/tools/reverse-engineer/analyzer.js +14 -14
- package/dist/tools/rollback-release.js +3 -2
- package/dist/tools/safe-handler.js +295 -171
- package/dist/tools/schema-generator-handler.js +2 -1
- package/dist/tools/schemas/output-schemas.d.ts +88 -82
- package/dist/tools/schemas/output-schemas.js +12 -94
- package/dist/tools/schemas/plugins-schemas.js +0 -2
- package/dist/tools/schemas/registry.js +0 -2
- package/dist/tools/schemas/skill-registry-schemas.js +0 -2
- package/dist/tools/schemas/validate-output-schema.d.ts +256 -0
- package/dist/tools/schemas/validate-output-schema.js +212 -0
- package/dist/tools/sentry-handler.js +6 -1
- package/dist/tools/skill-bootstrap-handler.js +7 -4
- package/dist/tools/status-handler.js +4 -0
- package/dist/tools/storage-bundle-handler.d.ts +9 -0
- package/dist/tools/storage-bundle-handler.js +29 -0
- package/dist/tools/storage-paths-handler.d.ts +9 -0
- package/dist/tools/storage-paths-handler.js +17 -0
- package/dist/tools/suggest-mcp-server.js +11 -5
- package/dist/tools/suggest-mcps.js +29 -9
- package/dist/tools/suggest-tooling/advanced-testing-catalog.js +4 -5
- package/dist/tools/suggest-tooling/build-tool-catalog.js +2 -1
- package/dist/tools/suggest-tooling/css-framework-catalog.js +13 -7
- package/dist/tools/suggest-tooling/framework-catalog.js +3 -5
- package/dist/tools/suggest-tooling/frontend-perf-catalog.js +2 -6
- package/dist/tools/suggest-tooling/handler.js +10 -4
- package/dist/tools/suggest-tooling/hypermedia-catalog.js +11 -3
- package/dist/tools/suggest-tooling/linting-catalog.js +4 -7
- package/dist/tools/suggest-tooling/llm-security-catalog.js +2 -1
- package/dist/tools/suggest-tooling/local-first-catalog.js +7 -5
- package/dist/tools/suggest-tooling/observability-catalog.js +3 -4
- package/dist/tools/suggest-tooling/otel-catalog.js +4 -1
- package/dist/tools/suggest-tooling/resilience-catalog.js +16 -5
- package/dist/tools/suggest-tooling/skills-catalog.js +10 -9
- package/dist/tools/suggest-tooling/supply-chain-catalog.js +2 -3
- package/dist/tools/supabase-handler.js +2 -1
- package/dist/tools/token-intelligence-handler.js +2 -2
- package/dist/tools/token-recording.js +2 -2
- package/dist/tools/token-savings-handler.js +2 -2
- package/dist/tools/tool-registry/core-tools.js +131 -0
- package/dist/tools/tool-registry/group-infra.js +10 -12
- package/dist/tools/tool-registry/group-quality-compliance.js +5 -12
- package/dist/tools/update-status/approval-gates.d.ts +13 -0
- package/dist/tools/update-status/approval-gates.js +81 -0
- package/dist/tools/update-status/batch.js +4 -2
- package/dist/tools/update-status/dod-gates.d.ts +6 -24
- package/dist/tools/update-status/dod-gates.js +60 -135
- package/dist/tools/update-status/done-receipt-verifier.d.ts +15 -0
- package/dist/tools/update-status/done-receipt-verifier.js +145 -0
- package/dist/tools/update-status/evidence-gate.js +154 -2
- package/dist/tools/update-status/file-sync.js +23 -12
- package/dist/tools/update-status/gate-harness.d.ts +7 -0
- package/dist/tools/update-status/gate-harness.js +8 -0
- package/dist/tools/update-status/index.js +228 -325
- package/dist/tools/update-status/qa-gate.d.ts +1 -1
- package/dist/tools/update-status/qa-gate.js +2 -2
- package/dist/tools/update-status/side-effects.js +30 -37
- package/dist/tools/update-status/transition-guard.d.ts +4 -2
- package/dist/tools/update-status/transition-guard.js +57 -10
- package/dist/tools/update-status-convention-gate.js +24 -23
- package/dist/tools/update-status-reconcile.js +2 -2
- package/dist/tools/validate-api-contract-handler.js +3 -3
- package/dist/tools/validate-lint.js +20 -13
- package/dist/tools/validate.d.ts +3 -1
- package/dist/tools/validate.js +213 -5
- package/dist/transports/http-transport.js +84 -61
- package/dist/transports/middleware/with-telemetry.js +3 -2
- package/dist/types/abortable-process.d.ts +2 -0
- package/dist/types/advanced-framework.js +0 -2
- package/dist/types/atomic-upgrade.d.ts +71 -0
- package/dist/types/atomic-upgrade.js +2 -0
- package/dist/types/ci.js +0 -2
- package/dist/types/core-bridge.d.ts +78 -1
- package/dist/types/crash-shield-framework-rules.d.ts +24 -0
- package/dist/types/crash-shield-framework-rules.js +2 -0
- package/dist/types/data-gc.d.ts +16 -0
- package/dist/types/deploy.js +0 -2
- package/dist/types/durable-job.d.ts +78 -0
- package/dist/types/durable-job.js +2 -0
- package/dist/types/durable-validation.d.ts +60 -0
- package/dist/types/durable-validation.js +2 -0
- package/dist/types/estimation.d.ts +2 -0
- package/dist/types/evidence-gates.d.ts +9 -1
- package/dist/types/execution.d.ts +43 -0
- package/dist/types/handoff-artifacts.d.ts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/infrastructure.js +0 -2
- package/dist/types/lifecycle.js +0 -2
- package/dist/types/migration/canonical-storage.d.ts +37 -0
- package/dist/types/migration/canonical-storage.js +2 -0
- package/dist/types/migration/index.d.ts +1 -1
- package/dist/types/native-worker.d.ts +48 -0
- package/dist/types/native-worker.js +2 -0
- package/dist/types/network-policy.d.ts +12 -0
- package/dist/types/network-policy.js +2 -0
- package/dist/types/oauth.js +0 -2
- package/dist/types/observability.d.ts +32 -0
- package/dist/types/outbox-worker.d.ts +35 -0
- package/dist/types/outbox-worker.js +11 -0
- package/dist/types/permissions-config.d.ts +0 -27
- package/dist/types/permissions-config.js +0 -2
- package/dist/types/plugin-install.d.ts +0 -11
- package/dist/types/plugin-install.js +0 -2
- package/dist/types/portal.d.ts +1 -0
- package/dist/types/product-public.d.ts +75 -0
- package/dist/types/product-public.js +2 -0
- package/dist/types/project/inputs.d.ts +2 -0
- package/dist/types/project/mfe-detection.js +0 -2
- package/dist/types/project/platform-mobile.js +0 -2
- package/dist/types/project/platform-specialty.js +0 -2
- package/dist/types/project-knowledge-graph.d.ts +7 -0
- package/dist/types/runtime-database.d.ts +10 -0
- package/dist/types/runtime-database.js +2 -0
- package/dist/types/runtime-policy.d.ts +40 -0
- package/dist/types/runtime-policy.js +2 -0
- package/dist/types/safety.d.ts +4 -5
- package/dist/types/schema-registry.d.ts +12 -0
- package/dist/types/schema-registry.js +2 -0
- package/dist/types/security.d.ts +52 -0
- package/dist/types/skill-registry.js +0 -2
- package/dist/types/spec/inputs.d.ts +2 -0
- package/dist/types/spec-lock-v2.d.ts +13 -7
- package/dist/types/spec-lock-v2.js +1 -1
- package/dist/types/spec-registry.js +0 -2
- package/dist/types/storage-bundle.d.ts +13 -0
- package/dist/types/storage-bundle.js +2 -0
- package/dist/types/storage-catalog.d.ts +18 -0
- package/dist/types/storage-catalog.js +2 -0
- package/dist/types/team-planner.js +0 -2
- package/dist/types/technology-registry.d.ts +35 -0
- package/dist/types/technology-registry.js +2 -0
- package/dist/types/technology-symbols.generated.d.ts +117 -0
- package/dist/types/technology-symbols.generated.js +2 -0
- package/dist/types/telemetry.d.ts +3 -3
- package/dist/types/transport.d.ts +2 -0
- package/dist/types/validate-worker.d.ts +44 -0
- package/dist/types/validate-worker.js +2 -0
- package/dist/types/validation-evidence.d.ts +1 -1
- package/dist/types/validation-receipt.d.ts +104 -0
- package/dist/types/validation-receipt.js +2 -0
- package/package.json +31 -20
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
- package/dist/engine/telemetry/geo-resolver.d.ts +0 -9
- package/dist/engine/telemetry/geo-resolver.js +0 -43
- package/dist/storage/data-dir-discovery.d.ts +0 -31
- package/dist/storage/data-dir-discovery.js +0 -140
- package/dist/storage/migrations/cwd-to-absolute.d.ts +0 -25
- package/dist/storage/migrations/cwd-to-absolute.js +0 -281
- package/dist/tools/create-spec/adapters/prior-decisions-hint.d.ts +0 -14
- package/dist/tools/create-spec/adapters/prior-decisions-hint.js +0 -30
- package/dist/tools/init-project/ancestor-data-detector.d.ts +0 -22
- package/dist/tools/init-project/ancestor-data-detector.js +0 -81
- package/dist/tools/update-status/force-done-audit.d.ts +0 -2
- package/dist/tools/update-status/force-done-audit.js +0 -23
- package/dist/types/migration/cwd-to-absolute.d.ts +0 -8
- 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 {
|
|
7
|
-
import {
|
|
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 {
|
|
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
|
|
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
|
|
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
|
-
/**
|
|
315
|
-
function computeIdempotencyKey(title, projectPath) {
|
|
316
|
-
|
|
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
|
|
319
|
-
const
|
|
320
|
-
const
|
|
321
|
-
const
|
|
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
|
|
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
|
|
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
|
|
592
|
+
await executionRemove(quarantinePath, { force: true });
|
|
481
593
|
return true;
|
|
482
594
|
}
|
|
483
595
|
try {
|
|
484
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
797
|
-
const criticalResult = await withTotalBudget('create_spec-critical',
|
|
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,
|
|
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
|
-
//
|
|
823
|
-
//
|
|
824
|
-
//
|
|
825
|
-
const
|
|
826
|
-
const autopilot = unwrapBudget(
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
1004
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1064
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|