@opengsd/gsd-core 1.10.0 → 1.12.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/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +12 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-doc-synthesizer.md +2 -4
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +22 -14
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +5 -3
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +23 -2
- package/agents/gsd-plan-checker.md +50 -53
- package/agents/gsd-planner.md +50 -50
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +63 -4
- package/agents/gsd-ui-researcher.md +41 -3
- package/agents/gsd-user-profiler.md +3 -0
- package/agents/gsd-verifier.md +13 -4
- package/bin/install.js +1448 -1103
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/map-codebase.md +1 -1
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/mempalace-recall.md +1 -1
- package/commands/gsd/new-milestone.md +1 -1
- package/commands/gsd/quick.md +9 -5
- package/commands/gsd/review-backlog.md +2 -1
- package/commands/gsd/verify-work.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +1035 -138
- package/gsd-core/bin/lib/active-workstream-store.cjs +146 -22
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +392 -32
- package/gsd-core/bin/lib/api-coverage.cjs +33 -14
- package/gsd-core/bin/lib/artifacts.cjs +5 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +32 -15
- package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
- package/gsd-core/bin/lib/audit.cjs +1026 -268
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-consent.cjs +149 -15
- package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +845 -130
- package/gsd-core/bin/lib/capability-source.cjs +92 -0
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-trust.cjs +444 -25
- package/gsd-core/bin/lib/capability-validator.cjs +700 -40
- package/gsd-core/bin/lib/capability-writer.cjs +3 -2
- package/gsd-core/bin/lib/check-command-router.cjs +216 -42
- package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +735 -0
- package/gsd-core/bin/lib/command-aliases.cjs +22 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-roster.cjs +44 -1
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +1172 -108
- package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
- package/gsd-core/bin/lib/complexity-trigger.cjs +1192 -0
- package/gsd-core/bin/lib/config-loader.cjs +187 -23
- package/gsd-core/bin/lib/config.cjs +102 -3
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +208 -33
- package/gsd-core/bin/lib/decisions.cjs +23 -0
- package/gsd-core/bin/lib/edge-probe.cjs +9 -1
- package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
- package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
- package/gsd-core/bin/lib/frontmatter.cjs +899 -229
- package/gsd-core/bin/lib/gap-checker.cjs +95 -10
- package/gsd-core/bin/lib/git-base-branch.cjs +276 -39
- package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +149 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +268 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +187 -0
- package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
- package/gsd-core/bin/lib/health-diagnostic.cjs +451 -0
- package/gsd-core/bin/lib/host-integration.cjs +39 -6
- package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +439 -168
- package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
- package/gsd-core/bin/lib/install-engine.cjs +811 -259
- package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +235 -0
- package/gsd-core/bin/lib/install-profiles.cjs +212 -61
- package/gsd-core/bin/lib/install-scope.cjs +270 -0
- package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
- package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +148 -38
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +170 -15
- package/gsd-core/bin/lib/learnings.cjs +85 -14
- package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
- package/gsd-core/bin/lib/markdown-table.cjs +183 -22
- package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
- package/gsd-core/bin/lib/milestone.cjs +842 -73
- package/gsd-core/bin/lib/model-catalog.cjs +232 -16
- package/gsd-core/bin/lib/model-resolver.cjs +193 -68
- package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/pattern.cjs +122 -0
- package/gsd-core/bin/lib/phase-estimation.cjs +18 -9
- package/gsd-core/bin/lib/phase-id.cjs +514 -40
- package/gsd-core/bin/lib/phase-lifecycle.cjs +52 -19
- package/gsd-core/bin/lib/phase-locator.cjs +262 -34
- package/gsd-core/bin/lib/phase.cjs +1038 -214
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
- package/gsd-core/bin/lib/plan-document.cjs +263 -0
- package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
- package/gsd-core/bin/lib/plan-scan.cjs +98 -3
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-scope.cjs +31 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +894 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +112 -6
- package/gsd-core/bin/lib/probe-core.cjs +5 -2
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +766 -0
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +22 -13
- package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
- package/gsd-core/bin/lib/roadmap-command-router.cjs +59 -11
- package/gsd-core/bin/lib/roadmap-parser.cjs +1006 -184
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
- package/gsd-core/bin/lib/roadmap.cjs +442 -96
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +702 -52
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +459 -55
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
- package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +402 -58
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
- package/gsd-core/bin/lib/runtime-slash.cjs +96 -8
- package/gsd-core/bin/lib/security.cjs +104 -5
- package/gsd-core/bin/lib/shell-command-projection.cjs +342 -7
- package/gsd-core/bin/lib/smart-entry.cjs +133 -23
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +52 -19
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +338 -8
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +846 -176
- package/gsd-core/bin/lib/state.cjs +2589 -369
- package/gsd-core/bin/lib/surface.cjs +33 -11
- package/gsd-core/bin/lib/task-command-router.cjs +111 -1
- package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/text-lines.cjs +80 -0
- package/gsd-core/bin/lib/token-scanner.cjs +76 -0
- package/gsd-core/bin/lib/uat-predicate.cjs +67 -23
- package/gsd-core/bin/lib/uat.cjs +1761 -167
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +51 -12
- package/gsd-core/bin/lib/unusable-input.cjs +37 -0
- package/gsd-core/bin/lib/update-context.cjs +8 -2
- package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +20 -6
- package/gsd-core/bin/lib/vendor/README.md +75 -0
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
- package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +272 -9
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +453 -918
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
- package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/workstream.cjs +2 -2
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +341 -18
- package/gsd-core/bin/shared/config-defaults.manifest.json +8 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +12 -1
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/references/agent-contracts.md +44 -26
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +39 -21
- package/gsd-core/references/context-budget.md +1 -1
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/dispatch-isolation-gate.md +138 -0
- package/gsd-core/references/doc-conflict-engine.md +1 -1
- package/gsd-core/references/edge-probe.md +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +4 -6
- package/gsd-core/references/execute-phase-between-wave-reset.md +15 -14
- package/gsd-core/references/execute-phase-context-guard.md +1 -1
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/execute-phase-wave-guard.md +17 -11
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +5 -4
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +61 -2
- package/gsd-core/references/model-profiles.md +12 -4
- package/gsd-core/references/mvp-concepts.md +9 -9
- package/gsd-core/references/nyquist-compliance.md +74 -0
- package/gsd-core/references/offer-next.md +3 -5
- package/gsd-core/references/phase-argument-parsing.md +3 -3
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-guidance.md +3 -9
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-preconditions.md +1 -1
- package/gsd-core/references/planner-reviews.md +1 -1
- package/gsd-core/references/planner-revision.md +1 -1
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +44 -13
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/revision-loop.md +1 -1
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/specless-probe-fallback.md +1 -1
- package/gsd-core/references/tdd.md +1 -3
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +5 -5
- package/gsd-core/references/verifier-phase-gates.md +192 -0
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -17
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/discussion-log.md +1 -1
- package/gsd-core/templates/phase-prompt.md +5 -4
- package/gsd-core/templates/state.md +11 -4
- package/gsd-core/templates/verification-report.md +9 -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 +3 -3
- package/gsd-core/workflows/add-tests.md +3 -8
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +13 -20
- package/gsd-core/workflows/audit-fix.md +12 -3
- package/gsd-core/workflows/audit-milestone.md +9 -9
- package/gsd-core/workflows/audit-uat.md +17 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +11 -27
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +64 -5
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +14 -4
- package/gsd-core/workflows/code-review-fix.md +38 -11
- package/gsd-core/workflows/code-review.md +159 -52
- package/gsd-core/workflows/complete-milestone.md +151 -23
- package/gsd-core/workflows/debug.md +12 -8
- package/gsd-core/workflows/diagnose-issues.md +47 -15
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -8
- package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -3
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +3 -6
- package/gsd-core/workflows/docs-update.md +5 -4
- package/gsd-core/workflows/edit-phase.md +27 -2
- package/gsd-core/workflows/eval-review.md +7 -14
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +142 -15
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +24 -4
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase.md +72 -100
- package/gsd-core/workflows/execute-plan.md +52 -15
- package/gsd-core/workflows/explore.md +131 -4
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +10 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +76 -10
- package/gsd-core/workflows/import.md +18 -15
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +49 -16
- package/gsd-core/workflows/insert-phase.md +5 -5
- package/gsd-core/workflows/list-seeds.md +5 -3
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +12 -23
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +8 -5
- package/gsd-core/workflows/new-milestone.md +22 -29
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +26 -40
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +14 -2
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
- package/gsd-core/workflows/plan-phase.md +162 -59
- package/gsd-core/workflows/plan-review-convergence.md +96 -11
- package/gsd-core/workflows/plant-seed.md +2 -2
- package/gsd-core/workflows/pr-branch.md +187 -51
- package/gsd-core/workflows/profile-user.md +16 -14
- package/gsd-core/workflows/progress.md +61 -18
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +5 -7
- package/gsd-core/workflows/quick/steps/quick-verification.md +28 -9
- package/gsd-core/workflows/quick/steps/research-phase.md +4 -6
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +55 -44
- package/gsd-core/workflows/remove-phase.md +4 -4
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +8 -12
- package/gsd-core/workflows/review.md +219 -20
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -3
- package/gsd-core/workflows/session-report.md +2 -1
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +69 -7
- package/gsd-core/workflows/ship.md +116 -50
- package/gsd-core/workflows/sketch-wrap-up.md +11 -17
- package/gsd-core/workflows/sketch.md +12 -18
- package/gsd-core/workflows/smart-entry.md +3 -5
- package/gsd-core/workflows/spec-phase.md +53 -13
- package/gsd-core/workflows/spike-wrap-up.md +7 -11
- package/gsd-core/workflows/spike.md +20 -31
- package/gsd-core/workflows/stats.md +2 -2
- package/gsd-core/workflows/sync-skills.md +64 -9
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +49 -14
- package/gsd-core/workflows/ui-phase.md +15 -21
- package/gsd-core/workflows/ui-review.md +8 -12
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +7 -11
- package/gsd-core/workflows/validate-phase.md +3 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +66 -25
- package/hooks/dist/gsd-agent-isolation-guard.js +158 -30
- package/hooks/dist/gsd-check-update-worker.js +56 -13
- package/hooks/dist/gsd-check-update.js +19 -1
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +19 -10
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +2 -3
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +83 -3
- package/hooks/dist/gsd-cursor-subagent-stop.js +6 -3
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +76 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +37 -27
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +55 -32
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +231 -24
- package/hooks/dist/gsd-update-banner.js +22 -1
- package/hooks/dist/gsd-validate-commit.sh +80 -6
- package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
- package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
- package/hooks/dist/gsd-workflow-guard.js +162 -46
- package/hooks/dist/gsd-worktree-path-guard.js +36 -21
- package/hooks/dist/gsd-write-guard.js +35 -25
- package/hooks/dist/lib/cli-exit.js +560 -0
- package/hooks/dist/lib/exit-code-registry.js +98 -0
- package/hooks/dist/lib/git-cmd.js +92 -59
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/lib/injection-patterns.js +45 -0
- package/hooks/dist/lib/isolation-deny-reason.js +39 -0
- package/hooks/dist/lib/isolation-sentinel.js +9 -0
- package/hooks/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +158 -30
- package/hooks/gsd-check-update-worker.js +56 -13
- package/hooks/gsd-check-update.js +19 -1
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +19 -10
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +2 -3
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +83 -3
- package/hooks/gsd-cursor-subagent-stop.js +6 -3
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +76 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +37 -27
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +55 -32
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +231 -24
- package/hooks/gsd-update-banner.js +22 -1
- package/hooks/gsd-validate-commit.sh +80 -6
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +162 -46
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-cmd.js +92 -59
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/lib/injection-patterns.js +45 -0
- package/hooks/lib/isolation-deny-reason.js +39 -0
- package/hooks/lib/isolation-sentinel.js +9 -0
- package/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +28 -11
- package/pi/gsd.cjs +19 -5
- package/scripts/base64-scan.sh +74 -12
- package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
- package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
- package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
- package/scripts/build-hooks.js +5 -0
- package/scripts/changeset/lint.cjs +60 -5
- package/scripts/check-alias-drift.cjs +7 -43
- package/scripts/check-contract-drift.cjs +297 -0
- package/scripts/check-glossary-refs.cjs +77 -15
- package/scripts/check-mutation-score-ratchet.cjs +156 -0
- package/scripts/ci-check-job-near-cap.cjs +49 -0
- package/scripts/ci-pr-mergeability.cjs +262 -0
- package/scripts/ci-test-scope.cjs +64 -14
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/command-contract-helpers.cjs +903 -1
- package/scripts/docs-guard-registry.cjs +396 -0
- package/scripts/gen-adr-index.cjs +728 -38
- package/scripts/gen-capability-registry.cjs +11 -21
- package/scripts/gen-context-index.cjs +2 -11
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-health-docs.cjs +390 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-inventory-manifest.cjs +50 -4
- package/scripts/gen-loop-host-contract.cjs +138 -25
- package/scripts/gen-registry.cjs +3 -14
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/alias-drift-families.cjs +46 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +308 -0
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
- package/scripts/lint-canary-version-leak.cjs +73 -0
- package/scripts/lint-command-contract.cjs +96 -13
- package/scripts/lint-completion-predicate-drift.cjs +933 -0
- package/scripts/lint-completion-ratio-drift.cjs +214 -0
- package/scripts/lint-default-flip-documentation.cjs +193 -0
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +38 -0
- package/scripts/lint-eslint-glob-coverage.cjs +340 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
- package/scripts/lint-health-diagnostic-rule-table.cjs +461 -0
- package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
- package/scripts/lint-milestone-window-drift.cjs +468 -0
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +492 -0
- package/scripts/lint-plan-count-drift.cjs +318 -0
- package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
- package/scripts/lint-planning-prompt-drift.cjs +471 -0
- package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
- package/scripts/lint-regression-test-names.cjs +15 -13
- package/scripts/lint-removed-but-needed.cjs +488 -0
- package/scripts/lint-seam-enforcement.cjs +182 -0
- package/scripts/lint-slug-derivation-drift.cjs +921 -0
- package/scripts/lint-source-test-name-collision.cjs +241 -0
- package/scripts/lint-state-field-drift.cjs +805 -0
- package/scripts/lint-state-write-path-drift.cjs +950 -0
- package/scripts/lint-test-file-count.allowlist.json +137 -8
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +830 -0
- package/scripts/lint-vendored-deps.cjs +297 -0
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/pr-changed-files.cjs +63 -0
- package/scripts/pr-template-policy.cjs +14 -4
- package/scripts/prompt-injection-scan.sh +100 -14
- package/scripts/require-issue-link-policy.cjs +192 -0
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +24 -7
- package/skills/gsd-autonomous/SKILL.md +0 -1
- package/skills/gsd-code-review/SKILL.md +1 -1
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -2
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-map-codebase/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-recall/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-next/SKILL.md +0 -1
- package/skills/gsd-plan-phase/SKILL.md +0 -1
- package/skills/gsd-progress/SKILL.md +0 -1
- package/skills/gsd-quick/SKILL.md +9 -5
- package/skills/gsd-review-backlog/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +0 -1
- package/skills/gsd-verify-work/SKILL.md +1 -1
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -107
- package/gsd-core/workflows/discovery-phase.md +0 -298
- package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
- package/gsd-core/workflows/verify-phase.md +0 -574
- package/scripts/affected-tests-lib.cjs +0 -554
- package/scripts/lint-allow-test-rule-refs.cjs +0 -162
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/run-affected-tests.cjs +0 -7
- package/scripts/run-tests.cjs +0 -1051
|
@@ -43,6 +43,10 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
43
43
|
const node_path_1 = __importDefault(require("node:path"));
|
|
44
44
|
const node_child_process_1 = require("node:child_process");
|
|
45
45
|
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
46
|
+
// #3696: the calendar-validity predicate moved to the STATE.md document module
|
|
47
|
+
// so `state validate` can assert the same `last_activity` invariant this reader
|
|
48
|
+
// already enforces (ADR-227). Two copies would let the two surfaces disagree
|
|
49
|
+
// about whether a STATE.md is usable — which is the defect #3696 reports.
|
|
46
50
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
47
51
|
const ioMod = require("./io.cjs");
|
|
48
52
|
const { output } = ioMod;
|
|
@@ -57,10 +61,13 @@ const phaseLifecycle = require("./phase-lifecycle.cjs");
|
|
|
57
61
|
const { deriveProgressFromRoadmap } = phaseLifecycle;
|
|
58
62
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
59
63
|
const stateDocument = require("./state-document.cjs");
|
|
60
|
-
const {
|
|
64
|
+
const { stateFieldValue } = stateDocument;
|
|
61
65
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
62
66
|
const phaseId = require("./phase-id.cjs");
|
|
63
|
-
const { comparePhaseNum, extractPhaseToken, normalizePhaseName,
|
|
67
|
+
const { comparePhaseNum, extractPhaseToken, matchPhaseDirs, normalizePhaseName, stripProjectCodePrefix } = phaseId;
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
69
|
+
const stateMod = require("./state.cjs");
|
|
70
|
+
const { readStateHeadFreshness } = stateMod;
|
|
64
71
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
65
72
|
const unusableInput = require("./unusable-input.cjs");
|
|
66
73
|
const { warnUnusableInput, UNUSABLE_REASON } = unusableInput;
|
|
@@ -86,15 +93,6 @@ exports.SITUATIONS = Object.freeze([
|
|
|
86
93
|
'unknown',
|
|
87
94
|
]);
|
|
88
95
|
// ─── Detection ─────────────────────────────────────────────────────────────────
|
|
89
|
-
/** Frontmatter scalar helper: prefer YAML frontmatter, fall back to body field. */
|
|
90
|
-
function fmScalar(fm, body, key, bodyField) {
|
|
91
|
-
const v = fm[key];
|
|
92
|
-
if (typeof v === 'string' && v.trim())
|
|
93
|
-
return v.trim();
|
|
94
|
-
if (typeof v === 'number' || typeof v === 'boolean')
|
|
95
|
-
return String(v);
|
|
96
|
-
return stateExtractField(body, bodyField);
|
|
97
|
-
}
|
|
98
96
|
/** Read a scalar value from a nested frontmatter object (e.g. progress.total_phases). */
|
|
99
97
|
function fmScalarKey(obj, key) {
|
|
100
98
|
if (!obj || typeof obj !== 'object')
|
|
@@ -115,17 +113,95 @@ function parseIntOrNull(s) {
|
|
|
115
113
|
}
|
|
116
114
|
function phaseTokenFromDirName(name) {
|
|
117
115
|
const token = extractPhaseToken(name);
|
|
118
|
-
|
|
116
|
+
// #2528: the shape probe runs on the PROJECT-CODE-STRIPPED token. A prefixed
|
|
117
|
+
// directory tokenizes to `MEM-05-80-20`, which does not start with a digit,
|
|
118
|
+
// so the unstripped probe rejected it and the entry was dropped before any
|
|
119
|
+
// resolution ran — every phase in a project-coded plan was invisible here.
|
|
120
|
+
// The full token is still what is returned: `comparePhaseNum` strips the
|
|
121
|
+
// prefix itself, so the sort is unaffected, and `matchPhaseDirs` needs the
|
|
122
|
+
// real directory name.
|
|
123
|
+
const probe = stripProjectCodePrefix(token);
|
|
124
|
+
return /^\d+(?:[A-Z])?(?:\.\d+)*(?:-|$)/i.test(probe) ? token : null;
|
|
119
125
|
}
|
|
120
126
|
/**
|
|
121
127
|
* Parse a `last_activity` value that may be an ISO date or a free-form string
|
|
122
128
|
* into an epoch-ms timestamp. Returns null when unparseable.
|
|
129
|
+
*
|
|
130
|
+
* #2570: `last_activity` routinely carries a trailing " — <description>" — the
|
|
131
|
+
* shape `templates/state.md` itself prescribes (`Last activity: [YYYY-MM-DD] —
|
|
132
|
+
* [What happened]`), which gsd-core's own STATE.md mirrors into frontmatter.
|
|
133
|
+
* `Date.parse` on the whole string returns NaN, and because `staleActivity`
|
|
134
|
+
* treats null as "not stale" (fails open), the ONLY idle/staleness detector
|
|
135
|
+
* never fired on any project whose last_activity retained its description.
|
|
136
|
+
* Be liberal in what we accept (Postel): read the leading ISO date/time token
|
|
137
|
+
* when the value carries one, so the description suffix — whatever separator
|
|
138
|
+
* (em dash or hyphen) it uses — no longer silently blinds the detector; fall
|
|
139
|
+
* back to a whole-string parse for any other shape a hand edit might use.
|
|
140
|
+
*/
|
|
141
|
+
/** Leading ISO date, with an optional time-of-day and offset. */
|
|
142
|
+
const ISO_LEADING_RE = /^(\d{4})-(\d{2})-(\d{2})((?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?)/;
|
|
143
|
+
/**
|
|
144
|
+
* A NAMED timezone designator at the start of the un-reconstructable remainder
|
|
145
|
+
* (#2571). ISO_LEADING_RE's offset group captures only `Z` / `±HH:MM`, so a
|
|
146
|
+
* named zone (GMT, EST, ...) is not in the leading token — it sits here.
|
|
147
|
+
* Reconstructing the token without it would let Date.parse read the time as
|
|
148
|
+
* LOCAL, shifting the instant by the host's offset (a wrong, host-dependent
|
|
149
|
+
* value), so a zone-shaped remainder must fail open (ADR-227).
|
|
150
|
+
*
|
|
151
|
+
* The shape is a short all-caps run (2–5 letters) that stands alone — the
|
|
152
|
+
* negative lookahead excludes the first letter of a Capitalised word like
|
|
153
|
+
* "Milestone", and an optional trailing offset is subsumed because the leading
|
|
154
|
+
* all-caps run already matches. Everything else — a lowercase or Capitalised
|
|
155
|
+
* description, a separator — is describable text and is reconstructed from the
|
|
156
|
+
* leading date.
|
|
157
|
+
*
|
|
158
|
+
* Consulted ONLY when the leading token captured a time-of-day (see the caller):
|
|
159
|
+
* a zone designator qualifies a clock time, so a BARE date can carry no zone
|
|
160
|
+
* hazard — reconstructing it is always just that date's UTC midnight, whatever
|
|
161
|
+
* trails it. Gating on the time keeps a description that merely opens with a
|
|
162
|
+
* tech acronym ("2026-06-08 CI green", "API refactor") on the reconstruct path
|
|
163
|
+
* instead of failing open. The prior "any letter" guard was too liberal — it
|
|
164
|
+
* failed open on every letter-led description and re-opened #2570.
|
|
123
165
|
*/
|
|
166
|
+
const ZONE_DESIGNATOR_RE = /^\s*[A-Z]{2,5}(?![A-Za-z])/;
|
|
124
167
|
function parseActivityTimestamp(raw) {
|
|
125
168
|
if (!raw)
|
|
126
169
|
return null;
|
|
127
|
-
const
|
|
128
|
-
|
|
170
|
+
const trimmed = raw.trim();
|
|
171
|
+
const iso = trimmed.match(ISO_LEADING_RE);
|
|
172
|
+
if (iso) {
|
|
173
|
+
const [, year, month, day, time] = iso;
|
|
174
|
+
// Reject an impossible calendar date outright rather than letting
|
|
175
|
+
// Date.parse substitute a rolled-forward one. null = "no activity signal",
|
|
176
|
+
// the safe default staleActivity already fails open on.
|
|
177
|
+
if (!stateDocument.isRealCalendarDate(Number(year), Number(month), Number(day)))
|
|
178
|
+
return null;
|
|
179
|
+
// The date is real, so stay as liberal as before (Postel): a whole-string
|
|
180
|
+
// parse still wins when the engine can make sense of the value. Reading the
|
|
181
|
+
// token first would silently DROP a trailing zone name -- "2026-06-08
|
|
182
|
+
// 12:34:56 GMT" parses whole as 12:34:56Z but as local time from the token,
|
|
183
|
+
// shifting the instant by the host's UTC offset.
|
|
184
|
+
const whole = Date.parse(trimmed);
|
|
185
|
+
if (!Number.isNaN(whole))
|
|
186
|
+
return whole;
|
|
187
|
+
// Whole-string failed: the value carries a suffix the engine can't read as
|
|
188
|
+
// one instant (#2570). Reconstruct from the leading token UNLESS the remainder
|
|
189
|
+
// is a named zone the token dropped (GMT, EST, ...): reconstructing without it
|
|
190
|
+
// reads the time as LOCAL and shifts the instant by the host's offset, so a
|
|
191
|
+
// zone-shaped remainder fails open (ADR-227: never propagate a wrong instant;
|
|
192
|
+
// null is the base's not-stale default). An ordinary description -- the #2570
|
|
193
|
+
// template's " -- description", or a hand edit's bare-space/tab/colon suffix --
|
|
194
|
+
// carries no zone and IS reconstructed. See ZONE_DESIGNATOR_RE for the shape;
|
|
195
|
+
// the earlier "any letter" guard failed open on every description and re-opened
|
|
196
|
+
// #2570 for whitespace-separated suffixes.
|
|
197
|
+
const rest = trimmed.slice(iso[0].length);
|
|
198
|
+
if (time && ZONE_DESIGNATOR_RE.test(rest))
|
|
199
|
+
return null;
|
|
200
|
+
const ms = Date.parse(`${year}-${month}-${day}${time}`);
|
|
201
|
+
return Number.isNaN(ms) ? null : ms;
|
|
202
|
+
}
|
|
203
|
+
const direct = Date.parse(trimmed);
|
|
204
|
+
return Number.isNaN(direct) ? null : direct;
|
|
129
205
|
}
|
|
130
206
|
/** Read-only git signals. Any git error is swallowed → "no git signal". */
|
|
131
207
|
function readGitSignals(cwd) {
|
|
@@ -137,6 +213,7 @@ function readGitSignals(cwd) {
|
|
|
137
213
|
maxBuffer: 4 * 1024 * 1024,
|
|
138
214
|
windowsHide: true,
|
|
139
215
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
216
|
+
timeout: 10_000,
|
|
140
217
|
});
|
|
141
218
|
}
|
|
142
219
|
catch {
|
|
@@ -186,7 +263,16 @@ function detectVerifyFailed(cwd, currentPhaseRaw) {
|
|
|
186
263
|
let targetDir;
|
|
187
264
|
if (phaseToken) {
|
|
188
265
|
const normalized = normalizePhaseName(phaseToken);
|
|
189
|
-
|
|
266
|
+
// #2528: the fourth directory-resolution site, and the one where a miss is
|
|
267
|
+
// silent — a phase whose directory cannot be found reports "not failed",
|
|
268
|
+
// which reads identically to a healthy phase. It must therefore apply the
|
|
269
|
+
// same canonical selection as the locator and the two command scans, or a
|
|
270
|
+
// dir like `05-80-20-cleanup` (phase 5 named "80/20 Cleanup") never
|
|
271
|
+
// surfaces its own failed verification. `entries` is already sorted, and
|
|
272
|
+
// `matchPhaseDirs` filters without reordering, so taking the first match
|
|
273
|
+
// preserves the previous `.find()` selection exactly.
|
|
274
|
+
const { matches } = matchPhaseDirs(entries, normalized);
|
|
275
|
+
targetDir = matches[0];
|
|
190
276
|
if (!targetDir)
|
|
191
277
|
return false;
|
|
192
278
|
}
|
|
@@ -253,6 +339,9 @@ function detectSignals(cwd, now = Date.now) {
|
|
|
253
339
|
stale_activity: false,
|
|
254
340
|
roadmap_total_phases: null,
|
|
255
341
|
roadmap_completed_phases: null,
|
|
342
|
+
// No STATE.md (or unreadable) → no stamp to compare. Unknown, not fresh.
|
|
343
|
+
state_commits_behind: null,
|
|
344
|
+
state_commit_stale: null,
|
|
256
345
|
};
|
|
257
346
|
if (!hasPlanning)
|
|
258
347
|
return empty;
|
|
@@ -266,21 +355,29 @@ function detectSignals(cwd, now = Date.now) {
|
|
|
266
355
|
// - body prose: `Phase: 3`, `**Status:** verifying`, `Total Phases: 5`
|
|
267
356
|
// Read each field across every form, scalar-first then nested then body, so
|
|
268
357
|
// the classifier works on real STATE.md files written by current GSD.
|
|
269
|
-
const statusRaw =
|
|
270
|
-
const pausedAtRaw =
|
|
271
|
-
const lastActivityRaw =
|
|
358
|
+
const statusRaw = stateFieldValue(fm, body, 'status', 'Status').value;
|
|
359
|
+
const pausedAtRaw = stateFieldValue(fm, body, 'paused_at', 'Paused At').value;
|
|
360
|
+
const lastActivityRaw = stateFieldValue(fm, body, 'last_activity', 'Last Activity').value;
|
|
272
361
|
// current_phase: scalar fm → nested (none) → body "Current Phase" → body "Phase".
|
|
273
362
|
// The body `Phase:` field is the canonical location in prose-form STATE.md
|
|
274
363
|
// (e.g. "Phase: 3" or "Phase: 3 — ui-review"); parse the leading number.
|
|
275
|
-
|
|
276
|
-
|
|
364
|
+
// #3187 / ADR-3180 Amendment 3 ("0.x split"): this read is DELIBERATELY
|
|
365
|
+
// unscoped — smart-entry classifies `gsd next` routing over the whole body,
|
|
366
|
+
// whereas state.cts's copies of this same field scope it to `## Current
|
|
367
|
+
// Position` (#1776/#2956). Those are two different questions sharing a
|
|
368
|
+
// name; folding the scoped read in here would silently change smart-entry's
|
|
369
|
+
// routing, an undisclosed Tier-2 change (design's Rejected #3). Both owner
|
|
370
|
+
// calls below intentionally pass the unscoped `body`, never a Current-
|
|
371
|
+
// Position slice.
|
|
372
|
+
const currentPhaseRaw = stateFieldValue(fm, body, 'current_phase', 'Current Phase').value ??
|
|
373
|
+
stateFieldValue(fm, body, null, 'Phase').value;
|
|
277
374
|
// total_phases & percent: nested `progress:` object takes precedence in the
|
|
278
375
|
// nested schema; scalar fm / body fields cover the flat schema.
|
|
279
376
|
const progressFm = typeof fm.progress === 'object' ? fm.progress : null;
|
|
280
377
|
const totalPhasesRaw = fmScalarKey(progressFm, 'total_phases') ??
|
|
281
|
-
|
|
378
|
+
stateFieldValue(fm, body, 'total_phases', 'Total Phases').value;
|
|
282
379
|
const progressRaw = fmScalarKey(progressFm, 'percent') ??
|
|
283
|
-
|
|
380
|
+
stateFieldValue(fm, body, 'progress', 'Progress').value;
|
|
284
381
|
// Blockers list: `- <text>` items under a `## Blockers` heading.
|
|
285
382
|
const blockers = [];
|
|
286
383
|
const blockersSection = (0, markdown_sectionizer_cjs_1.collectSection)(body, (h) => h.level === 2 && h.text.trim().toLowerCase() === 'blockers', { levelBounded: true });
|
|
@@ -326,6 +423,11 @@ function detectSignals(cwd, now = Date.now) {
|
|
|
326
423
|
/* ROADMAP.md unreadable — leave null; isComplete falls back to legacy. */
|
|
327
424
|
}
|
|
328
425
|
}
|
|
426
|
+
// #2573: commit-age freshness proxy. Derived through state.cjs's
|
|
427
|
+
// readStateHeadFreshness so the tri-state and the hash fence stay identical
|
|
428
|
+
// to validate.health's W024 — one derivation, two surfaces.
|
|
429
|
+
const stateHeadRaw = stateFieldValue(fm, body, 'state_head', 'State Head').value;
|
|
430
|
+
const freshness = readStateHeadFreshness(cwd, stateHeadRaw);
|
|
329
431
|
return {
|
|
330
432
|
current_phase: parseIntOrNull(currentPhaseRaw),
|
|
331
433
|
total_phases: parseIntOrNull(totalPhasesRaw),
|
|
@@ -342,6 +444,8 @@ function detectSignals(cwd, now = Date.now) {
|
|
|
342
444
|
stale_activity: staleActivity,
|
|
343
445
|
roadmap_total_phases: roadmapTotalPhases,
|
|
344
446
|
roadmap_completed_phases: roadmapCompletedPhases,
|
|
447
|
+
state_commits_behind: freshness.commits_behind,
|
|
448
|
+
state_commit_stale: freshness.commit_stale,
|
|
345
449
|
};
|
|
346
450
|
}
|
|
347
451
|
// ─── Situation classification ─────────────────────────────────────────────────
|
|
@@ -422,7 +526,13 @@ function classify(s) {
|
|
|
422
526
|
return 'planning';
|
|
423
527
|
if (/\bexecut(e|ing)|active|in.progress|building\b/i.test(s.status))
|
|
424
528
|
return 'executing';
|
|
425
|
-
|
|
529
|
+
// #3864: `verif` (not `verify`) — the same stem state-document's
|
|
530
|
+
// normalizeStateStatus matches. "verified" and "verification" contain no
|
|
531
|
+
// "verify" substring, so the exact word left them falling through to
|
|
532
|
+
// `unknown` (or idle-stranded on a clean unpushed tree — differently
|
|
533
|
+
// wrong). verify_failed is tested above, so a failed verification still
|
|
534
|
+
// wins over this branch.
|
|
535
|
+
if (/\bverif|review|needs.review|pending.review\b/i.test(s.status))
|
|
426
536
|
return 'verify-pending';
|
|
427
537
|
if (isIdleStranded(s))
|
|
428
538
|
return 'idle-stranded';
|
|
@@ -26,6 +26,9 @@ exports.SECTION_HEADERS = void 0;
|
|
|
26
26
|
exports.countSectionDataRows = countSectionDataRows;
|
|
27
27
|
exports.specSectionStatus = specSectionStatus;
|
|
28
28
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
30
|
+
const cliExitModule = require("./cli-exit.cjs");
|
|
31
|
+
const { ExitError, runMain } = cliExitModule;
|
|
29
32
|
/**
|
|
30
33
|
* Canonical SPEC section header matchers — the SINGLE source of truth for the headings
|
|
31
34
|
* `templates/spec.md` renders. Suffix-tolerant by design: `prohibitions` matches BOTH
|
|
@@ -101,11 +104,13 @@ const VALID_KEYS = ['edges', 'prohibitions'];
|
|
|
101
104
|
// 2 only on a usage error (missing args / bad key). `require.main === module` so it runs only when
|
|
102
105
|
// the compiled `.cjs` is executed directly, never when imported by tests.
|
|
103
106
|
if (require.main === module) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
runMain(() => {
|
|
108
|
+
const specFile = process.argv[2];
|
|
109
|
+
const key = process.argv[3];
|
|
110
|
+
if (!specFile || !key || !VALID_KEYS.includes(key)) {
|
|
111
|
+
process.stderr.write('usage: spec-section.cjs <specFile> <edges|prohibitions>\n');
|
|
112
|
+
throw new ExitError(2);
|
|
113
|
+
}
|
|
114
|
+
process.stdout.write(JSON.stringify(specSectionStatus(specFile, key)) + '\n');
|
|
115
|
+
});
|
|
111
116
|
}
|
|
@@ -53,8 +53,19 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
|
|
|
53
53
|
handlers: {
|
|
54
54
|
load: () => state.cmdStateLoad(cwd, raw),
|
|
55
55
|
json: () => state.cmdStateJson(cwd, raw),
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
// ADR-3473 §8.4 / #3358 gap: these two read args[2]/args[3] positionally
|
|
57
|
+
// without ever calling parseNamedArgsOrExit, so an unrecognized flag or
|
|
58
|
+
// stray positional was silently dropped instead of rejected. No flags
|
|
59
|
+
// are declared — none are documented for these subcommands
|
|
60
|
+
// (docs/CLI-TOOLS.md:86,89) and no shipped workflow passes any.
|
|
61
|
+
get: () => {
|
|
62
|
+
(0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { positionals: 3 }, error);
|
|
63
|
+
state.cmdStateGet(cwd, args[2], raw);
|
|
64
|
+
},
|
|
65
|
+
update: () => {
|
|
66
|
+
(0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { positionals: 4 }, error);
|
|
67
|
+
state.cmdStateUpdate(cwd, args[2], args[3]);
|
|
68
|
+
},
|
|
58
69
|
patch: () => {
|
|
59
70
|
const patches = {};
|
|
60
71
|
if (args.length === 3 && typeof args[2] === 'string' && args[2].trim().startsWith('{')) {
|
|
@@ -90,7 +101,7 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
|
|
|
90
101
|
},
|
|
91
102
|
'advance-plan': () => state.cmdStateAdvancePlan(cwd, raw),
|
|
92
103
|
'record-metric': () => {
|
|
93
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
104
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'plan', 'duration', 'tasks', 'files'], positionals: 2 }, error);
|
|
94
105
|
state.cmdStateRecordMetric(cwd, {
|
|
95
106
|
phase: strArg(a, 'phase'),
|
|
96
107
|
plan: strArg(a, 'plan'),
|
|
@@ -101,7 +112,7 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
|
|
|
101
112
|
},
|
|
102
113
|
'update-progress': () => state.cmdStateUpdateProgress(cwd, raw),
|
|
103
114
|
'add-decision': () => {
|
|
104
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
115
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'summary', 'summary-file', 'rationale', 'rationale-file'], positionals: 2 }, error);
|
|
105
116
|
state.cmdStateAddDecision(cwd, {
|
|
106
117
|
phase: strArg(a, 'phase'),
|
|
107
118
|
summary: strArg(a, 'summary'),
|
|
@@ -111,11 +122,11 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
|
|
|
111
122
|
}, raw);
|
|
112
123
|
},
|
|
113
124
|
'add-blocker': () => {
|
|
114
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
125
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['text', 'text-file'], positionals: 2 }, error);
|
|
115
126
|
state.cmdStateAddBlocker(cwd, { text: strArg(a, 'text'), text_file: strArg(a, 'text-file') }, raw);
|
|
116
127
|
},
|
|
117
128
|
'add-roadmap-evolution': () => {
|
|
118
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
129
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'action', 'after', 'note', 'note-file'], booleanFlags: ['urgent'], positionals: 2 }, error);
|
|
119
130
|
state.cmdStateAddRoadmapEvolution(cwd, {
|
|
120
131
|
phase: strArg(a, 'phase'),
|
|
121
132
|
action: strArg(a, 'action'),
|
|
@@ -125,47 +136,69 @@ function routeStateCommand({ state, args, cwd, raw, error }) {
|
|
|
125
136
|
urgent: a['urgent'] === true,
|
|
126
137
|
}, raw);
|
|
127
138
|
},
|
|
128
|
-
'resolve-blocker': () => state.cmdStateResolveBlocker(cwd, strArg((0, command_arg_projection_cjs_1.
|
|
139
|
+
'resolve-blocker': () => state.cmdStateResolveBlocker(cwd, strArg((0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['text'], positionals: 2 }, error), 'text'), raw),
|
|
129
140
|
'record-session': () => {
|
|
130
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
141
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['stopped-at', 'resume-file'], positionals: 2 }, error);
|
|
131
142
|
// Pass resume_file as-is (undefined when --resume-file was not provided) so
|
|
132
143
|
// cmdStateRecordSession can distinguish "caller explicitly passed a value" from
|
|
133
144
|
// "option was not supplied" and apply the template-default-only replacement guard.
|
|
134
145
|
state.cmdStateRecordSession(cwd, { stopped_at: strArg(a, 'stopped-at'), resume_file: strArg(a, 'resume-file') }, raw);
|
|
135
146
|
},
|
|
136
147
|
'begin-phase': () => {
|
|
137
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
148
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'name', 'plans'], positionals: 2 }, error);
|
|
138
149
|
state.cmdStateBeginPhase(cwd, strArg(a, 'phase'), strArg(a, 'name'), parsePlans(strArg(a, 'plans')), raw);
|
|
139
150
|
},
|
|
140
151
|
'signal-waiting': () => {
|
|
141
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
152
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['type', 'question', 'options', 'phase'], positionals: 2 }, error);
|
|
142
153
|
state.cmdSignalWaiting(cwd, strArg(a, 'type'), strArg(a, 'question'), strArg(a, 'options'), strArg(a, 'phase'), raw);
|
|
143
154
|
},
|
|
144
155
|
'signal-resume': () => state.cmdSignalResume(cwd, raw),
|
|
145
156
|
'planned-phase': () => {
|
|
146
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
147
|
-
|
|
157
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase', 'name', 'plans'], positionals: 2 }, error);
|
|
158
|
+
// #3395: --name was parsed here but never forwarded (the StateModule
|
|
159
|
+
// signature had no channel for it), so the argument was silently
|
|
160
|
+
// dropped. It now persists into the Current Position `Phase:` line and
|
|
161
|
+
// the authoritative current_phase_name, mirroring begin-phase.
|
|
162
|
+
state.cmdStatePlannedPhase(cwd, strArg(a, 'phase'), strArg(a, 'name'), parsePlans(strArg(a, 'plans')), raw);
|
|
163
|
+
},
|
|
164
|
+
validate: () => {
|
|
165
|
+
// #3696: --strict makes the verdict gateable by exit status. The
|
|
166
|
+
// default stays exit 0 — the exit code is Tier-2 observable output
|
|
167
|
+
// reaching unenumerable downstream consumers (ADR-3180 Decision 3).
|
|
168
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { booleanFlags: ['strict'], positionals: 2 }, error);
|
|
169
|
+
state.cmdStateValidate(cwd, raw, { strict: a['strict'] === true });
|
|
148
170
|
},
|
|
149
|
-
validate: () => state.cmdStateValidate(cwd, raw),
|
|
150
171
|
sync: () => {
|
|
151
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
172
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { booleanFlags: ['verify'], positionals: 2 }, error);
|
|
152
173
|
state.cmdStateSync(cwd, { verify: a['verify'] }, raw);
|
|
153
174
|
},
|
|
154
175
|
prune: () => {
|
|
155
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
176
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['keep-recent'], booleanFlags: ['dry-run'], positionals: 2 }, error);
|
|
156
177
|
state.cmdStatePrune(cwd, { keepRecent: strArg(a, 'keep-recent') || '3', dryRun: a['dry-run'] === true }, raw);
|
|
157
178
|
},
|
|
158
179
|
rebuild: () => {
|
|
159
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
180
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { booleanFlags: ['dry-run', 'verbose'], positionals: 2 }, error);
|
|
160
181
|
state.cmdStateRebuild(cwd, { dryRun: a['dry-run'] === true, verbose: a['verbose'] === true }, raw);
|
|
161
182
|
},
|
|
162
|
-
// complete-phase: CJS-only — no SDK counterpart.
|
|
183
|
+
// complete-phase: CJS-only — no SDK counterpart. Supports two shapes:
|
|
184
|
+
// the documented `--phase N` flag (docs/COMMANDS.md:2207) and an
|
|
185
|
+
// undocumented-but-preserved bare positional `state complete-phase N`
|
|
186
|
+
// (N3). A single static `positionals` count cannot represent both: if
|
|
187
|
+
// args[2] is the flag `--phase`, the boundary must be 2 so the generic
|
|
188
|
+
// flag/value walk (which starts at the boundary) recognizes `--phase`
|
|
189
|
+
// and consumes its value; only when args[2] is itself a bare, non-flag
|
|
190
|
+
// token does the boundary widen to 3 to accept it as the positional
|
|
191
|
+
// phase. Getting this wrong either breaks the documented flag form
|
|
192
|
+
// (boundary 3 treats `--phase`'s value as an unexpected trailing
|
|
193
|
+
// positional) or silently re-admits unknown flags (a static boundary
|
|
194
|
+
// of 3 with an empty args[2] never validates anything past it).
|
|
163
195
|
'complete-phase': () => {
|
|
164
|
-
const
|
|
196
|
+
const bareTrailingPositional = args[2] !== undefined && !args[2].startsWith('--');
|
|
197
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['phase'], positionals: bareTrailingPositional ? 3 : 2 }, error);
|
|
165
198
|
state.cmdStateCompletePhase(cwd, raw, strArg(a, 'phase') || args[2]);
|
|
166
199
|
},
|
|
167
200
|
'milestone-switch': () => {
|
|
168
|
-
const a = (0, command_arg_projection_cjs_1.
|
|
201
|
+
const a = (0, command_arg_projection_cjs_1.parseNamedArgsOrExit)(args, { valueFlags: ['milestone', 'name'], positionals: 2 }, error);
|
|
169
202
|
state.cmdStateMilestoneSwitch(cwd, strArg(a, 'milestone'), strArg(a, 'name'), raw);
|
|
170
203
|
},
|
|
171
204
|
},
|