@planu/cli 4.14.1 → 5.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +82 -0
- 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 +12 -3
- 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 +33 -19
- 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 +12 -1
- package/dist/engine/evidence-gates/artifact-reader.js +174 -4
- package/dist/engine/evidence-gates/evidence-autofill.d.ts +10 -0
- package/dist/engine/evidence-gates/evidence-autofill.js +148 -0
- package/dist/engine/evidence-gates/evidence-skeletons.d.ts +19 -0
- package/dist/engine/evidence-gates/evidence-skeletons.js +69 -0
- 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/operation-journal.js +10 -4
- 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/minimality/policy-loader.js +247 -6
- 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 +20 -20
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +20 -20
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +20 -20
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +20 -20
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +20 -20
- package/dist/engine/readiness-checker.d.ts +1 -16
- package/dist/engine/readiness-checker.js +27 -88
- package/dist/engine/reverse-engineer/api-detector.js +2 -13
- package/dist/engine/reverse-engineer/complexity-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/config-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/dependency-graph.js +2 -13
- package/dist/engine/reverse-engineer/test-analyzer.js +2 -13
- package/dist/engine/reverse-engineer/walk-ignore.d.ts +3 -0
- package/dist/engine/reverse-engineer/walk-ignore.js +26 -0
- 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 +82 -22
- 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/text-fences.js +20 -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/spec-state-syncer.js +1 -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 +31 -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 +13 -1
- 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-helpers.d.ts +10 -1
- package/dist/tools/challenge-spec-helpers.js +63 -22
- package/dist/tools/challenge-spec.js +23 -8
- package/dist/tools/check-readiness.js +38 -14
- package/dist/tools/configure-telemetry.js +30 -2
- package/dist/tools/create-spec/spec-builder.d.ts +7 -0
- package/dist/tools/create-spec/spec-builder.js +19 -15
- package/dist/tools/create-spec.d.ts +1 -0
- package/dist/tools/create-spec.js +584 -309
- 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 +29 -19
- 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 +50 -2
- 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/batch.d.ts +6 -2
- package/dist/tools/update-status/batch.js +58 -1
- package/dist/tools/update-status/dod-gates.d.ts +16 -1
- package/dist/tools/update-status/dod-gates.js +191 -1
- package/dist/tools/update-status/done-receipt-verifier.d.ts +8 -0
- package/dist/tools/update-status/done-receipt-verifier.js +75 -27
- package/dist/tools/update-status/evidence-gate.d.ts +4 -0
- package/dist/tools/update-status/evidence-gate.js +103 -3
- package/dist/tools/update-status/file-sync.d.ts +4 -3
- package/dist/tools/update-status/file-sync.js +57 -6
- package/dist/tools/update-status/index.d.ts +25 -1
- package/dist/tools/update-status/index.js +292 -78
- 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 +45 -16
- 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/tools/workspace-dashboard-handler.js +38 -0
- 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-autofill.d.ts +34 -0
- package/dist/types/evidence-autofill.js +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 +3 -6
- package/dist/types/index.js +2 -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 +20 -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 +35 -1
- package/dist/types/spec-format.d.ts +25 -1
- package/dist/types/telemetry.d.ts +4 -1
- package/dist/types/transition-log.d.ts +1 -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 +10 -4
- package/package.json +17 -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
|
@@ -50,6 +50,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
50
50
|
var e = new Error(message);
|
|
51
51
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
52
|
});
|
|
53
|
+
/* eslint-disable max-lines, no-param-reassign -- watcher lifecycle remains co-located and owns one mutable state machine per epoch */
|
|
53
54
|
import { createHash, randomUUID } from 'node:crypto';
|
|
54
55
|
import { constants, watch } from 'node:fs';
|
|
55
56
|
import { lstat, mkdir, open, readdir } from 'node:fs/promises';
|
|
@@ -59,32 +60,76 @@ import { resolveStorageLayout } from '../../storage/storage-layout.js';
|
|
|
59
60
|
import { ValidationReceiptStore } from './validation-receipt.js';
|
|
60
61
|
import { isValidationSourcePath } from './validation-source-policy.js';
|
|
61
62
|
import { reportClassifiedDegradation } from '../../errors/classified-degradation.js';
|
|
62
|
-
import { gitSourceTreeDigest } from './
|
|
63
|
-
|
|
63
|
+
import { gitSourceTreeDigest } from './validation-source-digest.js';
|
|
64
|
+
import { getRuntimePolicy } from '../runtime-policy.js';
|
|
64
65
|
const MAX_EVIDENCE_FILE_BYTES = 2 * 1024 * 1024;
|
|
65
66
|
const FINGERPRINT_CHUNK_BYTES = 64 * 1024;
|
|
66
67
|
const EVIDENCE_FILE = /^(?:discovery|task-plan|traceability-matrix|contract-validation-(?:api|graphql|event|ui|mcp))\.json$/u;
|
|
67
68
|
const active = new Map();
|
|
69
|
+
const beginQueues = new Map();
|
|
68
70
|
function key(projectId, specId) {
|
|
69
71
|
return `${projectId}:${specId}`;
|
|
70
72
|
}
|
|
71
|
-
function
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
async function invalidateDurably(projectId, specId) {
|
|
74
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
75
|
+
try {
|
|
76
|
+
const database = __addDisposableResource(env_1, new RuntimeDatabase({
|
|
77
|
+
path: resolveStorageLayout().runtimeDatabase,
|
|
78
|
+
checkIntegrity: false,
|
|
79
|
+
}), false);
|
|
80
|
+
const store = new ValidationReceiptStore({ database, workspaceId: 'global' });
|
|
81
|
+
await store.invalidateCurrentBindings(projectId, specId);
|
|
82
|
+
}
|
|
83
|
+
catch (e_1) {
|
|
84
|
+
env_1.error = e_1;
|
|
85
|
+
env_1.hasError = true;
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
__disposeResources(env_1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function invalidateDurablyWithCanonicalIntegrity(projectId, specId) {
|
|
92
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
93
|
+
try {
|
|
94
|
+
const database = __addDisposableResource(env_2, new RuntimeDatabase({ path: resolveStorageLayout().runtimeDatabase }), false);
|
|
95
|
+
const store = new ValidationReceiptStore({ database, workspaceId: 'global' });
|
|
96
|
+
await store.invalidateCurrentBindings(projectId, specId);
|
|
97
|
+
}
|
|
98
|
+
catch (e_2) {
|
|
99
|
+
env_2.error = e_2;
|
|
100
|
+
env_2.hasError = true;
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
__disposeResources(env_2);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function runInvalidationTurn(projectId, specId, state) {
|
|
107
|
+
if (state.running) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
state.running = true;
|
|
111
|
+
state.dirty = false;
|
|
112
|
+
const turn = state.invalidating.then(async () => {
|
|
113
|
+
await invalidateDurably(projectId, specId);
|
|
114
|
+
});
|
|
115
|
+
state.invalidating = turn
|
|
116
|
+
.catch((error) => {
|
|
117
|
+
state.healthy = false;
|
|
118
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
119
|
+
})
|
|
120
|
+
.finally(() => {
|
|
121
|
+
state.running = false;
|
|
122
|
+
if (state.dirty && state.accepting && !state.coalesceTimer) {
|
|
123
|
+
const delay = getRuntimePolicy().validation.freshnessInvalidationCoalesceMs;
|
|
124
|
+
state.coalesceTimer = setTimeout(() => {
|
|
125
|
+
state.coalesceTimer = undefined;
|
|
126
|
+
if (state.accepting && active.get(key(projectId, specId)) === state) {
|
|
127
|
+
runInvalidationTurn(projectId, specId, state);
|
|
128
|
+
}
|
|
129
|
+
}, delay);
|
|
130
|
+
state.coalesceTimer.unref();
|
|
85
131
|
}
|
|
86
132
|
});
|
|
87
|
-
return { ...state, generation: state.generation + 1, bindings: undefined, invalidating };
|
|
88
133
|
}
|
|
89
134
|
/**
|
|
90
135
|
* Invalidate the active validation lease for a spec.
|
|
@@ -95,10 +140,13 @@ function invalidateState(projectId, specId, state) {
|
|
|
95
140
|
export function invalidateValidationFreshness(input) {
|
|
96
141
|
const identity = key(input.projectId, input.specId);
|
|
97
142
|
const state = active.get(identity);
|
|
98
|
-
if (!state) {
|
|
143
|
+
if (!state?.accepting) {
|
|
99
144
|
return false;
|
|
100
145
|
}
|
|
101
|
-
|
|
146
|
+
state.generation += 1;
|
|
147
|
+
state.bindings = undefined;
|
|
148
|
+
state.dirty = true;
|
|
149
|
+
runInvalidationTurn(input.projectId, input.specId, state);
|
|
102
150
|
return true;
|
|
103
151
|
}
|
|
104
152
|
function startWatch(path, relevant, onRelevantChange, onError) {
|
|
@@ -115,6 +163,7 @@ function startWatch(path, relevant, onRelevantChange, onError) {
|
|
|
115
163
|
}
|
|
116
164
|
});
|
|
117
165
|
watcher.on('error', onError);
|
|
166
|
+
watcher.unref();
|
|
118
167
|
return watcher;
|
|
119
168
|
}
|
|
120
169
|
catch (error) {
|
|
@@ -187,70 +236,145 @@ async function evidenceFingerprint(path) {
|
|
|
187
236
|
return hash.digest('hex');
|
|
188
237
|
}
|
|
189
238
|
/** Start both watchers before snapshotting and invalidate any older receipt immediately. */
|
|
239
|
+
// eslint-disable-next-line max-lines-per-function -- serialized setup and rollback form one auditable ownership boundary
|
|
190
240
|
export async function beginValidationFreshnessBarrier(input) {
|
|
191
241
|
const identity = key(input.projectId, input.specId);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
242
|
+
const predecessor = beginQueues.get(identity) ?? Promise.resolve();
|
|
243
|
+
let release;
|
|
244
|
+
const queued = new Promise((resolve) => {
|
|
245
|
+
release = resolve;
|
|
196
246
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const watchedEpoch = state.epoch;
|
|
209
|
-
const changed = () => {
|
|
210
|
-
if (active.get(identity)?.epoch !== watchedEpoch) {
|
|
211
|
-
return;
|
|
247
|
+
const tail = predecessor.then(() => queued);
|
|
248
|
+
beginQueues.set(identity, tail);
|
|
249
|
+
await predecessor;
|
|
250
|
+
try {
|
|
251
|
+
const previous = active.get(identity);
|
|
252
|
+
if (previous) {
|
|
253
|
+
await closeValidationFreshnessLease({
|
|
254
|
+
projectId: input.projectId,
|
|
255
|
+
specId: input.specId,
|
|
256
|
+
epoch: previous.epoch,
|
|
257
|
+
});
|
|
212
258
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
259
|
+
await mkdir(input.handoffPath, { recursive: true, mode: 0o700 });
|
|
260
|
+
const initialEvidenceFingerprint = await evidenceFingerprint(input.handoffPath);
|
|
261
|
+
const policy = getRuntimePolicy().validation;
|
|
262
|
+
const state = {
|
|
263
|
+
epoch: randomUUID(),
|
|
264
|
+
expiresAt: Date.now() + policy.freshnessLeaseTtlMs,
|
|
265
|
+
generation: 0,
|
|
266
|
+
healthy: true,
|
|
267
|
+
accepting: true,
|
|
268
|
+
projectPath: input.projectPath,
|
|
269
|
+
handoffPath: input.handoffPath,
|
|
270
|
+
evidenceFingerprint: initialEvidenceFingerprint,
|
|
271
|
+
invalidating: Promise.resolve(),
|
|
272
|
+
watchers: [],
|
|
273
|
+
dirty: false,
|
|
274
|
+
running: false,
|
|
275
|
+
};
|
|
276
|
+
const watchedEpoch = state.epoch;
|
|
277
|
+
const changed = () => {
|
|
278
|
+
if (active.get(identity)?.epoch === watchedEpoch && state.accepting) {
|
|
279
|
+
invalidateValidationFreshness(input);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
const failed = () => {
|
|
283
|
+
if (active.get(identity)?.epoch === watchedEpoch && state.accepting) {
|
|
284
|
+
state.healthy = false;
|
|
285
|
+
changed();
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
const projectWatcher = startWatch(input.projectPath, isValidationSourcePath, changed, failed);
|
|
289
|
+
const handoffWatcher = startWatch(input.handoffPath, (filename) => EVIDENCE_FILE.test(filename), changed, failed);
|
|
290
|
+
if (!projectWatcher || !handoffWatcher) {
|
|
291
|
+
projectWatcher?.close();
|
|
292
|
+
handoffWatcher?.close();
|
|
293
|
+
throw new Error('[Planu] Validation freshness watchers could not be established');
|
|
219
294
|
}
|
|
220
|
-
|
|
221
|
-
state = { ...state, healthy: false };
|
|
295
|
+
state.watchers.push(projectWatcher, handoffWatcher);
|
|
222
296
|
active.set(identity, state);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
297
|
+
state.ttlTimer = setTimeout(() => {
|
|
298
|
+
if (!state.accepting || active.get(identity) !== state) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
void closeValidationFreshnessLease({
|
|
302
|
+
projectId: input.projectId,
|
|
303
|
+
specId: input.specId,
|
|
304
|
+
epoch: state.epoch,
|
|
305
|
+
}).catch((error) => {
|
|
306
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
307
|
+
});
|
|
308
|
+
}, policy.freshnessLeaseTtlMs);
|
|
309
|
+
state.ttlTimer.unref();
|
|
310
|
+
if (input.invalidateCurrentBindings !== false) {
|
|
311
|
+
try {
|
|
312
|
+
await invalidateDurablyWithCanonicalIntegrity(input.projectId, input.specId);
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
await closeValidationFreshnessLease({
|
|
316
|
+
projectId: input.projectId,
|
|
317
|
+
specId: input.specId,
|
|
318
|
+
epoch: state.epoch,
|
|
319
|
+
});
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
projectId: input.projectId,
|
|
325
|
+
specId: input.specId,
|
|
326
|
+
epoch: state.epoch,
|
|
327
|
+
generation: state.generation,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
332
|
+
throw error;
|
|
333
|
+
}
|
|
334
|
+
finally {
|
|
335
|
+
release();
|
|
336
|
+
if (beginQueues.get(identity) === tail) {
|
|
337
|
+
beginQueues.delete(identity);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
/** Stop one exact epoch and drain all invalidations accepted before closure. */
|
|
342
|
+
export async function closeValidationFreshnessLease(lease) {
|
|
343
|
+
const identity = key(lease.projectId, lease.specId);
|
|
344
|
+
const state = active.get(identity);
|
|
345
|
+
if (state?.epoch !== lease.epoch) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
state.closing ??= (async () => {
|
|
349
|
+
state.accepting = false;
|
|
350
|
+
state.watchers.splice(0).forEach((watcher) => {
|
|
351
|
+
watcher.close();
|
|
352
|
+
});
|
|
353
|
+
if (state.ttlTimer) {
|
|
354
|
+
clearTimeout(state.ttlTimer);
|
|
239
355
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
356
|
+
state.ttlTimer = undefined;
|
|
357
|
+
if (state.coalesceTimer) {
|
|
358
|
+
clearTimeout(state.coalesceTimer);
|
|
359
|
+
}
|
|
360
|
+
state.coalesceTimer = undefined;
|
|
361
|
+
try {
|
|
362
|
+
if (state.dirty && !state.running) {
|
|
363
|
+
runInvalidationTurn(lease.projectId, lease.specId, state);
|
|
364
|
+
}
|
|
365
|
+
await state.invalidating;
|
|
366
|
+
if (state.dirty) {
|
|
367
|
+
state.dirty = false;
|
|
368
|
+
await invalidateDurably(lease.projectId, lease.specId);
|
|
369
|
+
}
|
|
243
370
|
}
|
|
244
371
|
finally {
|
|
245
|
-
|
|
372
|
+
if (active.get(identity)?.epoch === lease.epoch) {
|
|
373
|
+
active.delete(identity);
|
|
374
|
+
}
|
|
246
375
|
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
projectId: input.projectId,
|
|
250
|
-
specId: input.specId,
|
|
251
|
-
epoch: state.epoch,
|
|
252
|
-
generation: state.generation,
|
|
253
|
-
};
|
|
376
|
+
})();
|
|
377
|
+
await state.closing;
|
|
254
378
|
}
|
|
255
379
|
/** Bind the post-watch snapshot; an event before this call makes the lease unusable. */
|
|
256
380
|
export async function bindValidationFreshnessLease(lease, bindings) {
|
|
@@ -285,10 +409,7 @@ export async function bindValidationFreshnessLease(lease, bindings) {
|
|
|
285
409
|
confirmed.generation !== state.generation) {
|
|
286
410
|
return false;
|
|
287
411
|
}
|
|
288
|
-
|
|
289
|
-
...confirmed,
|
|
290
|
-
bindings: structuredClone(bindings),
|
|
291
|
-
});
|
|
412
|
+
confirmed.bindings = structuredClone(bindings);
|
|
292
413
|
return true;
|
|
293
414
|
}
|
|
294
415
|
async function readStableState(lease, expectedGeneration) {
|
|
@@ -300,12 +421,15 @@ async function readStableState(lease, expectedGeneration) {
|
|
|
300
421
|
(expectedGeneration !== undefined && before.generation !== expectedGeneration)) {
|
|
301
422
|
return undefined;
|
|
302
423
|
}
|
|
303
|
-
|
|
424
|
+
const generationBefore = before.generation;
|
|
425
|
+
const invalidatingBefore = before.invalidating;
|
|
426
|
+
await invalidatingBefore;
|
|
304
427
|
const after = active.get(identity);
|
|
305
428
|
if (after?.healthy &&
|
|
306
429
|
after.epoch === before.epoch &&
|
|
307
|
-
after.generation ===
|
|
308
|
-
after.
|
|
430
|
+
after.generation === generationBefore &&
|
|
431
|
+
(expectedGeneration === undefined || after.generation === expectedGeneration) &&
|
|
432
|
+
after.invalidating === invalidatingBefore) {
|
|
309
433
|
return after;
|
|
310
434
|
}
|
|
311
435
|
}
|
|
@@ -383,6 +507,7 @@ export async function rebaselineValidationFreshnessLeaseAfterRecompute(input) {
|
|
|
383
507
|
if (!before || Date.now() >= before.expiresAt) {
|
|
384
508
|
return undefined;
|
|
385
509
|
}
|
|
510
|
+
const generationBefore = before.generation;
|
|
386
511
|
let fingerprintBefore;
|
|
387
512
|
let observedBindings;
|
|
388
513
|
let fingerprintAfter;
|
|
@@ -397,7 +522,7 @@ export async function rebaselineValidationFreshnessLeaseAfterRecompute(input) {
|
|
|
397
522
|
return undefined;
|
|
398
523
|
}
|
|
399
524
|
const after = await readStableState(input.lease);
|
|
400
|
-
if (after?.generation !==
|
|
525
|
+
if (after?.generation !== generationBefore || fingerprintBefore !== fingerprintAfter) {
|
|
401
526
|
continue;
|
|
402
527
|
}
|
|
403
528
|
if (JSON.stringify(input.expectedBindings) !== JSON.stringify(observedBindings)) {
|
|
@@ -407,21 +532,36 @@ export async function rebaselineValidationFreshnessLeaseAfterRecompute(input) {
|
|
|
407
532
|
if (confirmed?.generation !== after.generation) {
|
|
408
533
|
continue;
|
|
409
534
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
bindings: structuredClone(observedBindings),
|
|
413
|
-
evidenceFingerprint: fingerprintAfter,
|
|
414
|
-
});
|
|
535
|
+
confirmed.bindings = structuredClone(observedBindings);
|
|
536
|
+
confirmed.evidenceFingerprint = fingerprintAfter;
|
|
415
537
|
return { ...input.lease, generation: confirmed.generation };
|
|
416
538
|
}
|
|
417
539
|
return undefined;
|
|
418
540
|
}
|
|
419
|
-
export function resetValidationFreshnessForTests() {
|
|
541
|
+
export async function resetValidationFreshnessForTests() {
|
|
542
|
+
const leases = [...active.entries()].map(([identity, state]) => {
|
|
543
|
+
const separator = identity.indexOf(':');
|
|
544
|
+
return {
|
|
545
|
+
projectId: identity.slice(0, separator),
|
|
546
|
+
specId: identity.slice(separator + 1),
|
|
547
|
+
epoch: state.epoch,
|
|
548
|
+
};
|
|
549
|
+
});
|
|
550
|
+
await Promise.all(leases.map((lease) => closeValidationFreshnessLease(lease)));
|
|
551
|
+
beginQueues.clear();
|
|
552
|
+
}
|
|
553
|
+
/** Count-only process diagnostic; intentionally absent from the package entrypoint. */
|
|
554
|
+
export function getValidationFreshnessDiagnosticsForTests() {
|
|
555
|
+
let watchers = 0;
|
|
556
|
+
let queuedInvalidations = 0;
|
|
557
|
+
let timers = 0;
|
|
558
|
+
let generationTotal = 0;
|
|
420
559
|
for (const state of active.values()) {
|
|
421
|
-
state.watchers.
|
|
422
|
-
|
|
423
|
-
|
|
560
|
+
watchers += state.watchers.length;
|
|
561
|
+
queuedInvalidations += Number(state.running) + Number(state.dirty);
|
|
562
|
+
timers += Number(Boolean(state.ttlTimer)) + Number(Boolean(state.coalesceTimer));
|
|
563
|
+
generationTotal += state.generation;
|
|
424
564
|
}
|
|
425
|
-
active.
|
|
565
|
+
return { activeLeases: active.size, watchers, queuedInvalidations, timers, generationTotal };
|
|
426
566
|
}
|
|
427
567
|
//# sourceMappingURL=validation-freshness.js.map
|
|
@@ -3,10 +3,6 @@ import type { RuntimeDatabase } from '../../storage/runtime-db.js';
|
|
|
3
3
|
import { type StorageCatalogContext } from '../../storage/storage-catalog.js';
|
|
4
4
|
export { normalizeValidationCommand } from './validation-receipt-codec.js';
|
|
5
5
|
export declare const LOCAL_VALIDATION_RECEIPT_ISSUER = "planu-local-validator";
|
|
6
|
-
export declare class ValidationIssuerKeyError extends Error {
|
|
7
|
-
readonly code: 'VALIDATION_ISSUER_KEY_NOT_CONFIGURED';
|
|
8
|
-
constructor();
|
|
9
|
-
}
|
|
10
6
|
export declare class ValidationReceiptStore implements ValidationReceiptPersistence {
|
|
11
7
|
private readonly options;
|
|
12
8
|
private readonly logDirectory;
|
|
@@ -14,6 +10,7 @@ export declare class ValidationReceiptStore implements ValidationReceiptPersiste
|
|
|
14
10
|
readonly database: RuntimeDatabase;
|
|
15
11
|
readonly workspaceId: string;
|
|
16
12
|
readonly catalogContext?: StorageCatalogContext;
|
|
13
|
+
readonly authorizePersistence?: (database: RuntimeDatabase) => void;
|
|
17
14
|
});
|
|
18
15
|
logPath(logDigest: string): string;
|
|
19
16
|
persist(receipt: ValidationReceipt, log: Buffer): Promise<void>;
|
|
@@ -21,7 +18,7 @@ export declare class ValidationReceiptStore implements ValidationReceiptPersiste
|
|
|
21
18
|
readCurrent(projectId: string, specId: string): Promise<ValidationReceipt | undefined>;
|
|
22
19
|
readCurrentBindings(projectId: string, specId: string): Promise<ValidationReceiptBindings | undefined>;
|
|
23
20
|
projectCurrentBindings(bindings: ValidationReceiptBindings): Promise<void>;
|
|
24
|
-
invalidateCurrentBindings(projectId: string, specId: string): Promise<void>;
|
|
21
|
+
invalidateCurrentBindings(projectId: string, specId: string, receiptId?: string): Promise<void>;
|
|
25
22
|
readLog(logDigest: string): Promise<Buffer | undefined>;
|
|
26
23
|
private writeLog;
|
|
27
24
|
}
|
|
@@ -46,6 +43,7 @@ export declare function createValidationReceiptAuthority(options: {
|
|
|
46
43
|
readonly projectId: string;
|
|
47
44
|
readonly issuerId: string;
|
|
48
45
|
readonly catalogContext?: StorageCatalogContext;
|
|
46
|
+
readonly authorizePersistence?: (database: RuntimeDatabase) => void;
|
|
49
47
|
}): {
|
|
50
48
|
readonly authority: ValidationReceiptAuthority;
|
|
51
49
|
readonly store: ValidationReceiptStore;
|
|
@@ -55,5 +53,10 @@ export declare function createValidationReceiptAuthority(options: {
|
|
|
55
53
|
export declare function ensureValidationIssuerKey(identity: {
|
|
56
54
|
readonly projectId: string;
|
|
57
55
|
readonly issuerId: string;
|
|
58
|
-
}): Promise<string>;
|
|
56
|
+
}, platform?: NodeJS.Platform): Promise<string>;
|
|
57
|
+
/** Prove that this process can resolve or provision its canonical receipt-signing key. */
|
|
58
|
+
export declare function preflightValidationReceiptSigner(identity: {
|
|
59
|
+
readonly projectId: string;
|
|
60
|
+
readonly issuerId: string;
|
|
61
|
+
}, platform?: NodeJS.Platform): Promise<string>;
|
|
59
62
|
//# sourceMappingURL=validation-receipt.d.ts.map
|
|
@@ -6,16 +6,11 @@ import { reportClassifiedDegradation } from '../../errors/classified-degradation
|
|
|
6
6
|
import { resolvedStorageArtifactPath, } from '../../storage/storage-catalog.js';
|
|
7
7
|
import { formatSecretReference, getSecretProvider, parseSecretReference, SecretProviderError, } from '../../security/secret-provider.js';
|
|
8
8
|
import { redactText } from '../../security/redactor.js';
|
|
9
|
+
import { ValidationReceiptSignerUnavailableError } from '../macos-keychain-native-port.js';
|
|
10
|
+
import { acquireLock, releaseLock } from '../safety/file-mutex.js';
|
|
9
11
|
import { canonicalize, DIGEST, ISSUER_ID, PROJECT_ID, receiptCore, safeProof, sha256, SPEC_ID, validBindings, validReceiptShape, } from './validation-receipt-codec.js';
|
|
10
12
|
export { normalizeValidationCommand } from './validation-receipt-codec.js';
|
|
11
13
|
export const LOCAL_VALIDATION_RECEIPT_ISSUER = 'planu-local-validator';
|
|
12
|
-
export class ValidationIssuerKeyError extends Error {
|
|
13
|
-
code = 'VALIDATION_ISSUER_KEY_NOT_CONFIGURED';
|
|
14
|
-
constructor() {
|
|
15
|
-
super('[Planu] Validation issuer key is not configured in the explicit environment adapter');
|
|
16
|
-
this.name = 'ValidationIssuerKeyError';
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
14
|
export class ValidationReceiptStore {
|
|
20
15
|
options;
|
|
21
16
|
logDirectory;
|
|
@@ -35,6 +30,7 @@ export class ValidationReceiptStore {
|
|
|
35
30
|
}
|
|
36
31
|
await this.writeLog(receipt.logDigest, log);
|
|
37
32
|
this.options.database.transaction(() => {
|
|
33
|
+
this.options.authorizePersistence?.(this.options.database);
|
|
38
34
|
this.options.database.putRecord({
|
|
39
35
|
projectId: receipt.bindings.projectId,
|
|
40
36
|
workspaceId: this.options.workspaceId,
|
|
@@ -96,16 +92,26 @@ export class ValidationReceiptStore {
|
|
|
96
92
|
});
|
|
97
93
|
return Promise.resolve();
|
|
98
94
|
}
|
|
99
|
-
invalidateCurrentBindings(projectId, specId) {
|
|
100
|
-
if (!PROJECT_ID.test(projectId) ||
|
|
95
|
+
invalidateCurrentBindings(projectId, specId, receiptId) {
|
|
96
|
+
if (!PROJECT_ID.test(projectId) ||
|
|
97
|
+
!SPEC_ID.test(specId) ||
|
|
98
|
+
(receiptId !== undefined && !DIGEST.test(receiptId))) {
|
|
101
99
|
throw new Error('[Planu] Validation binding identity is invalid');
|
|
102
100
|
}
|
|
103
|
-
this.options.database.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
this.options.database.transaction(() => {
|
|
102
|
+
if (receiptId !== undefined) {
|
|
103
|
+
const current = this.options.database.getRecord(projectId, this.options.workspaceId, 'audit-state', `validation-current:${specId}`);
|
|
104
|
+
if (!validReceiptShape(current?.value) || current.value.receiptId !== receiptId) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
this.options.database.putRecord({
|
|
109
|
+
projectId,
|
|
110
|
+
workspaceId: this.options.workspaceId,
|
|
111
|
+
kind: 'audit-state',
|
|
112
|
+
key: `validation-bindings-current:${specId}`,
|
|
113
|
+
value: { invalidatedAt: new Date().toISOString() },
|
|
114
|
+
});
|
|
109
115
|
});
|
|
110
116
|
return Promise.resolve();
|
|
111
117
|
}
|
|
@@ -261,22 +267,76 @@ export function createValidationReceiptAuthority(options) {
|
|
|
261
267
|
};
|
|
262
268
|
}
|
|
263
269
|
/** Provision or resolve a machine-local issuer key without exposing raw key material. */
|
|
264
|
-
export async function ensureValidationIssuerKey(identity) {
|
|
265
|
-
const
|
|
270
|
+
export async function ensureValidationIssuerKey(identity, platform = process.platform) {
|
|
271
|
+
const canonicalProvider = platform === 'darwin'
|
|
272
|
+
? 'macos-keychain'
|
|
273
|
+
: platform === 'linux'
|
|
274
|
+
? 'linux-secret-service'
|
|
275
|
+
: platform === 'win32'
|
|
276
|
+
? 'windows-credential-manager'
|
|
277
|
+
: undefined;
|
|
278
|
+
if (canonicalProvider === undefined) {
|
|
279
|
+
throw new ValidationReceiptSignerUnavailableError('PLATFORM_UNSUPPORTED');
|
|
280
|
+
}
|
|
281
|
+
let provider;
|
|
282
|
+
try {
|
|
283
|
+
provider = getSecretProvider();
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
|
|
287
|
+
}
|
|
288
|
+
if (provider.adapter.kind !== canonicalProvider) {
|
|
289
|
+
throw new ValidationReceiptSignerUnavailableError('PROVIDER_NONCANONICAL');
|
|
290
|
+
}
|
|
266
291
|
const reference = parseSecretReference(validationIssuerReference(identity));
|
|
292
|
+
let lock;
|
|
267
293
|
try {
|
|
268
|
-
await
|
|
269
|
-
|
|
294
|
+
lock = await acquireLock(`validation-issuer:${identity.projectId}:${identity.issuerId}`);
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
|
|
298
|
+
}
|
|
299
|
+
let result;
|
|
300
|
+
try {
|
|
301
|
+
try {
|
|
302
|
+
await provider.resolve(reference);
|
|
303
|
+
result = formatSecretReference(reference);
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
if (!(error instanceof SecretProviderError) || error.code !== 'SECRET_NOT_FOUND') {
|
|
307
|
+
throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
await provider.store(reference, randomBytes(32).toString('base64url'));
|
|
311
|
+
result = formatSecretReference(reference);
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
|
|
315
|
+
}
|
|
316
|
+
}
|
|
270
317
|
}
|
|
271
318
|
catch (error) {
|
|
272
|
-
|
|
319
|
+
try {
|
|
320
|
+
await releaseLock(lock);
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
reportClassifiedDegradation('VALIDATION_ISSUER_LOCK_RELEASE_FAILURE', new Error('Validation issuer lock release failed'));
|
|
324
|
+
}
|
|
325
|
+
if (error instanceof ValidationReceiptSignerUnavailableError) {
|
|
273
326
|
throw error;
|
|
274
327
|
}
|
|
328
|
+
throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
|
|
275
329
|
}
|
|
276
|
-
|
|
277
|
-
|
|
330
|
+
try {
|
|
331
|
+
await releaseLock(lock);
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
throw new ValidationReceiptSignerUnavailableError('PROVIDER_UNAVAILABLE');
|
|
278
335
|
}
|
|
279
|
-
|
|
280
|
-
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
338
|
+
/** Prove that this process can resolve or provision its canonical receipt-signing key. */
|
|
339
|
+
export function preflightValidationReceiptSigner(identity, platform = process.platform) {
|
|
340
|
+
return ensureValidationIssuerKey(identity, platform);
|
|
281
341
|
}
|
|
282
342
|
//# sourceMappingURL=validation-receipt.js.map
|