@opengsd/gsd-core 1.15.0 → 1.16.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +85 -5
- package/agents/gsd-code-fixer.compact.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +4 -4
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +7 -2
- package/agents/gsd-planner.md +3 -3
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +42 -51
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +31 -9
- package/bin/install.js +126 -196
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +5 -0
- package/commands/gsd/capture.md +8 -4
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +5 -1
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +5 -1
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +6 -1
- package/commands/gsd/quick-batch.md +20 -8
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +5 -1
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +142 -56
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +78 -44
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +183 -103
- package/gsd-core/bin/lib/capability-validator.cjs +16 -0
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +173 -170
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config.cjs +43 -12
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +413 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/init.cjs +162 -96
- package/gsd-core/bin/lib/install-engine.cjs +19 -35
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/milestone.cjs +19 -1
- package/gsd-core/bin/lib/model-resolver.cjs +18 -18
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- package/gsd-core/bin/lib/phase-id.cjs +1 -1
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +280 -80
- package/gsd-core/bin/lib/plan-document.cjs +93 -19
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +273 -40
- package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
- package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
- package/gsd-core/bin/lib/roadmap.cjs +169 -72
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
- package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
- package/gsd-core/bin/lib/smart-entry.cjs +19 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state.cjs +214 -105
- package/gsd-core/bin/lib/surface.cjs +2 -1
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
- package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
- package/gsd-core/bin/lib/uat.cjs +424 -7
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1165 -314
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +286 -567
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/execute-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +7 -1
- package/gsd-core/references/offer-next.md +1 -1
- package/gsd-core/references/planning-config.md +1 -1
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +10 -4
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +8 -7
- package/gsd-core/workflows/add-tests.md +3 -2
- package/gsd-core/workflows/add-todo.md +4 -3
- package/gsd-core/workflows/ai-integration-phase.md +3 -2
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous.md +28 -18
- package/gsd-core/workflows/check-todos.md +6 -5
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +5 -4
- package/gsd-core/workflows/code-review.md +84 -90
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +12 -7
- package/gsd-core/workflows/debug.md +30 -5
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +1 -1
- package/gsd-core/workflows/docs-update.md +4 -3
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +5 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase.md +78 -170
- package/gsd-core/workflows/execute-plan.md +13 -19
- package/gsd-core/workflows/explore.md +2 -2
- package/gsd-core/workflows/extract-learnings.md +3 -2
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -1
- package/gsd-core/workflows/import.md +3 -2
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +5 -3
- package/gsd-core/workflows/map-codebase.md +4 -3
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +10 -10
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +1 -1
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/pause-work.md +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
- package/gsd-core/workflows/plan-phase.md +27 -18
- package/gsd-core/workflows/plan-review-convergence.md +1 -1
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +1 -1
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +42 -31
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +3 -2
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +11 -12
- package/gsd-core/workflows/settings-advanced.md +1 -1
- package/gsd-core/workflows/settings-integrations.md +1 -1
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +12 -12
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +1 -1
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +1 -1
- package/gsd-core/workflows/thread.md +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +5 -4
- package/gsd-core/workflows/ui-review.md +4 -3
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/validate-phase.md +10 -12
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +68 -59
- package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +8 -0
- package/hooks/dist/gsd-context-monitor.js +31 -8
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +147 -16
- package/hooks/dist/gsd-statusline.js +15 -7
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +8 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +8 -0
- package/hooks/gsd-context-monitor.js +31 -8
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +147 -16
- package/hooks/gsd-statusline.js +15 -7
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +21 -4
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +12 -8
- package/scripts/docs-guard-registry.cjs +6 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +10 -1
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +20 -2
- package/scripts/lib/ndjson-reporter.cjs +28 -3
- package/scripts/lib/platform-conformance-tier.generated.cjs +34 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +29 -0
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-test-file-count.allowlist.json +11 -1
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
- package/scripts/mutation-matrix.cjs +50 -5
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +5 -0
- package/skills/gsd-capture/SKILL.md +8 -4
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +5 -1
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +6 -1
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +20 -8
- package/skills/gsd-review/SKILL.md +5 -1
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
|
@@ -128,6 +128,19 @@ const SCHEMA_DEFAULTS = {
|
|
|
128
128
|
// WARNING_THRESHOLD/CRITICAL_THRESHOLD so the copies cannot drift.
|
|
129
129
|
'hooks.context_warning_threshold': 35,
|
|
130
130
|
'hooks.context_critical_threshold': 25,
|
|
131
|
+
// #4974: gates.* confirmation toggles — an absent key must resolve to the
|
|
132
|
+
// documented default (true) rather than "Key not found", matching
|
|
133
|
+
// config-defaults.manifest.json's `gates` block. Literal here (like
|
|
134
|
+
// git.create_tag above) rather than derived from config-loader.cjs's flat
|
|
135
|
+
// CONFIG_DEFAULTS: that flat projection is enumerated 1:1 against
|
|
136
|
+
// gsd-core/references/planning-config.md by
|
|
137
|
+
// tests/config-field-docs.test.cjs, and these 3 keys are internal workflow
|
|
138
|
+
// wiring, not part of that public flat-key surface. Only the 3 keys
|
|
139
|
+
// actually read by workflow conditions are registered — see
|
|
140
|
+
// gsd-core/bin/shared/config-schema.manifest.json.
|
|
141
|
+
'gates.execute_next_plan': true,
|
|
142
|
+
'gates.confirm_transition': true,
|
|
143
|
+
'gates.confirm_milestone_scope': true,
|
|
131
144
|
};
|
|
132
145
|
/**
|
|
133
146
|
* Resolve a schema-level default for an absent key (#2256). Checks the legacy
|
|
@@ -264,7 +277,8 @@ function validateShipPrBodySections(value) {
|
|
|
264
277
|
*
|
|
265
278
|
* Merges (increasing priority):
|
|
266
279
|
* 1. Hardcoded defaults — every key that loadConfig() resolves, plus mode/granularity
|
|
267
|
-
* 2. User-level defaults from
|
|
280
|
+
* 2. User-level defaults from $GSD_HOME/.gsd/defaults.json (if present;
|
|
281
|
+
* GSD_HOME defaults to the home directory, as in the config loader)
|
|
268
282
|
* 3. userChoices — the settings the user explicitly selected during /gsd:new-project
|
|
269
283
|
*
|
|
270
284
|
* Uses the canonical `git` namespace for branching keys (consistent with VALID_CONFIG_KEYS
|
|
@@ -275,24 +289,27 @@ function validateShipPrBodySections(value) {
|
|
|
275
289
|
*/
|
|
276
290
|
function buildNewProjectConfig(userChoices) {
|
|
277
291
|
const choices = userChoices || {};
|
|
278
|
-
|
|
292
|
+
// #4976: the GSD-owned store resolves exactly as the config loader resolves
|
|
293
|
+
// it (`GSD_HOME || homedir()`), so the defaults.json seeding this project is
|
|
294
|
+
// the one the loader and its #3532 shadow warning read in the same run.
|
|
295
|
+
const gsdHome = process.env['GSD_HOME'] || node_os_1.default.homedir();
|
|
279
296
|
// Detect API key availability
|
|
280
|
-
const braveKeyFile = node_path_1.default.join(
|
|
297
|
+
const braveKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'brave_api_key');
|
|
281
298
|
const hasBraveSearch = !!(process.env['BRAVE_API_KEY'] || node_fs_1.default.existsSync(braveKeyFile));
|
|
282
|
-
const firecrawlKeyFile = node_path_1.default.join(
|
|
299
|
+
const firecrawlKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'firecrawl_api_key');
|
|
283
300
|
const hasFirecrawl = !!(process.env['FIRECRAWL_API_KEY'] || node_fs_1.default.existsSync(firecrawlKeyFile));
|
|
284
|
-
const exaKeyFile = node_path_1.default.join(
|
|
301
|
+
const exaKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'exa_api_key');
|
|
285
302
|
const hasExaSearch = !!(process.env['EXA_API_KEY'] || node_fs_1.default.existsSync(exaKeyFile));
|
|
286
|
-
const tavilyKeyFile = node_path_1.default.join(
|
|
303
|
+
const tavilyKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'tavily_api_key');
|
|
287
304
|
const hasTavilySearch = !!(process.env['TAVILY_API_KEY'] || node_fs_1.default.existsSync(tavilyKeyFile));
|
|
288
|
-
const refKeyFile = node_path_1.default.join(
|
|
305
|
+
const refKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'ref_api_key');
|
|
289
306
|
const hasRefSearch = !!(process.env['REF_API_KEY'] || node_fs_1.default.existsSync(refKeyFile));
|
|
290
|
-
const perplexityKeyFile = node_path_1.default.join(
|
|
307
|
+
const perplexityKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'perplexity_api_key');
|
|
291
308
|
const hasPerplexity = !!(process.env['PERPLEXITY_API_KEY'] || node_fs_1.default.existsSync(perplexityKeyFile));
|
|
292
|
-
const jinaKeyFile = node_path_1.default.join(
|
|
309
|
+
const jinaKeyFile = node_path_1.default.join(gsdHome, '.gsd', 'jina_api_key');
|
|
293
310
|
const hasJina = !!(process.env['JINA_API_KEY'] || node_fs_1.default.existsSync(jinaKeyFile));
|
|
294
|
-
// Load user-level defaults from
|
|
295
|
-
const globalDefaultsPath = node_path_1.default.join(
|
|
311
|
+
// Load user-level defaults from $GSD_HOME/.gsd/defaults.json if available
|
|
312
|
+
const globalDefaultsPath = node_path_1.default.join(gsdHome, '.gsd', 'defaults.json');
|
|
296
313
|
let userDefaults = {};
|
|
297
314
|
try {
|
|
298
315
|
if (node_fs_1.default.existsSync(globalDefaultsPath)) {
|
|
@@ -434,7 +451,7 @@ function buildNewProjectConfig(userChoices) {
|
|
|
434
451
|
*
|
|
435
452
|
* Accepts user-chosen settings as a JSON string (the keys the user explicitly
|
|
436
453
|
* configured during /gsd:new-project). All remaining keys are filled from
|
|
437
|
-
* hardcoded defaults and optional
|
|
454
|
+
* hardcoded defaults and optional $GSD_HOME/.gsd/defaults.json.
|
|
438
455
|
*
|
|
439
456
|
* Idempotent: if config.json already exists, returns { created: false }.
|
|
440
457
|
*/
|
|
@@ -818,6 +835,13 @@ function cmdConfigSet(cwd, keyPath, value, raw, options = {}) {
|
|
|
818
835
|
const VALID_CONTEXT_VALUES = ['dev', 'research', 'review'];
|
|
819
836
|
if (kp === 'context')
|
|
820
837
|
assertEnumValue(parsedValue, val, VALID_CONTEXT_VALUES, 'context value');
|
|
838
|
+
// #4974: `mode` was never enum-validated — `config-set mode custom` (or any
|
|
839
|
+
// other string) silently succeeded, even though only "interactive" and
|
|
840
|
+
// "yolo" are documented/read values (gsd-core/references/planning-config.md,
|
|
841
|
+
// docs/CONFIGURATION.md, pinned by tests/config-field-docs.test.cjs).
|
|
842
|
+
const VALID_MODE_VALUES = ['interactive', 'yolo'];
|
|
843
|
+
if (kp === 'mode')
|
|
844
|
+
assertEnumValue(parsedValue, val, VALID_MODE_VALUES, 'mode');
|
|
821
845
|
if (kp === 'phase_id_convention') {
|
|
822
846
|
assertEnumValue(parsedValue, val, VALID_PHASE_ID_CONVENTIONS, 'phase_id_convention');
|
|
823
847
|
}
|
|
@@ -875,6 +899,13 @@ function cmdConfigSet(cwd, keyPath, value, raw, options = {}) {
|
|
|
875
899
|
error(`Invalid planner.stall_detection_enabled '${val}'. Must be a boolean (true or false).`);
|
|
876
900
|
}
|
|
877
901
|
}
|
|
902
|
+
// Dispatch audit-trail opt-in (#4975) — boolean only. The live seams honour
|
|
903
|
+
// only a real `true`, so any other stored value would be silently ignored.
|
|
904
|
+
if (kp === 'audit.enabled') {
|
|
905
|
+
if (typeof parsedValue !== 'boolean') {
|
|
906
|
+
error(`Invalid audit.enabled '${val}'. Must be a boolean (true or false).`);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
878
909
|
// #3086 — git.create_tag: boolean only
|
|
879
910
|
if (kp === 'git.create_tag') {
|
|
880
911
|
if (typeof parsedValue !== 'boolean') {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* - node:fs / node:path (stdlib)
|
|
16
16
|
* - ./phase-id.cjs (comparePhaseNum, used by readSubdirectories)
|
|
17
17
|
* - ./planning-workspace.cjs (findContextMdIn, used by getPhaseFileStats)
|
|
18
|
+
* - ./frontmatter-fence.cjs (locateFrontmatterFence, used by extractOneLinerFromBody)
|
|
18
19
|
*
|
|
19
20
|
* #3883 (ADR-3473 §8.3): two of this module's cyclic partners require
|
|
20
21
|
* generateSlugInternal, the canonical slug formula:
|
|
@@ -37,6 +38,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
38
|
};
|
|
38
39
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
39
40
|
const node_path_1 = __importDefault(require("node:path"));
|
|
41
|
+
// frontmatter-fence.cjs is a leaf module (no imports), so this adds no cycle.
|
|
42
|
+
const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
|
|
40
43
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
41
44
|
const phaseIdModule = require("./phase-id.cjs");
|
|
42
45
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
@@ -139,7 +142,9 @@ function extractOneLinerFromBody(content) {
|
|
|
139
142
|
if (!content)
|
|
140
143
|
return null;
|
|
141
144
|
const normalized = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
142
|
-
|
|
145
|
+
// The body starts after the block the one fence owner finds, and the blank lines after it.
|
|
146
|
+
const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(normalized);
|
|
147
|
+
const body = fence?.closed ? normalized.slice(fence.closingFenceEnd).replace(/^\n+/, '') : normalized;
|
|
143
148
|
// #3170: anchor to a summary-shaped heading (Summary / Overview /
|
|
144
149
|
// Accomplishments) so an incidental first heading (a rule list, task
|
|
145
150
|
// breakdown, deviation note) does not contribute its first bold run as the
|
|
@@ -34,6 +34,7 @@ const { output, error } = io;
|
|
|
34
34
|
const coreUtils = require("./core-utils.cjs");
|
|
35
35
|
const { toPosixPath } = coreUtils;
|
|
36
36
|
const security_cjs_1 = require("./security.cjs");
|
|
37
|
+
const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
|
|
37
38
|
// ─── Frozen typed-IR surface ────────────────────────────────────────────────
|
|
38
39
|
const MODE = Object.freeze({
|
|
39
40
|
COVERAGE: 'coverage',
|
|
@@ -186,15 +187,10 @@ function setKey(obj, key, value) {
|
|
|
186
187
|
obj[key] = value;
|
|
187
188
|
}
|
|
188
189
|
// ─── Frontmatter region helpers ──────────────────────────────────────────────
|
|
190
|
+
/** The closed frontmatter block's YAML text, as the one fence owner finds it, or null. */
|
|
189
191
|
function getFrontmatterYaml(content) {
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
return null;
|
|
193
|
-
const closingLineStart = content.indexOf('\n---', headerEnd);
|
|
194
|
-
if (closingLineStart === -1)
|
|
195
|
-
return null;
|
|
196
|
-
const yamlEnd = content[closingLineStart - 1] === '\r' ? closingLineStart - 1 : closingLineStart;
|
|
197
|
-
return content.slice(headerEnd, yamlEnd);
|
|
192
|
+
const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(content);
|
|
193
|
+
return fence?.closed ? content.slice(fence.openEnd, fence.bodyEnd) : null;
|
|
198
194
|
}
|
|
199
195
|
/**
|
|
200
196
|
* Locate and parse the top-level `coverage:` block from a SUMMARY document.
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Decision-coverage support — the shared reading/matching helpers of the two decision-coverage
|
|
4
|
+
* gates (#5139, epic #5056, ADR-5057 §4 first bullet, design D3/D4).
|
|
5
|
+
*
|
|
6
|
+
* Moved verbatim (behaviour preserved) from `check-command-router.cts`, with the raw-content
|
|
7
|
+
* parsers replaced by their owning seams:
|
|
8
|
+
* - the frontmatter `must_haves` / `truths` / `objective` blocks are read through the
|
|
9
|
+
* Frontmatter Module (`frontmatterKeyBlockText`, the moved `extractYamlBlock`: raw text off
|
|
10
|
+
* the one fence owner's block, so frontmatter the YAML parser refuses is still scanned), and
|
|
11
|
+
* the SUMMARY `files_modified` list through its parsed reader (`rawFrontmatterField`), not a
|
|
12
|
+
* `files_modified:` regex;
|
|
13
|
+
* - the XML-tag body extraction lives in `markdown-sectionizer.cts` (`extractXmlTagBodies`).
|
|
14
|
+
*
|
|
15
|
+
* The router-facing gate modules (`gate-decision-coverage-plan.cts`,
|
|
16
|
+
* `gate-decision-coverage-verify.cts`) import from here. This module imports no io module and
|
|
17
|
+
* performs no direct console/stdout/stderr write (ESLint-enforced).
|
|
18
|
+
*/
|
|
19
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
20
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.decisionMentioned = decisionMentioned;
|
|
24
|
+
exports.loadPlanContents = loadPlanContents;
|
|
25
|
+
exports.loadSummaryContents = loadSummaryContents;
|
|
26
|
+
exports.loadDecisionExtraction = loadDecisionExtraction;
|
|
27
|
+
exports.extractPlanDesignatedSections = extractPlanDesignatedSections;
|
|
28
|
+
exports.buildPlanMessage = buildPlanMessage;
|
|
29
|
+
exports.buildVerifyMessage = buildVerifyMessage;
|
|
30
|
+
exports.phaseCommitMessages = phaseCommitMessages;
|
|
31
|
+
exports.readModifiedFilesContent = readModifiedFilesContent;
|
|
32
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
33
|
+
const decisions_cjs_1 = require("./decisions.cjs");
|
|
34
|
+
const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
|
|
35
|
+
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
36
|
+
const security_cjs_1 = require("./security.cjs");
|
|
37
|
+
const gate_evidence_cjs_1 = require("./gate-evidence.cjs");
|
|
38
|
+
const gate_evaluation_scope_cjs_1 = require("./gate-evaluation-scope.cjs");
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
40
|
+
const frontmatterMod = require("./frontmatter.cjs");
|
|
41
|
+
const { rawFrontmatterField, frontmatterKeyBlockText } = frontmatterMod;
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
43
|
+
const planScanMod = require("./plan-scan.cjs");
|
|
44
|
+
const { scanPhasePlans } = planScanMod;
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
46
|
+
const planningScopeMod = require("./planning-scope.cjs");
|
|
47
|
+
const { SCOPE } = planningScopeMod;
|
|
48
|
+
// ─── Decision matching ────────────────────────────────────────────────────────
|
|
49
|
+
function normalizePhrase(text) {
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
51
|
+
return String(text || '')
|
|
52
|
+
.toLowerCase()
|
|
53
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
54
|
+
.replace(/\s+/g, ' ')
|
|
55
|
+
.trim();
|
|
56
|
+
}
|
|
57
|
+
const SOFT_PHRASE_MIN_WORDS = 6;
|
|
58
|
+
function softPhrase(text) {
|
|
59
|
+
const words = normalizePhrase(text).split(' ').filter(Boolean);
|
|
60
|
+
if (words.length < SOFT_PHRASE_MIN_WORDS)
|
|
61
|
+
return '';
|
|
62
|
+
return words.slice(0, SOFT_PHRASE_MIN_WORDS).join(' ');
|
|
63
|
+
}
|
|
64
|
+
function decisionMentioned(haystack, decision) {
|
|
65
|
+
if (!haystack)
|
|
66
|
+
return false;
|
|
67
|
+
if (new RegExp(`\\b${decision.id}\\b`).test(haystack))
|
|
68
|
+
return true;
|
|
69
|
+
const phrase = softPhrase(decision.text);
|
|
70
|
+
return phrase ? normalizePhrase(haystack).includes(phrase) : false;
|
|
71
|
+
}
|
|
72
|
+
// ─── File reading ─────────────────────────────────────────────────────────────
|
|
73
|
+
/**
|
|
74
|
+
* The contents of the phase files `pick` selects (#5170, ADR-5057 §4). An ABSENT phase directory
|
|
75
|
+
* is "no files" (`found []`); a directory or file that exists but cannot be read is `unreadable` —
|
|
76
|
+
* a gate must not take "could not read the plan" for "the plan does not cite the decision".
|
|
77
|
+
*/
|
|
78
|
+
function readPhaseFiles(phaseDir, pick) {
|
|
79
|
+
const entries = (0, gate_evidence_cjs_1.readDirEvidence)(phaseDir);
|
|
80
|
+
if (entries.kind === 'none')
|
|
81
|
+
return (0, gate_evidence_cjs_1.evidenceFound)([]);
|
|
82
|
+
if (entries.kind === 'unreadable')
|
|
83
|
+
return entries;
|
|
84
|
+
const contents = [];
|
|
85
|
+
// #3183 (lint-plan-count-drift): source live plan/summary files from the single
|
|
86
|
+
// owner (scanPhasePlans) instead of a local readdirSync filter — picks up bare PLAN.md and
|
|
87
|
+
// nested plans/, and excludes plans marked `status: superseded`.
|
|
88
|
+
// Only SCOPE.COMPLETE is a real answer: an existing nested plans/ that could not be read (TRUNCATED)
|
|
89
|
+
// would otherwise hand the gate a short plan set and let it conclude "no plan cites the decision".
|
|
90
|
+
const scan = scanPhasePlans(phaseDir);
|
|
91
|
+
if (scan.scope !== SCOPE.COMPLETE) {
|
|
92
|
+
return { kind: 'unreadable', reason: `plan scan ${scan.scope}`, span: phaseDir };
|
|
93
|
+
}
|
|
94
|
+
for (const entry of pick(scan)) {
|
|
95
|
+
const read = (0, gate_evidence_cjs_1.readTextEvidence)(node_path_1.default.join(phaseDir, entry));
|
|
96
|
+
if (read.kind === 'unreadable')
|
|
97
|
+
return read;
|
|
98
|
+
if (read.kind === 'found')
|
|
99
|
+
contents.push(read.value);
|
|
100
|
+
}
|
|
101
|
+
return (0, gate_evidence_cjs_1.evidenceFound)(contents);
|
|
102
|
+
}
|
|
103
|
+
function loadPlanContents(phaseDir) {
|
|
104
|
+
return readPhaseFiles(phaseDir, (scan) => scan.planFiles);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* #3183 (lint-plan-count-drift): same single-owner sourcing as `loadPlanContents` —
|
|
108
|
+
* scanPhasePlans's summaryFiles instead of a local `-SUMMARY.md` readdirSync filter.
|
|
109
|
+
*/
|
|
110
|
+
function loadSummaryContents(phaseDir) {
|
|
111
|
+
return readPhaseFiles(phaseDir, (scan) => scan.summaryFiles);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The decisions of `CONTEXT.md`. `none` is an absent file (the caller's legitimate "nothing to
|
|
115
|
+
* check"); `unreadable` is a file that exists but could not be read — it must never be extracted as
|
|
116
|
+
* empty text, which would certify "no trackable decisions".
|
|
117
|
+
*/
|
|
118
|
+
function loadDecisionExtraction(contextPath) {
|
|
119
|
+
const read = (0, gate_evidence_cjs_1.readTextEvidence)(contextPath);
|
|
120
|
+
if (read.kind !== 'found')
|
|
121
|
+
return read;
|
|
122
|
+
const extraction = (0, decisions_cjs_1.extractDecisions)(read.value);
|
|
123
|
+
return (0, gate_evidence_cjs_1.evidenceFound)({
|
|
124
|
+
trackable: extraction.decisions.filter((d) => d.trackable),
|
|
125
|
+
outcome: extraction.outcome,
|
|
126
|
+
unreadableIds: extraction.unreadableIds ?? [],
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// ─── Plan surfaces scanned for a decision citation ────────────────────────────
|
|
130
|
+
const DESIGNATED_HEADINGS_RE = /^#{1,6}\s+(?:must[_ ]haves?|truths?|tasks?|objective)\b/i;
|
|
131
|
+
function stripCommentsAndFences(text) {
|
|
132
|
+
// HTML-comment stripping stays caller-side (the seam does not strip HTML comments).
|
|
133
|
+
// Stop-at-next-open body (ReDoS-safe, #2128); an UNCLOSED `<!--` does not match,
|
|
134
|
+
// so downstream tags are preserved (unlike a `(?:-->|$)` fallback, which would
|
|
135
|
+
// wipe to EOF and fail-close the decision-coverage gate).
|
|
136
|
+
const htmlStripped = text.replace(/<!--(?:(?!<!--)[\s\S])*?-->/g, ' ');
|
|
137
|
+
// Fenced-code stripping: delegate to the canonical CommonMark-correct seam.
|
|
138
|
+
// replaces the prior independent regex copy (```` ``` ``` ```` + `~~~ ~~~`).
|
|
139
|
+
return (0, markdown_sectionizer_cjs_1.stripFencedCode)(htmlStripped).text;
|
|
140
|
+
}
|
|
141
|
+
function extractPlanDesignatedSections(planContent) {
|
|
142
|
+
if (!planContent)
|
|
143
|
+
return '';
|
|
144
|
+
const cleaned = stripCommentsAndFences(planContent);
|
|
145
|
+
// The block is the one the one fence owner finds; the body starts after the closing fence
|
|
146
|
+
// line's line ending.
|
|
147
|
+
const fence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(cleaned);
|
|
148
|
+
const body = fence?.closed ? cleaned.slice(fence.closingFenceEnd).replace(/^\r?\n/, '') : cleaned;
|
|
149
|
+
const parts = [];
|
|
150
|
+
for (const key of ['must_haves', 'truths', 'objective']) {
|
|
151
|
+
const block = frontmatterKeyBlockText(cleaned, key);
|
|
152
|
+
if (block)
|
|
153
|
+
parts.push(block);
|
|
154
|
+
}
|
|
155
|
+
// Replace hand-rolled split(/\r?\n/) + heading walk with the seam's collectSections.
|
|
156
|
+
// stopPredicate fires on EVERY heading (collectSections needs to start a section at
|
|
157
|
+
// each heading), then we filter to designated ones — same semantics as the prior
|
|
158
|
+
// inDesignated flag: emit the heading line + body only when DESIGNATED_HEADINGS_RE matches.
|
|
159
|
+
const sections = (0, markdown_sectionizer_cjs_1.collectSections)(body, () => true);
|
|
160
|
+
const bodyParts = [];
|
|
161
|
+
for (const section of sections) {
|
|
162
|
+
const headingLine = '#'.repeat(section.heading.level) + ' ' + section.heading.text;
|
|
163
|
+
if (DESIGNATED_HEADINGS_RE.test(headingLine)) {
|
|
164
|
+
bodyParts.push(headingLine);
|
|
165
|
+
if (section.body)
|
|
166
|
+
bodyParts.push(section.body);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
parts.push(bodyParts.join('\n'));
|
|
170
|
+
parts.push((0, markdown_sectionizer_cjs_1.extractXmlTagBodies)(cleaned));
|
|
171
|
+
return parts.join('\n\n');
|
|
172
|
+
}
|
|
173
|
+
function buildPlanMessage(uncovered) {
|
|
174
|
+
if (uncovered.length === 0)
|
|
175
|
+
return 'All trackable CONTEXT.md decisions are covered by plans.';
|
|
176
|
+
return [
|
|
177
|
+
'## Decision Coverage Gap',
|
|
178
|
+
'',
|
|
179
|
+
`${uncovered.length} CONTEXT.md decision(s) are not covered by any plan:`,
|
|
180
|
+
'',
|
|
181
|
+
...uncovered.map((item) => `- **${item.id}** (${item.category || 'uncategorized'}): ${item.text}`),
|
|
182
|
+
'',
|
|
183
|
+
'Resolve by citing `D-NN:` in any of the scanned plan surfaces: front-matter',
|
|
184
|
+
'`must_haves`/`truths`/`objective`, a `## must_haves`/`truths`/`tasks`/`objective`',
|
|
185
|
+
'heading, or an `<objective>`/`<tasks>`/`<task>`/`<action>`/`<read_first>`/`<behavior>`/`<verify>`/`<acceptance_criteria>`/`<done>`',
|
|
186
|
+
'tag body. Other locations (prose outside those headings, comments, other XML tags) are not scanned.',
|
|
187
|
+
'OR move the decision to `### Claude\'s Discretion` / tag it `[informational]` if it should not be tracked.',
|
|
188
|
+
].join('\n');
|
|
189
|
+
}
|
|
190
|
+
function buildVerifyMessage(notHonored) {
|
|
191
|
+
if (notHonored.length === 0)
|
|
192
|
+
return 'All trackable CONTEXT.md decisions are honored by shipped artifacts.';
|
|
193
|
+
return [
|
|
194
|
+
'### Decision Coverage (warning)',
|
|
195
|
+
'',
|
|
196
|
+
`${notHonored.length} decision(s) not found in shipped artifacts:`,
|
|
197
|
+
'',
|
|
198
|
+
...notHonored.map((item) => `- **${item.id}** (${item.category || 'uncategorized'}): ${item.text}`),
|
|
199
|
+
'',
|
|
200
|
+
'This is a soft warning - verification status is unchanged.',
|
|
201
|
+
].join('\n');
|
|
202
|
+
}
|
|
203
|
+
// ─── Shipped-artifact haystack (verify gate) ──────────────────────────────────
|
|
204
|
+
/**
|
|
205
|
+
* The subjects and bodies of the PHASE'S OWN commits (#5164, ADR-5057 §4) — the evaluation-scope
|
|
206
|
+
* resolver's commit set for `phaseDir`, not the last 200 commits of whatever branch is checked
|
|
207
|
+
* out. A phase with no recorded task commits widens to the commits in its directory range (the
|
|
208
|
+
* resolver says so); an unreadable phase or repository yields '' ("could not look"), and a git
|
|
209
|
+
* failure on a non-git project dir writes nothing to the terminal.
|
|
210
|
+
*/
|
|
211
|
+
function phaseCommitMessages(projectDir, phaseDir) {
|
|
212
|
+
const scope = (0, gate_evaluation_scope_cjs_1.resolveEvaluationScope)(projectDir, { kind: 'phase', phase: '', phaseDir }, { includeBody: true, includeFiles: false });
|
|
213
|
+
return scope.commits.map((c) => `${c.subject}\n${c.body ?? ''}`).join('\n');
|
|
214
|
+
}
|
|
215
|
+
/** Cap on files read across all SUMMARYs, and on bytes read per file. */
|
|
216
|
+
const MODIFIED_FILES_MAX_COUNT = 50;
|
|
217
|
+
const MODIFIED_FILES_MAX_BYTES = 256 * 1024;
|
|
218
|
+
/**
|
|
219
|
+
* The contents of every file the SUMMARYs list under frontmatter `files_modified`, contained to
|
|
220
|
+
* `projectDir` and capped at `MODIFIED_FILES_MAX_COUNT` files / `MODIFIED_FILES_MAX_BYTES` each.
|
|
221
|
+
*/
|
|
222
|
+
function readModifiedFilesContent(projectDir, summaries) {
|
|
223
|
+
const out = [];
|
|
224
|
+
let total = 0;
|
|
225
|
+
for (const summary of summaries) {
|
|
226
|
+
if (!summary)
|
|
227
|
+
continue;
|
|
228
|
+
if (total >= MODIFIED_FILES_MAX_COUNT)
|
|
229
|
+
break;
|
|
230
|
+
const field = rawFrontmatterField(summary, 'files_modified');
|
|
231
|
+
const listed = field && Array.isArray(field.value) ? field.value : [];
|
|
232
|
+
for (const entry of listed) {
|
|
233
|
+
if (total >= MODIFIED_FILES_MAX_COUNT)
|
|
234
|
+
break;
|
|
235
|
+
if (typeof entry !== 'string')
|
|
236
|
+
continue;
|
|
237
|
+
const file = entry.trim();
|
|
238
|
+
if (!file)
|
|
239
|
+
continue;
|
|
240
|
+
// Migrated off the hand-rolled prefix check (ADR-4650): resolve+contain in one
|
|
241
|
+
// step via the canonical realpath predicate — the eventual read below follows
|
|
242
|
+
// symlinks, so containment must be decided on the resolved target, not a lexical
|
|
243
|
+
// prefix. Read the value the predicate RETURNED; do not re-derive the path.
|
|
244
|
+
const candidate = node_path_1.default.isAbsolute(file) ? file : node_path_1.default.join(projectDir, file);
|
|
245
|
+
const contained = (0, security_cjs_1.tryWithinRoot)(candidate, projectDir, security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
246
|
+
if (contained === null)
|
|
247
|
+
continue;
|
|
248
|
+
// An absent listed file contributes nothing readable (`''`); one that exists but cannot be
|
|
249
|
+
// read is `unreadable` — the decision it may cite was never seen (#5170).
|
|
250
|
+
const read = (0, gate_evidence_cjs_1.readTextEvidence)(contained);
|
|
251
|
+
if (read.kind === 'unreadable')
|
|
252
|
+
return read;
|
|
253
|
+
const content = read.kind === 'found' ? read.value : '';
|
|
254
|
+
out.push(content.length > MODIFIED_FILES_MAX_BYTES ? content.slice(0, MODIFIED_FILES_MAX_BYTES) : content);
|
|
255
|
+
total++;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return (0, gate_evidence_cjs_1.evidenceFound)(out.join('\n\n'));
|
|
259
|
+
}
|