@planu/cli 4.14.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -1
- package/LICENSE +55 -12
- package/README.md +10 -2
- package/dist/cli/commands/install.d.ts +1 -12
- package/dist/cli/commands/install.js +9 -65
- package/dist/cli/commands/job.js +4 -3
- package/dist/cli/commands/spec.js +2 -2
- package/dist/cli/commands/validate.js +2 -2
- package/dist/cli/router.js +1 -3
- package/dist/config/environment-schema.json +1 -3
- package/dist/config/official-sdd-tools.d.ts +4 -0
- package/dist/config/official-sdd-tools.js +35 -0
- package/dist/config/product-public.d.ts +139 -3
- package/dist/config/product-public.js +8 -1
- package/dist/config/product-public.json +7 -36
- package/dist/config/registries/hosts/codex.json +20 -363
- package/dist/config/release-policy.json +84 -2
- package/dist/config/runtime-policy.json +12 -1
- package/dist/config/skill-templates/planu-resume-work.md +2 -2
- package/dist/core/index.d.ts +1 -1
- package/dist/core/spec-validator.d.ts +4 -4
- package/dist/core/spec-validator.js +1 -1
- package/dist/engine/abortable-process-runner.d.ts +20 -2
- package/dist/engine/abortable-process-runner.js +243 -74
- package/dist/engine/ambiguity-scorer.js +4 -26
- package/dist/engine/auth/scope-mapper.js +1 -7
- package/dist/engine/autopilot/state-updater.js +4 -4
- package/dist/engine/cascade-hooks/hooks/review-enricher.hook.js +9 -6
- package/dist/engine/cascade-hooks/state-drift-detector.d.ts +3 -3
- package/dist/engine/cascade-hooks/state-drift-detector.js +1 -1
- package/dist/engine/ci-generator/planu-config.js +1 -7
- package/dist/engine/clarification-gate/gate.d.ts +3 -3
- package/dist/engine/code-scanner/layer-scanner.js +6 -22
- package/dist/engine/core-bridge.d.ts +3 -3
- package/dist/engine/cost-guardrails.d.ts +1 -1
- package/dist/engine/cost-guardrails.js +1 -1
- package/dist/engine/criterion-identity.d.ts +1 -0
- package/dist/engine/criterion-identity.js +7 -0
- package/dist/engine/dashboard/data-loader.js +2 -7
- package/dist/engine/dashboard/templates-layout.js +0 -3
- package/dist/engine/dashboard/templates-project.js +1 -13
- package/dist/engine/docs-site-generator/data-collector.d.ts +1 -1
- package/dist/engine/docs-site-generator/data-collector.js +7 -28
- package/dist/engine/docs-site-generator/tools-renderer.js +3 -10
- package/dist/engine/evidence-gates/artifact-reader.d.ts +10 -1
- package/dist/engine/evidence-gates/artifact-reader.js +115 -2
- package/dist/engine/evidence-gates/lifecycle-gate.js +4 -3
- package/dist/engine/evidence-gates/reconciliation-freshness.d.ts +11 -0
- package/dist/engine/evidence-gates/reconciliation-freshness.js +72 -0
- package/dist/engine/evidence-index/done-drift.d.ts +1 -1
- package/dist/engine/evidence-index/done-drift.js +40 -18
- package/dist/engine/execution/context.js +3 -0
- package/dist/engine/execution/durable-job-heartbeat-runtime.d.ts +4 -0
- package/dist/engine/execution/durable-job-heartbeat-runtime.js +400 -0
- package/dist/engine/execution/job-runtime.d.ts +30 -0
- package/dist/engine/execution/job-runtime.js +114 -6
- package/dist/engine/execution/public-job-sanitizer.d.ts +4 -0
- package/dist/engine/execution/public-job-sanitizer.js +31 -0
- package/dist/engine/execution/validate-job-executor.d.ts +12 -1
- package/dist/engine/execution/validate-job-executor.js +549 -86
- package/dist/engine/execution/validate-job-payload.js +107 -50
- package/dist/engine/execution/validate-job-recovery.js +1 -1
- package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
- package/dist/engine/execution/validate-worker-runtime.js +90 -2
- package/dist/engine/execution/validate-worker-thread.js +17 -24
- package/dist/engine/handoff-artifacts/schemas.d.ts +2 -1
- package/dist/engine/handoff-artifacts/schemas.js +33 -0
- package/dist/engine/handoff-packager.d.ts +19 -0
- package/dist/engine/handoff-packager.js +415 -13
- package/dist/engine/hooks/effort-configurator.js +1 -1
- package/dist/engine/impact-detector/test-break-predictor.js +3 -3
- package/dist/engine/impact-detector/tool-registration.js +1 -1
- package/dist/engine/implementation-contract/renderer.js +23 -8
- package/dist/engine/lifecycle-reconciliation-io.d.ts +11 -0
- package/dist/engine/lifecycle-reconciliation-io.js +180 -0
- package/dist/engine/lifecycle-reconciliation.d.ts +16 -0
- package/dist/engine/lifecycle-reconciliation.js +406 -0
- package/dist/engine/local-first/tool-classification.js +2 -0
- package/dist/engine/macos-keychain-native-port.d.ts +5 -0
- package/dist/engine/macos-keychain-native-port.js +19 -7
- package/dist/engine/migrations/remove-commercial-state.d.ts +3 -0
- package/dist/engine/migrations/remove-commercial-state.js +343 -0
- package/dist/engine/network-policy.js +1 -0
- package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-arm64.node.sbom.json +10 -10
- package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
- package/dist/engine/planu-core.darwin-x64.node.sbom.json +10 -10
- package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +10 -10
- package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +10 -10
- package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +10 -10
- package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
- package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +10 -10
- package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +10 -10
- package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
- package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +10 -10
- package/dist/engine/readiness-checker.d.ts +1 -16
- package/dist/engine/readiness-checker.js +27 -88
- package/dist/engine/runtime-policy.d.ts +2 -0
- package/dist/engine/runtime-policy.js +42 -5
- package/dist/engine/runtime-security/rate-limiter.js +0 -1
- package/dist/engine/safety/contained-project-file.d.ts +3 -0
- package/dist/engine/safety/contained-project-file.js +23 -0
- package/dist/engine/scope-boundaries/contradiction-checker.js +63 -1
- package/dist/engine/scope-boundaries/scope-validator.js +45 -7
- package/dist/engine/session/checkpoint-writer.js +0 -9
- package/dist/engine/spec-format/acceptance-criteria.d.ts +6 -2
- package/dist/engine/spec-format/acceptance-criteria.js +77 -18
- package/dist/engine/spec-format/markdown-sections.d.ts +14 -0
- package/dist/engine/spec-format/markdown-sections.js +105 -0
- package/dist/engine/spec-format/read-technical-section.js +33 -5
- package/dist/engine/spec-format/technical-md-populator.js +3 -2
- package/dist/engine/spec-format/unified-spec-builder.d.ts +7 -0
- package/dist/engine/spec-format/unified-spec-builder.js +202 -0
- package/dist/engine/spec-migrator/canonical-deduplicator.d.ts +18 -0
- package/dist/engine/spec-migrator/canonical-deduplicator.js +479 -0
- package/dist/engine/spec-migrator/filesystem-import.d.ts +4 -8
- package/dist/engine/spec-migrator/filesystem-import.js +121 -14
- package/dist/engine/spec-migrator/frontmatter-parser.js +32 -15
- package/dist/engine/spec-migrator/index.d.ts +1 -0
- package/dist/engine/spec-migrator/index.js +1 -0
- package/dist/engine/spec-state-machine/transition-spec.d.ts +6 -1
- package/dist/engine/spec-state-machine/transition-spec.js +10 -1
- package/dist/engine/technical-enricher/index.js +16 -8
- package/dist/engine/technical-enricher/render-enriched.d.ts +1 -0
- package/dist/engine/technical-enricher/render-enriched.js +42 -14
- package/dist/engine/telemetry/health-checker.js +53 -17
- package/dist/engine/telemetry/telemetry-client.js +26 -8
- package/dist/engine/text-signal-boundaries.d.ts +2 -0
- package/dist/engine/text-signal-boundaries.js +25 -2
- package/dist/engine/time/relative-date.d.ts +3 -0
- package/dist/engine/time/relative-date.js +16 -0
- package/dist/engine/timing/budget.d.ts +11 -0
- package/dist/engine/timing/budget.js +27 -9
- package/dist/engine/token-optimizer/analytics.d.ts +1 -1
- package/dist/engine/token-optimizer/analytics.js +5 -6
- package/dist/engine/usage-tracker/core.d.ts +2 -2
- package/dist/engine/usage-tracker/core.js +1 -2
- package/dist/engine/usage-tracker/index.d.ts +0 -3
- package/dist/engine/usage-tracker/index.js +0 -3
- package/dist/engine/usage-tracker/stats.d.ts +2 -2
- package/dist/engine/usage-tracker/stats.js +1 -28
- package/dist/engine/validation/durable-validation.d.ts +1 -1
- package/dist/engine/validation/durable-validation.js +3 -82
- package/dist/engine/validation/validation-freshness.d.ts +11 -1
- package/dist/engine/validation/validation-freshness.js +231 -91
- package/dist/engine/validation/validation-receipt.d.ts +9 -6
- package/dist/engine/validation/validation-receipt.js +84 -24
- package/dist/engine/validation/validation-source-digest.d.ts +2 -0
- package/dist/engine/validation/validation-source-digest.js +86 -0
- package/dist/engine/validation/validation-submission.d.ts +5 -4
- package/dist/engine/validation/validation-submission.js +25 -11
- package/dist/engine/validation/validation-worktree.d.ts +21 -0
- package/dist/engine/validation/validation-worktree.js +260 -0
- package/dist/engine/validation-impact-planner.d.ts +14 -2
- package/dist/engine/validation-impact-planner.js +0 -3
- package/dist/engine/validator/dor-dod.d.ts +1 -0
- package/dist/engine/validator/dor-dod.js +5 -3
- package/dist/engine/validator/extractors.d.ts +1 -5
- package/dist/engine/validator/extractors.js +24 -69
- package/dist/engine/validator/spec-compliance-runner.d.ts +12 -24
- package/dist/engine/validator/spec-compliance-runner.js +429 -211
- package/dist/engine/validator.js +35 -22
- package/dist/index.js +4 -16
- package/dist/resources/usage-stats-resource.js +2 -18
- package/dist/security/adapters/linux-secret-service.js +7 -3
- package/dist/security/adapters/windows-credential-manager.js +6 -4
- package/dist/server/routes/specs.js +10 -0
- package/dist/storage/base-store.d.ts +1 -1
- package/dist/storage/base-store.js +1 -1
- package/dist/storage/feedback-remote.d.ts +2 -3
- package/dist/storage/feedback-remote.js +45 -31
- package/dist/storage/global-store.d.ts +1 -17
- package/dist/storage/global-store.js +1 -42
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/index.js +0 -2
- package/dist/storage/migrations/canonical-storage.js +124 -11
- package/dist/storage/runtime-db.d.ts +9 -0
- package/dist/storage/runtime-db.js +64 -8
- package/dist/storage/spec-store.d.ts +14 -2
- package/dist/storage/spec-store.js +104 -14
- package/dist/storage/status-store/atomic-status-write.d.ts +5 -0
- package/dist/storage/status-store/atomic-status-write.js +57 -0
- package/dist/storage/status-store/file-lock.js +30 -11
- package/dist/storage/status-store/self-healing.js +3 -3
- package/dist/storage/status-store/version-sync.d.ts +2 -1
- package/dist/storage/status-store/version-sync.js +35 -40
- package/dist/storage/usage-store.d.ts +1 -5
- package/dist/storage/usage-store.js +0 -35
- package/dist/tools/auto-update-handler.d.ts +3 -3
- package/dist/tools/auto-update-handler.js +3 -3
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.d.ts +2 -1
- package/dist/tools/challenge-spec/resilience-challenge-scenarios.js +10 -7
- package/dist/tools/challenge-spec/scenario-collector.js +1 -1
- package/dist/tools/challenge-spec/scenarios-data.js +1 -1
- package/dist/tools/challenge-spec/scenarios-utils.d.ts +1 -1
- package/dist/tools/challenge-spec/scenarios-utils.js +35 -11
- package/dist/tools/challenge-spec.js +5 -5
- package/dist/tools/check-readiness.js +1 -1
- package/dist/tools/configure-telemetry.js +30 -2
- package/dist/tools/create-spec/spec-builder.js +0 -11
- package/dist/tools/create-spec.d.ts +1 -0
- package/dist/tools/create-spec.js +444 -239
- package/dist/tools/git/branch-ops.d.ts +1 -1
- package/dist/tools/git/branch-ops.js +3 -2
- package/dist/tools/init-project/handler.js +10 -12
- package/dist/tools/init-project/host-assets-writer.js +26 -1
- package/dist/tools/init-project/lint-scaffolder.d.ts +3 -3
- package/dist/tools/init-project/migration-runner.d.ts +2 -4
- package/dist/tools/init-project/migration-runner.js +3 -2
- package/dist/tools/init-project/portable-index-reconciler.d.ts +4 -0
- package/dist/tools/init-project/portable-index-reconciler.js +14 -0
- package/dist/tools/init-project/result-builder.js +1 -3
- package/dist/tools/jobs/handlers.js +38 -6
- package/dist/tools/list-specs.js +5 -26
- package/dist/tools/merge-risk-handler.js +2 -2
- package/dist/tools/package-handoff.js +2 -0
- package/dist/tools/reconcile-spec.js +0 -27
- package/dist/tools/register-agent-squad-tools.js +2 -2
- package/dist/tools/register-platform-tools/design-stack-tools.js +11 -11
- package/dist/tools/register-platform-tools/lifecycle-infra-tools.js +7 -7
- package/dist/tools/register-sdd-tools.d.ts +1 -1
- package/dist/tools/register-sdd-tools.js +2 -29
- package/dist/tools/register-spec-tools/analysis-tools.js +8 -8
- package/dist/tools/register-spec-tools/core-spec-tools.js +17 -8
- package/dist/tools/safe-handler.d.ts +5 -13
- package/dist/tools/safe-handler.js +7 -23
- package/dist/tools/schemas/index.d.ts +1 -1
- package/dist/tools/schemas/index.js +1 -1
- package/dist/tools/schemas/output-schemas.d.ts +0 -23
- package/dist/tools/schemas/output-schemas.js +0 -28
- package/dist/tools/schemas/spec.d.ts +4 -0
- package/dist/tools/schemas/spec.js +3 -0
- package/dist/tools/schemas/validate-output-schema.d.ts +11 -0
- package/dist/tools/schemas/validate-output-schema.js +7 -0
- package/dist/tools/spec-prompt-handler.js +3 -3
- package/dist/tools/sync-spec-state-handler.d.ts +1 -1
- package/dist/tools/sync-spec-state-handler.js +1 -1
- package/dist/tools/tool-entry.d.ts +4 -4
- package/dist/tools/tool-entry.js +3 -3
- package/dist/tools/tool-registry/core-tools.js +31 -15
- package/dist/tools/tool-registry/group-infra.js +27 -110
- package/dist/tools/tool-registry/group-quality-compliance.js +26 -26
- package/dist/tools/tool-registry/inventory.d.ts +2 -0
- package/dist/tools/tool-registry/inventory.js +2 -0
- package/dist/tools/tool-registry-helpers.d.ts +3 -3
- package/dist/tools/tool-registry-helpers.js +3 -3
- package/dist/tools/tool-usage-report/registered-tools.d.ts +1 -1
- package/dist/tools/tool-usage-report/registered-tools.js +3 -15
- package/dist/tools/update-status/approval-gates.js +3 -0
- package/dist/tools/update-status/done-receipt-verifier.js +40 -27
- package/dist/tools/update-status/evidence-gate.js +36 -1
- package/dist/tools/update-status/file-sync.d.ts +2 -1
- package/dist/tools/update-status/file-sync.js +57 -6
- package/dist/tools/update-status/index.d.ts +2 -0
- package/dist/tools/update-status/index.js +95 -58
- package/dist/tools/update-status/response-builder.js +3 -3
- package/dist/tools/update-status/side-effects.d.ts +2 -0
- package/dist/tools/update-status/side-effects.js +2 -2
- package/dist/tools/update-status/transition-guard.js +32 -15
- package/dist/tools/update-status-actions.d.ts +4 -2
- package/dist/tools/update-status-actions.js +16 -14
- package/dist/tools/usage-report.js +1 -16
- package/dist/tools/usage-stats.js +1 -18
- package/dist/tools/usage-tracking.d.ts +4 -0
- package/dist/tools/usage-tracking.js +20 -0
- package/dist/tools/validate-lint.d.ts +1 -0
- package/dist/tools/validate-lint.js +1 -1
- package/dist/tools/validate.d.ts +2 -1
- package/dist/tools/validate.js +114 -34
- package/dist/transports/http-transport.js +6 -8
- package/dist/transports/mcp-types.d.ts +0 -2
- package/dist/transports/session-context.js +1 -1
- package/dist/types/cascade-hooks.d.ts +1 -1
- package/dist/types/ci.d.ts +0 -4
- package/dist/types/clarification-token.d.ts +1 -1
- package/dist/types/claude-code-runtime.d.ts +0 -27
- package/dist/types/commercial-migration.d.ts +17 -0
- package/dist/types/commercial-migration.js +2 -0
- package/dist/types/common/primitives.d.ts +0 -2
- package/dist/types/core-bridge.d.ts +4 -10
- package/dist/types/dashboard.d.ts +3 -7
- package/dist/types/docs.d.ts +0 -1
- package/dist/types/durable-job.d.ts +4 -4
- package/dist/types/durable-validation.d.ts +100 -2
- package/dist/types/durable-validation.js +165 -1
- package/dist/types/errors/structured-error.d.ts +3 -3
- package/dist/types/estimation.d.ts +2 -0
- package/dist/types/evidence-gates.d.ts +9 -1
- package/dist/types/execution.d.ts +2 -0
- package/dist/types/gemini-integration.d.ts +0 -11
- package/dist/types/handoff-artifacts.d.ts +41 -0
- package/dist/types/hooks-advanced.d.ts +0 -13
- package/dist/types/impact-detection.d.ts +2 -2
- package/dist/types/index.d.ts +2 -6
- package/dist/types/index.js +1 -5
- package/dist/types/kiro-integration.d.ts +0 -6
- package/dist/types/network-policy.d.ts +1 -1
- package/dist/types/project/lint-scaffolder.d.ts +1 -1
- package/dist/types/runtime-policy.d.ts +11 -0
- package/dist/types/session-safeguard.d.ts +0 -31
- package/dist/types/spec/canonical-repair.d.ts +81 -0
- package/dist/types/spec/canonical-repair.js +2 -0
- package/dist/types/spec/core.d.ts +14 -0
- package/dist/types/spec/index.d.ts +1 -0
- package/dist/types/spec/index.js +1 -0
- package/dist/types/spec/inputs.d.ts +29 -0
- package/dist/types/spec-format.d.ts +24 -0
- package/dist/types/telemetry.d.ts +4 -1
- package/dist/types/transport.d.ts +0 -2
- package/dist/types/usage.d.ts +1 -36
- package/dist/types/usage.js +1 -1
- package/dist/types/validate-worker.d.ts +6 -0
- package/dist/types/validation-receipt.d.ts +1 -1
- package/dist/types/validation.d.ts +2 -2
- package/package.json +16 -12
- package/planu-native.json +1 -1
- package/planu-plugin.json +23 -40
- package/scripts/lib/pending-release-file.mjs +93 -0
- package/src/i18n/messages/en.json +0 -41
- package/src/i18n/messages/es.json +0 -41
- package/src/i18n/messages/pt.json +0 -41
- package/dist/cli/commands/activate.d.ts +0 -14
- package/dist/cli/commands/activate.js +0 -174
- package/dist/config/license-plans.json +0 -251
- package/dist/config/product-public.ts +0 -148
- package/dist/config/server-instructions.ts +0 -121
- package/dist/config/version-defaults.ts +0 -76
- package/dist/config/version.ts +0 -21
- package/dist/engine/ai-integration/gemini/settings-generator.d.ts +0 -4
- package/dist/engine/ai-integration/gemini/settings-generator.js +0 -195
- package/dist/engine/ai-integration/kiro/hooks-generator.d.ts +0 -6
- package/dist/engine/ai-integration/kiro/hooks-generator.js +0 -75
- package/dist/engine/hooks/full-spectrum-generator.d.ts +0 -32
- package/dist/engine/hooks/full-spectrum-generator.js +0 -117
- package/dist/engine/license-validator/config-loader.d.ts +0 -5
- package/dist/engine/license-validator/config-loader.js +0 -16
- package/dist/engine/license-validator/core.d.ts +0 -15
- package/dist/engine/license-validator/core.js +0 -151
- package/dist/engine/license-validator/fingerprint.d.ts +0 -3
- package/dist/engine/license-validator/fingerprint.js +0 -17
- package/dist/engine/license-validator/lemon-squeezy.d.ts +0 -5
- package/dist/engine/license-validator/lemon-squeezy.js +0 -55
- package/dist/engine/license-validator.d.ts +0 -5
- package/dist/engine/license-validator.js +0 -6
- package/dist/engine/product-intelligence/index.d.ts +0 -7
- package/dist/engine/product-intelligence/index.js +0 -211
- package/dist/engine/session/auto-save.d.ts +0 -18
- package/dist/engine/session/auto-save.js +0 -98
- package/dist/engine/session/context-snapshot.d.ts +0 -8
- package/dist/engine/session/context-snapshot.js +0 -49
- package/dist/engine/session/memory-sync.d.ts +0 -12
- package/dist/engine/session/memory-sync.js +0 -34
- package/dist/engine/session/session-diff.d.ts +0 -11
- package/dist/engine/session/session-diff.js +0 -42
- package/dist/engine/session/session-merge.d.ts +0 -12
- package/dist/engine/session/session-merge.js +0 -55
- package/dist/engine/session-safeguard/checkpoint-runner.d.ts +0 -4
- package/dist/engine/session-safeguard/checkpoint-runner.js +0 -70
- package/dist/engine/session-safeguard/learnings-buffer.d.ts +0 -15
- package/dist/engine/session-safeguard/learnings-buffer.js +0 -91
- package/dist/engine/session-safeguard/precompaction-drain.d.ts +0 -10
- package/dist/engine/session-safeguard/precompaction-drain.js +0 -82
- package/dist/engine/session-safeguard/unpushed-detector.d.ts +0 -7
- package/dist/engine/session-safeguard/unpushed-detector.js +0 -59
- package/dist/engine/spec-changelog/core.d.ts +0 -16
- package/dist/engine/spec-changelog/core.js +0 -176
- package/dist/engine/spec-changelog/diff.d.ts +0 -18
- package/dist/engine/spec-changelog/diff.js +0 -121
- package/dist/engine/spec-changelog/index.d.ts +0 -3
- package/dist/engine/spec-changelog/index.js +0 -4
- package/dist/engine/trial-engine.d.ts +0 -5
- package/dist/engine/trial-engine.js +0 -14
- package/dist/engine/usage-tracker/rate-check.d.ts +0 -7
- package/dist/engine/usage-tracker/rate-check.js +0 -18
- package/dist/engine/usage-tracker/rate-limiter.d.ts +0 -14
- package/dist/engine/usage-tracker/rate-limiter.js +0 -73
- package/dist/engine/usage-tracker/trial.d.ts +0 -27
- package/dist/engine/usage-tracker/trial.js +0 -49
- package/dist/engine/webhook/event-handlers.d.ts +0 -25
- package/dist/engine/webhook/event-handlers.js +0 -89
- package/dist/engine/webhook/index.d.ts +0 -4
- package/dist/engine/webhook/index.js +0 -5
- package/dist/engine/webhook/server.d.ts +0 -12
- package/dist/engine/webhook/server.js +0 -249
- package/dist/engine/webhook/signature.d.ts +0 -16
- package/dist/engine/webhook/signature.js +0 -49
- package/dist/storage/license-store.d.ts +0 -6
- package/dist/storage/license-store.js +0 -63
- package/dist/storage/session-store.d.ts +0 -20
- package/dist/storage/session-store.js +0 -136
- package/dist/tools/activate-license.d.ts +0 -6
- package/dist/tools/activate-license.js +0 -132
- package/dist/tools/checkpoint-handler.d.ts +0 -3
- package/dist/tools/checkpoint-handler.js +0 -130
- package/dist/tools/export-session.d.ts +0 -3
- package/dist/tools/export-session.js +0 -90
- package/dist/tools/license-gate.d.ts +0 -18
- package/dist/tools/license-gate.js +0 -222
- package/dist/tools/license-status.d.ts +0 -3
- package/dist/tools/license-status.js +0 -93
- package/dist/tools/list-sessions.d.ts +0 -3
- package/dist/tools/list-sessions.js +0 -46
- package/dist/tools/planu-session-checkpoint.d.ts +0 -6
- package/dist/tools/planu-session-checkpoint.js +0 -42
- package/dist/tools/restore-session.d.ts +0 -3
- package/dist/tools/restore-session.js +0 -71
- package/dist/tools/spec-history.d.ts +0 -3
- package/dist/tools/spec-history.js +0 -59
- package/dist/tools/webhook.d.ts +0 -6
- package/dist/tools/webhook.js +0 -150
- package/dist/types/changelog.d.ts +0 -49
- package/dist/types/changelog.js +0 -3
- package/dist/types/licensing.d.ts +0 -109
- package/dist/types/licensing.js +0 -4
- package/dist/types/product-intelligence.d.ts +0 -60
- package/dist/types/product-intelligence.js +0 -3
- package/dist/types/session.d.ts +0 -84
- package/dist/types/session.js +0 -3
- package/dist/types/webhook.d.ts +0 -62
- package/dist/types/webhook.js +0 -4
|
@@ -26,7 +26,7 @@ export declare function detectTechnicalPlaceholder(body: string): boolean;
|
|
|
26
26
|
/**
|
|
27
27
|
* SPEC-784: Returns true when the ## Technical body is too shallow:
|
|
28
28
|
* fewer than TECHNICAL_MIN_CHARS characters AND contains zero file
|
|
29
|
-
*
|
|
29
|
+
* safe repository-relative file paths.
|
|
30
30
|
*/
|
|
31
31
|
export declare function detectTechnicalTooShallow(body: string): boolean;
|
|
32
32
|
/**
|
|
@@ -47,20 +47,5 @@ export declare function extractFilePaths(text: string): Set<string>;
|
|
|
47
47
|
* - Inline: createFoo() detectBar(arg)
|
|
48
48
|
*/
|
|
49
49
|
export declare function extractFunctionNames(text: string): Set<string>;
|
|
50
|
-
/**
|
|
51
|
-
* SPEC-769: Pure in-memory readiness check — no file I/O.
|
|
52
|
-
* Accepts the raw spec.md content (including frontmatter) and returns a quick
|
|
53
|
-
* score + warnings without loading technical.md or any additional file.
|
|
54
|
-
*
|
|
55
|
-
* Scoring (max 100):
|
|
56
|
-
* - Base (title/metadata present): 20
|
|
57
|
-
* - Criteria: 0 | 20 | 35 | 50 (0 / 1-2 / 3-4 / 5+)
|
|
58
|
-
* - Technical files (src/*.ts paths found in body): 30
|
|
59
|
-
*/
|
|
60
|
-
export declare function checkReadinessInternal(body: string): {
|
|
61
|
-
score: number;
|
|
62
|
-
warnings: string[];
|
|
63
|
-
criteriaCount: number;
|
|
64
|
-
};
|
|
65
50
|
export declare function checkSpecReadiness(spec: Spec, mode: 'strict' | 'lenient', projectHash?: string): Promise<ReadinessReport>;
|
|
66
51
|
//# sourceMappingURL=readiness-checker.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// engine/readiness-checker.ts — Spec readiness evaluation for implementation gate (SPEC-039)
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { readSpecTechnicalSection } from './spec-format/read-technical-section.js';
|
|
3
|
+
import { extractSectionBody, readSpecTechnicalSection, } from './spec-format/read-technical-section.js';
|
|
4
4
|
import { stripFrontmatter } from './frontmatter-parser.js';
|
|
5
5
|
import { loadReadinessConfig } from './readiness-config-loader.js';
|
|
6
6
|
import { runEarsGate } from './ears-gate.js';
|
|
@@ -233,7 +233,7 @@ export function detectTechnicalPlaceholder(body) {
|
|
|
233
233
|
/**
|
|
234
234
|
* SPEC-784: Returns true when the ## Technical body is too shallow:
|
|
235
235
|
* fewer than TECHNICAL_MIN_CHARS characters AND contains zero file
|
|
236
|
-
*
|
|
236
|
+
* safe repository-relative file paths.
|
|
237
237
|
*/
|
|
238
238
|
export function detectTechnicalTooShallow(body) {
|
|
239
239
|
const section = extractTechnicalSection(body);
|
|
@@ -244,9 +244,7 @@ export function detectTechnicalTooShallow(body) {
|
|
|
244
244
|
if (section.length >= TECHNICAL_MIN_CHARS) {
|
|
245
245
|
return false;
|
|
246
246
|
}
|
|
247
|
-
|
|
248
|
-
const hasFilePaths = /\b(?:src|tests)\/[a-zA-Z0-9/_.-]+\.[a-z]+\b/.test(section);
|
|
249
|
-
return !hasFilePaths;
|
|
247
|
+
return extractFilePaths(section).size === 0;
|
|
250
248
|
}
|
|
251
249
|
// ── SPEC-629 / SPEC-777: Specificity gate helpers ────────────────────────────
|
|
252
250
|
/**
|
|
@@ -260,18 +258,27 @@ export function detectTechnicalTooShallow(body) {
|
|
|
260
258
|
*/
|
|
261
259
|
export function extractFilePaths(text) {
|
|
262
260
|
const found = new Set();
|
|
263
|
-
|
|
264
|
-
// Works inside backticks, after commas/spaces, after FILES: markers
|
|
265
|
-
const RE = /(?:[`\s,]|^|FILES:\s*)([a-zA-Z][a-zA-Z0-9_-]*(?:\/[a-zA-Z0-9_.-]+)+\.[a-zA-Z]{1,6})(?=[`\s,\n)]|$)/g;
|
|
261
|
+
const RE = /(?<![a-zA-Z0-9_./\\-])([a-zA-Z0-9_.-]+(?:\/[a-zA-Z0-9_.-]+)*\.[a-zA-Z][a-zA-Z0-9]*)(?=[`"'\s,):;.!?]|$)/g;
|
|
266
262
|
let m;
|
|
267
263
|
while ((m = RE.exec(text)) !== null) {
|
|
268
264
|
const p = m[1];
|
|
269
|
-
if (p !== undefined) {
|
|
265
|
+
if (p !== undefined && isSafeRepositoryFilePath(p)) {
|
|
270
266
|
found.add(p);
|
|
271
267
|
}
|
|
272
268
|
}
|
|
273
269
|
return found;
|
|
274
270
|
}
|
|
271
|
+
function isSafeRepositoryFilePath(path) {
|
|
272
|
+
const segments = path.split('/');
|
|
273
|
+
const filename = segments.at(-1) ?? '';
|
|
274
|
+
const extensionIndex = filename.lastIndexOf('.');
|
|
275
|
+
return (path.length > 0 &&
|
|
276
|
+
!path.startsWith('/') &&
|
|
277
|
+
!/^[a-zA-Z]:/u.test(path) &&
|
|
278
|
+
segments.every((segment) => segment.length > 0 && segment !== '.' && segment !== '..') &&
|
|
279
|
+
extensionIndex > 0 &&
|
|
280
|
+
extensionIndex < filename.length - 1);
|
|
281
|
+
}
|
|
275
282
|
/**
|
|
276
283
|
* Extract function/method names from text.
|
|
277
284
|
* Recognises:
|
|
@@ -294,27 +301,21 @@ export function extractFunctionNames(text) {
|
|
|
294
301
|
// ── SPEC-629: Specificity gate (difficulty >= 3) ────────────────────────────
|
|
295
302
|
/**
|
|
296
303
|
* For specs with difficulty >= 3, enforces that criteria contain:
|
|
297
|
-
* - 3+ concrete file paths
|
|
304
|
+
* - 3+ concrete repository-relative file paths
|
|
298
305
|
* - 1+ criterion with exact function/type name
|
|
299
306
|
* - 1+ anticipated test break (file + line number)
|
|
300
307
|
* Returns blocker strings; empty array = gate passed.
|
|
301
308
|
*/
|
|
302
|
-
function checkSpecificityGate(spec, criteriaLines, fichaContent) {
|
|
309
|
+
function checkSpecificityGate(spec, criteriaLines, fichaContent, anticipatedTestBreaksContent) {
|
|
303
310
|
if (spec.difficulty < 3) {
|
|
304
311
|
return [];
|
|
305
312
|
}
|
|
306
313
|
const allText = [...criteriaLines, fichaContent].join('\n');
|
|
307
314
|
const blockers = [];
|
|
308
|
-
// Count distinct file paths in src/ or tests/ — use enhanced extractor (SPEC-777)
|
|
309
315
|
const uniquePaths = extractFilePaths(allText);
|
|
310
|
-
// Also keep the legacy word-boundary regex for backward compat with bare paths not in backticks
|
|
311
|
-
const legacyMatches = allText.match(/\b(?:src|tests)\/[a-zA-Z0-9/_.-]+\.[a-z]+\b/g) ?? [];
|
|
312
|
-
for (const p of legacyMatches) {
|
|
313
|
-
uniquePaths.add(p);
|
|
314
|
-
}
|
|
315
316
|
if (uniquePaths.size < 3) {
|
|
316
|
-
blockers.push(`Difficulty ${String(spec.difficulty)} spec requires 3+ concrete file paths in criteria
|
|
317
|
-
`Add exact paths like '
|
|
317
|
+
blockers.push(`Difficulty ${String(spec.difficulty)} spec requires 3+ concrete repository-relative file paths in criteria — found ${String(uniquePaths.size)}. ` +
|
|
318
|
+
`Add exact paths like 'scripts/check-contract.mjs'.`);
|
|
318
319
|
}
|
|
319
320
|
// Detect function calls via enhanced extractor + legacy regex (SPEC-777)
|
|
320
321
|
const functionNames = extractFunctionNames(allText);
|
|
@@ -325,7 +326,8 @@ function checkSpecificityGate(spec, criteriaLines, fichaContent) {
|
|
|
325
326
|
}
|
|
326
327
|
// Detect anticipated test breaks: a test file path + "line N" (with optional ~) or "change ... from ... to"
|
|
327
328
|
const hasTestBreak = /\btests?\/[a-zA-Z0-9/_.-]+\.test\.[a-z]+.*\bline\s+~?\d+/i.test(allText) ||
|
|
328
|
-
/\bchange\b.*\bfrom\b.*\bto\b/i.test(allText)
|
|
329
|
+
/\bchange\b.*\bfrom\b.*\bto\b/i.test(allText) ||
|
|
330
|
+
/\btests\/[a-zA-Z0-9/_.-]+\.test\.[a-z0-9]+(?![a-zA-Z0-9_.\\/-])[^\n]*\bline\s+~?\d+/i.test(anticipatedTestBreaksContent);
|
|
329
331
|
if (!hasTestBreak) {
|
|
330
332
|
blockers.push(`Difficulty ${String(spec.difficulty)} spec requires at least 1 anticipated test break ` +
|
|
331
333
|
`(e.g. 'tests/api/foo.test.ts line 47: change count from 477 to 478').`);
|
|
@@ -333,76 +335,12 @@ function checkSpecificityGate(spec, criteriaLines, fichaContent) {
|
|
|
333
335
|
return blockers;
|
|
334
336
|
}
|
|
335
337
|
// ── Public API ───────────────────────────────────────────────────────────────
|
|
336
|
-
/**
|
|
337
|
-
* SPEC-769: Pure in-memory readiness check — no file I/O.
|
|
338
|
-
* Accepts the raw spec.md content (including frontmatter) and returns a quick
|
|
339
|
-
* score + warnings without loading technical.md or any additional file.
|
|
340
|
-
*
|
|
341
|
-
* Scoring (max 100):
|
|
342
|
-
* - Base (title/metadata present): 20
|
|
343
|
-
* - Criteria: 0 | 20 | 35 | 50 (0 / 1-2 / 3-4 / 5+)
|
|
344
|
-
* - Technical files (src/*.ts paths found in body): 30
|
|
345
|
-
*/
|
|
346
|
-
export function checkReadinessInternal(body) {
|
|
347
|
-
const bodyContent = stripFrontmatter(body);
|
|
348
|
-
const normalizedCriteria = extractNormalizedAcceptanceCriteria(body);
|
|
349
|
-
const criteriaLines = normalizedCriteria.map((criterion) => criterion.text);
|
|
350
|
-
const scenarioCount = criteriaLines.length === 0 ? countFrontmatterScenarios(body) : 0;
|
|
351
|
-
const criteriaCount = criteriaLines.length > 0 ? criteriaLines.length : scenarioCount;
|
|
352
|
-
const config = loadReadinessConfig();
|
|
353
|
-
const vagueWords = config.vagueWords.map((v) => v.word);
|
|
354
|
-
const warnings = [];
|
|
355
|
-
// Score based on criteria count
|
|
356
|
-
let criteriaScore;
|
|
357
|
-
if (criteriaCount === 0) {
|
|
358
|
-
criteriaScore = 0;
|
|
359
|
-
warnings.push('No acceptance criteria found — add at least 3 testable criteria');
|
|
360
|
-
}
|
|
361
|
-
else if (criteriaCount >= 5) {
|
|
362
|
-
criteriaScore = 50;
|
|
363
|
-
}
|
|
364
|
-
else if (criteriaCount >= 3) {
|
|
365
|
-
criteriaScore = 35;
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
criteriaScore = 20;
|
|
369
|
-
warnings.push('Add more acceptance criteria (need at least 3 for adequate readiness)');
|
|
370
|
-
}
|
|
371
|
-
// Vague criteria detection (re-uses existing logic)
|
|
372
|
-
const criteriaResult = scoreCriteria(criteriaLines.length > 0 ? criteriaLines : [], vagueWords);
|
|
373
|
-
warnings.push(...criteriaResult.warnings);
|
|
374
|
-
// Technical files presence (proxy for inline ## Technical — check src/ paths in body)
|
|
375
|
-
const hasTechnicalFiles = /\bsrc\/[^\s]+\.[jt]s\b/.test(bodyContent);
|
|
376
|
-
const technicalScore = hasTechnicalFiles ? 30 : 0;
|
|
377
|
-
if (!hasTechnicalFiles && criteriaCount > 0) {
|
|
378
|
-
warnings.push('No source file paths (e.g. src/engine/foo.ts) found — add file entries in ## Technical section');
|
|
379
|
-
}
|
|
380
|
-
// SPEC-784: Technical section quality gates
|
|
381
|
-
// Run both detectors against the raw body (includes ## Technical heading)
|
|
382
|
-
if (detectTechnicalPlaceholder(bodyContent)) {
|
|
383
|
-
warnings.push('TECHNICAL_PLACEHOLDER_DETECTED: ## Technical section contains a placeholder pointer ' +
|
|
384
|
-
'(e.g. "See technical.md") — inline the content instead of deferring to another file');
|
|
385
|
-
}
|
|
386
|
-
if (detectTechnicalTooShallow(bodyContent)) {
|
|
387
|
-
warnings.push('TECHNICAL_TOO_SHALLOW: ## Technical section is too short (< 500 chars) and has no ' +
|
|
388
|
-
'src/ or tests/ file paths — add concrete file paths and implementation details');
|
|
389
|
-
}
|
|
390
|
-
// Base points (title present, valid structure)
|
|
391
|
-
const baseScore = 20;
|
|
392
|
-
// When any SPEC-784 technical blocker is present, cap the score at 0 so the
|
|
393
|
-
// approval gate hard-blocks (score < 70 with no-forceApprove path).
|
|
394
|
-
const technicalBlockerCount = warnings.filter((w) => w.startsWith('TECHNICAL_PLACEHOLDER_DETECTED') || w.startsWith('TECHNICAL_TOO_SHALLOW')).length;
|
|
395
|
-
if (technicalBlockerCount > 0) {
|
|
396
|
-
return { score: 0, warnings, criteriaCount };
|
|
397
|
-
}
|
|
398
|
-
const score = Math.min(100, baseScore + criteriaScore + technicalScore);
|
|
399
|
-
return { score, warnings, criteriaCount };
|
|
400
|
-
}
|
|
401
338
|
export async function checkSpecReadiness(spec, mode, projectHash) {
|
|
402
339
|
const config = loadReadinessConfig(projectHash);
|
|
403
340
|
const vagueWords = config.vagueWords.map((v) => v.word);
|
|
404
341
|
const huRaw = await readHuRaw(spec);
|
|
405
342
|
const huContent = stripFrontmatter(huRaw);
|
|
343
|
+
const anticipatedTestBreaksContent = extractSectionBody(huRaw, 'Anticipated Test Breaks');
|
|
406
344
|
const fichaContent = await readFichaContent(spec);
|
|
407
345
|
const normalizedCriteria = extractNormalizedAcceptanceCriteria(huRaw);
|
|
408
346
|
const canonicalCriteriaLines = normalizedCriteria.map((criterion) => criterion.text);
|
|
@@ -414,6 +352,7 @@ export async function checkSpecReadiness(spec, mode, projectHash) {
|
|
|
414
352
|
// evidence model so specificity gates still see exact test paths and line refs.
|
|
415
353
|
const scenarioCriteria = usesFrontmatterAsCanonical ? frontmatterScenarioCriteria(huRaw) : [];
|
|
416
354
|
const effectiveCriteriaLines = scenarioCriteria.length > 0 ? scenarioCriteria : canonicalCriteriaLines;
|
|
355
|
+
const specificityEvidenceLines = [...scenarioCriteria, ...extractCriteriaLines(huContent)];
|
|
417
356
|
const hu = scoreHuCompleteness(spec);
|
|
418
357
|
const criteria = scoreCriteria(effectiveCriteriaLines, vagueWords);
|
|
419
358
|
const files = scoreFilesIdentified(spec, fichaContent);
|
|
@@ -450,11 +389,11 @@ export async function checkSpecReadiness(spec, mode, projectHash) {
|
|
|
450
389
|
}
|
|
451
390
|
if (detectTechnicalTooShallow(huContent)) {
|
|
452
391
|
allBlockers.push('TECHNICAL_TOO_SHALLOW: ## Technical section is too short (< 500 chars) and has no ' +
|
|
453
|
-
'
|
|
392
|
+
'repository-relative file paths — add concrete file paths and implementation details');
|
|
454
393
|
}
|
|
455
394
|
// SPEC-629: Specificity gate caps score at 60 for difficulty >= 3 specs that lack
|
|
456
395
|
// concrete file paths, function names, or anticipated test breaks.
|
|
457
|
-
const specificityBlockers = checkSpecificityGate(spec,
|
|
396
|
+
const specificityBlockers = checkSpecificityGate(spec, specificityEvidenceLines, fichaContent, anticipatedTestBreaksContent);
|
|
458
397
|
allBlockers.push(...specificityBlockers);
|
|
459
398
|
const effectiveScore = specificityBlockers.length > 0 && spec.difficulty >= 3 ? Math.min(totalScore, 60) : totalScore;
|
|
460
399
|
const breakdown = {
|
|
@@ -481,7 +420,7 @@ export async function checkSpecReadiness(spec, mode, projectHash) {
|
|
|
481
420
|
const isReady = effectiveScore >= cautionThreshold && allBlockers.length === 0;
|
|
482
421
|
const recommendations = buildRecommendations(effectiveScore, hu.points, criteria.points, files.points, deps.points);
|
|
483
422
|
if (specificityBlockers.length > 0) {
|
|
484
|
-
recommendations.push('Add exact file paths
|
|
423
|
+
recommendations.push('Add exact repository-relative file paths, function names (e.g. createFoo()), and anticipated test breaks to unlock implementation for this difficulty spec.');
|
|
485
424
|
}
|
|
486
425
|
return {
|
|
487
426
|
specId: spec.id,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { BoundedDurationPolicy, RuntimePolicy } from '../types/runtime-policy.js';
|
|
2
|
+
/** Validate an in-memory policy fixture without mutating the process cache. */
|
|
3
|
+
export declare function parseRuntimePolicyForTests(raw: unknown): RuntimePolicy;
|
|
2
4
|
/** Load the validated bundled runtime authority once per process. */
|
|
3
5
|
export declare function getRuntimePolicy(): RuntimePolicy;
|
|
4
6
|
/** Resolve a numeric environment override without duplicating policy bounds. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
+
import { PROCESS_TERMINATION_GRACE_MS } from './abortable-process-runner.js';
|
|
3
4
|
const boundedDurationSchema = z
|
|
4
5
|
.object({
|
|
5
6
|
defaultTimeoutMs: z.number().int().positive(),
|
|
@@ -45,11 +46,22 @@ const runtimePolicySchema = z
|
|
|
45
46
|
validation: z
|
|
46
47
|
.object({
|
|
47
48
|
defaultDeadlineMs: z.number().int().positive(),
|
|
49
|
+
durableLintTimeoutMs: z.number().int().positive(),
|
|
50
|
+
complianceCommandTimeoutMs: z.number().int().positive(),
|
|
51
|
+
noProgressTimeoutMs: z.number().int().positive(),
|
|
48
52
|
submissionLockWaitMs: z.number().int().positive(),
|
|
49
53
|
submissionLockPollMs: z.number().int().positive(),
|
|
50
54
|
workerLeaseMs: z.number().int().positive(),
|
|
51
55
|
workerHeartbeatMs: z.number().int().positive(),
|
|
52
56
|
workerConcurrency: z.number().int().positive(),
|
|
57
|
+
heartbeatStartupTimeoutMs: z.number().int().positive(),
|
|
58
|
+
heartbeatShutdownTimeoutMs: z.number().int().positive(),
|
|
59
|
+
heartbeatDatabaseBusyTimeoutMs: z.number().int().positive(),
|
|
60
|
+
freshnessLeaseTtlMs: z.number().int().positive(),
|
|
61
|
+
freshnessInvalidationCoalesceMs: z.number().int().positive(),
|
|
62
|
+
receiptPublicationDeadlineMs: z.number().int().positive(),
|
|
63
|
+
receiptCheckpointLogMaxBytes: z.number().int().positive(),
|
|
64
|
+
receiptCheckpointResultMaxBytes: z.number().int().positive(),
|
|
53
65
|
})
|
|
54
66
|
.strict()
|
|
55
67
|
.refine((value) => value.submissionLockPollMs < value.submissionLockWaitMs, {
|
|
@@ -57,6 +69,27 @@ const runtimePolicySchema = z
|
|
|
57
69
|
})
|
|
58
70
|
.refine((value) => value.workerHeartbeatMs < value.workerLeaseMs, {
|
|
59
71
|
message: 'workerHeartbeatMs must be below workerLeaseMs',
|
|
72
|
+
})
|
|
73
|
+
.refine((value) => value.durableLintTimeoutMs < value.complianceCommandTimeoutMs, {
|
|
74
|
+
message: 'durableLintTimeoutMs must be below complianceCommandTimeoutMs',
|
|
75
|
+
})
|
|
76
|
+
.refine((value) => value.complianceCommandTimeoutMs + PROCESS_TERMINATION_GRACE_MS <
|
|
77
|
+
value.noProgressTimeoutMs, {
|
|
78
|
+
message: 'complianceCommandTimeoutMs plus termination grace must be below noProgressTimeoutMs',
|
|
79
|
+
})
|
|
80
|
+
.refine((value) => value.complianceCommandTimeoutMs < value.defaultDeadlineMs, {
|
|
81
|
+
message: 'complianceCommandTimeoutMs must be below defaultDeadlineMs',
|
|
82
|
+
})
|
|
83
|
+
.refine((value) => value.noProgressTimeoutMs < value.defaultDeadlineMs, {
|
|
84
|
+
message: 'noProgressTimeoutMs must be below defaultDeadlineMs',
|
|
85
|
+
})
|
|
86
|
+
.refine((value) => value.heartbeatDatabaseBusyTimeoutMs < value.workerLeaseMs - value.workerHeartbeatMs, { message: 'heartbeatDatabaseBusyTimeoutMs must fit within the worker lease' })
|
|
87
|
+
.refine((value) => value.freshnessInvalidationCoalesceMs < value.freshnessLeaseTtlMs, {
|
|
88
|
+
message: 'freshnessInvalidationCoalesceMs must be below freshnessLeaseTtlMs',
|
|
89
|
+
})
|
|
90
|
+
.refine((value) => value.receiptPublicationDeadlineMs <= value.workerLeaseMs - value.workerHeartbeatMs, { message: 'receiptPublicationDeadlineMs must fit within the worker lease' })
|
|
91
|
+
.refine((value) => value.receiptCheckpointLogMaxBytes <= value.receiptCheckpointResultMaxBytes, {
|
|
92
|
+
message: 'receiptCheckpointLogMaxBytes must not exceed receiptCheckpointResultMaxBytes',
|
|
60
93
|
}),
|
|
61
94
|
postCommit: z
|
|
62
95
|
.object({
|
|
@@ -71,15 +104,19 @@ const runtimePolicySchema = z
|
|
|
71
104
|
.strict();
|
|
72
105
|
const require = createRequire(import.meta.url);
|
|
73
106
|
let cachedPolicy;
|
|
107
|
+
/** Validate an in-memory policy fixture without mutating the process cache. */
|
|
108
|
+
export function parseRuntimePolicyForTests(raw) {
|
|
109
|
+
const parsed = runtimePolicySchema.safeParse(raw);
|
|
110
|
+
if (!parsed.success) {
|
|
111
|
+
throw new Error(`Invalid bundled runtime-policy config: ${parsed.error.message}`);
|
|
112
|
+
}
|
|
113
|
+
return parsed.data;
|
|
114
|
+
}
|
|
74
115
|
/** Load the validated bundled runtime authority once per process. */
|
|
75
116
|
export function getRuntimePolicy() {
|
|
76
117
|
if (cachedPolicy === undefined) {
|
|
77
118
|
const raw = require('../config/runtime-policy.json');
|
|
78
|
-
|
|
79
|
-
if (!parsed.success) {
|
|
80
|
-
throw new Error(`Invalid bundled runtime-policy config: ${parsed.error.message}`);
|
|
81
|
-
}
|
|
82
|
-
cachedPolicy = parsed.data;
|
|
119
|
+
cachedPolicy = parseRuntimePolicyForTests(raw);
|
|
83
120
|
}
|
|
84
121
|
return cachedPolicy;
|
|
85
122
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { lstat, realpath } from 'node:fs/promises';
|
|
2
|
+
import { isAbsolute, relative, resolve, sep } from 'node:path';
|
|
3
|
+
function isOutside(root, candidate) {
|
|
4
|
+
const pathFromRoot = relative(root, candidate);
|
|
5
|
+
return pathFromRoot === '..' || pathFromRoot.startsWith(`..${sep}`) || isAbsolute(pathFromRoot);
|
|
6
|
+
}
|
|
7
|
+
/** Resolve a currently existing regular file whose physical path is contained by a project root. */
|
|
8
|
+
export async function resolveContainedProjectFile(projectPath, candidatePath) {
|
|
9
|
+
const lexicalRoot = resolve(projectPath);
|
|
10
|
+
const lexicalCandidate = resolve(candidatePath);
|
|
11
|
+
const [projectRealPath, candidateRealPath, candidateStatus] = await Promise.all([
|
|
12
|
+
realpath(lexicalRoot),
|
|
13
|
+
realpath(lexicalCandidate),
|
|
14
|
+
lstat(lexicalCandidate),
|
|
15
|
+
]);
|
|
16
|
+
if (candidateStatus.isSymbolicLink() ||
|
|
17
|
+
!candidateStatus.isFile() ||
|
|
18
|
+
isOutside(projectRealPath, candidateRealPath)) {
|
|
19
|
+
throw new Error('CONTAINED_PROJECT_FILE_REJECTED: candidate is not a contained regular file');
|
|
20
|
+
}
|
|
21
|
+
return candidateRealPath;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=contained-project-file.js.map
|
|
@@ -43,6 +43,58 @@ function keywords(phrase) {
|
|
|
43
43
|
.split(' ')
|
|
44
44
|
.filter((w) => w.length > 3 && !STOP_WORDS.has(w));
|
|
45
45
|
}
|
|
46
|
+
/** Return true only for explicit language that preserves an existing boundary. */
|
|
47
|
+
function preservesBoundary(text) {
|
|
48
|
+
const normalized = normalize(text);
|
|
49
|
+
return [
|
|
50
|
+
/\bremains? unchanged\b/,
|
|
51
|
+
/\bkeeps?\b.{0,80}\bunchanged\b/,
|
|
52
|
+
/\bpreserves?\b.{0,80}\b(?:behavior|contract|boundary|semantics|state)\b/,
|
|
53
|
+
/\bwithout (?:any )?(?:changing|modifying|altering|adding|introducing)\b/,
|
|
54
|
+
/\b(?:does|do|must|will|should) not (?:change|modify|alter|add|introduce|implement|enable)\b/,
|
|
55
|
+
/\bno changes? to\b/,
|
|
56
|
+
].some((pattern) => pattern.test(normalized));
|
|
57
|
+
}
|
|
58
|
+
function splitClauses(text) {
|
|
59
|
+
return text
|
|
60
|
+
.split(/\b(?:but|while|although|however)\b|[,;.]/i)
|
|
61
|
+
.map((clause) => clause.trim())
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
}
|
|
64
|
+
function hasAffirmativeDrift(text, outOfScopeItem) {
|
|
65
|
+
const action = /\b(?:changes?|modif(?:y|ies)|alters?|adds?|introduces?|implements?|enables?)\b/g;
|
|
66
|
+
const actionSegments = text.split(/\band\b/i).map(normalize);
|
|
67
|
+
for (const [index, segment] of actionSegments.entries()) {
|
|
68
|
+
const inheritsRelevantSubject = index > 0 &&
|
|
69
|
+
/^(?:changes?|modif(?:y|ies)|alters?|adds?|introduces?|implements?|enables?)\b/.test(segment) &&
|
|
70
|
+
clauseMatchesScope(actionSegments[index - 1] ?? '', outOfScopeItem);
|
|
71
|
+
for (const match of segment.matchAll(action)) {
|
|
72
|
+
const before = segment.slice(Math.max(0, match.index - 24), match.index);
|
|
73
|
+
const after = segment.slice(match.index + match[0].length);
|
|
74
|
+
if (/\b(?:not|without|no)\s*$/.test(before)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (/^\s+remains? unchanged\b/.test(after)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (inheritsRelevantSubject || clauseMatchesScope(segment, outOfScopeItem)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
function clauseMatchesScope(clause, outOfScopeItem) {
|
|
88
|
+
const normalizedClause = normalize(clause);
|
|
89
|
+
const normalizedScope = normalize(outOfScopeItem);
|
|
90
|
+
if (normalizedClause.includes(normalizedScope) || normalizedScope.includes(normalizedClause)) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
const scopeKeywords = keywords(outOfScopeItem);
|
|
94
|
+
const matchCount = scopeKeywords.filter((keyword) => normalizedClause.includes(keyword)).length;
|
|
95
|
+
const threshold = scopeKeywords.length <= 2 ? scopeKeywords.length : 2;
|
|
96
|
+
return scopeKeywords.length > 0 && matchCount >= threshold;
|
|
97
|
+
}
|
|
46
98
|
/**
|
|
47
99
|
* Determine whether a criterion text contradicts an out-of-scope item.
|
|
48
100
|
* Uses substring match first, then keyword overlap as fuzzy fallback.
|
|
@@ -50,6 +102,13 @@ function keywords(phrase) {
|
|
|
50
102
|
function contradicts(criterionText, outOfScopeItem) {
|
|
51
103
|
const normCriterion = normalize(criterionText);
|
|
52
104
|
const normScope = normalize(outOfScopeItem);
|
|
105
|
+
const relevantClauses = splitClauses(criterionText).filter((clause) => clauseMatchesScope(clause, outOfScopeItem));
|
|
106
|
+
const hasConditionalException = /\b(?:unless|except)\b/i.test(criterionText);
|
|
107
|
+
if (!hasConditionalException &&
|
|
108
|
+
relevantClauses.length > 0 &&
|
|
109
|
+
relevantClauses.every((clause) => preservesBoundary(clause) && !hasAffirmativeDrift(clause, outOfScopeItem))) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
53
112
|
// 1. Direct substring match
|
|
54
113
|
if (normCriterion.includes(normScope)) {
|
|
55
114
|
return true;
|
|
@@ -74,9 +133,12 @@ function contradicts(criterionText, outOfScopeItem) {
|
|
|
74
133
|
*/
|
|
75
134
|
export function checkContradictions(outOfScope, criteria) {
|
|
76
135
|
const contradictions = [];
|
|
136
|
+
const seenPairs = new Set();
|
|
77
137
|
for (const criterion of criteria) {
|
|
78
138
|
for (const scopeItem of outOfScope) {
|
|
79
|
-
|
|
139
|
+
const pairKey = `${normalize(criterion)}\u0000${normalize(scopeItem)}`;
|
|
140
|
+
if (!seenPairs.has(pairKey) && contradicts(criterion, scopeItem)) {
|
|
141
|
+
seenPairs.add(pairKey);
|
|
80
142
|
contradictions.push({ criterion, contradicts: scopeItem });
|
|
81
143
|
}
|
|
82
144
|
}
|
|
@@ -24,10 +24,44 @@ const GENERIC_SCOPE_TOKENS = new Set([
|
|
|
24
24
|
'tool',
|
|
25
25
|
'tools',
|
|
26
26
|
]);
|
|
27
|
+
const GENERIC_SEMANTIC_TOKENS = new Set([
|
|
28
|
+
'change',
|
|
29
|
+
'validation',
|
|
30
|
+
'evidence',
|
|
31
|
+
'format',
|
|
32
|
+
'semantic',
|
|
33
|
+
'schema',
|
|
34
|
+
'receipt',
|
|
35
|
+
]);
|
|
36
|
+
function inflectionCandidates(token) {
|
|
37
|
+
const candidates = [token];
|
|
38
|
+
if (token.endsWith('s')) {
|
|
39
|
+
candidates.push(token.slice(0, -1));
|
|
40
|
+
}
|
|
41
|
+
for (const suffix of ['ed', 'ing']) {
|
|
42
|
+
if (token.endsWith(suffix)) {
|
|
43
|
+
const stem = token.slice(0, -suffix.length);
|
|
44
|
+
candidates.push(stem, `${stem}e`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return [...new Set(candidates.filter((candidate) => candidate.length >= 4))];
|
|
48
|
+
}
|
|
49
|
+
function semanticToken(token) {
|
|
50
|
+
const candidates = inflectionCandidates(token);
|
|
51
|
+
const generic = candidates.find((candidate) => GENERIC_SEMANTIC_TOKENS.has(candidate));
|
|
52
|
+
if (generic) {
|
|
53
|
+
return generic;
|
|
54
|
+
}
|
|
55
|
+
const singular = token.endsWith('s') ? token.slice(0, -1) : token;
|
|
56
|
+
return singular.length >= 4 ? singular : token;
|
|
57
|
+
}
|
|
27
58
|
function keywords(phrase) {
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
59
|
+
return [
|
|
60
|
+
...new Set(normalize(phrase)
|
|
61
|
+
.split(' ')
|
|
62
|
+
.filter((word) => word.length > 2 && !STOP_WORDS.has(word) && !GENERIC_SCOPE_TOKENS.has(word))
|
|
63
|
+
.map(semanticToken)),
|
|
64
|
+
];
|
|
31
65
|
}
|
|
32
66
|
/**
|
|
33
67
|
* Determine whether a file path matches an out-of-scope item.
|
|
@@ -39,9 +73,12 @@ function fileMatchesScopeItem(filePath, scopeItem) {
|
|
|
39
73
|
if (scopeKws.length === 0) {
|
|
40
74
|
return false;
|
|
41
75
|
}
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
76
|
+
const pathKeywords = new Set(keywords(normPath));
|
|
77
|
+
const specific = scopeKws.filter((token) => !GENERIC_SEMANTIC_TOKENS.has(token));
|
|
78
|
+
const matched = scopeKws.filter((token) => pathKeywords.has(token));
|
|
79
|
+
return specific.length > 0
|
|
80
|
+
? specific.some((token) => pathKeywords.has(token))
|
|
81
|
+
: new Set(matched).size >= 2;
|
|
45
82
|
}
|
|
46
83
|
/**
|
|
47
84
|
* Validate implementation file paths against the spec's outOfScope declarations.
|
|
@@ -52,8 +89,9 @@ export function validateScopeCompliance(outOfScope, filePaths) {
|
|
|
52
89
|
for (const filePath of filePaths) {
|
|
53
90
|
for (const scopeItem of outOfScope) {
|
|
54
91
|
if (fileMatchesScopeItem(filePath, scopeItem)) {
|
|
92
|
+
const pathKeywords = new Set(keywords(filePath));
|
|
55
93
|
const matchedKws = keywords(scopeItem)
|
|
56
|
-
.filter((
|
|
94
|
+
.filter((keyword) => pathKeywords.has(keyword))
|
|
57
95
|
.join(', ');
|
|
58
96
|
warnings.push({
|
|
59
97
|
filePath,
|
|
@@ -74,15 +74,6 @@ export async function writeCheckpoint(projectPath, snapshot) {
|
|
|
74
74
|
const updated = replaceLatestCheckpoint(existing, newBlock);
|
|
75
75
|
await mkdir(planuDir, { recursive: true });
|
|
76
76
|
await writeFile(filePath, updated, 'utf8');
|
|
77
|
-
void (async () => {
|
|
78
|
-
try {
|
|
79
|
-
const { planuAutoCommit } = await import('../git/planu-autocommit.js');
|
|
80
|
-
await planuAutoCommit({ projectPath, reason: 'session-checkpoint' });
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
/* best-effort — never blocks checkpoint writer */
|
|
84
|
-
}
|
|
85
|
-
})();
|
|
86
77
|
}
|
|
87
78
|
/**
|
|
88
79
|
* Fire-and-forget helper: records the tool call, then writes a checkpoint if
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { NormalizedAcceptanceCriterion } from '../../types/spec-format.js';
|
|
2
|
-
export declare function extractNormalizedAcceptanceCriteria(raw: string
|
|
3
|
-
|
|
2
|
+
export declare function extractNormalizedAcceptanceCriteria(raw: string, options?: {
|
|
3
|
+
allowLegacyBodyFallback?: boolean;
|
|
4
|
+
}): NormalizedAcceptanceCriterion[];
|
|
5
|
+
export declare function extractAcceptanceCriteriaTexts(raw: string, options?: {
|
|
6
|
+
allowLegacyBodyFallback?: boolean;
|
|
7
|
+
}): string[];
|
|
4
8
|
export declare function normalizeAcceptanceCriterionToken(value: string): string;
|
|
5
9
|
//# sourceMappingURL=acceptance-criteria.d.ts.map
|