@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
|
@@ -38,7 +38,7 @@ export function formatBudgetMessage(status) {
|
|
|
38
38
|
return msg;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* Enforces budget limits before executing a
|
|
41
|
+
* Enforces engineering budget limits before executing a governed tool.
|
|
42
42
|
* - If no budget is configured for the spec → no-op (pass through).
|
|
43
43
|
* - If budget is exhausted → throws an Error to block tool execution.
|
|
44
44
|
* - If warning threshold is reached → logs a warning but allows execution.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CriterionIdentity, CriterionIdentityOptions } from '../types/criterion-identity.js';
|
|
2
2
|
export type { CriterionIdentity, CriterionIdentityOptions } from '../types/criterion-identity.js';
|
|
3
|
+
export declare function hasExplicitCriterionId(value: string): boolean;
|
|
3
4
|
export declare function normalizeCriterionText(value: string): string;
|
|
4
5
|
export declare function createCriterionIdentity(value: string, options?: CriterionIdentityOptions): CriterionIdentity;
|
|
5
6
|
export declare function criterionIdentitiesMatch(left: CriterionIdentity, right: CriterionIdentity): boolean;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
const CRITERION_ID_PREFIX = /^(AC|AB)\s*-?\s*(\d+)\b\s*[:.)-]?\s*/i;
|
|
3
|
+
export function hasExplicitCriterionId(value) {
|
|
4
|
+
const stripped = value
|
|
5
|
+
.normalize('NFKC')
|
|
6
|
+
.replace(/^[-*+]\s*\[[ xX]\]\s*/, '')
|
|
7
|
+
.trim();
|
|
8
|
+
return CRITERION_ID_PREFIX.test(stripped);
|
|
9
|
+
}
|
|
3
10
|
export function normalizeCriterionText(value) {
|
|
4
11
|
return value
|
|
5
12
|
.normalize('NFKC')
|
|
@@ -324,18 +324,13 @@ export async function loadUsageStats() {
|
|
|
324
324
|
const raw = await readJsonFile(usageFile);
|
|
325
325
|
if (!raw) {
|
|
326
326
|
return {
|
|
327
|
-
tier: 'unknown',
|
|
328
327
|
callsToday: 0,
|
|
329
|
-
dailyLimit: null,
|
|
330
|
-
trialDaysLeft: null,
|
|
331
328
|
isAvailable: false,
|
|
332
329
|
};
|
|
333
330
|
}
|
|
331
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
334
332
|
return {
|
|
335
|
-
|
|
336
|
-
callsToday: raw.callsToday ?? 0,
|
|
337
|
-
dailyLimit: raw.dailyLimit ?? null,
|
|
338
|
-
trialDaysLeft: raw.trialDaysLeft ?? null,
|
|
333
|
+
callsToday: (raw.events ?? []).filter((event) => event.timestamp?.startsWith(today)).length,
|
|
339
334
|
isAvailable: true,
|
|
340
335
|
};
|
|
341
336
|
}
|
|
@@ -194,9 +194,6 @@ function getPageStyles() {
|
|
|
194
194
|
.usage-panel { background: var(--surface); border: 1px solid var(--border);
|
|
195
195
|
border-radius: var(--radius); padding: 1rem; margin-top: 1.5rem; }
|
|
196
196
|
.usage-panel h3 { font-size: 0.9rem; font-weight: 600; margin-bottom: 0.75rem; color: var(--text-muted); }
|
|
197
|
-
.usage-tier { font-size: 1.1rem; font-weight: 700; color: var(--accent); }
|
|
198
|
-
.trial-warning { color: #f59e0b; font-size: 0.82rem; margin-top: 0.35rem; }
|
|
199
|
-
.trial-critical { color: #ef4444; font-weight: 600; }
|
|
200
197
|
.status-indicator.updating { color: #f59e0b; }
|
|
201
198
|
.shortcuts-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.7);
|
|
202
199
|
z-index: 1000; align-items: center; justify-content: center; }
|
|
@@ -30,21 +30,9 @@ function renderUsagePanel(usage) {
|
|
|
30
30
|
<div style="color:var(--text-muted);font-size:0.85rem">Sin datos de uso disponibles</div>
|
|
31
31
|
</div>`;
|
|
32
32
|
}
|
|
33
|
-
const tierLabel = usage.tier.charAt(0).toUpperCase() + usage.tier.slice(1);
|
|
34
|
-
const limitLabel = usage.dailyLimit !== null ? String(usage.dailyLimit) : '∞';
|
|
35
|
-
const callsLabel = `${usage.callsToday} / ${limitLabel}`;
|
|
36
|
-
let trialHtml = '';
|
|
37
|
-
if (usage.trialDaysLeft !== null) {
|
|
38
|
-
const isCritical = usage.trialDaysLeft <= 3;
|
|
39
|
-
trialHtml = `<div class="trial-warning ${isCritical ? 'trial-critical' : ''}">
|
|
40
|
-
Trial: ${usage.trialDaysLeft} día${usage.trialDaysLeft !== 1 ? 's' : ''} restante${usage.trialDaysLeft !== 1 ? 's' : ''}
|
|
41
|
-
</div>`;
|
|
42
|
-
}
|
|
43
33
|
return `<div class="usage-panel">
|
|
44
34
|
<h3>Uso</h3>
|
|
45
|
-
<div
|
|
46
|
-
<div style="font-size:0.82rem;color:var(--text-muted);margin-top:0.35rem">Llamadas hoy: ${escapeHtml(callsLabel)}</div>
|
|
47
|
-
${trialHtml}
|
|
35
|
+
<div style="font-size:0.82rem;color:var(--text-muted);margin-top:0.35rem">Llamadas hoy: ${String(usage.callsToday)}</div>
|
|
48
36
|
</div>`;
|
|
49
37
|
}
|
|
50
38
|
/** Render the health metrics panel */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DocSpecSummary, ToolEntry, ProjectMetrics } from '../../types/docs.js';
|
|
2
2
|
export declare function collectSpecs(projectPath: string): Promise<DocSpecSummary[]>;
|
|
3
|
-
export declare function collectTools(
|
|
3
|
+
export declare function collectTools(_projectPath: string): ToolEntry[];
|
|
4
4
|
export declare function collectMetrics(projectPath: string): Promise<ProjectMetrics>;
|
|
5
5
|
//# sourceMappingURL=data-collector.d.ts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// @crash-shield-ignore-file — config/cache reader for Planu-controlled JSON; writer is this codebase, shape guaranteed by build/seed.
|
|
2
2
|
// SPEC-093: Data collector for docs site generator
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
4
3
|
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
5
4
|
import { join } from 'node:path';
|
|
5
|
+
import { readCanonicalToolNames } from '../../config/official-sdd-tools.js';
|
|
6
6
|
import { parseFrontmatter } from '../frontmatter-parser.js';
|
|
7
7
|
const SDD_PHASES = {
|
|
8
8
|
Initialize: ['init_project', 'init_constitution', 'set_locale'],
|
|
@@ -225,33 +225,12 @@ export async function collectSpecs(projectPath) {
|
|
|
225
225
|
});
|
|
226
226
|
return results;
|
|
227
227
|
}
|
|
228
|
-
export function collectTools(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
return [];
|
|
236
|
-
}
|
|
237
|
-
const entries = [];
|
|
238
|
-
for (const tool of plans.freeTools ?? []) {
|
|
239
|
-
entries.push({
|
|
240
|
-
name: tool,
|
|
241
|
-
description: tool.replace(/_/g, ' '),
|
|
242
|
-
phase: findPhaseForTool(tool),
|
|
243
|
-
tier: 'free',
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
for (const tool of plans.proTools ?? []) {
|
|
247
|
-
entries.push({
|
|
248
|
-
name: tool,
|
|
249
|
-
description: tool.replace(/_/g, ' '),
|
|
250
|
-
phase: findPhaseForTool(tool),
|
|
251
|
-
tier: 'pro',
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
return entries;
|
|
228
|
+
export function collectTools(_projectPath) {
|
|
229
|
+
return readCanonicalToolNames().map((tool) => ({
|
|
230
|
+
name: tool,
|
|
231
|
+
description: tool.replaceAll('_', ' '),
|
|
232
|
+
phase: findPhaseForTool(tool),
|
|
233
|
+
}));
|
|
255
234
|
}
|
|
256
235
|
async function countLinesInDir(dirPath) {
|
|
257
236
|
let total = 0;
|
|
@@ -11,18 +11,11 @@ function groupByPhase(tools) {
|
|
|
11
11
|
}
|
|
12
12
|
return groups;
|
|
13
13
|
}
|
|
14
|
-
function renderTierBadge(tier) {
|
|
15
|
-
const cls = tier === 'free' ? 'badge-free' : 'badge-pro';
|
|
16
|
-
const label = tier === 'free' ? 'Free' : 'Pro';
|
|
17
|
-
return `<span class="tier-badge ${cls}">${label}</span>`;
|
|
18
|
-
}
|
|
19
14
|
export function renderToolsCatalog(tools) {
|
|
20
|
-
const freeCount = tools.filter((t) => t.tier === 'free').length;
|
|
21
|
-
const proCount = tools.filter((t) => t.tier === 'pro').length;
|
|
22
15
|
if (tools.length === 0) {
|
|
23
16
|
return `<div class="tools-catalog">
|
|
24
17
|
<div class="tools-summary">
|
|
25
|
-
<p>Total: 0
|
|
18
|
+
<p>Total: 0</p>
|
|
26
19
|
</div>
|
|
27
20
|
<p class="empty">No tools found.</p>
|
|
28
21
|
</div>`;
|
|
@@ -34,7 +27,7 @@ export function renderToolsCatalog(tools) {
|
|
|
34
27
|
.map((tool) => {
|
|
35
28
|
const searchable = `${tool.name} ${tool.description}`.toLowerCase();
|
|
36
29
|
return ` <div class="tool-card" data-searchable="${searchable}">
|
|
37
|
-
<h3>${tool.name}
|
|
30
|
+
<h3>${tool.name}</h3>
|
|
38
31
|
<p>${tool.description}</p>
|
|
39
32
|
</div>`;
|
|
40
33
|
})
|
|
@@ -47,7 +40,7 @@ ${cards}
|
|
|
47
40
|
.join('\n');
|
|
48
41
|
return `<div class="tools-catalog">
|
|
49
42
|
<div class="tools-summary">
|
|
50
|
-
<p>Total: ${String(tools.length)}
|
|
43
|
+
<p>Total: ${String(tools.length)}</p>
|
|
51
44
|
</div>
|
|
52
45
|
${sections}
|
|
53
46
|
</div>`;
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import type { Spec } from '../../types/spec/core.js';
|
|
2
|
-
import type { EvidenceArtifacts } from '../../types/evidence-gates.js';
|
|
2
|
+
import type { EvidenceArtifacts, TraceabilityMatrixEvidence } from '../../types/evidence-gates.js';
|
|
3
3
|
/** Digest of canonical artifact content; the provenance envelope is excluded. */
|
|
4
4
|
export declare function evidenceArtifactDigest(artifact: unknown): string;
|
|
5
5
|
export declare function evidenceArtifactCollectionDigest(artifacts: readonly {
|
|
6
6
|
kind: string;
|
|
7
7
|
provenance?: unknown;
|
|
8
8
|
}[]): string;
|
|
9
|
+
/** Verify legacy test-backed evidence without admitting prose-only traceability rows. */
|
|
10
|
+
export declare function traceabilityRowHasCurrentTestEvidence(row: TraceabilityMatrixEvidence['rows'][number], args: {
|
|
11
|
+
projectPath: string;
|
|
12
|
+
}): boolean;
|
|
13
|
+
/** Verify strict command evidence against current repository inputs and the validation ledger. */
|
|
14
|
+
export declare function traceabilityRowHasCurrentCommandEvidence(row: TraceabilityMatrixEvidence['rows'][number], args: {
|
|
15
|
+
projectId: string;
|
|
16
|
+
projectPath: string;
|
|
17
|
+
}): boolean;
|
|
18
|
+
/** SPEC-1356: exported so evidence-autofill (and other producers) target the same path convention. */
|
|
19
|
+
export declare function handoffEvidencePath(projectId: string, specId: string, filename: string): string;
|
|
9
20
|
export declare function readEvidenceArtifacts(args: {
|
|
10
21
|
spec: Spec;
|
|
11
22
|
projectId: string;
|
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
import { technologyValue } from '../technology-registry.js';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { lstatSync, realpathSync } from 'node:fs';
|
|
3
4
|
import { createHash } from 'node:crypto';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
+
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
5
6
|
import { z } from 'zod';
|
|
6
7
|
import { projectDataDir } from '../../storage/base-store.js';
|
|
8
|
+
import { computeValidationEvidenceIdentity, computeValidationEvidenceKey, normalizeValidationCommand, readMatchingValidationEvidence, } from '../validation-evidence-ledger.js';
|
|
9
|
+
import { VALIDATION_COMMANDS } from '../validation-impact-planner.js';
|
|
7
10
|
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
8
11
|
const SPEC_ID = /^SPEC-[1-9]\d*$/u;
|
|
9
12
|
const ISSUER_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
13
|
+
const EVIDENCE_KEY = /^[a-f0-9]{64}$/u;
|
|
14
|
+
const ValidationGateCapabilitySchema = z.enum([
|
|
15
|
+
'typecheck',
|
|
16
|
+
'lint',
|
|
17
|
+
'test-related',
|
|
18
|
+
'test-full',
|
|
19
|
+
'contract',
|
|
20
|
+
'coverage',
|
|
21
|
+
'migration',
|
|
22
|
+
'fault-injection',
|
|
23
|
+
'security',
|
|
24
|
+
'native',
|
|
25
|
+
'website',
|
|
26
|
+
'reproducibility',
|
|
27
|
+
]);
|
|
10
28
|
const ProvenanceSchema = z
|
|
11
29
|
.object({
|
|
12
30
|
receiptId: z.string().regex(DIGEST),
|
|
@@ -69,6 +87,16 @@ const TraceabilityMatrixSchema = z
|
|
|
69
87
|
changedFiles: z.array(z.string().min(1)).max(200),
|
|
70
88
|
validationEvidence: z.string().optional(),
|
|
71
89
|
reviewerEvidence: z.string().optional(),
|
|
90
|
+
commandEvidence: z
|
|
91
|
+
.object({
|
|
92
|
+
capability: ValidationGateCapabilitySchema,
|
|
93
|
+
command: z.string().min(1),
|
|
94
|
+
scope: z.array(z.string().min(1)).min(1).max(200),
|
|
95
|
+
relevantPaths: z.array(z.string().min(1)).min(1).max(200).optional(),
|
|
96
|
+
evidenceKey: z.string().regex(EVIDENCE_KEY),
|
|
97
|
+
})
|
|
98
|
+
.strict()
|
|
99
|
+
.optional(),
|
|
72
100
|
})
|
|
73
101
|
.strict())
|
|
74
102
|
.max(1000),
|
|
@@ -118,10 +146,95 @@ export function evidenceArtifactCollectionDigest(artifacts) {
|
|
|
118
146
|
.map((artifact) => ({ kind: artifact.kind, digest: evidenceArtifactDigest(artifact) }))
|
|
119
147
|
.sort((left, right) => left.kind.localeCompare(right.kind)));
|
|
120
148
|
}
|
|
149
|
+
function safeRepositoryPath(path) {
|
|
150
|
+
const normalized = path.trim().replaceAll('\\', '/').replace(/^\.\//u, '');
|
|
151
|
+
return (normalized.length > 0 &&
|
|
152
|
+
!normalized.startsWith('/') &&
|
|
153
|
+
!/^[A-Za-z]:/u.test(normalized) &&
|
|
154
|
+
normalized
|
|
155
|
+
.split('/')
|
|
156
|
+
.every((segment) => segment.length > 0 && segment !== '.' && segment !== '..'));
|
|
157
|
+
}
|
|
158
|
+
function repositoryEvidencePathsAreCurrent(row, projectPath, additionalPaths = []) {
|
|
159
|
+
let repositoryRoot;
|
|
160
|
+
try {
|
|
161
|
+
repositoryRoot = realpathSync(projectPath);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const paths = [
|
|
167
|
+
...row.changedFiles,
|
|
168
|
+
...(row.testEvidence ?? []),
|
|
169
|
+
...(row.contractEvidence ?? []),
|
|
170
|
+
...additionalPaths,
|
|
171
|
+
];
|
|
172
|
+
return (paths.length > 0 &&
|
|
173
|
+
paths.every((path) => {
|
|
174
|
+
if (!safeRepositoryPath(path)) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
const candidate = resolve(repositoryRoot, path);
|
|
178
|
+
try {
|
|
179
|
+
if (lstatSync(candidate).isSymbolicLink()) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
const realPath = realpathSync(candidate);
|
|
183
|
+
const relativePath = relative(repositoryRoot, realPath);
|
|
184
|
+
return (relativePath.length > 0 &&
|
|
185
|
+
relativePath.split(/[\\/]/u)[0] !== '..' &&
|
|
186
|
+
!isAbsolute(relativePath));
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
function isExecutableTestPath(path) {
|
|
194
|
+
return /(?:^|\/)[^/]+\.(?:test|spec)\.[cm]?[jt]sx?$/u.test(path.replaceAll('\\', '/'));
|
|
195
|
+
}
|
|
196
|
+
/** Verify legacy test-backed evidence without admitting prose-only traceability rows. */
|
|
197
|
+
export function traceabilityRowHasCurrentTestEvidence(row, args) {
|
|
198
|
+
return (row.commandEvidence === undefined &&
|
|
199
|
+
row.changedFiles.length > 0 &&
|
|
200
|
+
(row.testEvidence?.length ?? 0) > 0 &&
|
|
201
|
+
row.testEvidence?.every(isExecutableTestPath) === true &&
|
|
202
|
+
Boolean(row.validationEvidence?.trim()) &&
|
|
203
|
+
Boolean(row.reviewerEvidence?.trim()) &&
|
|
204
|
+
repositoryEvidencePathsAreCurrent(row, args.projectPath));
|
|
205
|
+
}
|
|
206
|
+
/** Verify strict command evidence against current repository inputs and the validation ledger. */
|
|
207
|
+
export function traceabilityRowHasCurrentCommandEvidence(row, args) {
|
|
208
|
+
const evidence = row.commandEvidence;
|
|
209
|
+
const expectedCommand = evidence
|
|
210
|
+
? VALIDATION_COMMANDS[evidence.capability]
|
|
211
|
+
: undefined;
|
|
212
|
+
if (!evidence ||
|
|
213
|
+
!expectedCommand ||
|
|
214
|
+
normalizeValidationCommand(evidence.command) !== normalizeValidationCommand(expectedCommand)) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
const repositoryPaths = [...(evidence.relevantPaths ?? [])];
|
|
218
|
+
if (row.changedFiles.length === 0 ||
|
|
219
|
+
!repositoryEvidencePathsAreCurrent(row, args.projectPath, repositoryPaths) ||
|
|
220
|
+
evidence.scope.some((path) => !safeRepositoryPath(path))) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
const input = {
|
|
224
|
+
projectPath: args.projectPath,
|
|
225
|
+
capability: evidence.capability,
|
|
226
|
+
command: evidence.command,
|
|
227
|
+
scope: evidence.scope,
|
|
228
|
+
...(evidence.relevantPaths === undefined ? {} : { relevantPaths: evidence.relevantPaths }),
|
|
229
|
+
};
|
|
230
|
+
const currentKey = computeValidationEvidenceKey(computeValidationEvidenceIdentity(input));
|
|
231
|
+
return (currentKey === evidence.evidenceKey &&
|
|
232
|
+
readMatchingValidationEvidence(args.projectId, input)?.status === 'passed');
|
|
233
|
+
}
|
|
121
234
|
const ARTIFACT_HINTS = {
|
|
122
235
|
'Discovery evidence': 'Expected discovery.json with { version: 1, rules: string[], examples: [{ rule, example }], openQuestions: [{ question, status, resolution? }], outOfScope: string[], glossary: [{ term, meaning }] }.',
|
|
123
236
|
'Task plan evidence': 'Expected task-plan.json with { version: 1, tasks: [{ id, title, acceptanceCriteria: string[], status: "pending"|"doing"|"done" }] }. Acceptance criteria may be full text or stable IDs such as AC1 when they map to the canonical criteria order.',
|
|
124
|
-
'Traceability matrix evidence': 'Expected traceability-matrix.json with { version: 1, rows: [{ acceptanceCriterion, scenario?, testEvidence?, contractEvidence?, manualEvidence?, changedFiles: string[], validationEvidence?, reviewerEvidence
|
|
237
|
+
'Traceability matrix evidence': 'Expected traceability-matrix.json with { version: 1, rows: [{ acceptanceCriterion, scenario?, testEvidence?, contractEvidence?, manualEvidence?, changedFiles: string[], validationEvidence?, reviewerEvidence?, commandEvidence?: { capability, command, scope, relevantPaths?, evidenceKey } }] }.',
|
|
125
238
|
'contract-validation-api.json': 'Expected filename contract-validation-api.json with { version: 1, kind: "api", passed: boolean, reportPath?, summary? }.',
|
|
126
239
|
'contract-validation-graphql.json': 'Expected filename contract-validation-graphql.json with { version: 1, kind: "graphql", passed: boolean, reportPath?, summary? }.',
|
|
127
240
|
'contract-validation-event.json': 'Expected filename contract-validation-event.json with { version: 1, kind: "event", passed: boolean, reportPath?, summary? }.',
|
|
@@ -131,7 +244,58 @@ const ARTIFACT_HINTS = {
|
|
|
131
244
|
function artifactHint(label) {
|
|
132
245
|
return ARTIFACT_HINTS[label] ?? '';
|
|
133
246
|
}
|
|
134
|
-
|
|
247
|
+
/**
|
|
248
|
+
* SPEC-1356 / AC5: compact JSON literal per artifact kind, appended verbatim to
|
|
249
|
+
* schema-validation errors so a retrying caller sees the exact expected shape
|
|
250
|
+
* instead of re-deriving it from prose.
|
|
251
|
+
*/
|
|
252
|
+
const ARTIFACT_EXAMPLES = {
|
|
253
|
+
'Discovery evidence': JSON.stringify({
|
|
254
|
+
version: 1,
|
|
255
|
+
rules: ['Rule text'],
|
|
256
|
+
examples: [{ rule: 'Rule text', example: 'Example text' }],
|
|
257
|
+
openQuestions: [{ question: 'Open question?', status: 'open' }],
|
|
258
|
+
outOfScope: ['Not in scope item'],
|
|
259
|
+
glossary: [{ term: 'Term', meaning: 'Meaning' }],
|
|
260
|
+
}),
|
|
261
|
+
'Task plan evidence': JSON.stringify({
|
|
262
|
+
version: 1,
|
|
263
|
+
tasks: [{ id: 'T1', title: 'Task title', acceptanceCriteria: ['AC1'], status: 'pending' }],
|
|
264
|
+
}),
|
|
265
|
+
'Traceability matrix evidence': JSON.stringify({
|
|
266
|
+
version: 1,
|
|
267
|
+
rows: [
|
|
268
|
+
{
|
|
269
|
+
acceptanceCriterion: 'AC text',
|
|
270
|
+
testEvidence: ['tests/example.test.ts'],
|
|
271
|
+
changedFiles: ['src/example.ts'],
|
|
272
|
+
validationEvidence: 'validate passed with score 100',
|
|
273
|
+
reviewerEvidence: 'planu-implementation-reviewer approved',
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
}),
|
|
277
|
+
// Contract kinds are derived from the artifact filenames so no
|
|
278
|
+
// configurable technology literal is hardcoded here (audit:hardcodes).
|
|
279
|
+
...Object.fromEntries([
|
|
280
|
+
'contract-validation-api.json',
|
|
281
|
+
'contract-validation-graphql.json',
|
|
282
|
+
'contract-validation-event.json',
|
|
283
|
+
'contract-validation-ui.json',
|
|
284
|
+
'contract-validation-mcp.json',
|
|
285
|
+
].map((label) => [
|
|
286
|
+
label,
|
|
287
|
+
JSON.stringify({
|
|
288
|
+
version: 1,
|
|
289
|
+
kind: label.slice('contract-validation-'.length, -'.json'.length),
|
|
290
|
+
passed: true,
|
|
291
|
+
}),
|
|
292
|
+
])),
|
|
293
|
+
};
|
|
294
|
+
function artifactExample(label) {
|
|
295
|
+
return ARTIFACT_EXAMPLES[label] ?? '';
|
|
296
|
+
}
|
|
297
|
+
/** SPEC-1356: exported so evidence-autofill (and other producers) target the same path convention. */
|
|
298
|
+
export function handoffEvidencePath(projectId, specId, filename) {
|
|
135
299
|
return join(projectDataDir(projectId), 'handoffs', specId, filename);
|
|
136
300
|
}
|
|
137
301
|
async function readUnknown(paths) {
|
|
@@ -160,7 +324,13 @@ async function readOptional(args) {
|
|
|
160
324
|
}
|
|
161
325
|
const parsed = args.schema.safeParse(found.value);
|
|
162
326
|
if (!parsed.success) {
|
|
163
|
-
|
|
327
|
+
// SPEC-1356 / AC5: surface every Zod issue (field path + message), not just the
|
|
328
|
+
// first one, so a single retry can fix every constraint violation at once.
|
|
329
|
+
const allIssues = parsed.error.issues
|
|
330
|
+
.map((issue) => `${issue.path.length > 0 ? issue.path.join('.') : '(root)'}: ${issue.message}`)
|
|
331
|
+
.join('; ');
|
|
332
|
+
const example = artifactExample(args.label);
|
|
333
|
+
args.invalidArtifacts.push(`${args.label} is invalid at ${found.path}: ${allIssues} ${artifactHint(args.label)}${example ? ` Expected shape example: ${example}` : ''}`.trim());
|
|
164
334
|
return undefined;
|
|
165
335
|
}
|
|
166
336
|
return parsed.data;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AutofillTraceabilityMatrixArgs, AutofillTraceabilityMatrixResult } from '../../types/evidence-autofill.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate `traceability-matrix.json` in the handoff evidence store when it does
|
|
4
|
+
* not already exist. Never overwrites an existing file — if one is present this
|
|
5
|
+
* is a no-op that reports `already-exists`. Tolerates every failure by returning
|
|
6
|
+
* a typed non-throwing result; callers must never let this crash a lifecycle
|
|
7
|
+
* transition.
|
|
8
|
+
*/
|
|
9
|
+
export declare function autofillTraceabilityMatrix(args: AutofillTraceabilityMatrixArgs): Promise<AutofillTraceabilityMatrixResult>;
|
|
10
|
+
//# sourceMappingURL=evidence-autofill.d.ts.map
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// engine/evidence-gates/evidence-autofill.ts — SPEC-1356: automated lifecycle evidence pipeline
|
|
2
|
+
//
|
|
3
|
+
// Generates traceability-matrix.json in the handoff evidence store when it is
|
|
4
|
+
// missing, so a `done` transition never fails purely because nobody hand-wrote
|
|
5
|
+
// the traceability artifact.
|
|
6
|
+
//
|
|
7
|
+
// ORDERING CAVEAT (documented per SPEC-1356 T-A3): writing traceability-matrix.json
|
|
8
|
+
// *after* `validate` has already computed and bound durable validation receipts
|
|
9
|
+
// would make those bindings stale relative to the newly-written evidence — the
|
|
10
|
+
// receipt would be certifying a repository state that does not include this file.
|
|
11
|
+
// This module does NOT attempt to re-run or re-bind validation. Instead, callers
|
|
12
|
+
// (see `src/tools/update-status/index.ts`) MUST treat a write from this module as
|
|
13
|
+
// "evidence created, not yet bound": when autofill actually writes the file, the
|
|
14
|
+
// caller must block the `done` transition with a message telling the operator to
|
|
15
|
+
// re-run `validate` once so the freshly-created evidence gets bound, then retry
|
|
16
|
+
// `done`. This is the simpler, safe choice given SPEC-1356 could not fully verify
|
|
17
|
+
// that skipping straight through to the done gates after autofill would keep
|
|
18
|
+
// receipt bindings correct in every code path (reconciliation, forced bypass,
|
|
19
|
+
// legacy harnesses, etc.).
|
|
20
|
+
import { execFile } from 'node:child_process';
|
|
21
|
+
import { existsSync } from 'node:fs';
|
|
22
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
23
|
+
import { promisify } from 'node:util';
|
|
24
|
+
import { extractAcceptanceCriteriaTexts } from '../spec-format/acceptance-criteria.js';
|
|
25
|
+
import { parseFrontmatterScenarios } from '../validator/spec-compliance-runner.js';
|
|
26
|
+
import { extractCanonicalFileOwnership } from '../handoff-packager.js';
|
|
27
|
+
import { handoffEvidencePath } from './artifact-reader.js';
|
|
28
|
+
import { atomicWriteFile } from '../safety/atomic-write-file.js';
|
|
29
|
+
import { ValidationReportV1Schema } from '../handoff-artifacts/schemas.js';
|
|
30
|
+
import { projectDataDir } from '../../storage/base-store.js';
|
|
31
|
+
import { readFile } from 'node:fs/promises';
|
|
32
|
+
import { reportClassifiedDegradation } from '../../errors/classified-degradation.js';
|
|
33
|
+
const execFileAsync = promisify(execFile);
|
|
34
|
+
const defaultExec = async (command, args, options) => {
|
|
35
|
+
const { stdout } = await execFileAsync(command, args, { cwd: options.cwd, encoding: 'utf-8' });
|
|
36
|
+
return stdout;
|
|
37
|
+
};
|
|
38
|
+
/** Best-effort `git diff --name-only <mergeBase>...HEAD`; never throws. */
|
|
39
|
+
async function computeChangedFilesFromGit(projectPath, exec, baseBranch) {
|
|
40
|
+
try {
|
|
41
|
+
const mergeBaseOut = await exec('git', ['merge-base', 'HEAD', baseBranch], {
|
|
42
|
+
cwd: projectPath,
|
|
43
|
+
});
|
|
44
|
+
const mergeBase = mergeBaseOut.trim();
|
|
45
|
+
if (!mergeBase) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const diffOut = await exec('git', ['diff', '--name-only', `${mergeBase}...HEAD`], {
|
|
49
|
+
cwd: projectPath,
|
|
50
|
+
});
|
|
51
|
+
return diffOut
|
|
52
|
+
.split('\n')
|
|
53
|
+
.map((line) => line.trim())
|
|
54
|
+
.filter((line) => line.length > 0);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
/* reliability-optional: EVIDENCE_AUTOFILL_GIT_DIFF — falls back to ## Files ownership */
|
|
58
|
+
reportClassifiedDegradation('EVIDENCE_AUTOFILL_GIT_DIFF', error);
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function filterExistingRepoFiles(projectPath, paths) {
|
|
63
|
+
return paths.filter((path) => {
|
|
64
|
+
if (isAbsolute(path)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
return existsSync(resolve(projectPath, path));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Best-effort read + sha256 summary of the persisted validation report, for prose evidence. */
|
|
76
|
+
async function readValidationReportSummary(projectId, specId) {
|
|
77
|
+
const reportPath = join(projectDataDir(projectId), 'handoffs', specId, 'validation-report.json');
|
|
78
|
+
try {
|
|
79
|
+
const raw = await readFile(reportPath, 'utf-8');
|
|
80
|
+
const parsed = ValidationReportV1Schema.safeParse(JSON.parse(raw));
|
|
81
|
+
if (!parsed.success) {
|
|
82
|
+
return {};
|
|
83
|
+
}
|
|
84
|
+
const { score, reviewer } = parsed.data;
|
|
85
|
+
return {
|
|
86
|
+
validationEvidence: `Validated by handoffs/${specId}/validation-report.json (score=${score ?? 'n/a'}).`,
|
|
87
|
+
reviewerEvidence: `Reviewed by ${reviewer.agent} (${reviewer.kind}), verdict=${reviewer.verdict}.`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Generate `traceability-matrix.json` in the handoff evidence store when it does
|
|
96
|
+
* not already exist. Never overwrites an existing file — if one is present this
|
|
97
|
+
* is a no-op that reports `already-exists`. Tolerates every failure by returning
|
|
98
|
+
* a typed non-throwing result; callers must never let this crash a lifecycle
|
|
99
|
+
* transition.
|
|
100
|
+
*/
|
|
101
|
+
export async function autofillTraceabilityMatrix(args) {
|
|
102
|
+
const targetPath = handoffEvidencePath(args.projectId, args.specId, 'traceability-matrix.json');
|
|
103
|
+
try {
|
|
104
|
+
if (existsSync(targetPath)) {
|
|
105
|
+
return { written: false, reason: 'already-exists' };
|
|
106
|
+
}
|
|
107
|
+
const criteria = extractAcceptanceCriteriaTexts(args.specBody);
|
|
108
|
+
if (criteria.length === 0) {
|
|
109
|
+
return { written: false, reason: 'no-criteria' };
|
|
110
|
+
}
|
|
111
|
+
const scenarios = parseFrontmatterScenarios(args.specBody);
|
|
112
|
+
const exec = args.exec ?? defaultExec;
|
|
113
|
+
const baseBranch = args.baseBranch ?? 'main';
|
|
114
|
+
const gitChangedFiles = args.projectPath
|
|
115
|
+
? await computeChangedFilesFromGit(args.projectPath, exec, baseBranch)
|
|
116
|
+
: [];
|
|
117
|
+
const ownership = extractCanonicalFileOwnership(args.specBody);
|
|
118
|
+
const ownershipFiles = [...ownership.toCreate, ...ownership.toModify, ...ownership.toTest];
|
|
119
|
+
const rawChangedFiles = gitChangedFiles.length > 0 ? gitChangedFiles : ownershipFiles;
|
|
120
|
+
const changedFiles = args.projectPath
|
|
121
|
+
? filterExistingRepoFiles(args.projectPath, rawChangedFiles)
|
|
122
|
+
: rawChangedFiles;
|
|
123
|
+
const { validationEvidence, reviewerEvidence } = await readValidationReportSummary(args.projectId, args.specId);
|
|
124
|
+
const rows = criteria.map((acceptanceCriterion, index) => {
|
|
125
|
+
const testPaths = scenarios[index]?.tests?.map((test) => test.path) ?? [];
|
|
126
|
+
return {
|
|
127
|
+
acceptanceCriterion,
|
|
128
|
+
...(testPaths.length > 0 ? { testEvidence: testPaths } : {}),
|
|
129
|
+
changedFiles,
|
|
130
|
+
...(validationEvidence ? { validationEvidence } : {}),
|
|
131
|
+
...(reviewerEvidence ? { reviewerEvidence } : {}),
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
const payload = { version: 1, rows };
|
|
135
|
+
await atomicWriteFile(targetPath, JSON.stringify(payload, null, 2));
|
|
136
|
+
return { written: true, path: targetPath, rowCount: rows.length };
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
/* reliability-optional: EVIDENCE_AUTOFILL_WRITE — caller proceeds without autofill */
|
|
140
|
+
reportClassifiedDegradation('EVIDENCE_AUTOFILL_WRITE', error);
|
|
141
|
+
return {
|
|
142
|
+
written: false,
|
|
143
|
+
reason: 'write-failed',
|
|
144
|
+
error: error instanceof Error ? error.message : String(error),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=evidence-autofill.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Spec } from '../../types/spec/core.js';
|
|
2
|
+
import type { DiscoveryEvidence, TaskPlanEvidence } from '../../types/evidence-gates.js';
|
|
3
|
+
/** Build a strict-schema discovery.json skeleton grounded in the spec's own grounding metadata. */
|
|
4
|
+
export declare function generateDiscoverySkeleton(args: {
|
|
5
|
+
spec: Spec;
|
|
6
|
+
body: string | null;
|
|
7
|
+
}): DiscoveryEvidence;
|
|
8
|
+
/** Build a strict-schema task-plan.json skeleton with one pending task per canonical criterion. */
|
|
9
|
+
export declare function generateTaskPlanSkeleton(args: {
|
|
10
|
+
criteria: string[];
|
|
11
|
+
}): TaskPlanEvidence;
|
|
12
|
+
/** Persist an auto-generated evidence skeleton to the external handoff store. */
|
|
13
|
+
export declare function writeEvidenceSkeleton(args: {
|
|
14
|
+
projectId: string;
|
|
15
|
+
specId: string;
|
|
16
|
+
filename: string;
|
|
17
|
+
artifact: DiscoveryEvidence | TaskPlanEvidence;
|
|
18
|
+
}): Promise<string>;
|
|
19
|
+
//# sourceMappingURL=evidence-skeletons.d.ts.map
|