@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
|
@@ -45,16 +45,18 @@ const { loadConfig: loadConfigForScope } = configLoaderForScope;
|
|
|
45
45
|
const scanPhasePlans = require("./plan-scan.cjs");
|
|
46
46
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
47
47
|
const coreUtils = require("./core-utils.cjs");
|
|
48
|
-
const {
|
|
48
|
+
const { findUnsummarizedPlans } = coreUtils;
|
|
49
49
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
50
50
|
const frontmatter = require("./frontmatter.cjs");
|
|
51
|
-
const { extractFrontmatter, parseMustHavesBlock } = frontmatter;
|
|
51
|
+
const { extractFrontmatter, frontmatterRegion, parseMustHavesBlock } = frontmatter;
|
|
52
52
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
53
53
|
const verificationMod = require("./verification.cjs");
|
|
54
|
-
const { isPhaseComplete } = verificationMod;
|
|
54
|
+
const { isPhaseComplete, failOnVerificationStatusError, firstStatusError } = verificationMod;
|
|
55
55
|
// #4906 Phase 2 (#4917/ADR-4910): the PlanningDoc parse -> mutate -> serialize
|
|
56
56
|
// seam, mirroring phase.cts's already-migrated `writePlansField` site.
|
|
57
57
|
const planning_document_cjs_1 = require("./planning-document.cjs");
|
|
58
|
+
// #5060: the Phase Status Module owns the ladder; roadmap.cts is a consumer.
|
|
59
|
+
const phase_status_cjs_1 = require("./phase-status.cjs");
|
|
58
60
|
// ─── coerceTruthToString ──────────────────────────────────────────────────────
|
|
59
61
|
/**
|
|
60
62
|
* Coerce an arbitrary YAML scalar/object into a string for cross-cutting
|
|
@@ -212,7 +214,8 @@ function searchPhaseInContent(content, escapedPhase, phaseNum, convention) {
|
|
|
212
214
|
* Returns the phase section string if found, null if ROADMAP.md is missing,
|
|
213
215
|
* or throws if ROADMAP.md read fails.
|
|
214
216
|
*
|
|
215
|
-
* Used by
|
|
217
|
+
* Used by the shared gate phase context (lookupRoadmapPhase in gate-phase-context.cts, which
|
|
218
|
+
* computeUiPlanGate in gate-ui-plan.cts calls) so ui-plan-gate uses the SAME
|
|
216
219
|
* phase resolution as `roadmap.get-phase` — not a milestone-only subset.
|
|
217
220
|
*/
|
|
218
221
|
function getRoadmapPhaseWithFallback(cwd, phaseNum) {
|
|
@@ -310,6 +313,14 @@ function cmdRoadmapGetPhase(cwd, phaseNum, raw) {
|
|
|
310
313
|
error('Failed to read ROADMAP.md: ' + e.message);
|
|
311
314
|
}
|
|
312
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* #4757: the phase records whose `roadmap_complete` was READ from a ROADMAP
|
|
318
|
+
* checkbox. Table rows and headings with no checklist entry also report
|
|
319
|
+
* `roadmap_complete: false`, but there is no checkbox behind it, so they must
|
|
320
|
+
* not be compared against disk status by `checkbox_conflict`. A WeakSet keeps
|
|
321
|
+
* this out of the emitted `phases[]` shape.
|
|
322
|
+
*/
|
|
323
|
+
const PHASES_WITH_CHECKBOX = new WeakSet();
|
|
313
324
|
// #612 composes the convention-qualified sentinel reading with upstream's
|
|
314
325
|
// canonical legacy sentinel owner. A reserved bracket milestone OR a reserved
|
|
315
326
|
// phase token excludes the occurrence.
|
|
@@ -373,6 +384,7 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
373
384
|
// The caller needs the exact occurrence identities from the same scan that
|
|
374
385
|
// built `phases`; returning them together also keeps fallback rescans atomic.
|
|
375
386
|
const detailKeys = new Set();
|
|
387
|
+
let statusError;
|
|
376
388
|
while ((match = phasePattern.exec(content)) !== null) {
|
|
377
389
|
const bracketId = G ? match[1] : undefined;
|
|
378
390
|
const phaseNum = match[1 + G];
|
|
@@ -402,7 +414,7 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
402
414
|
const depends_on = dependsMatch ? dependsMatch[1].trim() : null;
|
|
403
415
|
// Check completion on disk
|
|
404
416
|
const normalized = normalizePhaseName(phaseNum);
|
|
405
|
-
let diskStatus =
|
|
417
|
+
let diskStatus = phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY;
|
|
406
418
|
let planCount = 0;
|
|
407
419
|
let summaryCount = 0;
|
|
408
420
|
let hasContext = false;
|
|
@@ -446,33 +458,32 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
446
458
|
hasResearch = counts.hasResearch;
|
|
447
459
|
contextReadError = counts.contextReadError;
|
|
448
460
|
contextScope = counts.scope;
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
//
|
|
453
|
-
//
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
// resolves and scopes its verification report like its legacy twin.
|
|
458
|
-
const completionResult = isPhaseComplete(node_path_1.default.join(phasesDir, dirMatch), { convention });
|
|
459
|
-
if (completionResult.value.complete)
|
|
460
|
-
diskStatus = 'complete';
|
|
461
|
-
else if (summaryCount > 0)
|
|
462
|
-
diskStatus = 'partial';
|
|
463
|
-
else if (planCount > 0)
|
|
464
|
-
diskStatus = 'planned';
|
|
465
|
-
else if (hasResearch)
|
|
466
|
-
diskStatus = 'researched';
|
|
467
|
-
else if (hasContext)
|
|
468
|
-
diskStatus = 'discussed';
|
|
469
|
-
else
|
|
470
|
-
diskStatus = 'empty';
|
|
461
|
+
// #5060: route the disk-status ladder through the Phase Status Module's
|
|
462
|
+
// single owner (`phaseStatus`/`toDiskStatus`) rather than a local
|
|
463
|
+
// if/else re-derivation. `convention` still threads through so a
|
|
464
|
+
// bracket phase's verification report resolves and scopes like its
|
|
465
|
+
// legacy twin (#612).
|
|
466
|
+
const ps = (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(phasesDir, dirMatch), { convention });
|
|
467
|
+
statusError = firstStatusError(statusError, ps.value.statusError);
|
|
468
|
+
diskStatus = (0, phase_status_cjs_1.toDiskStatus)(ps.value.status, { hasResearch, hasContext });
|
|
471
469
|
}
|
|
472
|
-
// Check ROADMAP checkbox status. #
|
|
473
|
-
//
|
|
474
|
-
//
|
|
475
|
-
//
|
|
470
|
+
// Check ROADMAP checkbox status. #4965: line-anchored, label-first — the
|
|
471
|
+
// old fragment allowed `\s*.*` between the checkbox and the label, which
|
|
472
|
+
// let "Phase N" match ANYWHERE in any checklist line's free-form
|
|
473
|
+
// description (not just this phase's own line), and `content.match`
|
|
474
|
+
// returns only the first hit in the document — so an earlier, unrelated
|
|
475
|
+
// line whose prose merely mentioned "Phase N" shadowed that phase's own
|
|
476
|
+
// checkbox state (both a false negative and a false positive were
|
|
477
|
+
// reported against real ROADMAPs). The label must now be the first thing
|
|
478
|
+
// after the checkbox, tolerating only an optional `**` bold marker and
|
|
479
|
+
// horizontal whitespace — matching `cmdRoadmapAnalyze`'s own
|
|
480
|
+
// `checklistPattern` (the missing-detail-section scan a bit further down
|
|
481
|
+
// in this file), which already hard-requires `\*\*` immediately after the
|
|
482
|
+
// checkbox for the same reason. A decoration the old `.*` used to tolerate
|
|
483
|
+
// by accident — a blockquoted bullet, an emoji/badge before the label —
|
|
484
|
+
// now resolves to `roadmap_complete: false` instead of matching; this is
|
|
485
|
+
// the deliberate, precedent-consistent narrowing (see 10-diagnosis.md's
|
|
486
|
+
// "Negative space" note), not a new gap.
|
|
476
487
|
//
|
|
477
488
|
// ADR-3180 §7.4 (disk-strict, #2957, maintainer decision 2026-08-08):
|
|
478
489
|
// `roadmapComplete` is reported below as metadata ONLY — it carries NO
|
|
@@ -483,10 +494,10 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
483
494
|
// checkbox — no passing `*-VERIFICATION.md`, plans outstanding — now
|
|
484
495
|
// reports incomplete; this is the deliberate Tier-2 break (ADR-3180 §7.4
|
|
485
496
|
// Decision 3).
|
|
486
|
-
const checkboxPattern = new RegExp(
|
|
497
|
+
const checkboxPattern = new RegExp(`^[ \\t]*-[ \\t]*\\[(x| )\\][ \\t]*(?:\\*\\*)?${phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.LABEL_ONLY, convention)}${phaseMarkdownRegexSource(phaseNum)}${OPTIONAL_PHASE_TAG_SOURCE}[:\\s]`, 'im');
|
|
487
498
|
const checkboxMatch = content.match(checkboxPattern);
|
|
488
499
|
const roadmapComplete = checkboxMatch ? checkboxMatch[1] === 'x' : false;
|
|
489
|
-
|
|
500
|
+
const headingPhase = {
|
|
490
501
|
number: phaseNum,
|
|
491
502
|
name: phaseName,
|
|
492
503
|
goal,
|
|
@@ -500,7 +511,10 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
500
511
|
roadmap_complete: roadmapComplete,
|
|
501
512
|
context_read_error: contextReadError,
|
|
502
513
|
context_scope: contextScope,
|
|
503
|
-
}
|
|
514
|
+
};
|
|
515
|
+
if (checkboxMatch)
|
|
516
|
+
PHASES_WITH_CHECKBOX.add(headingPhase);
|
|
517
|
+
phases.push(headingPhase);
|
|
504
518
|
}
|
|
505
519
|
// #3577: markdown-table row declarations join the enumeration — same
|
|
506
520
|
// enrichment contract as headings (disk counts when the directory exists),
|
|
@@ -514,7 +528,7 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
514
528
|
detailKeys.add(occurrenceKey(tr.id));
|
|
515
529
|
if (seen.has(stripPadA(tr.id)))
|
|
516
530
|
continue;
|
|
517
|
-
const dirMatchA = matchPhaseDirs(phaseDirNames, normalizePhaseName(tr.id)).matches[0];
|
|
531
|
+
const dirMatchA = matchPhaseDirs(phaseDirNames, normalizePhaseName(tr.id), convention).matches[0];
|
|
518
532
|
let tPlanCount = 0;
|
|
519
533
|
let tSummaryCount = 0;
|
|
520
534
|
let tHasContext = false;
|
|
@@ -523,8 +537,9 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
523
537
|
// #4014 (epic #3473 B4): additive sibling, same default rule as the
|
|
524
538
|
// heading-declared branch above.
|
|
525
539
|
let tContextScope = SCOPE.COMPLETE;
|
|
540
|
+
let tDiskStatus = phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY;
|
|
526
541
|
if (dirMatchA) {
|
|
527
|
-
const counts = countPhasePlansAndSummaries(node_path_1.default.join(phasesDir, dirMatchA));
|
|
542
|
+
const counts = countPhasePlansAndSummaries(node_path_1.default.join(phasesDir, dirMatchA), convention);
|
|
528
543
|
tPlanCount = counts.planCount;
|
|
529
544
|
tSummaryCount = counts.summaryCount;
|
|
530
545
|
tHasContext = node_fs_1.default.existsSync(node_path_1.default.join(phasesDir, dirMatchA, 'CONTEXT.md'));
|
|
@@ -535,6 +550,11 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
535
550
|
// an unreadable phase directory is still surfaced via the sibling call.
|
|
536
551
|
tContextReadError = counts.contextReadError;
|
|
537
552
|
tContextScope = counts.scope;
|
|
553
|
+
// #5060: route through the Phase Status Module's owner rather than the
|
|
554
|
+
// fixed 'ok' sentinel this row used to emit.
|
|
555
|
+
const tps = (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(phasesDir, dirMatchA), { convention });
|
|
556
|
+
statusError = firstStatusError(statusError, tps.value.statusError);
|
|
557
|
+
tDiskStatus = (0, phase_status_cjs_1.toDiskStatus)(tps.value.status, { hasResearch: tHasResearch, hasContext: tHasContext });
|
|
538
558
|
}
|
|
539
559
|
phases.push({
|
|
540
560
|
number: tr.id,
|
|
@@ -546,13 +566,13 @@ function collectAnalyzePhases(content, phasesDir, phaseDirNames, convention) {
|
|
|
546
566
|
summary_count: tSummaryCount,
|
|
547
567
|
has_context: tHasContext,
|
|
548
568
|
has_research: tHasResearch,
|
|
549
|
-
disk_status:
|
|
569
|
+
disk_status: tDiskStatus,
|
|
550
570
|
roadmap_complete: false,
|
|
551
571
|
context_read_error: tContextReadError,
|
|
552
572
|
context_scope: tContextScope,
|
|
553
573
|
});
|
|
554
574
|
}
|
|
555
|
-
return { phases, detailKeys };
|
|
575
|
+
return { phases, detailKeys, statusError };
|
|
556
576
|
}
|
|
557
577
|
function cmdRoadmapAnalyze(cwd, raw) {
|
|
558
578
|
const roadmapPath = planningPaths(cwd).roadmap;
|
|
@@ -588,6 +608,8 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
588
608
|
let collected = collectAnalyzePhases(content, phasesDir, _phaseDirNames, convention);
|
|
589
609
|
let phases = collected.phases;
|
|
590
610
|
let detailKeys = collected.detailKeys;
|
|
611
|
+
// #5118: carried from every phaseStatus read this command makes.
|
|
612
|
+
let statusError = collected.statusError;
|
|
591
613
|
// `effectiveContent` is what the downstream checklist scan (missing_details)
|
|
592
614
|
// iterates. Defaults to the scoped window; switched to the fallback document
|
|
593
615
|
// when the recovery path below fires, so a phase found via fallback is not
|
|
@@ -614,6 +636,7 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
614
636
|
collected = fallbackCollection;
|
|
615
637
|
phases = collected.phases;
|
|
616
638
|
detailKeys = collected.detailKeys;
|
|
639
|
+
statusError = firstStatusError(statusError, collected.statusError);
|
|
617
640
|
effectiveContent = fallbackContent;
|
|
618
641
|
}
|
|
619
642
|
}
|
|
@@ -626,12 +649,12 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
626
649
|
version: m.version,
|
|
627
650
|
}));
|
|
628
651
|
// Find current and next phase
|
|
629
|
-
const currentPhase = phases.find(p => p.disk_status ===
|
|
630
|
-
const nextPhase = phases.find(p => p.disk_status ===
|
|
652
|
+
const currentPhase = phases.find(p => p.disk_status === phase_status_cjs_1.DISK_STATUS.PLANNED || p.disk_status === phase_status_cjs_1.DISK_STATUS.PARTIAL || p.disk_status === phase_status_cjs_1.DISK_STATUS.EXECUTED) || null;
|
|
653
|
+
const nextPhase = phases.find(p => p.disk_status === phase_status_cjs_1.DISK_STATUS.EMPTY || p.disk_status === phase_status_cjs_1.DISK_STATUS.NO_DIRECTORY || p.disk_status === phase_status_cjs_1.DISK_STATUS.DISCUSSED || p.disk_status === phase_status_cjs_1.DISK_STATUS.RESEARCHED) || null;
|
|
631
654
|
// Aggregated stats
|
|
632
655
|
const totalPlans = phases.reduce((sum, p) => sum + p.plan_count, 0);
|
|
633
656
|
const totalSummaries = phases.reduce((sum, p) => sum + p.summary_count, 0);
|
|
634
|
-
const completedPhases = phases.filter(p => p.disk_status ===
|
|
657
|
+
const completedPhases = phases.filter(p => p.disk_status === phase_status_cjs_1.DISK_STATUS.COMPLETE).length;
|
|
635
658
|
// Detect phases in summary list without detail sections (malformed ROADMAP).
|
|
636
659
|
// The char class must allow `-` (not just `.`) so dash-separated milestone-prefixed
|
|
637
660
|
// IDs (e.g. `1-01`) match the detail-heading scanner above; otherwise they truncate
|
|
@@ -718,21 +741,12 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
718
741
|
hasResearch = counts.hasResearch;
|
|
719
742
|
contextReadError = counts.contextReadError;
|
|
720
743
|
contextScope = counts.scope;
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
diskStatus = 'partial';
|
|
726
|
-
else if (planCount > 0)
|
|
727
|
-
diskStatus = 'planned';
|
|
728
|
-
else if (hasResearch)
|
|
729
|
-
diskStatus = 'researched';
|
|
730
|
-
else if (hasContext)
|
|
731
|
-
diskStatus = 'discussed';
|
|
732
|
-
else
|
|
733
|
-
diskStatus = 'empty';
|
|
744
|
+
// #5060: same owner call as the heading branch above.
|
|
745
|
+
const ps = (0, phase_status_cjs_1.phaseStatus)(node_path_1.default.join(phasesDir, dirMatch), { convention });
|
|
746
|
+
statusError = firstStatusError(statusError, ps.value.statusError);
|
|
747
|
+
diskStatus = (0, phase_status_cjs_1.toDiskStatus)(ps.value.status, { hasResearch, hasContext });
|
|
734
748
|
}
|
|
735
|
-
|
|
749
|
+
const synthesized = {
|
|
736
750
|
number: occ.token,
|
|
737
751
|
name: `Phase ${occ.token}`,
|
|
738
752
|
goal: null,
|
|
@@ -746,7 +760,9 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
746
760
|
roadmap_complete: occ.checked,
|
|
747
761
|
context_read_error: contextReadError,
|
|
748
762
|
context_scope: contextScope,
|
|
749
|
-
}
|
|
763
|
+
};
|
|
764
|
+
PHASES_WITH_CHECKBOX.add(synthesized);
|
|
765
|
+
phases.push(synthesized);
|
|
750
766
|
}
|
|
751
767
|
}
|
|
752
768
|
// The EMITTED value stays the bare token, unchanged: `phases[].number` is a
|
|
@@ -790,6 +806,29 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
790
806
|
const progressPercent = progressScope === SCOPE.COMPLETE
|
|
791
807
|
? (0, phase_lifecycle_cjs_1.clampPercent)(scopedTotalSummaries, scopedTotalPlans)
|
|
792
808
|
: null;
|
|
809
|
+
// #4757: `current_phase` / `next_phase` / `completed_phases` are disk-
|
|
810
|
+
// authoritative (ADR-3180 §7.4, #2957 — a ticked ROADMAP checkbox carries no
|
|
811
|
+
// machine authority), so a phase whose checkbox disagrees with its disk
|
|
812
|
+
// status can be handed back as the phase to work on while the operator has
|
|
813
|
+
// already ticked it (a backfilled phase with a SUMMARY and no PLAN reads
|
|
814
|
+
// `empty`; an all-summarized phase with no VERIFICATION reads `executed`), or
|
|
815
|
+
// withheld from `completed_phases` while ticked-complete. The selectors stay
|
|
816
|
+
// disk-authoritative; the disagreement is SURFACED here rather than silently
|
|
817
|
+
// resolved either way. Computed after the heading/table/checklist phase
|
|
818
|
+
// enumeration is final so synthesized phases are covered too. Only phases
|
|
819
|
+
// that HAVE a checkbox can conflict: a progress-table row or a heading with
|
|
820
|
+
// no checklist entry reports `roadmap_complete: false` because there is no
|
|
821
|
+
// checkbox to read, not because one is unticked.
|
|
822
|
+
const checkboxConflict = phases
|
|
823
|
+
.filter(p => PHASES_WITH_CHECKBOX.has(p)
|
|
824
|
+
&& p.roadmap_complete !== (p.disk_status === phase_status_cjs_1.DISK_STATUS.COMPLETE))
|
|
825
|
+
.map(p => ({
|
|
826
|
+
number: p.number,
|
|
827
|
+
roadmap_complete: p.roadmap_complete,
|
|
828
|
+
disk_status: p.disk_status,
|
|
829
|
+
plan_count: p.plan_count,
|
|
830
|
+
summary_count: p.summary_count,
|
|
831
|
+
}));
|
|
793
832
|
const result = {
|
|
794
833
|
milestones,
|
|
795
834
|
phases,
|
|
@@ -817,6 +856,9 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
817
856
|
progress_scope: progressScope,
|
|
818
857
|
current_phase: currentPhase ? currentPhase.number : null,
|
|
819
858
|
next_phase: nextPhase ? nextPhase.number : null,
|
|
859
|
+
// #4757: phases whose ROADMAP checkbox disagrees with `disk_status`
|
|
860
|
+
// (`roadmap_complete` vs `disk_status === "complete"`); always an array.
|
|
861
|
+
checkbox_conflict: checkboxConflict,
|
|
820
862
|
missing_phase_details: missingDetails.length > 0 ? missingDetails : null,
|
|
821
863
|
// #3184/#3165: distinguishes a genuinely empty milestone (`scope:
|
|
822
864
|
// "complete"`, `phase_count: 0`) from a window that could not be fully
|
|
@@ -824,6 +866,10 @@ function cmdRoadmapAnalyze(cwd, raw) {
|
|
|
824
866
|
// were previously output-identical.
|
|
825
867
|
scope,
|
|
826
868
|
};
|
|
869
|
+
// #5118: a read-only aggregate over a refused report prints nothing and
|
|
870
|
+
// fails with the error's own reason.
|
|
871
|
+
if (statusError)
|
|
872
|
+
failOnVerificationStatusError(statusError);
|
|
827
873
|
output(result, raw, undefined);
|
|
828
874
|
}
|
|
829
875
|
// ─── cmdRoadmapMilestoneScope ────────────────────────────────────────────────
|
|
@@ -867,11 +913,11 @@ function cmdRoadmapMilestoneScope(cwd, raw) {
|
|
|
867
913
|
phaseIdConvention = undefined;
|
|
868
914
|
}
|
|
869
915
|
if (phaseIdConvention === undefined || phaseIdConvention === null) {
|
|
870
|
-
//
|
|
871
|
-
//
|
|
872
|
-
const
|
|
873
|
-
if (
|
|
874
|
-
const kvMatch =
|
|
916
|
+
// The block is the one the one fence owner finds (`frontmatterRegion`), the same one
|
|
917
|
+
// `roadmap validate` reads, so the two cannot disagree on where it ends (#3641 NEW-1).
|
|
918
|
+
const found = frontmatterRegion(rawContent);
|
|
919
|
+
if (found?.terminated) {
|
|
920
|
+
const kvMatch = found.region.match(/^phase_id_convention:\s*(.*)$/m);
|
|
875
921
|
if (kvMatch) {
|
|
876
922
|
const val = kvMatch[1].trim();
|
|
877
923
|
if (val !== 'null' && val !== '') {
|
|
@@ -928,11 +974,20 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
928
974
|
if (!phaseInfo) {
|
|
929
975
|
error(`Phase ${phaseNum} not found`);
|
|
930
976
|
}
|
|
931
|
-
const
|
|
932
|
-
//
|
|
933
|
-
//
|
|
934
|
-
//
|
|
935
|
-
|
|
977
|
+
const phaseDir = node_path_1.default.join(cwd, phaseInfo.directory);
|
|
978
|
+
// #5060: ONE count source for this verb — `scanPhasePlans` (the ADR-3180
|
|
979
|
+
// §7.5 count owner) — rather than `phaseInfo.plans.length` /
|
|
980
|
+
// `countMatchedSummaries(phaseInfo.plans, phaseInfo.summaries)`. The two
|
|
981
|
+
// diverge when a plan's frontmatter declares `status: superseded`:
|
|
982
|
+
// scanPhasePlans excludes it (and its summary) from both counts (#2349),
|
|
983
|
+
// the phaseInfo-based counts do not. Using scanPhasePlans everywhere in
|
|
984
|
+
// this verb — the `planCount === 0` decline, the `Plans Complete` cell,
|
|
985
|
+
// the `Plans:` line, the checkbox gate, and the JSON output — keeps every
|
|
986
|
+
// one of those in agreement with the Status-cell ladder below, which
|
|
987
|
+
// already read scanPhasePlans's counts.
|
|
988
|
+
const coverageScan = scanPhasePlans(phaseDir);
|
|
989
|
+
const planCount = coverageScan.planCount;
|
|
990
|
+
const summaryCount = coverageScan.summaryCount;
|
|
936
991
|
if (planCount === 0) {
|
|
937
992
|
declineNoOp(raw, 'updated', 'No plans found', 'roadmap update-plan-progress skipped — no plans found for this phase. ROADMAP.md was left unchanged.', { plan_count: 0, summary_count: 0 });
|
|
938
993
|
return;
|
|
@@ -949,12 +1004,15 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
949
1004
|
// agrees with `roadmap analyze` / `init manager` / `phase complete` for
|
|
950
1005
|
// the same phase (ADR-3180 §7.4's headline: one predicate for the read
|
|
951
1006
|
// path and the write path).
|
|
952
|
-
const phaseDir = node_path_1.default.join(cwd, phaseInfo.directory);
|
|
953
1007
|
// ADR-3180 §7.4 read/write-path symmetry with the threaded site at ~583:
|
|
954
1008
|
// thread convention here too, so this write path's completion reading
|
|
955
1009
|
// agrees with the read path's under the bracket convention.
|
|
956
1010
|
const convention = resolvePhaseIdConvention(cwd);
|
|
957
1011
|
const completionResult = isPhaseComplete(phaseDir, { convention });
|
|
1012
|
+
// #5118: no write before the error — a report whose `status` is outside the
|
|
1013
|
+
// closed set fails this writer before ROADMAP.md is touched.
|
|
1014
|
+
if (completionResult.value.statusError)
|
|
1015
|
+
failOnVerificationStatusError(completionResult.value.statusError);
|
|
958
1016
|
const verificationResult = completionResult.value.verification;
|
|
959
1017
|
// #2648 precedent, applied at this write site (ADR-3180 §7.4 / #3186):
|
|
960
1018
|
// `isPhaseComplete` deliberately carries NO plan-count precondition — the
|
|
@@ -970,14 +1028,29 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
970
1028
|
// (phase.cts:~1995, #2648: "a coverage gate that passes when it cannot
|
|
971
1029
|
// read the plans is no gate at all"), composed explicitly here rather than
|
|
972
1030
|
// folded into the predicate: complete AND all plans executed.
|
|
973
|
-
|
|
1031
|
+
// #5060: `coverageScan` (declared above, before the `planCount === 0`
|
|
1032
|
+
// decline) is now this verb's ONE count source — the `Plans Complete`
|
|
1033
|
+
// cell, the `Plans:` line, the checkbox gate, the JSON output, and the
|
|
1034
|
+
// Status-cell ladder below all read `planCount`/`summaryCount` from it, so
|
|
1035
|
+
// a phase with a `status: superseded` plan (#2349) reports the same
|
|
1036
|
+
// counts everywhere instead of diverging between the ladder and the rest
|
|
1037
|
+
// of this verb's output.
|
|
974
1038
|
const unsummarizedPlans = findUnsummarizedPlans(coverageScan.planFiles, coverageScan.summaryFiles);
|
|
975
1039
|
const isComplete = completionResult.value.complete && unsummarizedPlans.length === 0;
|
|
976
1040
|
// #3057 B3: routing above is unchanged (an indeterminate staleness check
|
|
977
1041
|
// still routes as if nothing were stale) — this only makes the fact visible
|
|
978
1042
|
// to whatever reads this command's JSON output.
|
|
979
|
-
const verificationStaleCheckIndeterminate = verificationResult.staleCheckIndeterminate === true;
|
|
980
|
-
|
|
1043
|
+
const verificationStaleCheckIndeterminate = 'staleCheckIndeterminate' in verificationResult && verificationResult.staleCheckIndeterminate === true;
|
|
1044
|
+
// #5060: route the Status-cell token through the Phase Status Module's
|
|
1045
|
+
// owner ladder rather than a local if/else, over the same `planCount`/
|
|
1046
|
+
// `summaryCount` (from `coverageScan`) every other output in this verb
|
|
1047
|
+
// uses.
|
|
1048
|
+
const status = (0, phase_status_cjs_1.toRoadmapStatusCell)((0, phase_status_cjs_1.phaseStatusFromFacts)({
|
|
1049
|
+
planCount,
|
|
1050
|
+
summaryCount,
|
|
1051
|
+
complete: isComplete,
|
|
1052
|
+
verificationStatus: verificationResult.status,
|
|
1053
|
+
}));
|
|
981
1054
|
const today = clock_cjs_1.realClock.localToday();
|
|
982
1055
|
if (!node_fs_1.default.existsSync(roadmapPath)) {
|
|
983
1056
|
declineNoOp(raw, 'updated', 'ROADMAP.md not found', 'roadmap update-plan-progress skipped — ROADMAP.md not found.', { plan_count: planCount, summary_count: summaryCount });
|
|
@@ -1068,7 +1141,29 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
1068
1141
|
text = plansResult.value;
|
|
1069
1142
|
tableRowFound = true;
|
|
1070
1143
|
}
|
|
1071
|
-
|
|
1144
|
+
// #4925: the verb owns the Status cell's leading status TOKEN only — the
|
|
1145
|
+
// same split #2853/#3584 made for the `Plans:` line below. It used to
|
|
1146
|
+
// overwrite the whole cell with ` ${status.padEnd(11)}` (no trailing
|
|
1147
|
+
// space), discarding any operator prose kept after the token. Three arms:
|
|
1148
|
+
// 1. empty or a dash placeholder → write the token, padded exactly as
|
|
1149
|
+
// phase complete writes ` Complete ` (phase.cts).
|
|
1150
|
+
// 2. a leading status token → rewrite the token only and keep the prose
|
|
1151
|
+
// after it; an unchanged token leaves the cell byte-identical.
|
|
1152
|
+
// 3. freeform prose with no leading token → operator-owned, untouched.
|
|
1153
|
+
// #5060: routed through the Phase Status Module's `matchRoadmapStatusCell`
|
|
1154
|
+
// owner rather than a local statusTokenRe. `ROADMAP_STATUS_TOKEN.DEFERRED`
|
|
1155
|
+
// is now a recognized token (the old regex never matched "deferred" at
|
|
1156
|
+
// all, so a Deferred cell fell through to arm 3 unchanged) — the DEFERRED
|
|
1157
|
+
// guard below preserves that same "leave it alone" outcome explicitly.
|
|
1158
|
+
const statusResult = (0, markdown_table_cjs_1.updateTableCell)(text, rowMatch, 'Status', (current) => {
|
|
1159
|
+
if (current === '' || /^[-–—]$/.test(current))
|
|
1160
|
+
return ` ${status.padEnd(11)} `;
|
|
1161
|
+
const m = (0, phase_status_cjs_1.matchRoadmapStatusCell)(current);
|
|
1162
|
+
if (!m || m.token === phase_status_cjs_1.ROADMAP_STATUS_TOKEN.DEFERRED || m.text === status)
|
|
1163
|
+
return current;
|
|
1164
|
+
const rest = current.slice(m.text.length);
|
|
1165
|
+
return rest === '' ? ` ${status.padEnd(11)} ` : ` ${(0, markdown_table_cjs_1.escapeCell)(status + rest)} `;
|
|
1166
|
+
});
|
|
1072
1167
|
if (statusResult.ok) {
|
|
1073
1168
|
text = statusResult.value;
|
|
1074
1169
|
tableRowFound = true;
|
|
@@ -1085,7 +1180,9 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
|
|
|
1085
1180
|
if (isComplete) {
|
|
1086
1181
|
return dateShape.test(current.trim()) ? current : ` ${today} `;
|
|
1087
1182
|
}
|
|
1088
|
-
|
|
1183
|
+
// #4925: only a stale ISO completion date — this verb's own stamp — is
|
|
1184
|
+
// cleared; a `-` placeholder or operator text stays byte-identical.
|
|
1185
|
+
return dateShape.test(current) ? ' ' : current;
|
|
1089
1186
|
});
|
|
1090
1187
|
if (completedResult.ok) {
|
|
1091
1188
|
text = completedResult.value;
|