@planu/cli 4.12.3 → 4.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +29 -25
- package/dist/cli/commands/inspect.d.ts +4 -0
- package/dist/cli/commands/inspect.js +144 -0
- package/dist/cli/commands/install.d.ts +19 -1
- package/dist/cli/commands/install.js +145 -43
- package/dist/cli/commands/job.d.ts +3 -0
- package/dist/cli/commands/job.js +119 -0
- package/dist/cli/commands/offline.d.ts +15 -0
- package/dist/cli/commands/offline.js +132 -0
- package/dist/cli/commands/serve.js +4 -0
- package/dist/cli/commands/spec.js +1 -1
- package/dist/cli/commands/storage.d.ts +3 -0
- package/dist/cli/commands/storage.js +102 -0
- package/dist/cli/commands/uninstall.d.ts +10 -0
- package/dist/cli/commands/uninstall.js +93 -7
- package/dist/cli/commands/validate.js +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/router.js +9 -1
- package/dist/config/crash-shield-framework-rules.json +93 -0
- package/dist/config/environment-schema.json +149 -0
- package/dist/config/hardcode-exceptions.json +4 -0
- package/dist/config/license-plans.json +7 -0
- package/dist/config/native-release-public-key.pem +3 -0
- package/dist/config/native-targets.json +87 -0
- package/dist/config/product-public.d.ts +89 -0
- package/dist/config/product-public.js +140 -0
- package/dist/config/product-public.json +312 -0
- package/dist/config/product-public.ts +148 -0
- package/dist/config/release-compatibility.json +13 -0
- package/dist/config/release-policy.json +26 -0
- package/dist/config/runtime-policy.json +44 -0
- package/dist/config/skill-templates/planu-validate.md +7 -4
- package/dist/config/subagent-templates/planu-spec-implementer.md +7 -3
- package/dist/config/subagent-templates/planu-validator.md +10 -5
- package/dist/config/technology-registry.json +120 -0
- package/dist/config/version.js +7 -8
- package/dist/config/version.ts +10 -7
- package/dist/engine/abortable-process-runner.js +40 -9
- package/dist/engine/advanced-testing/accessibility-checker.js +12 -14
- package/dist/engine/advanced-testing/mutation-advisor.js +3 -4
- package/dist/engine/advanced-testing/property-based.js +2 -3
- package/dist/engine/advanced-testing/test-data-advisor.js +2 -3
- package/dist/engine/agent-generator.js +2 -1
- package/dist/engine/agent-handoff-store.js +2 -1
- package/dist/engine/agent-prompt-generator.js +7 -5
- package/dist/engine/agent-telemetry.js +2 -1
- package/dist/engine/ai-integration/gemini/extensions-advisor.js +41 -9
- package/dist/engine/ambiguity-detector.js +12 -11
- package/dist/engine/analyzer/db-engine.js +2 -3
- package/dist/engine/analyzer/detectors.js +13 -14
- package/dist/engine/analyzer/env-setup.js +9 -10
- package/dist/engine/analyzer-env-scanner/env-example.js +7 -8
- package/dist/engine/api-spec-generator/graphql-parser.js +2 -2
- package/dist/engine/api-validation/graphql-schema-validator.js +2 -1
- package/dist/engine/api-validation/openapi-impl-validator.js +6 -7
- package/dist/engine/architecture-detector.js +10 -8
- package/dist/engine/auth/config.d.ts +1 -1
- package/dist/engine/auth/config.js +4 -3
- package/dist/engine/auto-updater/atomic-upgrade.d.ts +8 -0
- package/dist/engine/auto-updater/atomic-upgrade.js +381 -0
- package/dist/engine/auto-updater/config-detector.js +9 -3
- package/dist/engine/auto-updater/config-patcher.d.ts +0 -4
- package/dist/engine/auto-updater/config-patcher.js +10 -15
- package/dist/engine/auto-updater/index.d.ts +3 -1
- package/dist/engine/auto-updater/index.js +44 -30
- package/dist/engine/auto-updater/npm-registry.js +10 -2
- package/dist/engine/auto-updater/release-verifier.d.ts +3 -0
- package/dist/engine/auto-updater/release-verifier.js +112 -0
- package/dist/engine/auto-updater/upgrade-lock.d.ts +6 -0
- package/dist/engine/auto-updater/upgrade-lock.js +28 -0
- package/dist/engine/auto-updater/upgrade-trust-state.d.ts +7 -0
- package/dist/engine/auto-updater/upgrade-trust-state.js +59 -0
- package/dist/engine/autopilot/audit-logger.js +2 -5
- package/dist/engine/best-practices-library.js +2 -1
- package/dist/engine/browser-validator.js +2 -1
- package/dist/engine/build-tool-detector.js +3 -2
- package/dist/engine/ci-generator/context-builders.js +7 -5
- package/dist/engine/ci-generator/stack-detector.js +0 -2
- package/dist/engine/ci-generator/yaml-builder.js +0 -2
- package/dist/engine/claude-config-auditor/rules-auditor.js +4 -3
- package/dist/engine/code-transforms/typescript/ast-utils.js +2 -3
- package/dist/engine/complexity-budget/trivial-detector.js +2 -1
- package/dist/engine/compliance-test-generator/index.js +7 -2
- package/dist/engine/compliance-test-generator/test-formatter.js +2 -2
- package/dist/engine/config-health/mcp-config-checker.js +2 -1
- package/dist/engine/config-health/ts-checker-scripts.js +4 -3
- package/dist/engine/config-health/ts-checker.js +3 -2
- package/dist/engine/convention-injector.js +5 -7
- package/dist/engine/convention-scanner/convention-parser.js +3 -2
- package/dist/engine/core-bridge-duplicate-blocks.d.ts +3 -0
- package/dist/engine/core-bridge-duplicate-blocks.js +57 -0
- package/dist/engine/core-bridge-gaps.d.ts +4 -0
- package/dist/engine/core-bridge-gaps.js +75 -0
- package/dist/engine/core-bridge.d.ts +9 -9
- package/dist/engine/core-bridge.js +196 -283
- package/dist/engine/cost-tracking/ledger.js +2 -5
- package/dist/engine/coverage-gap-analyzer.js +10 -1
- package/dist/engine/crash-shield/detectors/framework-detector.d.ts +2 -0
- package/dist/engine/crash-shield/detectors/framework-detector.js +110 -192
- package/dist/engine/crash-shield/detectors/typescript-detector.js +2 -1
- package/dist/engine/dashboard/data-loader.js +2 -1
- package/dist/engine/data-projects-gc/gc-runner.d.ts +7 -0
- package/dist/engine/data-projects-gc/gc-runner.js +113 -3
- package/dist/engine/data-projects-gc/scanner.js +5 -1
- package/dist/engine/decision-store.js +11 -14
- package/dist/engine/deleter/core.js +5 -5
- package/dist/engine/dep-auditor/abandonment-data.js +2 -1
- package/dist/engine/dep-auditor/abandonment-registry.js +3 -1
- package/dist/engine/dep-auditor/cve-fetcher.js +3 -0
- package/dist/engine/dep-auditor/dep-duplicates-detector.js +36 -4
- package/dist/engine/dep-auditor/license-registry.js +2 -0
- package/dist/engine/dependency-evaluator.d.ts +14 -0
- package/dist/engine/dependency-evaluator.js +81 -0
- package/dist/engine/deploy/providers/fly.js +7 -7
- package/dist/engine/deploy/providers/netlify.js +7 -7
- package/dist/engine/deploy/providers/railway.js +10 -12
- package/dist/engine/deploy/providers/vercel.js +7 -9
- package/dist/engine/deprecation-scanner/pattern-loader.js +0 -2
- package/dist/engine/desktop-detector.js +2 -3
- package/dist/engine/detect-duplication.js +2 -1
- package/dist/engine/detectors/advanced-framework-detector/css-state-detector.js +2 -1
- package/dist/engine/detectors/advanced-framework-detector/legacy-detector.js +2 -3
- package/dist/engine/detectors/advanced-framework-detector/modern-detector.js +3 -4
- package/dist/engine/detectors/agent-framework-detector.js +3 -2
- package/dist/engine/detectors/ai-native-detector.js +4 -6
- package/dist/engine/detectors/cache-db-detector.js +4 -3
- package/dist/engine/detectors/cicd-detector.js +4 -3
- package/dist/engine/detectors/deployment-detector.js +11 -12
- package/dist/engine/detectors/frontend-perf-detector.js +14 -9
- package/dist/engine/detectors/library-detector-multilang-a.js +16 -3
- package/dist/engine/detectors/library-detector-node.js +14 -4
- package/dist/engine/detectors/library-detector-python.js +7 -1
- package/dist/engine/detectors/library-detector.js +0 -2
- package/dist/engine/detectors/llm-detector/provider-maps.js +3 -2
- package/dist/engine/detectors/mcp-candidate-detector.js +12 -16
- package/dist/engine/detectors/mfe-detector.js +6 -7
- package/dist/engine/detectors/monitoring-detector.js +4 -3
- package/dist/engine/detectors/otel-detector.js +3 -2
- package/dist/engine/detectors/otel-ecosystem-detectors.d.ts +2 -2
- package/dist/engine/detectors/otel-ecosystem-detectors.js +4 -3
- package/dist/engine/detectors/platform-specialty-detector.js +3 -5
- package/dist/engine/detectors/template-engine-detector.js +3 -4
- package/dist/engine/doc-generator/builders.js +2 -3
- package/dist/engine/doc-generator/mobile-distribution-guide.js +13 -17
- package/dist/engine/doc-generator/portal/dirty-flag-map.d.ts +2 -2
- package/dist/engine/doc-generator/portal/portal-regenerator.js +3 -47
- package/dist/engine/domain-detector.js +3 -6
- package/dist/engine/dynamic-knowledge/knowledge-cache.js +3 -4
- package/dist/engine/dynamic-knowledge/knowledge-merger.js +17 -2
- package/dist/engine/dynamic-knowledge/web-researcher.js +15 -14
- package/dist/engine/dynamic-migration-detector/manifest-readers-extended.js +0 -2
- package/dist/engine/e2e-test-generator.js +4 -3
- package/dist/engine/ecosystem-absorber/knowledge-cache.js +2 -1
- package/dist/engine/ecosystem-absorber/platform-crawler.js +2 -2
- package/dist/engine/escalator/retry-counter.js +2 -1
- package/dist/engine/evidence-gates/artifact-reader.d.ts +6 -0
- package/dist/engine/evidence-gates/artifact-reader.js +105 -21
- package/dist/engine/evidence-gates/lifecycle-gate.d.ts +2 -1
- package/dist/engine/evidence-gates/lifecycle-gate.js +54 -0
- package/dist/engine/execution/context.d.ts +19 -0
- package/dist/engine/execution/context.js +127 -0
- package/dist/engine/execution/deadline-io.d.ts +21 -0
- package/dist/engine/execution/deadline-io.js +45 -0
- package/dist/engine/execution/job-executor.d.ts +16 -0
- package/dist/engine/execution/job-executor.js +140 -0
- package/dist/engine/execution/job-runtime.d.ts +78 -0
- package/dist/engine/execution/job-runtime.js +220 -0
- package/dist/engine/execution/native-relevance-scorer.d.ts +6 -0
- package/dist/engine/execution/native-relevance-scorer.js +64 -0
- package/dist/engine/execution/native-worker-dispatch.d.ts +3 -0
- package/dist/engine/execution/native-worker-dispatch.js +46 -0
- package/dist/engine/execution/native-worker-protocol.d.ts +6 -0
- package/dist/engine/execution/native-worker-protocol.js +33 -0
- package/dist/engine/execution/native-worker-runtime.d.ts +4 -0
- package/dist/engine/execution/native-worker-runtime.js +177 -0
- package/dist/engine/execution/native-worker-thread.d.ts +2 -0
- package/dist/engine/execution/native-worker-thread.js +66 -0
- package/dist/engine/execution/operation-journal.d.ts +66 -0
- package/dist/engine/execution/operation-journal.js +260 -0
- package/dist/engine/execution/outbox-worker.d.ts +31 -0
- package/dist/engine/execution/outbox-worker.js +192 -0
- package/dist/engine/execution/validate-job-executor.d.ts +24 -0
- package/dist/engine/execution/validate-job-executor.js +342 -0
- package/dist/engine/execution/validate-job-payload.d.ts +5 -0
- package/dist/engine/execution/validate-job-payload.js +87 -0
- package/dist/engine/execution/validate-job-recovery.d.ts +4 -0
- package/dist/engine/execution/validate-job-recovery.js +47 -0
- package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
- package/dist/engine/execution/validate-worker-runtime.js +100 -0
- package/dist/engine/execution/validate-worker-thread.d.ts +2 -0
- package/dist/engine/execution/validate-worker-thread.js +71 -0
- package/dist/engine/execution-plan/desktop-distribution.js +3 -7
- package/dist/engine/execution-plan/mobile-distribution.js +4 -9
- package/dist/engine/execution-plan/phases.js +4 -5
- package/dist/engine/execution-plan/plan-utils.js +8 -5
- package/dist/engine/facilitate/context-loader.js +3 -9
- package/dist/engine/figma/code-connect-fetcher.js +9 -8
- package/dist/engine/filesystem-watcher/index.d.ts +3 -3
- package/dist/engine/filesystem-watcher/index.js +5 -5
- package/dist/engine/framework-detector.js +14 -15
- package/dist/engine/git/planu-autocommit.js +8 -7
- package/dist/engine/git/repository-probe.d.ts +3 -0
- package/dist/engine/git/repository-probe.js +13 -0
- package/dist/engine/global-rules-manager.js +2 -2
- package/dist/engine/handoff-artifacts/io.js +2 -3
- package/dist/engine/handoff-artifacts/schemas/red-tests-handoff.js +8 -1
- package/dist/engine/handoff-artifacts/schemas.d.ts +4 -0
- package/dist/engine/handoff-artifacts/schemas.js +5 -0
- package/dist/engine/hook-generator/stack-hook-templates.js +4 -4
- package/dist/engine/hooks/config-loader.js +1 -1
- package/dist/engine/hooks/context-injector.js +4 -7
- package/dist/engine/hooks/file-watcher.js +1 -14
- package/dist/engine/hooks-reconciler.js +6 -4
- package/dist/engine/infrastructure/component-mapper.js +5 -7
- package/dist/engine/infrastructure/docker-compose-generator.js +8 -10
- package/dist/engine/infrastructure/index.js +6 -3
- package/dist/engine/infrastructure/kubernetes-generator.js +2 -2
- package/dist/engine/infrastructure/railway-generator.js +10 -8
- package/dist/engine/infrastructure/signal-detector.js +6 -8
- package/dist/engine/infrastructure/terraform-generator.js +6 -8
- package/dist/engine/legal-compliance/detector.js +3 -2
- package/dist/engine/local-first/storage-advisor.js +5 -6
- package/dist/engine/macos-keychain-native-port.d.ts +5 -0
- package/dist/engine/macos-keychain-native-port.js +26 -0
- package/dist/engine/marketplace-fetcher/cache.js +3 -1
- package/dist/engine/mcp-config/mcp-config-writer.d.ts +2 -2
- package/dist/engine/mcp-config/mcp-config-writer.js +10 -8
- package/dist/engine/migration/db-migrator.js +2 -5
- package/dist/engine/migration/equivalence-mapper.js +12 -13
- package/dist/engine/migration/service-catalogs.js +6 -7
- package/dist/engine/migration/service-migrator-catalogs.js +6 -7
- package/dist/engine/mobile-detector-ios.js +2 -3
- package/dist/engine/mobile-detector.js +16 -4
- package/dist/engine/model-router/complexity-analyzer.js +4 -7
- package/dist/engine/multi-agent-review/security-analyzer.js +3 -1
- package/dist/engine/multi-app-detector/app-type.js +26 -21
- package/dist/engine/multi-app-detector/core.js +3 -2
- package/dist/engine/multi-teammate-review/disagreement-counter.js +2 -1
- package/dist/engine/multi-teammate-review/panel-orchestrator.js +0 -2
- package/dist/engine/mutation-config-generator.js +10 -7
- package/dist/engine/native-capability-policy.d.ts +4 -0
- package/dist/engine/native-capability-policy.js +24 -0
- package/dist/engine/native-platform.d.ts +3 -0
- package/dist/engine/native-platform.js +44 -0
- package/dist/engine/native-runtime-handshake.d.ts +20 -0
- package/dist/engine/native-runtime-handshake.js +230 -0
- package/dist/engine/network-policy.d.ts +27 -0
- package/dist/engine/network-policy.js +174 -0
- package/dist/engine/next-spec-resolver/dependency-filter.js +2 -22
- package/dist/engine/nfr-profile-detector.js +12 -16
- package/dist/engine/nli-keywords.js +8 -9
- package/dist/engine/oauth/config-guard.js +4 -5
- package/dist/engine/observability/local-execution-spans.d.ts +15 -0
- package/dist/engine/observability/local-execution-spans.js +63 -0
- package/dist/engine/orchestrator/runtime.js +0 -1
- package/dist/engine/package-registry.js +2 -6
- package/dist/engine/performance-analyzer.js +2 -5
- package/dist/engine/permissions-merger/stack-detectors.js +5 -5
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +39 -0
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +1310 -0
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +39 -0
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +1310 -0
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +38 -0
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +1310 -0
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +38 -0
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +1310 -0
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +38 -0
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +1310 -0
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +38 -0
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +1310 -0
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +38 -0
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +1310 -0
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +38 -0
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +1310 -0
- package/dist/engine/platform-detector/desktop.js +15 -2
- package/dist/engine/platform-detector/extensions.js +2 -1
- package/dist/engine/platform-detector/games.js +2 -1
- package/dist/engine/platform-detector.js +3 -2
- package/dist/engine/platform-engineering/idp-detector.js +2 -1
- package/dist/engine/plugin-installer/stack-matcher.js +9 -17
- package/dist/engine/plugins/lifecycle.js +6 -2
- package/dist/engine/prior-decisions/contradiction-detector.js +60 -30
- package/dist/engine/project-dna/stack-detector.js +15 -17
- package/dist/engine/project-graph/builder.js +11 -0
- package/dist/engine/project-graph/cache.js +1 -1
- package/dist/engine/project-graph/freshness-projection.d.ts +16 -0
- package/dist/engine/project-graph/freshness-projection.js +95 -0
- package/dist/engine/project-graph/index.d.ts +1 -0
- package/dist/engine/project-graph/index.js +1 -0
- package/dist/engine/project-graph/query.js +15 -25
- package/dist/engine/project-health-checker.js +3 -4
- package/dist/engine/project-scanner/stack-detector.js +17 -17
- package/dist/engine/property-test-generator.js +2 -3
- package/dist/engine/qa-gate.d.ts +1 -0
- package/dist/engine/qa-gate.js +6 -4
- package/dist/engine/quality-gates/gate-catalog.js +47 -46
- package/dist/engine/quality-gates/gate-injector.js +9 -4
- package/dist/engine/registry/core.js +0 -2
- package/dist/engine/registry/loader.js +9 -12
- package/dist/engine/registry/matcher.js +129 -24
- package/dist/engine/resilience-detector/concurrency-detector.js +4 -4
- package/dist/engine/resilience-detector/middleware-detector.js +11 -13
- package/dist/engine/resilience-detector/validation-detector.js +17 -4
- package/dist/engine/reverse-engineer/config-analyzer.js +9 -8
- package/dist/engine/reverse-engineer/orchestrator.js +5 -9
- package/dist/engine/reverse-engineer/test-file-parser.js +6 -3
- package/dist/engine/rules-generator/index.js +6 -5
- package/dist/engine/runtime-policy.d.ts +7 -0
- package/dist/engine/runtime-policy.js +101 -0
- package/dist/engine/runtime-security/checkers/content-security.js +21 -6
- package/dist/engine/runtime-security/checkers/file-permissions.js +0 -2
- package/dist/engine/safety/atomic-write-file.js +20 -9
- package/dist/engine/safety/atomic-writer.js +10 -3
- package/dist/engine/safety/cross-process-lock.d.ts +3 -40
- package/dist/engine/safety/cross-process-lock.js +268 -272
- package/dist/engine/safety/file-mutex.d.ts +2 -9
- package/dist/engine/safety/file-mutex.js +155 -87
- package/dist/engine/safety/health-monitor.js +15 -6
- package/dist/engine/safety/lock-lease-store.d.ts +79 -0
- package/dist/engine/safety/lock-lease-store.js +372 -0
- package/dist/engine/safety/lock-scavenger.d.ts +2 -5
- package/dist/engine/safety/lock-scavenger.js +158 -76
- package/dist/engine/safety/lock-staleness.js +4 -1
- package/dist/engine/safety/obsolete-lock-guard.d.ts +8 -0
- package/dist/engine/safety/obsolete-lock-guard.js +31 -0
- package/dist/engine/safety/transaction.js +3 -3
- package/dist/engine/sandbox/index.js +2 -1
- package/dist/engine/sandbox/runner-detect.js +3 -2
- package/dist/engine/sandbox/runner-docker.js +4 -3
- package/dist/engine/scan-project/module-discoverer.js +3 -2
- package/dist/engine/schema-generator.js +16 -9
- package/dist/engine/security-analyzer/criteria-generator.js +2 -3
- package/dist/engine/self-healing/healer.js +4 -4
- package/dist/engine/session-safeguard/learnings-buffer.d.ts +1 -2
- package/dist/engine/session-safeguard/learnings-buffer.js +42 -65
- package/dist/engine/shared-agent-memory.js +66 -74
- package/dist/engine/skill-adapter/command-rewriter.js +3 -2
- package/dist/engine/skill-adapter/index.js +3 -3
- package/dist/engine/skill-adapter/placeholder-map.js +3 -2
- package/dist/engine/skill-bootstrap/stack-matcher.js +47 -48
- package/dist/engine/skill-generation/stack-content-generator.js +0 -2
- package/dist/engine/skill-generator/workflow-skill-generator.js +2 -1
- package/dist/engine/skill-registry/ttl-refresh.js +3 -1
- package/dist/engine/skills/skills-fetcher.js +3 -6
- package/dist/engine/skills-reconciler.js +19 -39
- package/dist/engine/spec-coverage/test-finder.js +7 -6
- package/dist/engine/spec-diff-engine.js +3 -3
- package/dist/engine/spec-generator/api-key-resolver.d.ts +1 -1
- package/dist/engine/spec-generator/api-key-resolver.js +3 -24
- package/dist/engine/spec-generators/issue-extractor.js +9 -3
- package/dist/engine/spec-migrator/drift-detector.js +5 -13
- package/dist/engine/spec-migrator/filesystem-import.js +14 -10
- package/dist/engine/spec-migrator/planu-canonical-policy.js +10 -1
- package/dist/engine/spec-migrator/strict-planu-cleanup.js +24 -25
- package/dist/engine/spec-registry/adapter.d.ts +0 -5
- package/dist/engine/spec-registry/adapter.js +45 -46
- package/dist/engine/spec-registry/client.js +2 -0
- package/dist/engine/spec-source-sync.js +3 -2
- package/dist/engine/spec-templates/custom-loader.js +2 -3
- package/dist/engine/spec-templates/templates-domain-specific.js +8 -5
- package/dist/engine/spec-templates/templates-perf-integration.js +2 -3
- package/dist/engine/stack-auditor/manifest-reader.js +0 -2
- package/dist/engine/staleness/stale-implementing.js +7 -7
- package/dist/engine/tdd-scaffold-generator.js +24 -11
- package/dist/engine/teammate-router/green-phase-verifier.js +2 -1
- package/dist/engine/teammate-router/red-phase-verifier.js +2 -1
- package/dist/engine/technology-registry.d.ts +11 -0
- package/dist/engine/technology-registry.js +142 -0
- package/dist/engine/telemetry/error-reporter.d.ts +1 -2
- package/dist/engine/telemetry/error-reporter.js +11 -18
- package/dist/engine/telemetry/health-checker.js +5 -14
- package/dist/engine/telemetry/index.d.ts +0 -1
- package/dist/engine/telemetry/index.js +0 -1
- package/dist/engine/telemetry/stance.js +3 -2
- package/dist/engine/telemetry/telemetry-client.d.ts +1 -5
- package/dist/engine/telemetry/telemetry-client.js +45 -29
- package/dist/engine/telemetry/telemetry-store.d.ts +3 -3
- package/dist/engine/telemetry/telemetry-store.js +30 -23
- package/dist/engine/test-framework-detector/detectors.js +8 -8
- package/dist/engine/test-framework-detector/strategy.js +8 -9
- package/dist/engine/test-generators/agent-test-templates.js +2 -3
- package/dist/engine/test-generators/contract-test-generator.d.ts +1 -1
- package/dist/engine/test-generators/contract-test-generator.js +9 -202
- package/dist/engine/test-generators/platform-test-templates-b.js +2 -3
- package/dist/engine/test-generators/platform-test-templates.js +2 -5
- package/dist/engine/test-mocks-generator.js +4 -3
- package/dist/engine/test-plan-generator.js +30 -12
- package/dist/engine/test-scaffold-generator/advanced-scaffold.js +4 -5
- package/dist/engine/test-scaffold-generator/unit-scaffold.js +5 -6
- package/dist/engine/timing/budget.d.ts +6 -17
- package/dist/engine/timing/budget.js +80 -64
- package/dist/engine/tool-groups/group-manager.js +3 -3
- package/dist/engine/universal-rules/installer.js +1 -1
- package/dist/engine/universal-rules/rules/planu-modes.js +2 -0
- package/dist/engine/universal-rules/rules/planu-release-policy.js +1 -0
- package/dist/engine/update-notifier.js +8 -5
- package/dist/engine/validation/approved-spec-portability.d.ts +12 -0
- package/dist/engine/validation/approved-spec-portability.js +107 -0
- package/dist/engine/validation/durable-validation.d.ts +36 -0
- package/dist/engine/validation/durable-validation.js +335 -0
- package/dist/engine/validation/validation-freshness.d.ts +36 -0
- package/dist/engine/validation/validation-freshness.js +427 -0
- package/dist/engine/validation/validation-receipt-codec.d.ts +13 -0
- package/dist/engine/validation/validation-receipt-codec.js +182 -0
- package/dist/engine/validation/validation-receipt.d.ts +59 -0
- package/dist/engine/validation/validation-receipt.js +282 -0
- package/dist/engine/validation/validation-source-policy.d.ts +4 -0
- package/dist/engine/validation/validation-source-policy.js +16 -0
- package/dist/engine/validation/validation-submission.d.ts +36 -0
- package/dist/engine/validation/validation-submission.js +128 -0
- package/dist/engine/validation-evidence-ledger.js +41 -0
- package/dist/engine/validation-impact-planner.js +25 -9
- package/dist/engine/validator/spec-compliance-runner.d.ts +1 -1
- package/dist/engine/validator/spec-compliance-runner.js +17 -8
- package/dist/engine/validator/validation-report-writer.js +1 -1
- package/dist/engine/validator.js +2 -1
- package/dist/engine/verify-integrations/index.js +1 -1
- package/dist/engine/version-resolver.js +5 -6
- package/dist/engine/web-fetcher/stack-advisor.js +156 -92
- package/dist/engine/web-fetcher/stack-detector.js +114 -54
- package/dist/engine/workspace-manager.js +3 -2
- package/dist/errors/classified-degradation.d.ts +3 -0
- package/dist/errors/classified-degradation.js +10 -0
- package/dist/errors/degradation-sink.d.ts +3 -0
- package/dist/errors/degradation-sink.js +5 -0
- package/dist/errors/error-taxonomy.d.ts +12 -0
- package/dist/errors/error-taxonomy.js +62 -0
- package/dist/hosts/claude-code/ux/mcp-prompts.js +10 -4
- package/dist/hosts/claude-code/ux/mcp-resources.js +4 -2
- package/dist/hosts/codex/config-scaffold.js +4 -3
- package/dist/hosts/gemini/config-scaffold.js +2 -1
- package/dist/hosts/gemini/multimodal-spec-flow.js +7 -4
- package/dist/index.js +21 -6
- package/dist/resources/patterns.js +3 -1
- package/dist/resources/specs.js +3 -1
- package/dist/resources/templates.js +3 -1
- package/dist/security/adapters/environment.d.ts +12 -0
- package/dist/security/adapters/environment.js +25 -0
- package/dist/security/adapters/linux-secret-service.d.ts +8 -0
- package/dist/security/adapters/linux-secret-service.js +60 -0
- package/dist/security/adapters/macos-keychain.d.ts +18 -0
- package/dist/security/adapters/macos-keychain.js +90 -0
- package/dist/security/adapters/windows-credential-manager.d.ts +8 -0
- package/dist/security/adapters/windows-credential-manager.js +58 -0
- package/dist/security/redactor.d.ts +5 -0
- package/dist/security/redactor.js +58 -0
- package/dist/security/secret-field.d.ts +5 -0
- package/dist/security/secret-field.js +17 -0
- package/dist/security/secret-migration.d.ts +3 -0
- package/dist/security/secret-migration.js +123 -0
- package/dist/security/secret-provider.d.ts +23 -0
- package/dist/security/secret-provider.js +145 -0
- package/dist/security/secure-json.d.ts +3 -0
- package/dist/security/secure-json.js +29 -0
- package/dist/storage/api-surfaces-store.js +2 -2
- package/dist/storage/approval-operation-lock.d.ts +1 -1
- package/dist/storage/approval-operation-lock.js +5 -3
- package/dist/storage/audit-trail-store.d.ts +1 -1
- package/dist/storage/audit-trail-store.js +48 -62
- package/dist/storage/autopilot-log-store.js +12 -5
- package/dist/storage/base-store.d.ts +8 -8
- package/dist/storage/base-store.js +57 -20
- package/dist/storage/checkpoint-store.js +5 -2
- package/dist/storage/comments-store.js +2 -2
- package/dist/storage/compliance-audit-store.js +5 -2
- package/dist/storage/compliance-gate-config-store.js +7 -4
- package/dist/storage/compliance-store.js +2 -2
- package/dist/storage/context-profile-store.js +2 -2
- package/dist/storage/crash-shield-store.js +8 -4
- package/dist/storage/feedback-store.js +10 -6
- package/dist/storage/figma-store.js +8 -4
- package/dist/storage/file-mutex.js +9 -1
- package/dist/storage/gaps-log.js +7 -4
- package/dist/storage/global-projects-store.js +4 -2
- package/dist/storage/ideas-store.js +2 -2
- package/dist/storage/index.d.ts +5 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/knowledge-store/knowledge.js +27 -33
- package/dist/storage/lessons-store.js +2 -2
- package/dist/storage/license-store.js +13 -41
- package/dist/storage/migrations/canonical-storage.d.ts +15 -0
- package/dist/storage/migrations/canonical-storage.js +599 -0
- package/dist/storage/oauth-store.js +36 -8
- package/dist/storage/path-resolver.js +16 -3
- package/dist/storage/pr-store.js +2 -2
- package/dist/storage/project-drift-store.js +20 -8
- package/dist/storage/project-identity.d.ts +32 -0
- package/dist/storage/project-identity.js +194 -0
- package/dist/storage/project-resolver.js +14 -7
- package/dist/storage/release-notes-store.js +2 -6
- package/dist/storage/runtime-db.d.ts +186 -0
- package/dist/storage/runtime-db.js +1054 -0
- package/dist/storage/schema-registry.d.ts +5 -0
- package/dist/storage/schema-registry.js +74 -0
- package/dist/storage/sentry-store.js +20 -9
- package/dist/storage/session-state-store.js +12 -5
- package/dist/storage/session-store.js +12 -4
- package/dist/storage/skill-registry-storage.d.ts +1 -1
- package/dist/storage/skill-registry-storage.js +13 -11
- package/dist/storage/slack-store.js +10 -5
- package/dist/storage/spec-store.js +31 -24
- package/dist/storage/status-store/file-lock.js +31 -9
- package/dist/storage/status-store/self-healing.js +10 -5
- package/dist/storage/status-store/version-sync.js +8 -6
- package/dist/storage/steering-store.js +2 -2
- package/dist/storage/storage-bundle.d.ts +5 -0
- package/dist/storage/storage-bundle.js +117 -0
- package/dist/storage/storage-catalog-validation.d.ts +3 -0
- package/dist/storage/storage-catalog-validation.js +20 -0
- package/dist/storage/storage-catalog.d.ts +25 -0
- package/dist/storage/storage-catalog.js +390 -0
- package/dist/storage/storage-layout.d.ts +24 -0
- package/dist/storage/storage-layout.js +101 -0
- package/dist/storage/storybook-store.js +2 -2
- package/dist/storage/supabase-store.js +24 -6
- package/dist/storage/tdd-policy-store.js +8 -6
- package/dist/storage/tech-debt-store.js +3 -3
- package/dist/storage/technology-selection-store.d.ts +1 -1
- package/dist/storage/technology-selection-store.js +6 -3
- package/dist/storage/token-cache-store.js +3 -3
- package/dist/storage/token-ledger-store.js +13 -8
- package/dist/storage/transition-log.js +7 -4
- package/dist/storage/trash-store.js +15 -6
- package/dist/storage/vector-store/migrator.js +7 -2
- package/dist/storage/vector-store/sqlite-adapter.js +4 -1
- package/dist/storage/webhook-server-store.js +2 -2
- package/dist/tools/api-spec-generator-handler.js +3 -2
- package/dist/tools/auto-update-handler.d.ts +1 -1
- package/dist/tools/auto-update-handler.js +1 -1
- package/dist/tools/browser-validate-handler.js +2 -1
- package/dist/tools/challenge-spec/platform-challenge-scenarios-b.js +8 -5
- package/dist/tools/challenge-spec/scenarios-desktop.js +8 -3
- package/dist/tools/challenge-spec/scenarios-failure.js +7 -2
- package/dist/tools/challenge-spec/security-challenge-scenarios.js +3 -3
- package/dist/tools/clarify-requirements/multiple-choice.js +53 -41
- package/dist/tools/comments-handler.js +2 -3
- package/dist/tools/compliance-test-handler.js +2 -2
- package/dist/tools/configure-telemetry.js +11 -11
- package/dist/tools/create-spec/auto-pipeline.js +13 -1
- package/dist/tools/create-spec/autopilot-analyzer.d.ts +1 -1
- package/dist/tools/create-spec/autopilot-analyzer.js +2 -4
- package/dist/tools/create-spec/mcp-tool-contract.d.ts +10 -4
- package/dist/tools/create-spec/mcp-tool-contract.js +7 -36
- package/dist/tools/create-spec/post-creation.d.ts +2 -1
- package/dist/tools/create-spec/post-creation.js +56 -54
- package/dist/tools/create-spec/relevance-scorer.d.ts +1 -1
- package/dist/tools/create-spec/relevance-scorer.js +17 -1
- package/dist/tools/create-spec/spec-builder.js +2 -12
- package/dist/tools/create-spec/spec-created-outbox-consumer.d.ts +14 -0
- package/dist/tools/create-spec/spec-created-outbox-consumer.js +176 -0
- package/dist/tools/create-spec.js +385 -520
- package/dist/tools/define-ui-contract/agent-interaction-contract.js +2 -4
- package/dist/tools/define-ui-contract-desktop/desktop-contract.js +12 -4
- package/dist/tools/define-ui-contract-desktop/native-contract.js +7 -3
- package/dist/tools/define-ui-contract-extensions.js +2 -3
- package/dist/tools/define-ui-contract-mobile.js +5 -9
- package/dist/tools/define-ui-contract-web/component-tree.js +4 -3
- package/dist/tools/define-ui-contract.js +7 -4
- package/dist/tools/deploy/deploy-spec.js +2 -4
- package/dist/tools/deploy/deploy-status.js +2 -4
- package/dist/tools/design-schema/nosql-category-schemas.js +2 -3
- package/dist/tools/design-schema-sql/migrations.js +3 -2
- package/dist/tools/design-schema-sql/tables.js +4 -1
- package/dist/tools/design-schema.js +4 -3
- package/dist/tools/feedback-handler.js +2 -4
- package/dist/tools/gc-data-projects.js +5 -5
- package/dist/tools/generate-execution-plan.js +3 -4
- package/dist/tools/generate-sub-agent.js +2 -1
- package/dist/tools/generate-tests/generators/a11y-tests-generator.js +5 -4
- package/dist/tools/generate-tests/generators/advanced-testing-generator.js +5 -4
- package/dist/tools/generate-tests/generators/concurrency-test-generator/js-templates.js +9 -4
- package/dist/tools/generate-tests/generators/concurrency-test-generator.js +8 -4
- package/dist/tools/generate-tests/generators/database/detectors.js +9 -3
- package/dist/tools/generate-tests/generators/database/index.js +2 -4
- package/dist/tools/generate-tests/generators/event-test-generator.js +5 -4
- package/dist/tools/generate-tests/generators/game-tests-generator.js +2 -1
- package/dist/tools/generate-tests/generators/graphql-test-generator.js +11 -5
- package/dist/tools/generate-tests/generators/grpc-test-generator.js +2 -3
- package/dist/tools/generate-tests/generators/llm-security-test-generator.js +4 -3
- package/dist/tools/generate-tests/generators/local-first-test-generator.js +4 -3
- package/dist/tools/generate-tests/generators/mcp-tests-generator.js +11 -9
- package/dist/tools/generate-tests/generators/microservices/index.js +2 -3
- package/dist/tools/generate-tests/generators/otel-test-generator.js +6 -3
- package/dist/tools/generate-tests/generators/security/detectors.js +2 -5
- package/dist/tools/generate-tests/generators/security/index.js +2 -4
- package/dist/tools/generate-tests/generators/supply-chain-test-generator.js +2 -3
- package/dist/tools/generate-tests/generators/visual-regression-generator.js +14 -17
- package/dist/tools/generate-tests/generators/websocket-test-generator.js +2 -3
- package/dist/tools/generate-tests/test-helpers.js +11 -12
- package/dist/tools/generate-tests-content.js +4 -3
- package/dist/tools/generate-tests.js +7 -4
- package/dist/tools/git/git-helpers.d.ts +0 -2
- package/dist/tools/git/git-helpers.js +7 -7
- package/dist/tools/github-pr-handler.js +10 -3
- package/dist/tools/heal-spec-docs.js +6 -53
- package/dist/tools/hook-generator-handler.js +6 -6
- package/dist/tools/init-constitution/platform-principles.js +4 -2
- package/dist/tools/init-project/agents-md-writer.js +14 -5
- package/dist/tools/init-project/claude-md-generator.js +19 -12
- package/dist/tools/init-project/handler.js +165 -73
- package/dist/tools/init-project/host-assets-writer.d.ts +1 -1
- package/dist/tools/init-project/host-assets-writer.js +4 -2
- package/dist/tools/init-project/lifecycle-helpers.js +3 -5
- package/dist/tools/init-project/lint-scaffolder.js +6 -2
- package/dist/tools/init-project/migration-runner.d.ts +10 -1
- package/dist/tools/init-project/migration-runner.js +68 -3
- package/dist/tools/init-project/per-client-files-writer.js +14 -4
- package/dist/tools/init-project/rules-generator.js +10 -2
- package/dist/tools/init-project/scaffold-writer.d.ts +1 -1
- package/dist/tools/init-project/scaffold-writer.js +17 -15
- package/dist/tools/jobs/handlers.d.ts +15 -0
- package/dist/tools/jobs/handlers.js +126 -0
- package/dist/tools/list-specs.js +35 -34
- package/dist/tools/manage-plugins-handler.js +17 -9
- package/dist/tools/migrate-tech/advanced-handlers.js +3 -2
- package/dist/tools/migrate-tech/build-tool-handlers.js +3 -2
- package/dist/tools/migrate-tech/core-handlers.js +5 -2
- package/dist/tools/migrate-tech/data-handlers.js +6 -3
- package/dist/tools/migrate-tech-advanced/rollback-handlers.js +3 -2
- package/dist/tools/migrate-tech-advanced/service-handlers.js +5 -2
- package/dist/tools/oauth-handler.js +7 -1
- package/dist/tools/register-sdd-tools.d.ts +1 -1
- package/dist/tools/register-sdd-tools.js +5 -0
- package/dist/tools/register-spec-tools/core-spec-tools.js +31 -0
- package/dist/tools/registry/auth.js +13 -5
- package/dist/tools/registry/publish.js +7 -4
- package/dist/tools/resolve-project-path.d.ts +2 -2
- package/dist/tools/resolve-project-path.js +7 -7
- package/dist/tools/reverse-engineer/analyzer.js +14 -14
- package/dist/tools/rollback-release.js +3 -2
- package/dist/tools/safe-handler.js +295 -171
- package/dist/tools/schema-generator-handler.js +2 -1
- package/dist/tools/schemas/output-schemas.d.ts +88 -82
- package/dist/tools/schemas/output-schemas.js +12 -94
- package/dist/tools/schemas/plugins-schemas.js +0 -2
- package/dist/tools/schemas/registry.js +0 -2
- package/dist/tools/schemas/skill-registry-schemas.js +0 -2
- package/dist/tools/schemas/validate-output-schema.d.ts +256 -0
- package/dist/tools/schemas/validate-output-schema.js +212 -0
- package/dist/tools/sentry-handler.js +6 -1
- package/dist/tools/skill-bootstrap-handler.js +7 -4
- package/dist/tools/status-handler.js +4 -0
- package/dist/tools/storage-bundle-handler.d.ts +9 -0
- package/dist/tools/storage-bundle-handler.js +29 -0
- package/dist/tools/storage-paths-handler.d.ts +9 -0
- package/dist/tools/storage-paths-handler.js +17 -0
- package/dist/tools/suggest-mcp-server.js +11 -5
- package/dist/tools/suggest-mcps.js +29 -9
- package/dist/tools/suggest-tooling/advanced-testing-catalog.js +4 -5
- package/dist/tools/suggest-tooling/build-tool-catalog.js +2 -1
- package/dist/tools/suggest-tooling/css-framework-catalog.js +13 -7
- package/dist/tools/suggest-tooling/framework-catalog.js +3 -5
- package/dist/tools/suggest-tooling/frontend-perf-catalog.js +2 -6
- package/dist/tools/suggest-tooling/handler.js +10 -4
- package/dist/tools/suggest-tooling/hypermedia-catalog.js +11 -3
- package/dist/tools/suggest-tooling/linting-catalog.js +4 -7
- package/dist/tools/suggest-tooling/llm-security-catalog.js +2 -1
- package/dist/tools/suggest-tooling/local-first-catalog.js +7 -5
- package/dist/tools/suggest-tooling/observability-catalog.js +3 -4
- package/dist/tools/suggest-tooling/otel-catalog.js +4 -1
- package/dist/tools/suggest-tooling/resilience-catalog.js +16 -5
- package/dist/tools/suggest-tooling/skills-catalog.js +10 -9
- package/dist/tools/suggest-tooling/supply-chain-catalog.js +2 -3
- package/dist/tools/supabase-handler.js +2 -1
- package/dist/tools/token-intelligence-handler.js +2 -2
- package/dist/tools/token-recording.js +2 -2
- package/dist/tools/token-savings-handler.js +2 -2
- package/dist/tools/tool-registry/core-tools.js +131 -0
- package/dist/tools/tool-registry/group-infra.js +10 -12
- package/dist/tools/tool-registry/group-quality-compliance.js +5 -12
- package/dist/tools/update-status/approval-gates.d.ts +13 -0
- package/dist/tools/update-status/approval-gates.js +81 -0
- package/dist/tools/update-status/batch.js +4 -2
- package/dist/tools/update-status/dod-gates.d.ts +6 -24
- package/dist/tools/update-status/dod-gates.js +60 -135
- package/dist/tools/update-status/done-receipt-verifier.d.ts +15 -0
- package/dist/tools/update-status/done-receipt-verifier.js +145 -0
- package/dist/tools/update-status/evidence-gate.js +154 -2
- package/dist/tools/update-status/file-sync.js +23 -12
- package/dist/tools/update-status/gate-harness.d.ts +7 -0
- package/dist/tools/update-status/gate-harness.js +8 -0
- package/dist/tools/update-status/index.js +228 -325
- package/dist/tools/update-status/qa-gate.d.ts +1 -1
- package/dist/tools/update-status/qa-gate.js +2 -2
- package/dist/tools/update-status/side-effects.js +30 -37
- package/dist/tools/update-status/transition-guard.d.ts +4 -2
- package/dist/tools/update-status/transition-guard.js +57 -10
- package/dist/tools/update-status-convention-gate.js +24 -23
- package/dist/tools/update-status-reconcile.js +2 -2
- package/dist/tools/validate-api-contract-handler.js +3 -3
- package/dist/tools/validate-lint.js +20 -13
- package/dist/tools/validate.d.ts +3 -1
- package/dist/tools/validate.js +213 -5
- package/dist/transports/http-transport.js +84 -61
- package/dist/transports/middleware/with-telemetry.js +3 -2
- package/dist/types/abortable-process.d.ts +2 -0
- package/dist/types/advanced-framework.js +0 -2
- package/dist/types/atomic-upgrade.d.ts +71 -0
- package/dist/types/atomic-upgrade.js +2 -0
- package/dist/types/ci.js +0 -2
- package/dist/types/core-bridge.d.ts +78 -1
- package/dist/types/crash-shield-framework-rules.d.ts +24 -0
- package/dist/types/crash-shield-framework-rules.js +2 -0
- package/dist/types/data-gc.d.ts +16 -0
- package/dist/types/deploy.js +0 -2
- package/dist/types/durable-job.d.ts +78 -0
- package/dist/types/durable-job.js +2 -0
- package/dist/types/durable-validation.d.ts +60 -0
- package/dist/types/durable-validation.js +2 -0
- package/dist/types/estimation.d.ts +2 -0
- package/dist/types/evidence-gates.d.ts +9 -1
- package/dist/types/execution.d.ts +43 -0
- package/dist/types/handoff-artifacts.d.ts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/infrastructure.js +0 -2
- package/dist/types/lifecycle.js +0 -2
- package/dist/types/migration/canonical-storage.d.ts +37 -0
- package/dist/types/migration/canonical-storage.js +2 -0
- package/dist/types/migration/index.d.ts +1 -1
- package/dist/types/native-worker.d.ts +48 -0
- package/dist/types/native-worker.js +2 -0
- package/dist/types/network-policy.d.ts +12 -0
- package/dist/types/network-policy.js +2 -0
- package/dist/types/oauth.js +0 -2
- package/dist/types/observability.d.ts +32 -0
- package/dist/types/outbox-worker.d.ts +35 -0
- package/dist/types/outbox-worker.js +11 -0
- package/dist/types/permissions-config.d.ts +0 -27
- package/dist/types/permissions-config.js +0 -2
- package/dist/types/plugin-install.d.ts +0 -11
- package/dist/types/plugin-install.js +0 -2
- package/dist/types/portal.d.ts +1 -0
- package/dist/types/product-public.d.ts +75 -0
- package/dist/types/product-public.js +2 -0
- package/dist/types/project/inputs.d.ts +2 -0
- package/dist/types/project/mfe-detection.js +0 -2
- package/dist/types/project/platform-mobile.js +0 -2
- package/dist/types/project/platform-specialty.js +0 -2
- package/dist/types/project-knowledge-graph.d.ts +7 -0
- package/dist/types/runtime-database.d.ts +10 -0
- package/dist/types/runtime-database.js +2 -0
- package/dist/types/runtime-policy.d.ts +40 -0
- package/dist/types/runtime-policy.js +2 -0
- package/dist/types/safety.d.ts +4 -5
- package/dist/types/schema-registry.d.ts +12 -0
- package/dist/types/schema-registry.js +2 -0
- package/dist/types/security.d.ts +52 -0
- package/dist/types/skill-registry.js +0 -2
- package/dist/types/spec/inputs.d.ts +2 -0
- package/dist/types/spec-lock-v2.d.ts +13 -7
- package/dist/types/spec-lock-v2.js +1 -1
- package/dist/types/spec-registry.js +0 -2
- package/dist/types/storage-bundle.d.ts +13 -0
- package/dist/types/storage-bundle.js +2 -0
- package/dist/types/storage-catalog.d.ts +18 -0
- package/dist/types/storage-catalog.js +2 -0
- package/dist/types/team-planner.js +0 -2
- package/dist/types/technology-registry.d.ts +35 -0
- package/dist/types/technology-registry.js +2 -0
- package/dist/types/technology-symbols.generated.d.ts +117 -0
- package/dist/types/technology-symbols.generated.js +2 -0
- package/dist/types/telemetry.d.ts +3 -3
- package/dist/types/transport.d.ts +2 -0
- package/dist/types/validate-worker.d.ts +44 -0
- package/dist/types/validate-worker.js +2 -0
- package/dist/types/validation-evidence.d.ts +1 -1
- package/dist/types/validation-receipt.d.ts +104 -0
- package/dist/types/validation-receipt.js +2 -0
- package/package.json +31 -20
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
- package/dist/engine/telemetry/geo-resolver.d.ts +0 -9
- package/dist/engine/telemetry/geo-resolver.js +0 -43
- package/dist/storage/data-dir-discovery.d.ts +0 -31
- package/dist/storage/data-dir-discovery.js +0 -140
- package/dist/storage/migrations/cwd-to-absolute.d.ts +0 -25
- package/dist/storage/migrations/cwd-to-absolute.js +0 -281
- package/dist/tools/create-spec/adapters/prior-decisions-hint.d.ts +0 -14
- package/dist/tools/create-spec/adapters/prior-decisions-hint.js +0 -30
- package/dist/tools/init-project/ancestor-data-detector.d.ts +0 -22
- package/dist/tools/init-project/ancestor-data-detector.js +0 -81
- package/dist/tools/update-status/force-done-audit.d.ts +0 -2
- package/dist/tools/update-status/force-done-audit.js +0 -23
- package/dist/types/migration/cwd-to-absolute.d.ts +0 -8
- package/dist/types/migration/cwd-to-absolute.js +0 -3
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
54
|
+
import { constants, watch } from 'node:fs';
|
|
55
|
+
import { lstat, mkdir, open, readdir } from 'node:fs/promises';
|
|
56
|
+
import { basename, join } from 'node:path';
|
|
57
|
+
import { RuntimeDatabase } from '../../storage/runtime-db.js';
|
|
58
|
+
import { resolveStorageLayout } from '../../storage/storage-layout.js';
|
|
59
|
+
import { ValidationReceiptStore } from './validation-receipt.js';
|
|
60
|
+
import { isValidationSourcePath } from './validation-source-policy.js';
|
|
61
|
+
import { reportClassifiedDegradation } from '../../errors/classified-degradation.js';
|
|
62
|
+
import { gitSourceTreeDigest } from './durable-validation.js';
|
|
63
|
+
const LEASE_TTL_MS = 35 * 60 * 1_000;
|
|
64
|
+
const MAX_EVIDENCE_FILE_BYTES = 2 * 1024 * 1024;
|
|
65
|
+
const FINGERPRINT_CHUNK_BYTES = 64 * 1024;
|
|
66
|
+
const EVIDENCE_FILE = /^(?:discovery|task-plan|traceability-matrix|contract-validation-(?:api|graphql|event|ui|mcp))\.json$/u;
|
|
67
|
+
const active = new Map();
|
|
68
|
+
function key(projectId, specId) {
|
|
69
|
+
return `${projectId}:${specId}`;
|
|
70
|
+
}
|
|
71
|
+
function invalidateState(projectId, specId, state) {
|
|
72
|
+
const invalidating = state.invalidating.then(async () => {
|
|
73
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
74
|
+
try {
|
|
75
|
+
const database = __addDisposableResource(env_1, new RuntimeDatabase({ path: resolveStorageLayout().runtimeDatabase }), false);
|
|
76
|
+
const store = new ValidationReceiptStore({ database, workspaceId: 'global' });
|
|
77
|
+
await store.invalidateCurrentBindings(projectId, specId);
|
|
78
|
+
}
|
|
79
|
+
catch (e_1) {
|
|
80
|
+
env_1.error = e_1;
|
|
81
|
+
env_1.hasError = true;
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
__disposeResources(env_1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
return { ...state, generation: state.generation + 1, bindings: undefined, invalidating };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Invalidate the active validation lease for a spec.
|
|
91
|
+
*
|
|
92
|
+
* Filesystem watchers and Planu-owned writers share this entry point so callers
|
|
93
|
+
* that know they changed validation evidence do not depend on fs.watch timing.
|
|
94
|
+
*/
|
|
95
|
+
export function invalidateValidationFreshness(input) {
|
|
96
|
+
const identity = key(input.projectId, input.specId);
|
|
97
|
+
const state = active.get(identity);
|
|
98
|
+
if (!state) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
active.set(identity, invalidateState(input.projectId, input.specId, state));
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
function startWatch(path, relevant, onRelevantChange, onError) {
|
|
105
|
+
try {
|
|
106
|
+
const watchedRoot = basename(path);
|
|
107
|
+
const watcher = watch(path, { recursive: true }, (event, filename) => {
|
|
108
|
+
// macOS emits a synthetic `change` for the watched directory itself in
|
|
109
|
+
// addition to the actionable relative child event.
|
|
110
|
+
if (event === 'change' && filename === watchedRoot) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (!filename || relevant(filename.replaceAll('\\', '/'))) {
|
|
114
|
+
onRelevantChange();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
watcher.on('error', onError);
|
|
118
|
+
return watcher;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
/* reliability-optional: FILE_MTIME_UNAVAILABLE — explicit undefined invalidates reuse */
|
|
122
|
+
reportClassifiedDegradation('FILE_MTIME_UNAVAILABLE', error);
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function evidenceFingerprint(path) {
|
|
127
|
+
const names = (await readdir(path, { withFileTypes: true }))
|
|
128
|
+
.filter((entry) => EVIDENCE_FILE.test(entry.name))
|
|
129
|
+
.map((entry) => entry.name.normalize('NFC'))
|
|
130
|
+
.sort((left, right) => Buffer.compare(Buffer.from(left), Buffer.from(right)));
|
|
131
|
+
const entries = await Promise.all(names.map(async (name) => {
|
|
132
|
+
const evidencePath = join(path, name);
|
|
133
|
+
const pathStats = await lstat(evidencePath, { bigint: true });
|
|
134
|
+
if (!pathStats.isFile() || pathStats.isSymbolicLink()) {
|
|
135
|
+
throw new Error(`[Planu] Validation evidence must be a regular file: ${name}`);
|
|
136
|
+
}
|
|
137
|
+
const noFollow = typeof constants.O_NOFOLLOW === 'number' ? constants.O_NOFOLLOW : 0;
|
|
138
|
+
const handle = await open(evidencePath, constants.O_RDONLY | noFollow);
|
|
139
|
+
try {
|
|
140
|
+
const openedStats = await handle.stat({ bigint: true });
|
|
141
|
+
if (!openedStats.isFile() ||
|
|
142
|
+
openedStats.dev !== pathStats.dev ||
|
|
143
|
+
openedStats.ino !== pathStats.ino ||
|
|
144
|
+
openedStats.size > BigInt(MAX_EVIDENCE_FILE_BYTES)) {
|
|
145
|
+
throw new Error(`[Planu] Validation evidence changed or exceeds its size limit: ${name}`);
|
|
146
|
+
}
|
|
147
|
+
const contentHash = createHash('sha256');
|
|
148
|
+
const chunk = Buffer.allocUnsafe(FINGERPRINT_CHUNK_BYTES);
|
|
149
|
+
let position = 0;
|
|
150
|
+
for (;;) {
|
|
151
|
+
const { bytesRead } = await handle.read(chunk, 0, chunk.length, position);
|
|
152
|
+
if (bytesRead === 0) {
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
position += bytesRead;
|
|
156
|
+
if (position > MAX_EVIDENCE_FILE_BYTES) {
|
|
157
|
+
throw new Error(`[Planu] Validation evidence exceeds its size limit: ${name}`);
|
|
158
|
+
}
|
|
159
|
+
contentHash.update(chunk.subarray(0, bytesRead));
|
|
160
|
+
}
|
|
161
|
+
const finalStats = await handle.stat({ bigint: true });
|
|
162
|
+
if (finalStats.dev !== openedStats.dev ||
|
|
163
|
+
finalStats.ino !== openedStats.ino ||
|
|
164
|
+
finalStats.size !== openedStats.size ||
|
|
165
|
+
finalStats.mtimeNs !== openedStats.mtimeNs ||
|
|
166
|
+
finalStats.ctimeNs !== openedStats.ctimeNs) {
|
|
167
|
+
throw new Error(`[Planu] Validation evidence changed while being read: ${name}`);
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
name,
|
|
171
|
+
bytes: position,
|
|
172
|
+
digest: contentHash.digest('hex'),
|
|
173
|
+
device: openedStats.dev.toString(),
|
|
174
|
+
inode: openedStats.ino.toString(),
|
|
175
|
+
changedAt: openedStats.ctimeNs.toString(),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
await handle.close();
|
|
180
|
+
}
|
|
181
|
+
}));
|
|
182
|
+
const hash = createHash('sha256');
|
|
183
|
+
hash.update('planu-validation-evidence-v1\0');
|
|
184
|
+
for (const entry of entries) {
|
|
185
|
+
hash.update(`${Buffer.byteLength(entry.name)}:${entry.name}${entry.bytes}:${entry.device}:${entry.inode}:${entry.changedAt}:${entry.digest.length}:${entry.digest}`);
|
|
186
|
+
}
|
|
187
|
+
return hash.digest('hex');
|
|
188
|
+
}
|
|
189
|
+
/** Start both watchers before snapshotting and invalidate any older receipt immediately. */
|
|
190
|
+
export async function beginValidationFreshnessBarrier(input) {
|
|
191
|
+
const identity = key(input.projectId, input.specId);
|
|
192
|
+
await mkdir(input.handoffPath, { recursive: true, mode: 0o700 });
|
|
193
|
+
const initialEvidenceFingerprint = await evidenceFingerprint(input.handoffPath);
|
|
194
|
+
active.get(identity)?.watchers.forEach((watcher) => {
|
|
195
|
+
watcher.close();
|
|
196
|
+
});
|
|
197
|
+
let state = {
|
|
198
|
+
epoch: randomUUID(),
|
|
199
|
+
expiresAt: Date.now() + LEASE_TTL_MS,
|
|
200
|
+
generation: 0,
|
|
201
|
+
healthy: true,
|
|
202
|
+
projectPath: input.projectPath,
|
|
203
|
+
handoffPath: input.handoffPath,
|
|
204
|
+
evidenceFingerprint: initialEvidenceFingerprint,
|
|
205
|
+
invalidating: Promise.resolve(),
|
|
206
|
+
watchers: [],
|
|
207
|
+
};
|
|
208
|
+
const watchedEpoch = state.epoch;
|
|
209
|
+
const changed = () => {
|
|
210
|
+
if (active.get(identity)?.epoch !== watchedEpoch) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
invalidateValidationFreshness(input);
|
|
214
|
+
state = active.get(identity) ?? state;
|
|
215
|
+
};
|
|
216
|
+
const failed = () => {
|
|
217
|
+
if (active.get(identity)?.epoch !== watchedEpoch) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
changed();
|
|
221
|
+
state = { ...state, healthy: false };
|
|
222
|
+
active.set(identity, state);
|
|
223
|
+
};
|
|
224
|
+
const projectWatcher = startWatch(input.projectPath, isValidationSourcePath, changed, failed);
|
|
225
|
+
const handoffWatcher = startWatch(input.handoffPath, (filename) => EVIDENCE_FILE.test(filename), changed, failed);
|
|
226
|
+
if (!projectWatcher || !handoffWatcher) {
|
|
227
|
+
projectWatcher?.close();
|
|
228
|
+
handoffWatcher?.close();
|
|
229
|
+
throw new Error('[Planu] Validation freshness watchers could not be established');
|
|
230
|
+
}
|
|
231
|
+
state = { ...state, watchers: [projectWatcher, handoffWatcher] };
|
|
232
|
+
active.set(identity, state);
|
|
233
|
+
if (input.invalidateCurrentBindings !== false) {
|
|
234
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
235
|
+
try {
|
|
236
|
+
const database = __addDisposableResource(env_2, new RuntimeDatabase({ path: resolveStorageLayout().runtimeDatabase }), false);
|
|
237
|
+
const store = new ValidationReceiptStore({ database, workspaceId: 'global' });
|
|
238
|
+
await store.invalidateCurrentBindings(input.projectId, input.specId);
|
|
239
|
+
}
|
|
240
|
+
catch (e_2) {
|
|
241
|
+
env_2.error = e_2;
|
|
242
|
+
env_2.hasError = true;
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
__disposeResources(env_2);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
projectId: input.projectId,
|
|
250
|
+
specId: input.specId,
|
|
251
|
+
epoch: state.epoch,
|
|
252
|
+
generation: state.generation,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/** Bind the post-watch snapshot; an event before this call makes the lease unusable. */
|
|
256
|
+
export async function bindValidationFreshnessLease(lease, bindings) {
|
|
257
|
+
const state = active.get(key(lease.projectId, lease.specId));
|
|
258
|
+
if (!state ||
|
|
259
|
+
!state.healthy ||
|
|
260
|
+
state.epoch !== lease.epoch ||
|
|
261
|
+
state.generation !== lease.generation ||
|
|
262
|
+
Date.now() >= state.expiresAt) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
let fingerprintBefore;
|
|
266
|
+
try {
|
|
267
|
+
fingerprintBefore = await evidenceFingerprint(state.handoffPath);
|
|
268
|
+
if ((await gitSourceTreeDigest(state.projectPath)) !== bindings.sourceDigest) {
|
|
269
|
+
invalidateValidationFreshness(lease);
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
275
|
+
invalidateValidationFreshness(lease);
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
if (fingerprintBefore !== state.evidenceFingerprint) {
|
|
279
|
+
invalidateValidationFreshness(lease);
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
const confirmed = active.get(key(lease.projectId, lease.specId));
|
|
283
|
+
if (!confirmed?.healthy ||
|
|
284
|
+
confirmed.epoch !== state.epoch ||
|
|
285
|
+
confirmed.generation !== state.generation) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
active.set(key(lease.projectId, lease.specId), {
|
|
289
|
+
...confirmed,
|
|
290
|
+
bindings: structuredClone(bindings),
|
|
291
|
+
});
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
async function readStableState(lease, expectedGeneration) {
|
|
295
|
+
const identity = key(lease.projectId, lease.specId);
|
|
296
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
297
|
+
const before = active.get(identity);
|
|
298
|
+
if (!before?.healthy ||
|
|
299
|
+
before.epoch !== lease.epoch ||
|
|
300
|
+
(expectedGeneration !== undefined && before.generation !== expectedGeneration)) {
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
await before.invalidating;
|
|
304
|
+
const after = active.get(identity);
|
|
305
|
+
if (after?.healthy &&
|
|
306
|
+
after.epoch === before.epoch &&
|
|
307
|
+
after.generation === before.generation &&
|
|
308
|
+
after.invalidating === before.invalidating) {
|
|
309
|
+
return after;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
/** Drain invalidation work and verify epoch, generation, health, expiry and bound inputs. */
|
|
315
|
+
export async function assertValidationFreshnessBarrier(lease, bindings) {
|
|
316
|
+
const candidate = active.get(key(lease.projectId, lease.specId));
|
|
317
|
+
if (!candidate?.healthy ||
|
|
318
|
+
candidate.epoch !== lease.epoch ||
|
|
319
|
+
candidate.generation !== lease.generation) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
let fingerprintBefore;
|
|
323
|
+
try {
|
|
324
|
+
fingerprintBefore = await evidenceFingerprint(candidate.handoffPath);
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
328
|
+
invalidateValidationFreshness(lease);
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
if (fingerprintBefore !== candidate.evidenceFingerprint) {
|
|
332
|
+
invalidateValidationFreshness(lease);
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
if (candidate.bindings &&
|
|
337
|
+
(await gitSourceTreeDigest(candidate.projectPath)) !== candidate.bindings.sourceDigest) {
|
|
338
|
+
invalidateValidationFreshness(lease);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
344
|
+
invalidateValidationFreshness(lease);
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
// A generation change invalidates the lease synchronously. Do not wait for
|
|
348
|
+
// the durable receipt cleanup when the in-memory barrier already fails
|
|
349
|
+
// closed; under database contention that cleanup can legitimately be slow.
|
|
350
|
+
const state = await readStableState(lease, lease.generation);
|
|
351
|
+
let fingerprintAfter;
|
|
352
|
+
try {
|
|
353
|
+
fingerprintAfter = state ? await evidenceFingerprint(state.handoffPath) : undefined;
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
357
|
+
fingerprintAfter = undefined;
|
|
358
|
+
}
|
|
359
|
+
if (!state || fingerprintAfter !== fingerprintBefore) {
|
|
360
|
+
invalidateValidationFreshness(lease);
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
if (state.generation !== lease.generation) {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
if (Date.now() >= state.expiresAt) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
return bindings === undefined || JSON.stringify(state.bindings) === JSON.stringify(bindings);
|
|
370
|
+
}
|
|
371
|
+
export async function captureValidationFreshnessLease(identity, bindings) {
|
|
372
|
+
const state = active.get(key(identity.projectId, identity.specId));
|
|
373
|
+
if (!state) {
|
|
374
|
+
return undefined;
|
|
375
|
+
}
|
|
376
|
+
const lease = { ...identity, epoch: state.epoch, generation: state.generation };
|
|
377
|
+
return (await assertValidationFreshnessBarrier(lease, bindings)) ? lease : undefined;
|
|
378
|
+
}
|
|
379
|
+
/** Accept validation-generated filesystem activity only after an exact full recomputation. */
|
|
380
|
+
export async function rebaselineValidationFreshnessLeaseAfterRecompute(input) {
|
|
381
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
382
|
+
const before = await readStableState(input.lease);
|
|
383
|
+
if (!before || Date.now() >= before.expiresAt) {
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
let fingerprintBefore;
|
|
387
|
+
let observedBindings;
|
|
388
|
+
let fingerprintAfter;
|
|
389
|
+
try {
|
|
390
|
+
fingerprintBefore = await evidenceFingerprint(before.handoffPath);
|
|
391
|
+
observedBindings = await input.recompute();
|
|
392
|
+
fingerprintAfter = await evidenceFingerprint(before.handoffPath);
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
reportClassifiedDegradation('VALIDATION_FRESHNESS_CHECK_FAILED', error);
|
|
396
|
+
invalidateValidationFreshness(input.lease);
|
|
397
|
+
return undefined;
|
|
398
|
+
}
|
|
399
|
+
const after = await readStableState(input.lease);
|
|
400
|
+
if (after?.generation !== before.generation || fingerprintBefore !== fingerprintAfter) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
if (JSON.stringify(input.expectedBindings) !== JSON.stringify(observedBindings)) {
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
const confirmed = await readStableState(input.lease);
|
|
407
|
+
if (confirmed?.generation !== after.generation) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
active.set(key(input.lease.projectId, input.lease.specId), {
|
|
411
|
+
...confirmed,
|
|
412
|
+
bindings: structuredClone(observedBindings),
|
|
413
|
+
evidenceFingerprint: fingerprintAfter,
|
|
414
|
+
});
|
|
415
|
+
return { ...input.lease, generation: confirmed.generation };
|
|
416
|
+
}
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
export function resetValidationFreshnessForTests() {
|
|
420
|
+
for (const state of active.values()) {
|
|
421
|
+
state.watchers.forEach((watcher) => {
|
|
422
|
+
watcher.close();
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
active.clear();
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=validation-freshness.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ValidationCommandInput, ValidationReceipt, ValidationReceiptBindings, ValidationReceiptIssueInput } from '../../types/validation-receipt.js';
|
|
2
|
+
export declare const DIGEST: RegExp;
|
|
3
|
+
export declare const PROJECT_ID: RegExp;
|
|
4
|
+
export declare const SPEC_ID: RegExp;
|
|
5
|
+
export declare const ISSUER_ID: RegExp;
|
|
6
|
+
export declare function sha256(value: string | Buffer): string;
|
|
7
|
+
export declare function canonicalize(value: unknown): string;
|
|
8
|
+
export declare function normalizeValidationCommand(command: ValidationCommandInput): string;
|
|
9
|
+
export declare function validBindings(value: unknown): value is ValidationReceiptBindings;
|
|
10
|
+
export declare function safeProof(receipt: ValidationReceipt, key: string): boolean;
|
|
11
|
+
export declare function receiptCore(input: ValidationReceiptIssueInput, issuer: string, logDigest: string): Omit<ValidationReceipt, 'receiptId' | 'authenticity'>;
|
|
12
|
+
export declare function validReceiptShape(value: unknown): value is ValidationReceipt;
|
|
13
|
+
//# sourceMappingURL=validation-receipt-codec.d.ts.map
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { createHash, createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { reportClassifiedDegradation } from '../../errors/classified-degradation.js';
|
|
3
|
+
export const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
4
|
+
export const PROJECT_ID = /^[a-f0-9]{32}$/u;
|
|
5
|
+
export const SPEC_ID = /^SPEC-[1-9]\d*$/u;
|
|
6
|
+
export const ISSUER_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
7
|
+
const ARTIFACT_KEYS = [
|
|
8
|
+
'approvedSpec',
|
|
9
|
+
'discovery',
|
|
10
|
+
'taskPlan',
|
|
11
|
+
'traceability',
|
|
12
|
+
'contractValidation',
|
|
13
|
+
];
|
|
14
|
+
export function sha256(value) {
|
|
15
|
+
return `sha256:${createHash('sha256').update(value).digest('hex')}`;
|
|
16
|
+
}
|
|
17
|
+
export function canonicalize(value) {
|
|
18
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean') {
|
|
19
|
+
return JSON.stringify(value);
|
|
20
|
+
}
|
|
21
|
+
if (typeof value === 'number') {
|
|
22
|
+
if (!Number.isFinite(value)) {
|
|
23
|
+
throw new Error('[Planu] Receipt values must be finite');
|
|
24
|
+
}
|
|
25
|
+
return JSON.stringify(value);
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(value)) {
|
|
28
|
+
return `[${value.map(canonicalize).join(',')}]`;
|
|
29
|
+
}
|
|
30
|
+
if (typeof value === 'object') {
|
|
31
|
+
const record = value;
|
|
32
|
+
return `{${Object.keys(record)
|
|
33
|
+
.sort()
|
|
34
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalize(record[key])}`)
|
|
35
|
+
.join(',')}}`;
|
|
36
|
+
}
|
|
37
|
+
throw new Error('[Planu] Receipt values must be JSON serializable');
|
|
38
|
+
}
|
|
39
|
+
function normalizedPart(value, label) {
|
|
40
|
+
const normalized = value.normalize('NFC').trim();
|
|
41
|
+
if (!normalized || normalized.includes('\0')) {
|
|
42
|
+
throw new Error(`[Planu] Invalid validation ${label}`);
|
|
43
|
+
}
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
46
|
+
export function normalizeValidationCommand(command) {
|
|
47
|
+
const executable = normalizedPart(command.executable, 'command');
|
|
48
|
+
const args = (command.args ?? []).map((arg) => normalizedPart(arg, 'command argument'));
|
|
49
|
+
const hasCwd = command.cwd !== undefined;
|
|
50
|
+
if (hasCwd) {
|
|
51
|
+
normalizedPart(command.cwd ?? '', 'working directory');
|
|
52
|
+
}
|
|
53
|
+
return JSON.stringify(hasCwd ? [executable, ...args, '<project>'] : [executable, ...args]);
|
|
54
|
+
}
|
|
55
|
+
export function validBindings(value) {
|
|
56
|
+
if (!value || typeof value !== 'object') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const candidate = value;
|
|
60
|
+
const artifacts = candidate.artifactDigests;
|
|
61
|
+
return (Object.keys(candidate).length === 7 &&
|
|
62
|
+
typeof candidate.projectId === 'string' &&
|
|
63
|
+
PROJECT_ID.test(candidate.projectId) &&
|
|
64
|
+
typeof candidate.specId === 'string' &&
|
|
65
|
+
SPEC_ID.test(candidate.specId) &&
|
|
66
|
+
['sourceDigest', 'specDigest', 'policyDigest', 'toolchainDigest'].every((key) => typeof candidate[key] === 'string' && DIGEST.test(candidate[key])) &&
|
|
67
|
+
artifacts !== null &&
|
|
68
|
+
typeof artifacts === 'object' &&
|
|
69
|
+
Object.keys(artifacts).length === ARTIFACT_KEYS.length &&
|
|
70
|
+
ARTIFACT_KEYS.every((key) => {
|
|
71
|
+
const digest = artifacts[key];
|
|
72
|
+
return typeof digest === 'string' && DIGEST.test(digest);
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
function normalizeVersions(versions) {
|
|
76
|
+
const entries = Object.entries(versions);
|
|
77
|
+
if (entries.length === 0) {
|
|
78
|
+
throw new Error('[Planu] Validation toolchain versions are required');
|
|
79
|
+
}
|
|
80
|
+
return Object.fromEntries(entries
|
|
81
|
+
.map(([name, version]) => [normalizedPart(name, 'version name'), normalizedPart(version, 'version')])
|
|
82
|
+
.sort(([left], [right]) => left.localeCompare(right)));
|
|
83
|
+
}
|
|
84
|
+
function normalizeGates(gates) {
|
|
85
|
+
if (gates.length === 0 || gates.some((gate) => gate.status !== 'passed')) {
|
|
86
|
+
throw new Error('[Planu] A receipt requires passing validation gates');
|
|
87
|
+
}
|
|
88
|
+
const names = new Set();
|
|
89
|
+
return gates.map((gate) => {
|
|
90
|
+
const name = normalizedPart(gate.gate, 'gate');
|
|
91
|
+
if (names.has(name) || !Number.isSafeInteger(gate.durationMs) || gate.durationMs < 0) {
|
|
92
|
+
throw new Error('[Planu] Validation gate results are invalid');
|
|
93
|
+
}
|
|
94
|
+
names.add(name);
|
|
95
|
+
return { gate: name, status: 'passed', durationMs: gate.durationMs };
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function unsignedReceipt(receipt) {
|
|
99
|
+
const { authenticity: _authenticity, ...unsigned } = receipt;
|
|
100
|
+
return unsigned;
|
|
101
|
+
}
|
|
102
|
+
function proofFor(receipt, key) {
|
|
103
|
+
return createHmac('sha256', key)
|
|
104
|
+
.update(canonicalize(unsignedReceipt(receipt)))
|
|
105
|
+
.digest();
|
|
106
|
+
}
|
|
107
|
+
export function safeProof(receipt, key) {
|
|
108
|
+
try {
|
|
109
|
+
const received = Buffer.from(receipt.authenticity.proof, 'base64url');
|
|
110
|
+
const expected = proofFor(receipt, key);
|
|
111
|
+
return received.length === expected.length && timingSafeEqual(received, expected);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
/* reliability-optional: RECEIPT_SIGNATURE_INVALID — false is the fail-closed result */
|
|
115
|
+
reportClassifiedDegradation('RECEIPT_SIGNATURE_INVALID', error);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function receiptCore(input, issuer, logDigest) {
|
|
120
|
+
if (!validBindings(input.bindings)) {
|
|
121
|
+
throw new Error('[Planu] Validation bindings require a canonical projectId and complete digests');
|
|
122
|
+
}
|
|
123
|
+
if (input.exitCode !== 0 || !Number.isSafeInteger(input.durationMs) || input.durationMs < 0) {
|
|
124
|
+
throw new Error('[Planu] A receipt requires passing validation with valid duration');
|
|
125
|
+
}
|
|
126
|
+
const issuedAt = input.issuedAt ?? new Date().toISOString();
|
|
127
|
+
if (new Date(issuedAt).toISOString() !== issuedAt) {
|
|
128
|
+
throw new Error('[Planu] Receipt issuedAt must be canonical ISO-8601');
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
schemaVersion: 1,
|
|
132
|
+
issuer,
|
|
133
|
+
issuedAt,
|
|
134
|
+
bindings: structuredClone(input.bindings),
|
|
135
|
+
normalizedCommand: normalizeValidationCommand(input.command),
|
|
136
|
+
versions: normalizeVersions(input.versions),
|
|
137
|
+
exitCode: 0,
|
|
138
|
+
durationMs: input.durationMs,
|
|
139
|
+
logDigest,
|
|
140
|
+
gates: normalizeGates(input.gates),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function hasReceiptIdentity(candidate) {
|
|
144
|
+
return (candidate.schemaVersion === 1 &&
|
|
145
|
+
typeof candidate.receiptId === 'string' &&
|
|
146
|
+
DIGEST.test(candidate.receiptId) &&
|
|
147
|
+
typeof candidate.issuer === 'string' &&
|
|
148
|
+
ISSUER_ID.test(candidate.issuer) &&
|
|
149
|
+
typeof candidate.issuedAt === 'string' &&
|
|
150
|
+
Number.isFinite(Date.parse(candidate.issuedAt)));
|
|
151
|
+
}
|
|
152
|
+
function hasReceiptExecution(candidate) {
|
|
153
|
+
return (validBindings(candidate.bindings) &&
|
|
154
|
+
typeof candidate.normalizedCommand === 'string' &&
|
|
155
|
+
candidate.normalizedCommand.length > 0 &&
|
|
156
|
+
candidate.versions !== null &&
|
|
157
|
+
typeof candidate.versions === 'object' &&
|
|
158
|
+
candidate.exitCode === 0 &&
|
|
159
|
+
Number.isSafeInteger(candidate.durationMs) &&
|
|
160
|
+
candidate.durationMs >= 0 &&
|
|
161
|
+
typeof candidate.logDigest === 'string' &&
|
|
162
|
+
DIGEST.test(candidate.logDigest) &&
|
|
163
|
+
Array.isArray(candidate.gates) &&
|
|
164
|
+
candidate.gates.length > 0);
|
|
165
|
+
}
|
|
166
|
+
function hasReceiptAuthenticity(candidate) {
|
|
167
|
+
if (!candidate.authenticity || typeof candidate.authenticity !== 'object') {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
const authenticity = candidate.authenticity;
|
|
171
|
+
return authenticity.algorithm === 'hmac-sha256' && typeof authenticity.proof === 'string';
|
|
172
|
+
}
|
|
173
|
+
export function validReceiptShape(value) {
|
|
174
|
+
if (!value || typeof value !== 'object') {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
const candidate = value;
|
|
178
|
+
return (hasReceiptIdentity(candidate) &&
|
|
179
|
+
hasReceiptExecution(candidate) &&
|
|
180
|
+
hasReceiptAuthenticity(candidate));
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=validation-receipt-codec.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ValidationReceipt, ValidationReceiptBindings, ValidationReceiptIssueInput, ValidationReceiptIssuerOptions, ValidationReceiptPersistence, ValidationReceiptVerification, ValidationReceiptVerificationOptions } from '../../types/validation-receipt.js';
|
|
2
|
+
import type { RuntimeDatabase } from '../../storage/runtime-db.js';
|
|
3
|
+
import { type StorageCatalogContext } from '../../storage/storage-catalog.js';
|
|
4
|
+
export { normalizeValidationCommand } from './validation-receipt-codec.js';
|
|
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
|
+
export declare class ValidationReceiptStore implements ValidationReceiptPersistence {
|
|
11
|
+
private readonly options;
|
|
12
|
+
private readonly logDirectory;
|
|
13
|
+
constructor(options: {
|
|
14
|
+
readonly database: RuntimeDatabase;
|
|
15
|
+
readonly workspaceId: string;
|
|
16
|
+
readonly catalogContext?: StorageCatalogContext;
|
|
17
|
+
});
|
|
18
|
+
logPath(logDigest: string): string;
|
|
19
|
+
persist(receipt: ValidationReceipt, log: Buffer): Promise<void>;
|
|
20
|
+
readReceipt(projectId: string, receiptId: string): Promise<ValidationReceipt | undefined>;
|
|
21
|
+
readCurrent(projectId: string, specId: string): Promise<ValidationReceipt | undefined>;
|
|
22
|
+
readCurrentBindings(projectId: string, specId: string): Promise<ValidationReceiptBindings | undefined>;
|
|
23
|
+
projectCurrentBindings(bindings: ValidationReceiptBindings): Promise<void>;
|
|
24
|
+
invalidateCurrentBindings(projectId: string, specId: string): Promise<void>;
|
|
25
|
+
readLog(logDigest: string): Promise<Buffer | undefined>;
|
|
26
|
+
private writeLog;
|
|
27
|
+
}
|
|
28
|
+
export declare function issueValidationReceipt(input: ValidationReceiptIssueInput, options: ValidationReceiptIssuerOptions): Promise<ValidationReceipt>;
|
|
29
|
+
export declare function verifyValidationReceipt(value: unknown, options: ValidationReceiptVerificationOptions): Promise<ValidationReceiptVerification>;
|
|
30
|
+
export declare function validationLogPath(store: ValidationReceiptPersistence, logDigest: string): string;
|
|
31
|
+
export declare function readCurrentValidationReceipt(store: ValidationReceiptPersistence, identity: {
|
|
32
|
+
readonly projectId: string;
|
|
33
|
+
readonly specId: string;
|
|
34
|
+
}): Promise<ValidationReceipt | undefined>;
|
|
35
|
+
/** Trust bootstrap is explicit: construct once with locally provisioned opaque issuer references. */
|
|
36
|
+
export declare class ValidationReceiptAuthority {
|
|
37
|
+
private readonly store;
|
|
38
|
+
private readonly trustedIssuers;
|
|
39
|
+
constructor(store: ValidationReceiptPersistence, trustedIssuers: Readonly<Record<string, string>>);
|
|
40
|
+
verifyCurrent(bindings: ValidationReceiptBindings): Promise<ValidationReceiptVerification>;
|
|
41
|
+
}
|
|
42
|
+
/** Construct the production verifier from runtime/catalog context without exposing key material. */
|
|
43
|
+
export declare function createValidationReceiptAuthority(options: {
|
|
44
|
+
readonly database: RuntimeDatabase;
|
|
45
|
+
readonly workspaceId: string;
|
|
46
|
+
readonly projectId: string;
|
|
47
|
+
readonly issuerId: string;
|
|
48
|
+
readonly catalogContext?: StorageCatalogContext;
|
|
49
|
+
}): {
|
|
50
|
+
readonly authority: ValidationReceiptAuthority;
|
|
51
|
+
readonly store: ValidationReceiptStore;
|
|
52
|
+
readonly signingKeyReference: string;
|
|
53
|
+
};
|
|
54
|
+
/** Provision or resolve a machine-local issuer key without exposing raw key material. */
|
|
55
|
+
export declare function ensureValidationIssuerKey(identity: {
|
|
56
|
+
readonly projectId: string;
|
|
57
|
+
readonly issuerId: string;
|
|
58
|
+
}): Promise<string>;
|
|
59
|
+
//# sourceMappingURL=validation-receipt.d.ts.map
|