@planu/cli 4.14.1 → 5.0.0
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 +35 -1
- package/LICENSE +55 -12
- package/README.md +10 -2
- package/dist/cli/commands/install.d.ts +1 -12
- package/dist/cli/commands/install.js +9 -65
- package/dist/cli/commands/job.js +4 -3
- package/dist/cli/commands/spec.js +2 -2
- package/dist/cli/commands/validate.js +2 -2
- package/dist/cli/router.js +1 -3
- package/dist/config/environment-schema.json +1 -3
- package/dist/config/official-sdd-tools.d.ts +4 -0
- package/dist/config/official-sdd-tools.js +35 -0
- package/dist/config/product-public.d.ts +139 -3
- package/dist/config/product-public.js +8 -1
- package/dist/config/product-public.json +7 -36
- package/dist/config/registries/hosts/codex.json +20 -363
- package/dist/config/release-policy.json +84 -2
- package/dist/config/runtime-policy.json +12 -1
- package/dist/config/skill-templates/planu-resume-work.md +2 -2
- package/dist/core/index.d.ts +1 -1
- package/dist/core/spec-validator.d.ts +4 -4
- package/dist/core/spec-validator.js +1 -1
- package/dist/engine/abortable-process-runner.d.ts +20 -2
- package/dist/engine/abortable-process-runner.js +243 -74
- package/dist/engine/ambiguity-scorer.js +4 -26
- package/dist/engine/auth/scope-mapper.js +1 -7
- package/dist/engine/autopilot/state-updater.js +4 -4
- package/dist/engine/cascade-hooks/hooks/review-enricher.hook.js +9 -6
- package/dist/engine/cascade-hooks/state-drift-detector.d.ts +3 -3
- package/dist/engine/cascade-hooks/state-drift-detector.js +1 -1
- package/dist/engine/ci-generator/planu-config.js +1 -7
- package/dist/engine/clarification-gate/gate.d.ts +3 -3
- package/dist/engine/code-scanner/layer-scanner.js +6 -22
- package/dist/engine/core-bridge.d.ts +3 -3
- package/dist/engine/cost-guardrails.d.ts +1 -1
- package/dist/engine/cost-guardrails.js +1 -1
- package/dist/engine/criterion-identity.d.ts +1 -0
- package/dist/engine/criterion-identity.js +7 -0
- package/dist/engine/dashboard/data-loader.js +2 -7
- package/dist/engine/dashboard/templates-layout.js +0 -3
- package/dist/engine/dashboard/templates-project.js +1 -13
- package/dist/engine/docs-site-generator/data-collector.d.ts +1 -1
- package/dist/engine/docs-site-generator/data-collector.js +7 -28
- package/dist/engine/docs-site-generator/tools-renderer.js +3 -10
- package/dist/engine/evidence-gates/artifact-reader.d.ts +10 -1
- package/dist/engine/evidence-gates/artifact-reader.js +115 -2
- package/dist/engine/evidence-gates/lifecycle-gate.js +4 -3
- package/dist/engine/evidence-gates/reconciliation-freshness.d.ts +11 -0
- package/dist/engine/evidence-gates/reconciliation-freshness.js +72 -0
- package/dist/engine/evidence-index/done-drift.d.ts +1 -1
- package/dist/engine/evidence-index/done-drift.js +40 -18
- package/dist/engine/execution/context.js +3 -0
- package/dist/engine/execution/durable-job-heartbeat-runtime.d.ts +4 -0
- package/dist/engine/execution/durable-job-heartbeat-runtime.js +400 -0
- package/dist/engine/execution/job-runtime.d.ts +30 -0
- package/dist/engine/execution/job-runtime.js +114 -6
- package/dist/engine/execution/public-job-sanitizer.d.ts +4 -0
- package/dist/engine/execution/public-job-sanitizer.js +31 -0
- package/dist/engine/execution/validate-job-executor.d.ts +12 -1
- package/dist/engine/execution/validate-job-executor.js +549 -86
- package/dist/engine/execution/validate-job-payload.js +107 -50
- package/dist/engine/execution/validate-job-recovery.js +1 -1
- package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
- package/dist/engine/execution/validate-worker-runtime.js +90 -2
- package/dist/engine/execution/validate-worker-thread.js +17 -24
- package/dist/engine/handoff-artifacts/schemas.d.ts +2 -1
- package/dist/engine/handoff-artifacts/schemas.js +33 -0
- package/dist/engine/handoff-packager.d.ts +19 -0
- package/dist/engine/handoff-packager.js +415 -13
- package/dist/engine/hooks/effort-configurator.js +1 -1
- package/dist/engine/impact-detector/test-break-predictor.js +3 -3
- package/dist/engine/impact-detector/tool-registration.js +1 -1
- package/dist/engine/implementation-contract/renderer.js +23 -8
- package/dist/engine/lifecycle-reconciliation-io.d.ts +11 -0
- package/dist/engine/lifecycle-reconciliation-io.js +180 -0
- package/dist/engine/lifecycle-reconciliation.d.ts +16 -0
- package/dist/engine/lifecycle-reconciliation.js +406 -0
- package/dist/engine/local-first/tool-classification.js +2 -0
- package/dist/engine/macos-keychain-native-port.d.ts +5 -0
- package/dist/engine/macos-keychain-native-port.js +19 -7
- package/dist/engine/migrations/remove-commercial-state.d.ts +3 -0
- package/dist/engine/migrations/remove-commercial-state.js +343 -0
- package/dist/engine/network-policy.js +1 -0
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +10 -10
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +10 -10
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +10 -10
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +10 -10
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +10 -10
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +10 -10
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +10 -10
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +10 -10
- package/dist/engine/readiness-checker.d.ts +1 -16
- package/dist/engine/readiness-checker.js +27 -88
- package/dist/engine/runtime-policy.d.ts +2 -0
- package/dist/engine/runtime-policy.js +42 -5
- package/dist/engine/runtime-security/rate-limiter.js +0 -1
- package/dist/engine/safety/contained-project-file.d.ts +3 -0
- package/dist/engine/safety/contained-project-file.js +23 -0
- package/dist/engine/scope-boundaries/contradiction-checker.js +63 -1
- package/dist/engine/scope-boundaries/scope-validator.js +45 -7
- package/dist/engine/session/checkpoint-writer.js +0 -9
- package/dist/engine/spec-format/acceptance-criteria.d.ts +6 -2
- package/dist/engine/spec-format/acceptance-criteria.js +77 -18
- package/dist/engine/spec-format/markdown-sections.d.ts +14 -0
- package/dist/engine/spec-format/markdown-sections.js +105 -0
- package/dist/engine/spec-format/read-technical-section.js +33 -5
- package/dist/engine/spec-format/technical-md-populator.js +3 -2
- package/dist/engine/spec-format/unified-spec-builder.d.ts +7 -0
- package/dist/engine/spec-format/unified-spec-builder.js +202 -0
- package/dist/engine/spec-migrator/canonical-deduplicator.d.ts +18 -0
- package/dist/engine/spec-migrator/canonical-deduplicator.js +479 -0
- package/dist/engine/spec-migrator/filesystem-import.d.ts +4 -8
- package/dist/engine/spec-migrator/filesystem-import.js +121 -14
- package/dist/engine/spec-migrator/frontmatter-parser.js +32 -15
- package/dist/engine/spec-migrator/index.d.ts +1 -0
- package/dist/engine/spec-migrator/index.js +1 -0
- package/dist/engine/spec-state-machine/transition-spec.d.ts +6 -1
- package/dist/engine/spec-state-machine/transition-spec.js +10 -1
- package/dist/engine/technical-enricher/index.js +16 -8
- package/dist/engine/technical-enricher/render-enriched.d.ts +1 -0
- package/dist/engine/technical-enricher/render-enriched.js +42 -14
- package/dist/engine/telemetry/health-checker.js +53 -17
- package/dist/engine/telemetry/telemetry-client.js +26 -8
- package/dist/engine/text-signal-boundaries.d.ts +2 -0
- package/dist/engine/text-signal-boundaries.js +25 -2
- package/dist/engine/time/relative-date.d.ts +3 -0
- package/dist/engine/time/relative-date.js +16 -0
- package/dist/engine/timing/budget.d.ts +11 -0
- package/dist/engine/timing/budget.js +27 -9
- package/dist/engine/token-optimizer/analytics.d.ts +1 -1
- package/dist/engine/token-optimizer/analytics.js +5 -6
- package/dist/engine/usage-tracker/core.d.ts +2 -2
- package/dist/engine/usage-tracker/core.js +1 -2
- package/dist/engine/usage-tracker/index.d.ts +0 -3
- package/dist/engine/usage-tracker/index.js +0 -3
- package/dist/engine/usage-tracker/stats.d.ts +2 -2
- package/dist/engine/usage-tracker/stats.js +1 -28
- package/dist/engine/validation/durable-validation.d.ts +1 -1
- package/dist/engine/validation/durable-validation.js +3 -82
- package/dist/engine/validation/validation-freshness.d.ts +11 -1
- package/dist/engine/validation/validation-freshness.js +231 -91
- package/dist/engine/validation/validation-receipt.d.ts +9 -6
- package/dist/engine/validation/validation-receipt.js +84 -24
- package/dist/engine/validation/validation-source-digest.d.ts +2 -0
- package/dist/engine/validation/validation-source-digest.js +86 -0
- package/dist/engine/validation/validation-submission.d.ts +5 -4
- package/dist/engine/validation/validation-submission.js +25 -11
- package/dist/engine/validation/validation-worktree.d.ts +21 -0
- package/dist/engine/validation/validation-worktree.js +260 -0
- package/dist/engine/validation-impact-planner.d.ts +14 -2
- package/dist/engine/validation-impact-planner.js +0 -3
- package/dist/engine/validator/dor-dod.d.ts +1 -0
- package/dist/engine/validator/dor-dod.js +5 -3
- package/dist/engine/validator/extractors.d.ts +1 -5
- package/dist/engine/validator/extractors.js +24 -69
- package/dist/engine/validator/spec-compliance-runner.d.ts +12 -24
- package/dist/engine/validator/spec-compliance-runner.js +429 -211
- package/dist/engine/validator.js +35 -22
- package/dist/index.js +4 -16
- package/dist/resources/usage-stats-resource.js +2 -18
- package/dist/security/adapters/linux-secret-service.js +7 -3
- package/dist/security/adapters/windows-credential-manager.js +6 -4
- package/dist/server/routes/specs.js +10 -0
- package/dist/storage/base-store.d.ts +1 -1
- package/dist/storage/base-store.js +1 -1
- package/dist/storage/feedback-remote.d.ts +2 -3
- package/dist/storage/feedback-remote.js +45 -31
- package/dist/storage/global-store.d.ts +1 -17
- package/dist/storage/global-store.js +1 -42
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/index.js +0 -2
- package/dist/storage/migrations/canonical-storage.js +124 -11
- package/dist/storage/runtime-db.d.ts +9 -0
- package/dist/storage/runtime-db.js +64 -8
- package/dist/storage/spec-store.d.ts +14 -2
- package/dist/storage/spec-store.js +104 -14
- package/dist/storage/status-store/atomic-status-write.d.ts +5 -0
- package/dist/storage/status-store/atomic-status-write.js +57 -0
- package/dist/storage/status-store/file-lock.js +30 -11
- package/dist/storage/status-store/self-healing.js +3 -3
- package/dist/storage/status-store/version-sync.d.ts +2 -1
- package/dist/storage/status-store/version-sync.js +35 -40
- package/dist/storage/usage-store.d.ts +1 -5
- package/dist/storage/usage-store.js +0 -35
- package/dist/tools/auto-update-handler.d.ts +3 -3
- package/dist/tools/auto-update-handler.js +3 -3
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.d.ts +2 -1
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.js +10 -7
- package/dist/tools/challenge-spec/scenario-collector.js +1 -1
- package/dist/tools/challenge-spec/scenarios-data.js +1 -1
- package/dist/tools/challenge-spec/scenarios-utils.d.ts +1 -1
- package/dist/tools/challenge-spec/scenarios-utils.js +35 -11
- package/dist/tools/challenge-spec.js +5 -5
- package/dist/tools/check-readiness.js +1 -1
- package/dist/tools/configure-telemetry.js +30 -2
- package/dist/tools/create-spec/spec-builder.js +0 -11
- package/dist/tools/create-spec.d.ts +1 -0
- package/dist/tools/create-spec.js +444 -239
- package/dist/tools/git/branch-ops.d.ts +1 -1
- package/dist/tools/git/branch-ops.js +3 -2
- package/dist/tools/init-project/handler.js +10 -12
- package/dist/tools/init-project/host-assets-writer.js +26 -1
- package/dist/tools/init-project/lint-scaffolder.d.ts +3 -3
- package/dist/tools/init-project/migration-runner.d.ts +2 -4
- package/dist/tools/init-project/migration-runner.js +3 -2
- package/dist/tools/init-project/portable-index-reconciler.d.ts +4 -0
- package/dist/tools/init-project/portable-index-reconciler.js +14 -0
- package/dist/tools/init-project/result-builder.js +1 -3
- package/dist/tools/jobs/handlers.js +38 -6
- package/dist/tools/list-specs.js +5 -26
- package/dist/tools/merge-risk-handler.js +2 -2
- package/dist/tools/package-handoff.js +2 -0
- package/dist/tools/reconcile-spec.js +0 -27
- package/dist/tools/register-agent-squad-tools.js +2 -2
- package/dist/tools/register-platform-tools/design-stack-tools.js +11 -11
- package/dist/tools/register-platform-tools/lifecycle-infra-tools.js +7 -7
- package/dist/tools/register-sdd-tools.d.ts +1 -1
- package/dist/tools/register-sdd-tools.js +2 -29
- package/dist/tools/register-spec-tools/analysis-tools.js +8 -8
- package/dist/tools/register-spec-tools/core-spec-tools.js +17 -8
- package/dist/tools/safe-handler.d.ts +5 -13
- package/dist/tools/safe-handler.js +7 -23
- package/dist/tools/schemas/index.d.ts +1 -1
- package/dist/tools/schemas/index.js +1 -1
- package/dist/tools/schemas/output-schemas.d.ts +0 -23
- package/dist/tools/schemas/output-schemas.js +0 -28
- package/dist/tools/schemas/spec.d.ts +4 -0
- package/dist/tools/schemas/spec.js +3 -0
- package/dist/tools/schemas/validate-output-schema.d.ts +11 -0
- package/dist/tools/schemas/validate-output-schema.js +7 -0
- package/dist/tools/spec-prompt-handler.js +3 -3
- package/dist/tools/sync-spec-state-handler.d.ts +1 -1
- package/dist/tools/sync-spec-state-handler.js +1 -1
- package/dist/tools/tool-entry.d.ts +4 -4
- package/dist/tools/tool-entry.js +3 -3
- package/dist/tools/tool-registry/core-tools.js +31 -15
- package/dist/tools/tool-registry/group-infra.js +27 -110
- package/dist/tools/tool-registry/group-quality-compliance.js +26 -26
- package/dist/tools/tool-registry/inventory.d.ts +2 -0
- package/dist/tools/tool-registry/inventory.js +2 -0
- package/dist/tools/tool-registry-helpers.d.ts +3 -3
- package/dist/tools/tool-registry-helpers.js +3 -3
- package/dist/tools/tool-usage-report/registered-tools.d.ts +1 -1
- package/dist/tools/tool-usage-report/registered-tools.js +3 -15
- package/dist/tools/update-status/approval-gates.js +3 -0
- package/dist/tools/update-status/done-receipt-verifier.js +40 -27
- package/dist/tools/update-status/evidence-gate.js +36 -1
- package/dist/tools/update-status/file-sync.d.ts +2 -1
- package/dist/tools/update-status/file-sync.js +57 -6
- package/dist/tools/update-status/index.d.ts +2 -0
- package/dist/tools/update-status/index.js +95 -58
- package/dist/tools/update-status/response-builder.js +3 -3
- package/dist/tools/update-status/side-effects.d.ts +2 -0
- package/dist/tools/update-status/side-effects.js +2 -2
- package/dist/tools/update-status/transition-guard.js +32 -15
- package/dist/tools/update-status-actions.d.ts +4 -2
- package/dist/tools/update-status-actions.js +16 -14
- package/dist/tools/usage-report.js +1 -16
- package/dist/tools/usage-stats.js +1 -18
- package/dist/tools/usage-tracking.d.ts +4 -0
- package/dist/tools/usage-tracking.js +20 -0
- package/dist/tools/validate-lint.d.ts +1 -0
- package/dist/tools/validate-lint.js +1 -1
- package/dist/tools/validate.d.ts +2 -1
- package/dist/tools/validate.js +114 -34
- package/dist/transports/http-transport.js +6 -8
- package/dist/transports/mcp-types.d.ts +0 -2
- package/dist/transports/session-context.js +1 -1
- package/dist/types/cascade-hooks.d.ts +1 -1
- package/dist/types/ci.d.ts +0 -4
- package/dist/types/clarification-token.d.ts +1 -1
- package/dist/types/claude-code-runtime.d.ts +0 -27
- package/dist/types/commercial-migration.d.ts +17 -0
- package/dist/types/commercial-migration.js +2 -0
- package/dist/types/common/primitives.d.ts +0 -2
- package/dist/types/core-bridge.d.ts +4 -10
- package/dist/types/dashboard.d.ts +3 -7
- package/dist/types/docs.d.ts +0 -1
- package/dist/types/durable-job.d.ts +4 -4
- package/dist/types/durable-validation.d.ts +100 -2
- package/dist/types/durable-validation.js +165 -1
- package/dist/types/errors/structured-error.d.ts +3 -3
- package/dist/types/estimation.d.ts +2 -0
- package/dist/types/evidence-gates.d.ts +9 -1
- package/dist/types/execution.d.ts +2 -0
- package/dist/types/gemini-integration.d.ts +0 -11
- package/dist/types/handoff-artifacts.d.ts +41 -0
- package/dist/types/hooks-advanced.d.ts +0 -13
- package/dist/types/impact-detection.d.ts +2 -2
- package/dist/types/index.d.ts +2 -6
- package/dist/types/index.js +1 -5
- package/dist/types/kiro-integration.d.ts +0 -6
- package/dist/types/network-policy.d.ts +1 -1
- package/dist/types/project/lint-scaffolder.d.ts +1 -1
- package/dist/types/runtime-policy.d.ts +11 -0
- package/dist/types/session-safeguard.d.ts +0 -31
- package/dist/types/spec/canonical-repair.d.ts +81 -0
- package/dist/types/spec/canonical-repair.js +2 -0
- package/dist/types/spec/core.d.ts +14 -0
- package/dist/types/spec/index.d.ts +1 -0
- package/dist/types/spec/index.js +1 -0
- package/dist/types/spec/inputs.d.ts +29 -0
- package/dist/types/spec-format.d.ts +24 -0
- package/dist/types/telemetry.d.ts +4 -1
- package/dist/types/transport.d.ts +0 -2
- package/dist/types/usage.d.ts +1 -36
- package/dist/types/usage.js +1 -1
- package/dist/types/validate-worker.d.ts +6 -0
- package/dist/types/validation-receipt.d.ts +1 -1
- package/dist/types/validation.d.ts +2 -2
- package/package.json +16 -12
- package/planu-native.json +1 -1
- package/planu-plugin.json +23 -40
- package/scripts/lib/pending-release-file.mjs +93 -0
- package/src/i18n/messages/en.json +0 -41
- package/src/i18n/messages/es.json +0 -41
- package/src/i18n/messages/pt.json +0 -41
- package/dist/cli/commands/activate.d.ts +0 -14
- package/dist/cli/commands/activate.js +0 -174
- package/dist/config/license-plans.json +0 -251
- package/dist/config/product-public.ts +0 -148
- package/dist/config/server-instructions.ts +0 -121
- package/dist/config/version-defaults.ts +0 -76
- package/dist/config/version.ts +0 -21
- package/dist/engine/ai-integration/gemini/settings-generator.d.ts +0 -4
- package/dist/engine/ai-integration/gemini/settings-generator.js +0 -195
- package/dist/engine/ai-integration/kiro/hooks-generator.d.ts +0 -6
- package/dist/engine/ai-integration/kiro/hooks-generator.js +0 -75
- package/dist/engine/hooks/full-spectrum-generator.d.ts +0 -32
- package/dist/engine/hooks/full-spectrum-generator.js +0 -117
- package/dist/engine/license-validator/config-loader.d.ts +0 -5
- package/dist/engine/license-validator/config-loader.js +0 -16
- package/dist/engine/license-validator/core.d.ts +0 -15
- package/dist/engine/license-validator/core.js +0 -151
- package/dist/engine/license-validator/fingerprint.d.ts +0 -3
- package/dist/engine/license-validator/fingerprint.js +0 -17
- package/dist/engine/license-validator/lemon-squeezy.d.ts +0 -5
- package/dist/engine/license-validator/lemon-squeezy.js +0 -55
- package/dist/engine/license-validator.d.ts +0 -5
- package/dist/engine/license-validator.js +0 -6
- package/dist/engine/product-intelligence/index.d.ts +0 -7
- package/dist/engine/product-intelligence/index.js +0 -211
- package/dist/engine/session/auto-save.d.ts +0 -18
- package/dist/engine/session/auto-save.js +0 -98
- package/dist/engine/session/context-snapshot.d.ts +0 -8
- package/dist/engine/session/context-snapshot.js +0 -49
- package/dist/engine/session/memory-sync.d.ts +0 -12
- package/dist/engine/session/memory-sync.js +0 -34
- package/dist/engine/session/session-diff.d.ts +0 -11
- package/dist/engine/session/session-diff.js +0 -42
- package/dist/engine/session/session-merge.d.ts +0 -12
- package/dist/engine/session/session-merge.js +0 -55
- package/dist/engine/session-safeguard/checkpoint-runner.d.ts +0 -4
- package/dist/engine/session-safeguard/checkpoint-runner.js +0 -70
- package/dist/engine/session-safeguard/learnings-buffer.d.ts +0 -15
- package/dist/engine/session-safeguard/learnings-buffer.js +0 -91
- package/dist/engine/session-safeguard/precompaction-drain.d.ts +0 -10
- package/dist/engine/session-safeguard/precompaction-drain.js +0 -82
- package/dist/engine/session-safeguard/unpushed-detector.d.ts +0 -7
- package/dist/engine/session-safeguard/unpushed-detector.js +0 -59
- package/dist/engine/spec-changelog/core.d.ts +0 -16
- package/dist/engine/spec-changelog/core.js +0 -176
- package/dist/engine/spec-changelog/diff.d.ts +0 -18
- package/dist/engine/spec-changelog/diff.js +0 -121
- package/dist/engine/spec-changelog/index.d.ts +0 -3
- package/dist/engine/spec-changelog/index.js +0 -4
- package/dist/engine/trial-engine.d.ts +0 -5
- package/dist/engine/trial-engine.js +0 -14
- package/dist/engine/usage-tracker/rate-check.d.ts +0 -7
- package/dist/engine/usage-tracker/rate-check.js +0 -18
- package/dist/engine/usage-tracker/rate-limiter.d.ts +0 -14
- package/dist/engine/usage-tracker/rate-limiter.js +0 -73
- package/dist/engine/usage-tracker/trial.d.ts +0 -27
- package/dist/engine/usage-tracker/trial.js +0 -49
- package/dist/engine/webhook/event-handlers.d.ts +0 -25
- package/dist/engine/webhook/event-handlers.js +0 -89
- package/dist/engine/webhook/index.d.ts +0 -4
- package/dist/engine/webhook/index.js +0 -5
- package/dist/engine/webhook/server.d.ts +0 -12
- package/dist/engine/webhook/server.js +0 -249
- package/dist/engine/webhook/signature.d.ts +0 -16
- package/dist/engine/webhook/signature.js +0 -49
- package/dist/storage/license-store.d.ts +0 -6
- package/dist/storage/license-store.js +0 -63
- package/dist/storage/session-store.d.ts +0 -20
- package/dist/storage/session-store.js +0 -136
- package/dist/tools/activate-license.d.ts +0 -6
- package/dist/tools/activate-license.js +0 -132
- package/dist/tools/checkpoint-handler.d.ts +0 -3
- package/dist/tools/checkpoint-handler.js +0 -130
- package/dist/tools/export-session.d.ts +0 -3
- package/dist/tools/export-session.js +0 -90
- package/dist/tools/license-gate.d.ts +0 -18
- package/dist/tools/license-gate.js +0 -222
- package/dist/tools/license-status.d.ts +0 -3
- package/dist/tools/license-status.js +0 -93
- package/dist/tools/list-sessions.d.ts +0 -3
- package/dist/tools/list-sessions.js +0 -46
- package/dist/tools/planu-session-checkpoint.d.ts +0 -6
- package/dist/tools/planu-session-checkpoint.js +0 -42
- package/dist/tools/restore-session.d.ts +0 -3
- package/dist/tools/restore-session.js +0 -71
- package/dist/tools/spec-history.d.ts +0 -3
- package/dist/tools/spec-history.js +0 -59
- package/dist/tools/webhook.d.ts +0 -6
- package/dist/tools/webhook.js +0 -150
- package/dist/types/changelog.d.ts +0 -49
- package/dist/types/changelog.js +0 -3
- package/dist/types/licensing.d.ts +0 -109
- package/dist/types/licensing.js +0 -4
- package/dist/types/product-intelligence.d.ts +0 -60
- package/dist/types/product-intelligence.js +0 -3
- package/dist/types/session.d.ts +0 -84
- package/dist/types/session.js +0 -3
- package/dist/types/webhook.d.ts +0 -62
- package/dist/types/webhook.js +0 -4
|
@@ -22,13 +22,12 @@ import { recordDoneMetrics, syncSpecFiles, tryReconcile, recordTerminalTransitio
|
|
|
22
22
|
import { appendEntry, getLastHash } from '../../storage/audit-trail-store.js';
|
|
23
23
|
import { appendTransitionEvent } from '../../storage/transition-log.js';
|
|
24
24
|
import { createHash, randomUUID as uuid } from 'node:crypto';
|
|
25
|
-
import { updateFrontmatterField } from '../../engine/frontmatter-parser.js';
|
|
26
25
|
import { atomicWriteFile } from '../../engine/safety/atomic-write-file.js';
|
|
27
26
|
import { recordForceUsage } from '../../storage/force-analytics-store.js';
|
|
28
27
|
import { maybeSafePushOnDone, queuePostCommitTasks, runCascadeForResponse, } from './side-effects.js';
|
|
29
28
|
import { formatKeyValue } from '../output-formatter.js';
|
|
30
29
|
import { checkCodeReality } from '../../engine/code-scanner/index.js';
|
|
31
|
-
import { join } from 'node:path';
|
|
30
|
+
import { join, resolve } from 'node:path';
|
|
32
31
|
import { trackCost } from '../../engine/cost-tracking/operation-tracker.js';
|
|
33
32
|
import { resolveProjectIdOrAutoDetect } from '../resolve-project-id.js';
|
|
34
33
|
import { withToolTimeout } from '../safe-handler.js';
|
|
@@ -39,7 +38,8 @@ import { acquireLock, releaseLock, isLocked as isCrossProcessLocked, LockBusyErr
|
|
|
39
38
|
import { projectDataDir } from '../../storage/base-store.js';
|
|
40
39
|
import { assertExecutionCanCommit } from '../../engine/execution/context.js';
|
|
41
40
|
import { shouldSkipGateForExplicitLegacyHarness } from './gate-harness.js';
|
|
42
|
-
import { assertValidationFreshnessBarrier, } from '../../engine/validation/validation-freshness.js';
|
|
41
|
+
import { assertValidationFreshnessBarrier, closeValidationFreshnessLease, } from '../../engine/validation/validation-freshness.js';
|
|
42
|
+
import { currentReconciliationInvocationContext, reconcileImplementingSpec, } from '../../engine/lifecycle-reconciliation.js';
|
|
43
43
|
/**
|
|
44
44
|
* SPEC-280: Silently traverse intermediate states so callers can jump forward
|
|
45
45
|
* (e.g. draft → approved) without receiving an error.
|
|
@@ -199,6 +199,18 @@ function planBackgroundActions(args) {
|
|
|
199
199
|
}
|
|
200
200
|
return actions;
|
|
201
201
|
}
|
|
202
|
+
/** Bind deferred lifecycle work to one normalized absolute root without persisting that path. */
|
|
203
|
+
export function computeTransitionRootBinding(projectPath) {
|
|
204
|
+
return createHash('sha256')
|
|
205
|
+
.update('planu:transition-root:v1\0')
|
|
206
|
+
.update(resolve(projectPath))
|
|
207
|
+
.digest('hex');
|
|
208
|
+
}
|
|
209
|
+
function receiptMatchesTransitionRoot(receipt, projectPath) {
|
|
210
|
+
return (projectPath !== undefined &&
|
|
211
|
+
receipt.transitionRootBinding !== undefined &&
|
|
212
|
+
receipt.transitionRootBinding === computeTransitionRootBinding(projectPath));
|
|
213
|
+
}
|
|
202
214
|
function buildPostCommitTasks(args) {
|
|
203
215
|
const enabled = new Set(args.actionNames);
|
|
204
216
|
const tasks = [];
|
|
@@ -212,13 +224,13 @@ function buildPostCommitTasks(args) {
|
|
|
212
224
|
if (enabled.has('implementing-side-effects')) {
|
|
213
225
|
tasks.push({
|
|
214
226
|
name: 'implementing-side-effects',
|
|
215
|
-
run: () => runImplementingSideEffects(args.projectId, args.spec.id),
|
|
227
|
+
run: () => runImplementingSideEffects(args.projectId, args.spec.id, args.effectiveProjectPath),
|
|
216
228
|
});
|
|
217
229
|
}
|
|
218
230
|
if (enabled.has('done-side-effects')) {
|
|
219
231
|
tasks.push({
|
|
220
232
|
name: 'done-side-effects',
|
|
221
|
-
run: () => runDoneSideEffects(args.projectId, args.spec.id, args.spec.gitBranch),
|
|
233
|
+
run: () => runDoneSideEffects(args.projectId, args.spec.id, args.spec.gitBranch, args.effectiveProjectPath),
|
|
222
234
|
});
|
|
223
235
|
}
|
|
224
236
|
if (enabled.has('reconcile')) {
|
|
@@ -231,7 +243,7 @@ function buildPostCommitTasks(args) {
|
|
|
231
243
|
if (enabled.has('record-done-metrics') && actuals) {
|
|
232
244
|
tasks.push({
|
|
233
245
|
name: 'record-done-metrics',
|
|
234
|
-
run: () => recordDoneMetrics(args.projectId, args.spec.id, args.spec, actuals, args.
|
|
246
|
+
run: () => recordDoneMetrics(args.projectId, args.spec.id, args.spec, actuals, args.effectiveProjectPath),
|
|
235
247
|
});
|
|
236
248
|
}
|
|
237
249
|
const effectiveProjectPath = args.effectiveProjectPath;
|
|
@@ -253,6 +265,7 @@ function buildPostCommitTasks(args) {
|
|
|
253
265
|
projectId: args.projectId,
|
|
254
266
|
spec: args.spec,
|
|
255
267
|
currentStatus: args.previousStatus,
|
|
268
|
+
projectPath: args.effectiveProjectPath,
|
|
256
269
|
}),
|
|
257
270
|
});
|
|
258
271
|
}
|
|
@@ -291,7 +304,10 @@ async function replayIdempotentPostCommitTasks(args) {
|
|
|
291
304
|
return;
|
|
292
305
|
}
|
|
293
306
|
const knowledge = await knowledgeStore.getKnowledge(args.projectId);
|
|
294
|
-
const effectiveProjectPath =
|
|
307
|
+
const effectiveProjectPath = args.projectPath ?? knowledge?.projectPath;
|
|
308
|
+
if (!receiptMatchesTransitionRoot(receipt, effectiveProjectPath)) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
295
311
|
const specAtTransition = { ...args.spec, status: receipt.status };
|
|
296
312
|
const tasks = buildPostCommitTasks({
|
|
297
313
|
actionNames: receipt.pendingBackgroundActions,
|
|
@@ -317,13 +333,17 @@ async function recoverPendingPostCommitTasks(projectId, projectPath) {
|
|
|
317
333
|
knowledgeStore.getKnowledge(projectId),
|
|
318
334
|
specStore.listSpecs(projectId),
|
|
319
335
|
]);
|
|
320
|
-
const effectiveProjectPath =
|
|
336
|
+
const effectiveProjectPath = projectPath ?? knowledge?.projectPath;
|
|
321
337
|
for (const spec of specs) {
|
|
322
|
-
const
|
|
323
|
-
|
|
338
|
+
const recoverableReceipts = (spec.statusHistory ?? []).filter((receipt) => receipt.transitionId &&
|
|
339
|
+
receipt.pendingBackgroundActions?.length &&
|
|
340
|
+
receiptMatchesTransitionRoot(receipt, effectiveProjectPath));
|
|
341
|
+
if (recoverableReceipts.length === 0 || !effectiveProjectPath) {
|
|
324
342
|
continue;
|
|
325
343
|
}
|
|
326
|
-
const recoveryLock = await acquireLock(effectiveProjectPath
|
|
344
|
+
const recoveryLock = await acquireLock(effectiveProjectPath, spec.id, {
|
|
345
|
+
reason: 'recover pending post-commit tasks',
|
|
346
|
+
});
|
|
327
347
|
if (recoveryLock === null) {
|
|
328
348
|
continue;
|
|
329
349
|
}
|
|
@@ -335,7 +355,9 @@ async function recoverPendingPostCommitTasks(projectId, projectPath) {
|
|
|
335
355
|
continue;
|
|
336
356
|
}
|
|
337
357
|
for (const receipt of currentSpec.statusHistory ?? []) {
|
|
338
|
-
if (!receipt.transitionId ||
|
|
358
|
+
if (!receipt.transitionId ||
|
|
359
|
+
!receipt.pendingBackgroundActions?.length ||
|
|
360
|
+
!receiptMatchesTransitionRoot(receipt, effectiveProjectPath)) {
|
|
339
361
|
continue;
|
|
340
362
|
}
|
|
341
363
|
const specAtTransition = { ...currentSpec, status: receipt.status };
|
|
@@ -383,6 +405,18 @@ export async function recoverPendingPostCommitTasksAtStartup() {
|
|
|
383
405
|
});
|
|
384
406
|
}
|
|
385
407
|
}
|
|
408
|
+
async function runTransitionMaintenance(transitionProjectPath) {
|
|
409
|
+
if (transitionProjectPath) {
|
|
410
|
+
try {
|
|
411
|
+
const { runStrictPlanuCleanup } = await import('../../engine/spec-migrator/index.js');
|
|
412
|
+
await runStrictPlanuCleanup(transitionProjectPath);
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
/* reliability-cleanup: PRE_TRANSITION_STRICT_CLEANUP — validate remains fail-closed */
|
|
416
|
+
reportClassifiedDegradation('PRE_TRANSITION_STRICT_CLEANUP', error);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
386
420
|
function buildPersistenceFailureResponse(args) {
|
|
387
421
|
const committed = args.recoveryRequired ? null : false;
|
|
388
422
|
const message = args.recoveryRequired
|
|
@@ -469,7 +503,7 @@ async function commitTransitionWithNarrowLock(args) {
|
|
|
469
503
|
expectedSpec: freshSpec,
|
|
470
504
|
});
|
|
471
505
|
const updatedSpec = transitionRecord.spec;
|
|
472
|
-
const syncResult = await syncSpecFiles(updatedSpec, args.originalStatus, args.newStatus, args.projectPath);
|
|
506
|
+
const syncResult = await syncSpecFiles(updatedSpec, args.originalStatus, args.newStatus, args.projectPath, args.qualityWarnings);
|
|
473
507
|
if (!syncResult.warning) {
|
|
474
508
|
return { ok: true, transitionRecord, updatedSpec };
|
|
475
509
|
}
|
|
@@ -581,24 +615,29 @@ export async function handleUpdateStatus(params, server) {
|
|
|
581
615
|
}
|
|
582
616
|
const projectId = resolved.projectId;
|
|
583
617
|
const effectiveProjectPath = resolved.projectPath;
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
618
|
+
const knowledge = await knowledgeStore.getKnowledge(projectId);
|
|
619
|
+
const transitionProjectPath = (params.projectPath?.trim()
|
|
620
|
+
? effectiveProjectPath
|
|
621
|
+
: (knowledge?.projectPath ?? effectiveProjectPath)) || undefined;
|
|
622
|
+
if (params.reconciliationRequestId ||
|
|
623
|
+
params.expectedImplementingTransitionId ||
|
|
624
|
+
params.implementationReviewDigest) {
|
|
625
|
+
return reconcileImplementingSpec({
|
|
626
|
+
input: params,
|
|
627
|
+
projectId,
|
|
628
|
+
projectPath: transitionProjectPath,
|
|
629
|
+
context: currentReconciliationInvocationContext(),
|
|
630
|
+
syncSpecFiles,
|
|
631
|
+
});
|
|
593
632
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
633
|
+
if (newStatus !== 'done') {
|
|
634
|
+
await runTransitionMaintenance(transitionProjectPath);
|
|
635
|
+
}
|
|
636
|
+
let doneFreshnessLease;
|
|
598
637
|
return (async () => {
|
|
599
638
|
try {
|
|
600
639
|
// SPEC-301: Reject status changes when spec is locked by another holder (legacy manual lock)
|
|
601
|
-
const lockError = await checkSpecLockGate(
|
|
640
|
+
const lockError = await checkSpecLockGate(transitionProjectPath, specId);
|
|
602
641
|
if (lockError) {
|
|
603
642
|
return lockError;
|
|
604
643
|
}
|
|
@@ -608,7 +647,7 @@ export async function handleUpdateStatus(params, server) {
|
|
|
608
647
|
if (isDryRun) {
|
|
609
648
|
// SPEC-731: dry_run checks lock availability without acquiring it.
|
|
610
649
|
// isLocked returns null when no lockfile exists (available), or a LockInfo when locked.
|
|
611
|
-
const lockInfo = await isCrossProcessLocked(
|
|
650
|
+
const lockInfo = await isCrossProcessLocked(transitionProjectPath ?? projectId, specId).catch((error) => {
|
|
612
651
|
// reliability-optional: DRY_RUN_LOCK_PROBE — null conservatively avoids stale lock claims
|
|
613
652
|
reportClassifiedDegradation('DRY_RUN_LOCK_PROBE', error);
|
|
614
653
|
return null;
|
|
@@ -647,7 +686,7 @@ export async function handleUpdateStatus(params, server) {
|
|
|
647
686
|
await replayIdempotentPostCommitTasks({
|
|
648
687
|
projectId,
|
|
649
688
|
spec,
|
|
650
|
-
projectPath:
|
|
689
|
+
projectPath: transitionProjectPath,
|
|
651
690
|
});
|
|
652
691
|
const idempotentResult = checkIdempotentOrTransition(projectId, spec, newStatus);
|
|
653
692
|
if (idempotentResult) {
|
|
@@ -784,10 +823,8 @@ export async function handleUpdateStatus(params, server) {
|
|
|
784
823
|
if (elicitResult) {
|
|
785
824
|
return elicitResult;
|
|
786
825
|
}
|
|
787
|
-
// Load knowledge for project path (needed for DoD gates, validate trigger and HTML regen)
|
|
788
|
-
const knowledge = await knowledgeStore.getKnowledge(projectId);
|
|
789
826
|
// Resolve effective project path once — used across all gates below
|
|
790
|
-
const effectiveGatePath =
|
|
827
|
+
const effectiveGatePath = transitionProjectPath;
|
|
791
828
|
// SPEC-1044: SDD model-routing + context continuity hard gate.
|
|
792
829
|
const sddRoutingGate = {
|
|
793
830
|
blockResult: null,
|
|
@@ -839,7 +876,6 @@ export async function handleUpdateStatus(params, server) {
|
|
|
839
876
|
// security and repository scans belong to the durable validation worker.
|
|
840
877
|
let codeRealityWarning = null;
|
|
841
878
|
let forcedBypassWarning = null;
|
|
842
|
-
let doneFreshnessLease;
|
|
843
879
|
const [codeRealityResult, doneGatesResult] = await Promise.all([
|
|
844
880
|
// Code reality: only relevant for 'implementing'
|
|
845
881
|
newStatus === 'implementing' && !reverseTransition && effectiveGatePath
|
|
@@ -937,11 +973,15 @@ export async function handleUpdateStatus(params, server) {
|
|
|
937
973
|
const resolvedActuals = actuals;
|
|
938
974
|
// Run only fast, read-only transition checks before persistence.
|
|
939
975
|
const implActions = newStatus === 'implementing'
|
|
940
|
-
? await runImplementingActions(projectId, specId, {
|
|
976
|
+
? await runImplementingActions(projectId, specId, {
|
|
977
|
+
deferSideEffects: true,
|
|
978
|
+
projectPath: effectiveGatePath,
|
|
979
|
+
})
|
|
941
980
|
: null;
|
|
942
981
|
const doneActions = newStatus === 'done'
|
|
943
982
|
? await runDoneActions(projectId, specId, spec.gitBranch, {
|
|
944
983
|
deferSideEffects: true,
|
|
984
|
+
projectPath: effectiveGatePath,
|
|
945
985
|
})
|
|
946
986
|
: null;
|
|
947
987
|
const trigger = reverseTransition
|
|
@@ -1089,13 +1129,20 @@ export async function handleUpdateStatus(params, server) {
|
|
|
1089
1129
|
hasProjectPath: Boolean(effectiveGatePath),
|
|
1090
1130
|
shouldAutoStage,
|
|
1091
1131
|
});
|
|
1132
|
+
const transitionRootBinding = plannedBackgroundActions.length > 0 && effectiveGatePath
|
|
1133
|
+
? computeTransitionRootBinding(effectiveGatePath)
|
|
1134
|
+
: undefined;
|
|
1135
|
+
const qualityWarningsToWrite = newStatus === 'approved'
|
|
1136
|
+
? [...readinessGate.qualityWarnings, ...formatGate.qualityWarnings]
|
|
1137
|
+
: [];
|
|
1092
1138
|
const persistence = await commitTransitionWithNarrowLock({
|
|
1093
|
-
projectPath:
|
|
1139
|
+
projectPath: effectiveGatePath ?? projectId,
|
|
1094
1140
|
projectId,
|
|
1095
1141
|
specId,
|
|
1096
1142
|
newStatus,
|
|
1097
1143
|
originalStatus,
|
|
1098
1144
|
expectedSpec: spec,
|
|
1145
|
+
qualityWarnings: qualityWarningsToWrite,
|
|
1099
1146
|
options: {
|
|
1100
1147
|
trigger: trigger,
|
|
1101
1148
|
actor,
|
|
@@ -1103,6 +1150,7 @@ export async function handleUpdateStatus(params, server) {
|
|
|
1103
1150
|
reason: params.reason,
|
|
1104
1151
|
updates: nonStatusUpdates,
|
|
1105
1152
|
pendingBackgroundActions: plannedBackgroundActions,
|
|
1153
|
+
transitionRootBinding,
|
|
1106
1154
|
expectedSpec: spec,
|
|
1107
1155
|
},
|
|
1108
1156
|
...(doneFreshnessLease ? { freshnessLease: doneFreshnessLease } : {}),
|
|
@@ -1114,6 +1162,9 @@ export async function handleUpdateStatus(params, server) {
|
|
|
1114
1162
|
const frontmatterSyncWarnings = [];
|
|
1115
1163
|
const transitionId = transitionRecord.transitionId;
|
|
1116
1164
|
const committedAt = transitionRecord.timestamp;
|
|
1165
|
+
if (newStatus === 'done') {
|
|
1166
|
+
await runTransitionMaintenance(transitionProjectPath);
|
|
1167
|
+
}
|
|
1117
1168
|
await appendTransitionEvent({
|
|
1118
1169
|
projectId,
|
|
1119
1170
|
specId,
|
|
@@ -1145,29 +1196,6 @@ export async function handleUpdateStatus(params, server) {
|
|
|
1145
1196
|
reportClassifiedDegradation('REOPEN_EVENT_APPEND', err);
|
|
1146
1197
|
});
|
|
1147
1198
|
}
|
|
1148
|
-
// SPEC-769/SPEC-780: Write qualityWarnings to spec.md frontmatter when force-approved (best-effort)
|
|
1149
|
-
const qualityWarningsToWrite = [
|
|
1150
|
-
...readinessGate.qualityWarnings,
|
|
1151
|
-
...formatGate.qualityWarnings,
|
|
1152
|
-
];
|
|
1153
|
-
const specPathForWarnings = updatedSpec.specPath;
|
|
1154
|
-
if (newStatus === 'approved' &&
|
|
1155
|
-
qualityWarningsToWrite.length > 0 &&
|
|
1156
|
-
specPathForWarnings) {
|
|
1157
|
-
void (async () => {
|
|
1158
|
-
try {
|
|
1159
|
-
const { readFile: fsReadFile } = await import('node:fs/promises');
|
|
1160
|
-
const content = await fsReadFile(specPathForWarnings, 'utf-8');
|
|
1161
|
-
const warningsJson = JSON.stringify(qualityWarningsToWrite);
|
|
1162
|
-
const updated = updateFrontmatterField(content, 'qualityWarnings', warningsJson);
|
|
1163
|
-
await atomicWriteFile(specPathForWarnings, updated);
|
|
1164
|
-
}
|
|
1165
|
-
catch (error) {
|
|
1166
|
-
// reliability-optional: QUALITY_WARNING_FRONTMATTER — canonical receipt retains warnings
|
|
1167
|
-
reportClassifiedDegradation('QUALITY_WARNING_FRONTMATTER', error);
|
|
1168
|
-
}
|
|
1169
|
-
})();
|
|
1170
|
-
}
|
|
1171
1199
|
// SPEC-723: Record terminal transition in hash-chained log (best-effort, fire-and-forget)
|
|
1172
1200
|
// SPEC-734: Thread enriched payload — sessionId, modelId, gateResults
|
|
1173
1201
|
if (newStatus === 'done' || newStatus === 'discarded') {
|
|
@@ -1197,6 +1225,7 @@ export async function handleUpdateStatus(params, server) {
|
|
|
1197
1225
|
modelId: params.modelId,
|
|
1198
1226
|
gateResults: Object.keys(terminalGateResults).length > 0 ? terminalGateResults : undefined,
|
|
1199
1227
|
meta: transitionEvidenceMeta,
|
|
1228
|
+
projectPath: effectiveGatePath,
|
|
1200
1229
|
}).catch((error) => {
|
|
1201
1230
|
/* reliability-optional: TERMINAL_VALIDATION_REPORT — canonical receipt is authoritative */
|
|
1202
1231
|
reportClassifiedDegradation('TERMINAL_VALIDATION_REPORT', error);
|
|
@@ -1335,6 +1364,14 @@ export async function handleUpdateStatus(params, server) {
|
|
|
1335
1364
|
isError: true,
|
|
1336
1365
|
};
|
|
1337
1366
|
}
|
|
1367
|
+
finally {
|
|
1368
|
+
if (doneFreshnessLease) {
|
|
1369
|
+
await closeValidationFreshnessLease(doneFreshnessLease).catch((error) => {
|
|
1370
|
+
/* reliability-cleanup: freshness expiry remains the recovery boundary */
|
|
1371
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1338
1375
|
})();
|
|
1339
1376
|
}); // end trackCost
|
|
1340
1377
|
}
|
|
@@ -84,7 +84,7 @@ export function buildStatusResponse(result, specId, currentStatus, newStatus, re
|
|
|
84
84
|
const toEmoji = STATUS_EMOJIS[newStatus];
|
|
85
85
|
const r = result;
|
|
86
86
|
const lines = [
|
|
87
|
-
|
|
87
|
+
`**${specId}** moved: ${fromEmoji} \`${currentStatus}\` → ${toEmoji} \`${newStatus}\``,
|
|
88
88
|
];
|
|
89
89
|
if (r.committed && r.transitionId) {
|
|
90
90
|
lines.push(`\nTransition committed: \`${r.transitionId}\``);
|
|
@@ -125,7 +125,7 @@ export function buildStatusResponse(result, specId, currentStatus, newStatus, re
|
|
|
125
125
|
lines.push(`\n✅ Validate score: ${String(r.validateScore)}/100${sourceSuffix}`);
|
|
126
126
|
}
|
|
127
127
|
if (r.cascade.affectedSpecs.length > 0) {
|
|
128
|
-
lines.push(`\n🔗 Downstream specs affected: ${r.cascade.affectedSpecs.
|
|
128
|
+
lines.push(`\n🔗 Downstream specs affected: ${r.cascade.affectedSpecs.join(', ')}`);
|
|
129
129
|
}
|
|
130
130
|
if (r.codeRealityWarning) {
|
|
131
131
|
lines.push(`\n${r.codeRealityWarning}`);
|
|
@@ -200,7 +200,7 @@ export function buildStatusResponse(result, specId, currentStatus, newStatus, re
|
|
|
200
200
|
const markdownText = reconciliationMarkdown
|
|
201
201
|
? `${withNextSteps}\n\n${reconciliationMarkdown}`
|
|
202
202
|
: withNextSteps;
|
|
203
|
-
const displayTitle = specTitle ??
|
|
203
|
+
const displayTitle = specTitle ?? specId;
|
|
204
204
|
const humanSummary = buildUpdateStatusSummary(displayTitle, newStatus);
|
|
205
205
|
const warningItems = [
|
|
206
206
|
r.protectedBranchWarning,
|
|
@@ -35,6 +35,7 @@ export declare function fireAndForgetSideEffects(params: {
|
|
|
35
35
|
projectId: string;
|
|
36
36
|
spec: Spec;
|
|
37
37
|
currentStatus: SpecStatus;
|
|
38
|
+
projectPath?: string;
|
|
38
39
|
}): void;
|
|
39
40
|
/**
|
|
40
41
|
* SPEC-772: Run cascade and await fast hooks (fast: true) within a 2s window.
|
|
@@ -50,5 +51,6 @@ export declare function runCascadeForResponse(params: {
|
|
|
50
51
|
projectId: string;
|
|
51
52
|
spec: Spec;
|
|
52
53
|
currentStatus: SpecStatus;
|
|
54
|
+
projectPath?: string;
|
|
53
55
|
}): Promise<RunCascadeResult | null>;
|
|
54
56
|
//# sourceMappingURL=side-effects.d.ts.map
|
|
@@ -193,7 +193,7 @@ function readDisabledByEnv() {
|
|
|
193
193
|
/** Fire-and-forget side effects after a successful status transition. */
|
|
194
194
|
export function fireAndForgetSideEffects(params) {
|
|
195
195
|
const { knowledge, allSpecs, specId, newStatus, validateScore, projectId, spec, currentStatus } = params;
|
|
196
|
-
const projectPath = knowledge?.projectPath;
|
|
196
|
+
const projectPath = params.projectPath ?? knowledge?.projectPath;
|
|
197
197
|
const ctx = {
|
|
198
198
|
specId,
|
|
199
199
|
spec,
|
|
@@ -223,7 +223,7 @@ export function fireAndForgetSideEffects(params) {
|
|
|
223
223
|
*/
|
|
224
224
|
export async function runCascadeForResponse(params) {
|
|
225
225
|
const { knowledge, allSpecs, specId, newStatus, validateScore, projectId, spec, currentStatus } = params;
|
|
226
|
-
const projectPath = knowledge?.projectPath;
|
|
226
|
+
const projectPath = params.projectPath ?? knowledge?.projectPath;
|
|
227
227
|
const ctx = {
|
|
228
228
|
specId,
|
|
229
229
|
spec,
|
|
@@ -4,7 +4,7 @@ import { ti } from '../../i18n/index.js';
|
|
|
4
4
|
import { validateDoR } from '../../engine/dor-dod.js';
|
|
5
5
|
import { dispatchFeedbackEvent } from '../learn.js';
|
|
6
6
|
import { scoreAmbiguityFromPath } from '../../engine/ambiguity-scorer.js';
|
|
7
|
-
import {
|
|
7
|
+
import { checkSpecReadiness } from '../../engine/readiness-checker.js';
|
|
8
8
|
import { validateEnglishOnlySpecText } from '../../engine/spec-language/english-only.js';
|
|
9
9
|
import { checkGroundedSpecContract } from '../../engine/spec-grounding/contract.js';
|
|
10
10
|
import { checkGenericSpecOutput } from '../../engine/spec-quality/generic-output-gate.js';
|
|
@@ -331,18 +331,21 @@ export async function checkReadinessGate(spec, newStatus, forceApprove) {
|
|
|
331
331
|
qualityWarnings: [],
|
|
332
332
|
};
|
|
333
333
|
}
|
|
334
|
-
let
|
|
335
|
-
let warnings;
|
|
336
|
-
let criteriaCount;
|
|
334
|
+
let readiness;
|
|
337
335
|
try {
|
|
338
|
-
|
|
336
|
+
readiness = await checkSpecReadiness(spec, 'strict');
|
|
339
337
|
}
|
|
340
338
|
catch (error) {
|
|
341
339
|
/* reliability-optional: READINESS_EVALUATION_FAILED — transition fails closed below */
|
|
342
340
|
reportClassifiedDegradation('READINESS_EVALUATION_FAILED', error);
|
|
343
341
|
return readinessUnavailable('READINESS_EVALUATION_FAILED', error instanceof Error ? error.message : 'readiness evaluation failed');
|
|
344
342
|
}
|
|
345
|
-
|
|
343
|
+
const { score } = readiness;
|
|
344
|
+
const blockers = [...readiness.issues.blockers];
|
|
345
|
+
const warnings = [...readiness.issues.warnings];
|
|
346
|
+
const issues = [...blockers, ...warnings];
|
|
347
|
+
const hasNoCriteria = readiness.issues.breakdown.criteria === 0;
|
|
348
|
+
if (hasNoCriteria) {
|
|
346
349
|
if (newStatus === 'review') {
|
|
347
350
|
return {
|
|
348
351
|
blockResult: {
|
|
@@ -357,6 +360,7 @@ export async function checkReadinessGate(spec, newStatus, forceApprove) {
|
|
|
357
360
|
error: 'READINESS_GATE_BLOCKED',
|
|
358
361
|
score,
|
|
359
362
|
threshold: 70,
|
|
363
|
+
blockers,
|
|
360
364
|
warnings,
|
|
361
365
|
fixHint: 'Add at least 3 testable acceptance criteria before moving to review.',
|
|
362
366
|
},
|
|
@@ -388,24 +392,32 @@ export async function checkReadinessGate(spec, newStatus, forceApprove) {
|
|
|
388
392
|
},
|
|
389
393
|
],
|
|
390
394
|
structuredContent: {
|
|
395
|
+
error: 'READINESS_GATE_BLOCKED',
|
|
396
|
+
score,
|
|
397
|
+
threshold: 70,
|
|
398
|
+
blockers,
|
|
399
|
+
warnings,
|
|
391
400
|
interactiveQuestions: [question],
|
|
392
401
|
},
|
|
393
402
|
},
|
|
394
403
|
qualityWarnings: [],
|
|
395
404
|
};
|
|
396
405
|
}
|
|
397
|
-
if (
|
|
406
|
+
if (readiness.ready) {
|
|
398
407
|
return { blockResult: null, qualityWarnings: [] };
|
|
399
408
|
}
|
|
409
|
+
const diagnostic = score < 70
|
|
410
|
+
? `score ${String(score)}/100 is below the 70 threshold`
|
|
411
|
+
: `score ${String(score)}/100 meets the threshold, but ${String(blockers.length)} canonical blocker(s) remain`;
|
|
412
|
+
const issuesSummary = issues.slice(0, 3).join('; ');
|
|
400
413
|
if (newStatus === 'review') {
|
|
401
|
-
const warningsSummary = warnings.slice(0, 3).join('; ');
|
|
402
414
|
return {
|
|
403
415
|
blockResult: {
|
|
404
416
|
content: [
|
|
405
417
|
{
|
|
406
418
|
type: 'text',
|
|
407
|
-
text: `Readiness gate blocked transition to review:
|
|
408
|
-
`
|
|
419
|
+
text: `Readiness gate blocked transition to review: ${diagnostic}. ` +
|
|
420
|
+
`Issues: ${issuesSummary}`,
|
|
409
421
|
},
|
|
410
422
|
],
|
|
411
423
|
isError: true,
|
|
@@ -413,6 +425,7 @@ export async function checkReadinessGate(spec, newStatus, forceApprove) {
|
|
|
413
425
|
error: 'READINESS_GATE_BLOCKED',
|
|
414
426
|
score,
|
|
415
427
|
threshold: 70,
|
|
428
|
+
blockers,
|
|
416
429
|
warnings,
|
|
417
430
|
fixHint: 'Complete the spec before moving from draft to review.',
|
|
418
431
|
},
|
|
@@ -423,12 +436,11 @@ export async function checkReadinessGate(spec, newStatus, forceApprove) {
|
|
|
423
436
|
// Score < 70
|
|
424
437
|
if (forceApprove) {
|
|
425
438
|
// Caller wants to force through — proceed with warnings attached
|
|
426
|
-
return { blockResult: null, qualityWarnings:
|
|
439
|
+
return { blockResult: null, qualityWarnings: issues };
|
|
427
440
|
}
|
|
428
|
-
const warningsSummary = warnings.slice(0, 3).join('; ');
|
|
429
441
|
const question = {
|
|
430
442
|
header: 'Readiness gate',
|
|
431
|
-
question: `Spec readiness
|
|
443
|
+
question: `Spec readiness ${diagnostic}. How to proceed?`,
|
|
432
444
|
multiSelect: false,
|
|
433
445
|
options: [
|
|
434
446
|
{
|
|
@@ -437,7 +449,7 @@ export async function checkReadinessGate(spec, newStatus, forceApprove) {
|
|
|
437
449
|
},
|
|
438
450
|
{
|
|
439
451
|
label: 'view_missing',
|
|
440
|
-
description: `View missing items: ${
|
|
452
|
+
description: `View missing items: ${issuesSummary}`,
|
|
441
453
|
},
|
|
442
454
|
{
|
|
443
455
|
label: 'force_approve',
|
|
@@ -450,10 +462,15 @@ export async function checkReadinessGate(spec, newStatus, forceApprove) {
|
|
|
450
462
|
content: [
|
|
451
463
|
{
|
|
452
464
|
type: 'text',
|
|
453
|
-
text: `Readiness gate:
|
|
465
|
+
text: `Readiness gate: ${diagnostic}. Issues: ${issuesSummary}`,
|
|
454
466
|
},
|
|
455
467
|
],
|
|
456
468
|
structuredContent: {
|
|
469
|
+
error: 'READINESS_GATE_BLOCKED',
|
|
470
|
+
score,
|
|
471
|
+
threshold: 70,
|
|
472
|
+
blockers,
|
|
473
|
+
warnings,
|
|
457
474
|
interactiveQuestions: [question],
|
|
458
475
|
},
|
|
459
476
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ConstitutionViolation } from '../types/index.js';
|
|
2
2
|
export declare function runImplementingActions(projectId: string, specId: string, options?: {
|
|
3
3
|
deferSideEffects?: boolean;
|
|
4
|
+
projectPath?: string;
|
|
4
5
|
}): Promise<{
|
|
5
6
|
autoBranch: string | undefined;
|
|
6
7
|
protectedBranchWarning: string | null;
|
|
@@ -8,9 +9,10 @@ export declare function runImplementingActions(projectId: string, specId: string
|
|
|
8
9
|
autopilotSummary: string[];
|
|
9
10
|
}>;
|
|
10
11
|
/** Create the implementation branch and refresh derived context after commit. */
|
|
11
|
-
export declare function runImplementingSideEffects(projectId: string, specId: string): Promise<string | undefined>;
|
|
12
|
+
export declare function runImplementingSideEffects(projectId: string, specId: string, transitionProjectPath?: string): Promise<string | undefined>;
|
|
12
13
|
export declare function runDoneActions(projectId: string, specId: string, gitBranch: string | undefined, options?: {
|
|
13
14
|
deferSideEffects?: boolean;
|
|
15
|
+
projectPath?: string;
|
|
14
16
|
}): Promise<{
|
|
15
17
|
mergeWarning: string | null;
|
|
16
18
|
prSuggestion: {
|
|
@@ -22,7 +24,7 @@ export declare function runDoneActions(projectId: string, specId: string, gitBra
|
|
|
22
24
|
autopilotSummary: string[];
|
|
23
25
|
}>;
|
|
24
26
|
/** Run cleanup and state refreshes only after the done transition is durable. */
|
|
25
|
-
export declare function runDoneSideEffects(projectId: string, specId: string, gitBranch: string | undefined): Promise<void>;
|
|
27
|
+
export declare function runDoneSideEffects(projectId: string, specId: string, gitBranch: string | undefined, transitionProjectPath?: string): Promise<void>;
|
|
26
28
|
/**
|
|
27
29
|
* Best-effort constitution compliance check for status transitions.
|
|
28
30
|
* Returns warnings (never blocks the transition).
|
|
@@ -8,13 +8,17 @@ function normalizeRejectedReasons(results) {
|
|
|
8
8
|
return reason instanceof Error ? reason : new Error(String(reason));
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
|
+
function suppliedProjectPath(value) {
|
|
12
|
+
const trimmed = value?.trim();
|
|
13
|
+
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
14
|
+
}
|
|
11
15
|
export async function runImplementingActions(projectId, specId, options = {}) {
|
|
12
16
|
let autoBranch;
|
|
13
17
|
let protectedBranchWarning = null;
|
|
14
18
|
// Check if on a protected branch
|
|
15
19
|
try {
|
|
16
20
|
const { resolveProjectPath, git: gitCmd } = await import('./git/git-helpers.js');
|
|
17
|
-
const projectPath = await resolveProjectPath(projectId);
|
|
21
|
+
const projectPath = suppliedProjectPath(options.projectPath) ?? (await resolveProjectPath(projectId));
|
|
18
22
|
const { stdout } = await gitCmd(projectPath, ['rev-parse', '--abbrev-ref', 'HEAD']);
|
|
19
23
|
const currentBranch = stdout.trim();
|
|
20
24
|
const protectedBranches = ['main', 'master', 'develop', 'production'];
|
|
@@ -27,7 +31,7 @@ export async function runImplementingActions(projectId, specId, options = {}) {
|
|
|
27
31
|
}
|
|
28
32
|
if (!options.deferSideEffects) {
|
|
29
33
|
try {
|
|
30
|
-
autoBranch = await runImplementingSideEffects(projectId, specId);
|
|
34
|
+
autoBranch = await runImplementingSideEffects(projectId, specId, options.projectPath);
|
|
31
35
|
}
|
|
32
36
|
catch {
|
|
33
37
|
// Legacy direct callers keep best-effort behavior.
|
|
@@ -41,20 +45,20 @@ export async function runImplementingActions(projectId, specId, options = {}) {
|
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
/** Create the implementation branch and refresh derived context after commit. */
|
|
44
|
-
export async function runImplementingSideEffects(projectId, specId) {
|
|
48
|
+
export async function runImplementingSideEffects(projectId, specId, transitionProjectPath) {
|
|
49
|
+
const { resolveProjectPath } = await import('./git/git-helpers.js');
|
|
50
|
+
const projectPath = suppliedProjectPath(transitionProjectPath) ?? (await resolveProjectPath(projectId));
|
|
45
51
|
let autoBranch;
|
|
46
52
|
const foundSpec = await specStore.getSpec(projectId, specId);
|
|
47
53
|
if (foundSpec && !foundSpec.gitBranch) {
|
|
48
54
|
let branchResult;
|
|
49
55
|
try {
|
|
50
|
-
const { resolveProjectPath: resolveBranchPath } = await import('./git/git-helpers.js');
|
|
51
56
|
const { handleCreateBranch } = await import('./git/branch-ops.js');
|
|
52
|
-
|
|
53
|
-
branchResult = await withAudit(branchProjectPath, 'update_status(implementing)', 'handleCreateBranch', () => handleCreateBranch(projectId, specId), (r) => ({ isError: r.isError }));
|
|
57
|
+
branchResult = await withAudit(projectPath, 'update_status(implementing)', 'handleCreateBranch', () => handleCreateBranch(projectId, specId, undefined, projectPath), (r) => ({ isError: r.isError }));
|
|
54
58
|
}
|
|
55
59
|
catch {
|
|
56
60
|
const { handleCreateBranch } = await import('./git/branch-ops.js');
|
|
57
|
-
branchResult = await handleCreateBranch(projectId, specId);
|
|
61
|
+
branchResult = await handleCreateBranch(projectId, specId, undefined, projectPath);
|
|
58
62
|
}
|
|
59
63
|
if (!branchResult.isError) {
|
|
60
64
|
try {
|
|
@@ -70,8 +74,6 @@ export async function runImplementingSideEffects(projectId, specId) {
|
|
|
70
74
|
// SPEC-600: Fire-and-forget cascade — recommend_model, orchestration plan, context check
|
|
71
75
|
// -------------------------------------------------------------------------
|
|
72
76
|
try {
|
|
73
|
-
const { resolveProjectPath: resolveCascadePath } = await import('./git/git-helpers.js');
|
|
74
|
-
const projectPath = await resolveCascadePath(projectId);
|
|
75
77
|
const spec = foundSpec ?? (await specStore.getSpec(projectId, specId));
|
|
76
78
|
const results = await Promise.allSettled([
|
|
77
79
|
// SPEC-633: Write session state when spec moves to implementing
|
|
@@ -161,7 +163,7 @@ export async function runDoneActions(projectId, specId, gitBranch, options = {})
|
|
|
161
163
|
(async () => {
|
|
162
164
|
try {
|
|
163
165
|
const { resolveProjectPath, git: gitCmd } = await import('./git/git-helpers.js');
|
|
164
|
-
const projectPath = await resolveProjectPath(projectId);
|
|
166
|
+
const projectPath = suppliedProjectPath(options.projectPath) ?? (await resolveProjectPath(projectId));
|
|
165
167
|
if (process.env.PLANU_ENABLE_AUTOCOMMIT === 'true') {
|
|
166
168
|
await gitCmd(projectPath, ['add', 'planu/']);
|
|
167
169
|
const { planuAutoCommit } = await import('../engine/git/planu-autocommit.js');
|
|
@@ -193,7 +195,7 @@ export async function runDoneActions(projectId, specId, gitBranch, options = {})
|
|
|
193
195
|
const mergeResult = await Promise.resolve((async () => {
|
|
194
196
|
try {
|
|
195
197
|
const { resolveProjectPath, resolveBaseBranch, git: gitCmd, } = await import('./git/git-helpers.js');
|
|
196
|
-
const projectPath = await resolveProjectPath(projectId);
|
|
198
|
+
const projectPath = suppliedProjectPath(options.projectPath) ?? (await resolveProjectPath(projectId));
|
|
197
199
|
await gitCmd(projectPath, ['rev-parse', '--verify', gitBranch]);
|
|
198
200
|
const baseBranch = await resolveBaseBranch(projectPath);
|
|
199
201
|
if (!baseBranch) {
|
|
@@ -213,7 +215,7 @@ export async function runDoneActions(projectId, specId, gitBranch, options = {})
|
|
|
213
215
|
mergeWarning = mergeResult;
|
|
214
216
|
}
|
|
215
217
|
if (!options.deferSideEffects) {
|
|
216
|
-
void runDoneSideEffects(projectId, specId, gitBranch).catch(() => {
|
|
218
|
+
void runDoneSideEffects(projectId, specId, gitBranch, options.projectPath).catch(() => {
|
|
217
219
|
// Legacy direct callers keep best-effort behavior.
|
|
218
220
|
});
|
|
219
221
|
}
|
|
@@ -231,9 +233,9 @@ export async function runDoneActions(projectId, specId, gitBranch, options = {})
|
|
|
231
233
|
};
|
|
232
234
|
}
|
|
233
235
|
/** Run cleanup and state refreshes only after the done transition is durable. */
|
|
234
|
-
export async function runDoneSideEffects(projectId, specId, gitBranch) {
|
|
236
|
+
export async function runDoneSideEffects(projectId, specId, gitBranch, transitionProjectPath) {
|
|
235
237
|
const { resolveProjectPath } = await import('./git/git-helpers.js');
|
|
236
|
-
const projectPath = await resolveProjectPath(projectId);
|
|
238
|
+
const projectPath = suppliedProjectPath(transitionProjectPath) ?? (await resolveProjectPath(projectId));
|
|
237
239
|
const results = await Promise.allSettled([
|
|
238
240
|
(async () => {
|
|
239
241
|
const { cleanupSpecOnDone } = await import('./git/cleanup-ops.js');
|