@opengsd/gsd-core 1.9.0 → 1.10.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 +2 -3
- package/.opencode/plugins/gsd-core.js +8 -1
- package/agents/gsd-code-fixer.md +131 -34
- package/agents/gsd-debugger.md +12 -246
- package/agents/gsd-executor.md +7 -5
- package/agents/gsd-integration-checker.md +3 -0
- package/agents/gsd-plan-checker.md +9 -0
- package/agents/gsd-planner.md +5 -8
- package/agents/gsd-roadmapper.md +21 -3
- package/agents/gsd-verifier.md +14 -70
- package/bin/install.js +503 -341
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/new-milestone.md +1 -1
- package/commands/gsd/plan-phase.md +1 -1
- package/gsd-core/bin/gsd-tools.cjs +607 -63
- package/gsd-core/bin/lib/active-workstream-store.cjs +25 -0
- package/gsd-core/bin/lib/agent-install-check.cjs +38 -6
- package/gsd-core/bin/lib/api-coverage.cjs +120 -0
- package/gsd-core/bin/lib/audit.cjs +89 -1
- package/gsd-core/bin/lib/broken-windows.cjs +36 -6
- package/gsd-core/bin/lib/capability-registry.cjs +96 -110
- package/gsd-core/bin/lib/capability-validator.cjs +12 -2
- package/gsd-core/bin/lib/check-command-router.cjs +43 -1
- package/gsd-core/bin/lib/command-aliases.cjs +72 -0
- package/gsd-core/bin/lib/commands.cjs +26 -25
- package/gsd-core/bin/lib/commonjs-marker.cjs +136 -0
- package/gsd-core/bin/lib/config-loader.cjs +1 -0
- package/gsd-core/bin/lib/config.cjs +12 -1
- package/gsd-core/bin/lib/context-composer.cjs +278 -0
- package/gsd-core/bin/lib/context-predicates.cjs +506 -0
- package/gsd-core/bin/lib/core-utils.cjs +91 -12
- package/gsd-core/bin/lib/docs.cjs +3 -2
- package/gsd-core/bin/lib/external-job.cjs +19 -4
- package/gsd-core/bin/lib/frontmatter.cjs +84 -12
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
- package/gsd-core/bin/lib/git-base-branch.cjs +58 -15
- package/gsd-core/bin/lib/graphify.cjs +142 -27
- package/gsd-core/bin/lib/gsd2-import.cjs +27 -4
- package/gsd-core/bin/lib/host-integration.cjs +13 -1
- package/gsd-core/bin/lib/init-command-router.cjs +83 -8
- package/gsd-core/bin/lib/init.cjs +1021 -57
- package/gsd-core/bin/lib/install-engine.cjs +64 -10
- package/gsd-core/bin/lib/install-profiles.cjs +27 -1
- package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
- package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
- package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
- package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
- package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +87 -1
- package/gsd-core/bin/lib/io.cjs +28 -3
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +6 -0
- package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
- package/gsd-core/bin/lib/mcp-server.cjs +135 -3
- package/gsd-core/bin/lib/milestone.cjs +106 -51
- package/gsd-core/bin/lib/phase-id.cjs +63 -0
- package/gsd-core/bin/lib/phase-locator.cjs +138 -45
- package/gsd-core/bin/lib/phase.cjs +260 -25
- package/gsd-core/bin/lib/plan-dependency-graph.cjs +232 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +4 -0
- package/gsd-core/bin/lib/project-root.cjs +48 -0
- package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
- package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +80 -0
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +99 -0
- package/gsd-core/bin/lib/review-lane-runner.cjs +30 -6
- package/gsd-core/bin/lib/roadmap-command-router.cjs +42 -9
- package/gsd-core/bin/lib/roadmap-parser.cjs +100 -18
- package/gsd-core/bin/lib/roadmap.cjs +37 -7
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +195 -62
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +15 -3
- package/gsd-core/bin/lib/runtime-homes.cjs +154 -41
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +105 -41
- package/gsd-core/bin/lib/section-manifest.cjs +209 -0
- package/gsd-core/bin/lib/shell-command-projection.cjs +113 -27
- package/gsd-core/bin/lib/smart-entry.cjs +12 -0
- package/gsd-core/bin/lib/state-transition.cjs +73 -8
- package/gsd-core/bin/lib/state.cjs +151 -62
- package/gsd-core/bin/lib/surface.cjs +12 -1
- package/gsd-core/bin/lib/uat-predicate.cjs +11 -1
- package/gsd-core/bin/lib/uat.cjs +320 -21
- package/gsd-core/bin/lib/unusable-input.cjs +9 -0
- package/gsd-core/bin/lib/verification.cjs +29 -12
- package/gsd-core/bin/lib/verify.cjs +29 -5
- package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +181 -18
- package/gsd-core/bin/lib/workstream-inventory.cjs +519 -27
- package/gsd-core/bin/lib/workstream.cjs +6 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
- package/gsd-core/bin/lib/worktree-safety.cjs +276 -118
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
- package/gsd-core/references/artifact-types.md +10 -3
- package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
- package/gsd-core/references/debugger-techniques.md +255 -0
- package/gsd-core/references/research-documentation-lookup.md +5 -3
- package/gsd-core/references/specless-probe-fallback.md +7 -6
- package/gsd-core/references/verifier-wiring-patterns.md +100 -0
- package/gsd-core/references/worktree-branch-check.md +2 -2
- package/gsd-core/templates/summary-complex.md +2 -0
- package/gsd-core/templates/summary-minimal.md +2 -0
- package/gsd-core/templates/summary-standard.md +2 -0
- package/gsd-core/templates/summary.md +2 -0
- package/gsd-core/workflows/audit-milestone.md +3 -0
- package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
- package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
- package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
- package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
- package/gsd-core/workflows/autonomous.md +32 -69
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +83 -0
- package/gsd-core/workflows/code-review.md +42 -145
- package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
- package/gsd-core/workflows/complete-milestone.md +23 -81
- package/gsd-core/workflows/debug.md +9 -12
- package/gsd-core/workflows/diagnose-issues.md +22 -0
- package/gsd-core/workflows/discovery-phase.md +4 -4
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
- package/gsd-core/workflows/discuss-phase-assumptions.md +5 -16
- package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
- package/gsd-core/workflows/docs-update.md +8 -51
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +34 -2
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +19 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
- package/gsd-core/workflows/execute-phase.md +65 -137
- package/gsd-core/workflows/execute-plan.md +1 -1
- package/gsd-core/workflows/help/modes/full.md +6 -1
- package/gsd-core/workflows/ingest-docs.md +2 -1
- package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
- package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
- package/gsd-core/workflows/new-milestone.md +21 -38
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
- package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
- package/gsd-core/workflows/new-project.md +13 -226
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
- package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
- package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
- package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
- package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
- package/gsd-core/workflows/plan-phase.md +49 -193
- package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
- package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
- package/gsd-core/workflows/progress.md +11 -153
- package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +46 -0
- package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
- package/gsd-core/workflows/quick.md +20 -390
- package/gsd-core/workflows/resume-project.md +3 -0
- package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
- package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
- package/gsd-core/workflows/review.md +15 -8
- package/gsd-core/workflows/section-manifest.json +219 -0
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/spec-phase.md +17 -14
- package/gsd-core/workflows/spike-wrap-up.md +20 -5
- package/gsd-core/workflows/spike.md +50 -16
- package/gsd-core/workflows/sync-skills.md +49 -11
- package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
- package/gsd-core/workflows/transition.md +8 -21
- package/gsd-core/workflows/ui-phase.md +8 -7
- package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
- package/gsd-core/workflows/update.md +18 -7
- package/gsd-core/workflows/verify-phase.md +4 -7
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
- package/gsd-core/workflows/verify-work.md +8 -58
- package/hooks/dist/gsd-agent-isolation-guard.js +428 -0
- package/hooks/dist/gsd-check-update-worker.js +14 -5
- package/hooks/dist/gsd-cursor-subagent-start.js +532 -26
- package/hooks/dist/gsd-read-injection-scanner.js +7 -0
- package/hooks/dist/gsd-statusline.js +72 -6
- package/hooks/dist/gsd-worktree-path-guard.js +2 -1
- package/hooks/dist/gsd-write-guard.js +359 -0
- package/hooks/dist/lib/isolation-sentinel.js +268 -0
- package/hooks/dist/managed-hooks-registry.cjs +2 -0
- package/hooks/gsd-agent-isolation-guard.js +428 -0
- package/hooks/gsd-check-update-worker.js +14 -5
- package/hooks/gsd-cursor-subagent-start.js +532 -26
- package/hooks/gsd-read-injection-scanner.js +7 -0
- package/hooks/gsd-statusline.js +72 -6
- package/hooks/gsd-worktree-path-guard.js +2 -1
- package/hooks/gsd-write-guard.js +359 -0
- package/hooks/hooks.json +12 -0
- package/hooks/lib/isolation-sentinel.js +268 -0
- package/hooks/managed-hooks-registry.cjs +2 -0
- package/package.json +14 -5
- package/pi/gsd.cjs +57 -12
- package/scripts/build-hooks.js +9 -0
- package/scripts/changeset/lint.cjs +9 -2
- package/scripts/changeset/serialize.cjs +5 -1
- package/scripts/gen-capability-matrix.cjs +1 -1
- package/scripts/gen-context-index.cjs +448 -0
- package/scripts/gen-inventory-manifest.cjs +101 -1
- package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
- package/scripts/gen-registry.cjs +39 -15
- package/scripts/gen-section-manifest.cjs +638 -0
- package/scripts/generate-package-identity.cjs +4 -2
- package/scripts/lint-allow-test-rule-refs.allowlist.json +17 -31
- package/scripts/lint-compiled-artifact-sync.cjs +6 -1
- package/scripts/lint-docs-command-form.cjs +195 -0
- package/scripts/lint-docs-required.cjs +9 -1
- package/scripts/lint-emitted-drift-ack.cjs +215 -20
- package/scripts/lint-example-parser-parity.cjs +395 -0
- package/scripts/lint-test-file-count.allowlist.json +27 -1
- package/scripts/mutation-matrix.cjs +13 -0
- package/scripts/prompt-injection-scan.sh +27 -6
- package/scripts/registry-schema.cjs +323 -94
- package/scripts/run-tests.cjs +3 -2
- package/scripts/validate-registry.cjs +10 -6
- package/skills/gsd-autonomous/SKILL.md +1 -1
- package/skills/gsd-execute-phase/SKILL.md +1 -1
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-new-milestone/SKILL.md +1 -1
- package/skills/gsd-plan-phase/SKILL.md +2 -2
- package/vscode/package.json +1 -1
- package/scripts/gen-emitted-baseline.cjs +0 -145
|
@@ -92,3 +92,22 @@ fi
|
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
After running this for the plan, the dispatch branches in `execute_waves` step 3 MUST gate on `USE_WORKTREES_FOR_PLAN` for the current plan, not on the project-level `USE_WORKTREES`. Track which plans in this wave actually used worktrees (append `plan_id` to a `WAVE_WORKTREE_PLANS` accumulator when `USE_WORKTREES_FOR_PLAN != false`) — the post-wave cleanup step (5.5) uses this to decide whether worktree-merge cleanup is needed at all.
|
|
95
|
+
|
|
96
|
+
**Re-record the dispatch-isolation sentinel, scoped to THIS plan (#3045 BLOCKER 1):**
|
|
97
|
+
|
|
98
|
+
The phase-level sentinel (written by the "Resolve ISOLATION" step, before any per-plan decision exists) authorizes/denies at the PHASE level. This per-plan gate can override that decision (submodule intersection forcing `USE_WORKTREES_FOR_PLAN=false` on an otherwise harness-worktree phase) — without a fresh, plan-scoped re-record, the isolation guard hooks would still be reading the STALE phase-level `harness-worktree` sentinel when this plan's dispatch omits the isolation kwarg (correctly, since it isn't worktree-isolated), producing a false DENY; or, symmetrically, a plan-level submodule degrade elsewhere in the wave could leave a stale `none` sentinel that a LATER, genuinely harness-worktree plan's own dispatch could be misread against. Run this immediately before dispatching THIS plan (right after computing `USE_WORKTREES_FOR_PLAN` above), so the sentinel is always fresh at the moment of dispatch and always keyed to the plan it authorizes:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
102
|
+
if [ "$USE_WORKTREES_FOR_PLAN" = "false" ]; then
|
|
103
|
+
# Submodule intersection (or an inherited USE_WORKTREES=false) forces
|
|
104
|
+
# sequential dispatch for this plan specifically — force the resolver's
|
|
105
|
+
# single write path to record `none`, scoped to this plan, even though the
|
|
106
|
+
# phase/registry would otherwise resolve harness-worktree.
|
|
107
|
+
gsd_run query dispatch-isolation --raw --phase "${PHASE_NUMBER:-}" --plan "$plan_id" --force-isolation none >/dev/null 2>&1 || true
|
|
108
|
+
else
|
|
109
|
+
# No plan-level override — re-resolve normally, still scoped to this plan,
|
|
110
|
+
# so the sentinel's `plan` field always matches the plan about to dispatch.
|
|
111
|
+
gsd_run query dispatch-isolation --raw --phase "${PHASE_NUMBER:-}" --plan "$plan_id" >/dev/null 2>&1 || true
|
|
112
|
+
fi
|
|
113
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Step: regression_gate_run
|
|
2
|
+
|
|
3
|
+
Run the resolved prior-phase test command one-shot, bounded by a timeout, so a
|
|
4
|
+
watch-mode runner (vitest defaults to watch in a TTY; jest `--watch`) cannot
|
|
5
|
+
hang this gate forever (#1857). Uses the shared `normalize-test-command` helper
|
|
6
|
+
— the same one the post-merge gate uses — so the two gate paths cannot drift.
|
|
7
|
+
|
|
8
|
+
Expects `REGRESSION_FILES` (from the prior step) in scope for the pytest branch.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
12
|
+
# Resolve test command: project config > Makefile > language sniff
|
|
13
|
+
REG_TEST_CMD=$(gsd_run query config-get workflow.test_command --default "" --raw 2>/dev/null || true)
|
|
14
|
+
if [ -z "$REG_TEST_CMD" ]; then
|
|
15
|
+
if [ -f "Makefile" ] && grep -q "^test:" Makefile; then
|
|
16
|
+
REG_TEST_CMD="make test"
|
|
17
|
+
elif [ -f "Justfile" ] || [ -f "justfile" ]; then
|
|
18
|
+
REG_TEST_CMD="just test"
|
|
19
|
+
elif [ -f "package.json" ]; then
|
|
20
|
+
REG_TEST_CMD="npm test"
|
|
21
|
+
elif [ -f "Cargo.toml" ]; then
|
|
22
|
+
REG_TEST_CMD="cargo test"
|
|
23
|
+
elif [ -f "go.mod" ]; then
|
|
24
|
+
REG_TEST_CMD="go test ./..."
|
|
25
|
+
elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
|
|
26
|
+
REG_TEST_CMD="python -m pytest ${REGRESSION_FILES} -q --tb=short"
|
|
27
|
+
else
|
|
28
|
+
REG_TEST_CMD="true"
|
|
29
|
+
fi
|
|
30
|
+
fi
|
|
31
|
+
# #1857: normalize to a one-shot form (defeat vitest/jest watch mode) and bound
|
|
32
|
+
# with a timeout so a watch-mode runner cannot hang the gate indefinitely.
|
|
33
|
+
REG_TEST_CMD=$(gsd_run query normalize-test-command "$REG_TEST_CMD" --cwd . 2>/dev/null || echo "$REG_TEST_CMD")
|
|
34
|
+
TEST_GATE_TIMEOUT=$(gsd_run query config-get workflow.test_gate_timeout 2>/dev/null || echo "600")
|
|
35
|
+
gsd_run run-with-timeout "$TEST_GATE_TIMEOUT" -- bash -c "$REG_TEST_CMD" 2>&1
|
|
36
|
+
REG_TEST_EXIT=$?
|
|
37
|
+
if [ "$REG_TEST_EXIT" -eq 124 ]; then
|
|
38
|
+
echo "✗ REGRESSION GATE ABORTED — test runner did not exit within ${TEST_GATE_TIMEOUT}s, likely stuck in watch/dev mode (e.g. vitest without 'run'). Run tests one-shot (e.g. 'vitest run'), set workflow.test_command, or raise workflow.test_gate_timeout."
|
|
39
|
+
fi
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**On `REG_TEST_EXIT` 124 (`REGRESSION GATE ABORTED`):** HALT — do not proceed to verification. The runner did not exit within the budget (watch/dev mode is the likely cause). Surface the watch-mode cause and the recovery options; never silently continue.
|
|
@@ -1,42 +1,48 @@
|
|
|
1
|
-
|
|
1
|
+
<step name="regression_gate">
|
|
2
|
+
Run prior phases' test suites to catch cross-phase regressions BEFORE verification.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
watch-mode runner (vitest defaults to watch in a TTY; jest `--watch`) cannot
|
|
5
|
-
hang this gate forever (#1857). Uses the shared `normalize-test-command` helper
|
|
6
|
-
— the same one the post-merge gate uses — so the two gate paths cannot drift.
|
|
7
|
-
|
|
8
|
-
Expects `REGRESSION_FILES` (from the prior step) in scope for the pytest branch.
|
|
4
|
+
**Skip if:** This is the first phase (no prior phases), or no prior VERIFICATION.md files exist.
|
|
9
5
|
|
|
6
|
+
**Step 1: Discover prior phases' test files**
|
|
10
7
|
```bash
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
8
|
+
# Find all VERIFICATION.md files from prior phases in current milestone
|
|
9
|
+
PRIOR_VERIFICATIONS=$(find .planning/phases/ -name "*-VERIFICATION.md" ! -path "*${PHASE_NUMBER}*" 2>/dev/null)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Step 2: Extract test file lists from prior verifications**
|
|
13
|
+
|
|
14
|
+
For each VERIFICATION.md found, look for test file references:
|
|
15
|
+
- Lines containing `test`, `spec`, or `__tests__` paths
|
|
16
|
+
- The "Test Suite" or "Automated Checks" section
|
|
17
|
+
- File patterns from `key-files.created` in corresponding SUMMARY.md files that match `*.test.*` or `*.spec.*`
|
|
18
|
+
|
|
19
|
+
Collect all unique test file paths into `REGRESSION_FILES`.
|
|
20
|
+
|
|
21
|
+
**Step 3: Run regression tests (if any found)** — Read and execute `gsd-core/workflows/execute-phase/steps/regression-gate-run.md`. It resolves the project test command, normalizes it to a one-shot form (defeating vitest/jest watch mode via the shared `normalize-test-command` helper), runs it under `workflow.test_gate_timeout`, and aborts on timeout with a watch-mode hint (#1857). On `REGRESSION GATE ABORTED` (exit 124), HALT — do not proceed to verification.
|
|
22
|
+
|
|
23
|
+
**Step 4: Report results**
|
|
24
|
+
|
|
25
|
+
If all tests pass:
|
|
26
|
+
```
|
|
27
|
+
✓ Regression gate: {N} prior-phase test files passed — no regressions detected
|
|
28
|
+
```
|
|
29
|
+
→ Proceed to verify_phase_goal
|
|
30
|
+
|
|
31
|
+
If any tests fail:
|
|
32
|
+
```
|
|
33
|
+
## ⚠ Cross-Phase Regression Detected
|
|
34
|
+
|
|
35
|
+
Phase {X} execution may have broken functionality from prior phases.
|
|
36
|
+
|
|
37
|
+
| Test File | Phase | Status | Detail |
|
|
38
|
+
|-----------|-------|--------|--------|
|
|
39
|
+
| {file} | {origin_phase} | FAILED | {first_failure_line} |
|
|
40
|
+
|
|
41
|
+
Options:
|
|
42
|
+
1. Fix regressions before verification (recommended)
|
|
43
|
+
2. Continue to verification anyway (regressions will compound)
|
|
44
|
+
3. Abort phase — roll back and re-plan
|
|
40
45
|
```
|
|
41
46
|
|
|
42
|
-
|
|
47
|
+
If `TEXT_MODE` is true, present as a plain-text numbered list and ask the user to type their choice number. Otherwise, use AskUserQuestion to present the options.
|
|
48
|
+
</step>
|
|
@@ -81,12 +81,15 @@ Load all context in one call:
|
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
84
|
-
|
|
84
|
+
WAVE_PARAM=""; if [[ "$ARGUMENTS" =~ (^|[[:space:]])--wave[[:space:]]+([^[:space:]-][^[:space:]]*) ]]; then WAVE_PARAM="--wave ${BASH_REMATCH[2]}"; fi
|
|
85
|
+
INIT=$(gsd_run query init.execute-phase "${PHASE_ARG}" $WAVE_PARAM)
|
|
85
86
|
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
86
87
|
AGENT_SKILLS=$(gsd_run query agent-skills gsd-executor)
|
|
87
88
|
```
|
|
88
89
|
|
|
89
|
-
Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelization`, `branching_strategy`, `branch_name`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `plans`, `incomplete_plans`, `plan_count`, `incomplete_count`, `state_exists`, `roadmap_exists`, `phase_req_ids`, `response_language`, `requirements_path`.
|
|
90
|
+
Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelization`, `branching_strategy`, `branch_name`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `plans`, `incomplete_plans`, `plan_count`, `incomplete_count`, `state_exists`, `roadmap_exists`, `phase_req_ids`, `response_language`, `requirements_path`, `section_manifest`.
|
|
91
|
+
|
|
92
|
+
`section_manifest` (#2932) gates the three `steps/*.md` reads below: read a step file only when its `id` is in `section_manifest.included` (equivalently, its path is in `section_manifest.read`); skip it — without reading — when its `id` is in `section_manifest.excluded`. When `section_manifest` is `null` (degraded: manifest artifact missing/unreadable), read all three unconditionally — the safe superset.
|
|
90
93
|
|
|
91
94
|
**Model resolution:** If `executor_model` is `"inherit"`, omit the `model=` parameter from all `Agent()` calls — do NOT pass `model="inherit"` to Agent. Omitting the `model=` parameter causes Claude Code to inherit the current orchestrator model automatically. Only set `model=` when `executor_model` is an explicit model name (e.g., `"claude-sonnet-5"`, `"claude-opus-4-8"`).
|
|
92
95
|
|
|
@@ -301,7 +304,9 @@ else
|
|
|
301
304
|
else
|
|
302
305
|
git switch --quiet "$DEFAULT_BRANCH" 2>/dev/null && git merge --ff-only --quiet "origin/$DEFAULT_BRANCH" 2>/dev/null || true
|
|
303
306
|
fi
|
|
304
|
-
# Pinned base (#2916); --no-track (#2498)
|
|
307
|
+
# Pinned base (#2916); --no-track (#2498). #2639: warn if local ahead of origin.
|
|
308
|
+
AHEAD=$(git rev-list --count "origin/$DEFAULT_BRANCH..$DEFAULT_BRANCH" 2>/dev/null || echo 0)
|
|
309
|
+
[ "$AHEAD" != "0" ] && [ -n "$AHEAD" ] && echo "WARNING: $DEFAULT_BRANCH is $AHEAD ahead of origin — '$BRANCH_NAME' won't include those commits (#2639)." >&2
|
|
305
310
|
git checkout -b "$BRANCH_NAME" "origin/$DEFAULT_BRANCH" --no-track \
|
|
306
311
|
|| { echo "ERROR: Could not create '$BRANCH_NAME' from origin/$DEFAULT_BRANCH (#2916)." >&2; exit 1; }
|
|
307
312
|
fi
|
|
@@ -329,13 +334,54 @@ Load plan inventory with wave grouping in one call:
|
|
|
329
334
|
PLAN_INDEX=$(gsd_run query phase-plan-index "${PHASE_NUMBER}")
|
|
330
335
|
```
|
|
331
336
|
|
|
332
|
-
Parse JSON for: `phase`, `plans[]` (each with `id`, `wave`, `autonomous`, `objective`, `files_modified`, `task_count`, `has_summary`), `waves` (map of wave number → plan IDs), `incomplete`, `has_checkpoints`.
|
|
337
|
+
Parse JSON for: `phase`, `plans[]` (each with `id`, `wave`, `autonomous`, `objective`, `files_modified`, `task_count`, `has_summary`, `halted`, `blocked_by`), `waves` (map of wave number → plan IDs), `incomplete`, `runnable`, `has_checkpoints`.
|
|
333
338
|
|
|
334
|
-
**Filtering:** Skip plans where `has_summary: true`. If `--gaps-only`: also skip non-gap_closure plans. If `WAVE_FILTER` is set: also skip plans whose `wave` does not equal `WAVE_FILTER`.
|
|
339
|
+
**Filtering:** Skip plans where `has_summary: true`. Additionally skip any plan whose `blocked_by` array is non-empty (#2830) — it depends, directly or transitively, on a plan that halted at a designed stop rather than completing — and report it by name: "Skipping {plan.id}: blocked by halted {blocked_by.join(', ')}". Never silently drop a blocked plan from the report; it must appear by name with its reason, not merely vanish from the executable list. This rule is additive to the `has_summary` skip, not a replacement for it. If `--gaps-only`: also skip non-gap_closure plans. If `WAVE_FILTER` is set: also skip plans whose `wave` does not equal `WAVE_FILTER`.
|
|
335
340
|
|
|
336
341
|
**Wave safety check:** If `WAVE_FILTER` is set and there are still incomplete plans in any lower wave that match the current execution mode, STOP and tell the user to finish earlier waves first. Do not let Wave 2+ execute while prerequisite earlier-wave plans remain incomplete.
|
|
337
342
|
|
|
338
|
-
If all filtered
|
|
343
|
+
**If all filtered — do NOT exit unconditionally (#2868).** "No plan work left" and "phase fully
|
|
344
|
+
done" are different conditions: a run can be interrupted between the final wave's SUMMARY and
|
|
345
|
+
`verify_phase_goal` (most commonly by a checkpoint plan that is retired but still writes a SUMMARY),
|
|
346
|
+
leaving a phase that looks complete from every index yet never produced `*-VERIFICATION.md`. A
|
|
347
|
+
third condition looks identical to the first two by plan_count alone but is neither: some filtered
|
|
348
|
+
plans were filtered because they are **blocked** (non-empty `blocked_by`, #2830), not because they
|
|
349
|
+
are done. Blocked-and-incomplete must never be reported as finished.
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
VERIFY_STATUS=$(gsd_run query verification status "${PHASE_DIR}" --pick status)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Evaluate in this exact order — the first matching condition decides the outcome; do not evaluate
|
|
356
|
+
later conditions once one matches:
|
|
357
|
+
|
|
358
|
+
1. **A filter is active** (`--gaps-only`, or `WAVE_FILTER` set): report "No matching incomplete
|
|
359
|
+
plans" → exit, unchanged. A filtered run finding nothing left in ITS slice says nothing about
|
|
360
|
+
whether the phase as a whole is done, and must never jump to verification.
|
|
361
|
+
2. **No filter is active, and at least one filtered plan was skipped because of a non-empty
|
|
362
|
+
`blocked_by`** (irrespective of `VERIFY_STATUS`): the phase is NOT finished — it is **stuck on a
|
|
363
|
+
halt**. A plan with no SUMMARY and no dispatched work must never be treated as done merely
|
|
364
|
+
because nothing was left to filter. Report:
|
|
365
|
+
`"Phase stuck: {blocked plan ids} blocked by halted {their blocked_by ids} — resolve the halt, do not resume verification."`
|
|
366
|
+
→ exit. Do not fall through to condition 3; this is not a completion state.
|
|
367
|
+
3. **No filter is active, and every filtered plan was filtered by `has_summary` alone** (no
|
|
368
|
+
blocked-plan skip occurred):
|
|
369
|
+
- **`VERIFY_STATUS` is anything other than `missing`**: the phase genuinely finished. Report
|
|
370
|
+
"No matching incomplete plans" → exit, unchanged.
|
|
371
|
+
- **`VERIFY_STATUS == missing`**: the plans are all summarized but the run never reached the
|
|
372
|
+
tail gates. Report:
|
|
373
|
+
`"All {plan_count} plans are summarized but no VERIFICATION.md exists — resuming at the phase gates (#2868)."`
|
|
374
|
+
SKIP `cross_ai_delegation`, `execute_waves` and `checkpoint_handling` — there is no wave work
|
|
375
|
+
to do — and continue directly at `aggregate_results`, NOT `code_review_gate`. `aggregate_results`
|
|
376
|
+
is the only step that runs the `SECURITY_FILE` / secure-phase threats-open gate, and it reads
|
|
377
|
+
exclusively from on-disk `${PHASE_DIR}` artifacts (`*-SUMMARY.md`, `*-SECURITY.md` via `ls`) and
|
|
378
|
+
independent `gsd_run` calls — nothing it reads is produced only by `execute_waves` or
|
|
379
|
+
`checkpoint_handling` — so it tolerates having executed no plans in this run. From there the
|
|
380
|
+
run proceeds exactly as a normal one: `aggregate_results` → `code_review_gate` →
|
|
381
|
+
`close_parent_artifacts` → `regression_gate` → `verify_phase_goal` → `update_roadmap`. Never
|
|
382
|
+
skip `aggregate_results`, `code_review_gate` or `regression_gate` on this path — the manual
|
|
383
|
+
workaround this replaces skipped all three, and that gap is the reason this route exists
|
|
384
|
+
rather than telling users to spawn the verifier by hand.
|
|
339
385
|
|
|
340
386
|
Report:
|
|
341
387
|
```
|
|
@@ -433,7 +479,7 @@ cwd inside an agent worktree (or a subdirectory of one). Every subsequent
|
|
|
433
479
|
orchestrator-side git call would then target the wrong tree — this is how a wrong-base
|
|
434
480
|
merge nearly shipped ~1000 files. Resolve the *worktree root* (so a subdirectory cwd
|
|
435
481
|
cannot skew the check) and refuse if it is an agent worktree. The discriminator is the
|
|
436
|
-
per-agent branch namespace `agent
|
|
482
|
+
per-agent branch namespace `agent-`/`worktree-agent-`/`worktree-wf_`, NOT the path: the
|
|
437
483
|
orchestrator may itself be legitimately invoked from a feature worktree under
|
|
438
484
|
`.claude/worktrees/`, so a path-substring refusal would break legitimate runs. Do NOT
|
|
439
485
|
pin to `git worktree list`'s first entry — that is the main worktree, the wrong target
|
|
@@ -444,7 +490,7 @@ when the orchestrator legitimately runs from a feature worktree.
|
|
|
444
490
|
ORCHESTRATOR_WT=$(git rev-parse --show-toplevel 2>/dev/null) || {
|
|
445
491
|
echo "FATAL: execute_waves entry is not inside a git worktree (#48)." >&2; exit 1; }
|
|
446
492
|
ORCH_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
447
|
-
if printf '%s' "$ORCH_BRANCH" | grep -Eq '^(worktree-)?agent-'; then
|
|
493
|
+
if printf '%s' "$ORCH_BRANCH" | grep -Eq '^((worktree-)?agent-|worktree-wf_)'; then
|
|
448
494
|
echo "FATAL: orchestrator cwd is inside an agent worktree (branch '$ORCH_BRANCH', root '$ORCHESTRATOR_WT') — refusing to execute waves (#48). A prior isolation=\"worktree\" dispatch drifted the cwd; re-run from the orchestrator's own worktree." >&2
|
|
449
495
|
# #1856 handoff: the refusal above is correct, but on its own it is a dead end —
|
|
450
496
|
# this worktree may hold committed fixes AND uncommitted work, and "re-run from
|
|
@@ -1171,36 +1217,9 @@ If an active secure-phase step hook exists AND SECURITY.md exists: check frontma
|
|
|
1171
1217
|
```
|
|
1172
1218
|
</step>
|
|
1173
1219
|
|
|
1174
|
-
|
|
1175
|
-
If `
|
|
1176
|
-
|
|
1177
|
-
```bash
|
|
1178
|
-
POST_PLAN_INDEX=$(gsd_run query phase-plan-index "${PHASE_NUMBER}")
|
|
1179
|
-
```
|
|
1180
|
-
|
|
1181
|
-
Apply the same "incomplete" filtering rules as earlier:
|
|
1182
|
-
- ignore plans with `has_summary: true`
|
|
1183
|
-
- if `--gaps-only`, only consider `gap_closure: true` plans
|
|
1184
|
-
|
|
1185
|
-
**If incomplete plans still remain anywhere in the phase:**
|
|
1186
|
-
- STOP here
|
|
1187
|
-
- Do NOT run phase verification
|
|
1188
|
-
- Do NOT mark the phase complete in ROADMAP/STATE
|
|
1189
|
-
- Present:
|
|
1190
|
-
|
|
1191
|
-
```markdown
|
|
1192
|
-
## Wave {WAVE_FILTER} Complete
|
|
1193
|
-
|
|
1194
|
-
Selected wave finished successfully. This phase still has incomplete plans, so phase-level verification and completion were intentionally skipped.
|
|
1195
|
-
|
|
1196
|
-
/gsd:execute-phase {phase} ${GSD_WS} # Continue remaining waves
|
|
1197
|
-
/gsd:execute-phase {phase} --wave {next} ${GSD_WS} # Run the next wave explicitly
|
|
1198
|
-
```
|
|
1199
|
-
|
|
1200
|
-
**If no incomplete plans remain after the selected wave finishes:**
|
|
1201
|
-
- continue with the normal phase-level verification and completion flow below
|
|
1202
|
-
- this means the selected wave happened to be the last remaining work in the phase
|
|
1203
|
-
</step>
|
|
1220
|
+
<!-- gsd:section id="partial-wave" when="flag:--wave" -->
|
|
1221
|
+
If `section_manifest` is `null` or `"partial-wave"` is in its `included` list: read and execute `gsd-core/workflows/execute-phase/steps/partial-wave.md`. Otherwise skip — do not read the file.
|
|
1222
|
+
<!-- /gsd:section -->
|
|
1204
1223
|
|
|
1205
1224
|
<step name="code_review_gate" required="true">
|
|
1206
1225
|
**This step is REQUIRED to evaluate the capability hook.** When the code-review capability is active, auto-invoke code review on the phase's source changes. Advisory only — never blocks execution flow. Also dispatches advisory execute:post gate hooks (e.g. tdd.review-checkpoint).
|
|
@@ -1255,104 +1274,13 @@ Resolve and re-run /gsd execute-phase, or override with /gsd execute-phase {phas
|
|
|
1255
1274
|
**Proceed rule:** If `MVP_MODE && TDD_MODE && GATE_RESULT.block == true` for `tdd.review-checkpoint`: STOP — do NOT proceed to `close_parent_artifacts`, `regression_gate`, `verify_phase_goal`, or `phase.complete`. Otherwise proceed normally.
|
|
1256
1275
|
</step>
|
|
1257
1276
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
**Skip if** phase number has no decimal (e.g., `3`, `04`) — only applies to gap-closure phases like `4.1`, `03.1`.
|
|
1262
|
-
|
|
1263
|
-
**1. Detect decimal phase and derive parent:**
|
|
1264
|
-
```bash
|
|
1265
|
-
# Check if phase_number contains a decimal
|
|
1266
|
-
if [[ "$PHASE_NUMBER" == *.* ]]; then
|
|
1267
|
-
PARENT_PHASE="${PHASE_NUMBER%%.*}"
|
|
1268
|
-
fi
|
|
1269
|
-
```
|
|
1270
|
-
|
|
1271
|
-
**2. Find parent UAT file:**
|
|
1272
|
-
```bash
|
|
1273
|
-
PARENT_INFO=$(gsd_run query find-phase "${PARENT_PHASE}" --raw)
|
|
1274
|
-
# Extract directory from PARENT_INFO JSON, then find UAT file in that directory
|
|
1275
|
-
```
|
|
1276
|
-
|
|
1277
|
-
**If no parent UAT found:** Skip this step (gap-closure may have been triggered by VERIFICATION.md instead).
|
|
1278
|
-
|
|
1279
|
-
**3. Update UAT gap statuses:**
|
|
1280
|
-
|
|
1281
|
-
Read the parent UAT file's `## Gaps` section. For each gap entry with `status: failed`:
|
|
1282
|
-
- Update to `status: resolved`
|
|
1283
|
-
|
|
1284
|
-
**4. Update UAT frontmatter:**
|
|
1285
|
-
|
|
1286
|
-
If all gaps now have `status: resolved`:
|
|
1287
|
-
- Update frontmatter `status: diagnosed` → `status: resolved`
|
|
1288
|
-
- Update frontmatter `updated:` timestamp
|
|
1289
|
-
|
|
1290
|
-
**5. Resolve referenced debug sessions:**
|
|
1291
|
-
|
|
1292
|
-
For each gap that has a `debug_session:` field:
|
|
1293
|
-
- Read the debug session file
|
|
1294
|
-
- Update frontmatter `status:` → `resolved`
|
|
1295
|
-
- Update frontmatter `updated:` timestamp
|
|
1296
|
-
- Move to resolved directory:
|
|
1297
|
-
```bash
|
|
1298
|
-
mkdir -p .planning/debug/resolved
|
|
1299
|
-
mv .planning/debug/{slug}.md .planning/debug/resolved/
|
|
1300
|
-
```
|
|
1301
|
-
|
|
1302
|
-
**6. Commit updated artifacts:**
|
|
1303
|
-
```bash
|
|
1304
|
-
gsd_run query commit "docs(phase-${PARENT_PHASE}): resolve UAT gaps and debug sessions after ${PHASE_NUMBER} gap closure" --files .planning/phases/*${PARENT_PHASE}*/*-UAT.md .planning/debug/resolved/*.md
|
|
1305
|
-
```
|
|
1306
|
-
</step>
|
|
1307
|
-
|
|
1308
|
-
<step name="regression_gate">
|
|
1309
|
-
Run prior phases' test suites to catch cross-phase regressions BEFORE verification.
|
|
1310
|
-
|
|
1311
|
-
**Skip if:** This is the first phase (no prior phases), or no prior VERIFICATION.md files exist.
|
|
1312
|
-
|
|
1313
|
-
**Step 1: Discover prior phases' test files**
|
|
1314
|
-
```bash
|
|
1315
|
-
# Find all VERIFICATION.md files from prior phases in current milestone
|
|
1316
|
-
PRIOR_VERIFICATIONS=$(find .planning/phases/ -name "*-VERIFICATION.md" ! -path "*${PHASE_NUMBER}*" 2>/dev/null)
|
|
1317
|
-
```
|
|
1318
|
-
|
|
1319
|
-
**Step 2: Extract test file lists from prior verifications**
|
|
1277
|
+
<!-- gsd:section id="gap-closure-artifacts" when="state:gap-closure-phase" -->
|
|
1278
|
+
If `section_manifest` is `null` or `"gap-closure-artifacts"` is in its `included` list: read and execute `gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md`. Otherwise skip — do not read the file.
|
|
1279
|
+
<!-- /gsd:section -->
|
|
1320
1280
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
- File patterns from `key-files.created` in corresponding SUMMARY.md files that match `*.test.*` or `*.spec.*`
|
|
1325
|
-
|
|
1326
|
-
Collect all unique test file paths into `REGRESSION_FILES`.
|
|
1327
|
-
|
|
1328
|
-
**Step 3: Run regression tests (if any found)** — Read and execute `gsd-core/workflows/execute-phase/steps/regression-gate.md`. It resolves the project test command, normalizes it to a one-shot form (defeating vitest/jest watch mode via the shared `normalize-test-command` helper), runs it under `workflow.test_gate_timeout`, and aborts on timeout with a watch-mode hint (#1857). On `REGRESSION GATE ABORTED` (exit 124), HALT — do not proceed to verification.
|
|
1329
|
-
|
|
1330
|
-
**Step 4: Report results**
|
|
1331
|
-
|
|
1332
|
-
If all tests pass:
|
|
1333
|
-
```
|
|
1334
|
-
✓ Regression gate: {N} prior-phase test files passed — no regressions detected
|
|
1335
|
-
```
|
|
1336
|
-
→ Proceed to verify_phase_goal
|
|
1337
|
-
|
|
1338
|
-
If any tests fail:
|
|
1339
|
-
```
|
|
1340
|
-
## ⚠ Cross-Phase Regression Detected
|
|
1341
|
-
|
|
1342
|
-
Phase {X} execution may have broken functionality from prior phases.
|
|
1343
|
-
|
|
1344
|
-
| Test File | Phase | Status | Detail |
|
|
1345
|
-
|-----------|-------|--------|--------|
|
|
1346
|
-
| {file} | {origin_phase} | FAILED | {first_failure_line} |
|
|
1347
|
-
|
|
1348
|
-
Options:
|
|
1349
|
-
1. Fix regressions before verification (recommended)
|
|
1350
|
-
2. Continue to verification anyway (regressions will compound)
|
|
1351
|
-
3. Abort phase — roll back and re-plan
|
|
1352
|
-
```
|
|
1353
|
-
|
|
1354
|
-
If `TEXT_MODE` is true, present as a plain-text numbered list and ask the user to type their choice number. Otherwise, use AskUserQuestion to present the options.
|
|
1355
|
-
</step>
|
|
1281
|
+
<!-- gsd:section id="regression-gate" when="state:has-prior-phases" -->
|
|
1282
|
+
If `section_manifest` is `null` or `"regression-gate"` is in its `included` list: read and execute `gsd-core/workflows/execute-phase/steps/regression-gate.md`. Otherwise skip — do not read the file.
|
|
1283
|
+
<!-- /gsd:section -->
|
|
1356
1284
|
|
|
1357
1285
|
<step name="verify_phase_goal">
|
|
1358
1286
|
Verify phase achieved its GOAL, not just completed tasks.
|
|
@@ -1558,12 +1486,13 @@ Copy failure must NOT block phase completion.
|
|
|
1558
1486
|
After `update_roadmap`, moves todos whose `resolves_phase` matches to `completed/`.
|
|
1559
1487
|
|
|
1560
1488
|
```bash
|
|
1489
|
+
shopt -s nullglob 2>/dev/null; setopt NULL_GLOB 2>/dev/null
|
|
1561
1490
|
PHASE_NUM="${PHASE_NUMBER}"
|
|
1562
1491
|
PENDING_DIR=".planning/todos/pending"
|
|
1563
1492
|
COMPLETED_DIR=".planning/todos/completed"
|
|
1564
1493
|
mkdir -p "$COMPLETED_DIR"
|
|
1565
1494
|
|
|
1566
|
-
#
|
|
1495
|
+
#2576
|
|
1567
1496
|
normalize_phase_num() {
|
|
1568
1497
|
local p="${1//\"/}"; printf '%s' "$p" | sed 's/^0*\([0-9]\)/\1/'
|
|
1569
1498
|
}
|
|
@@ -1572,7 +1501,6 @@ PHASE_NUM_NORM=$(normalize_phase_num "$PHASE_NUM")
|
|
|
1572
1501
|
CLOSED=()
|
|
1573
1502
|
for TODO_FILE in "$PENDING_DIR"/*.md; do
|
|
1574
1503
|
[ -f "$TODO_FILE" ] || continue
|
|
1575
|
-
# resolves_phase from first frontmatter block
|
|
1576
1504
|
RP=$(awk '/^---/{c++;next} c==1 && /^resolves_phase:/{print $2;exit} c==2{exit}' "$TODO_FILE" 2>/dev/null || true)
|
|
1577
1505
|
RP_NORM=$(normalize_phase_num "$RP")
|
|
1578
1506
|
if [ -n "$RP_NORM" ] && [ "$RP_NORM" = "$PHASE_NUM_NORM" ]; then
|
|
@@ -113,7 +113,7 @@ Otherwise: Apply checkpoint-based routing below.
|
|
|
113
113
|
|
|
114
114
|
> **Runtime-aware dispatch (#2508 Phase 4).** GSD workflows dispatch specialized subagents by role. Before dispatching on a built-in-only runtime (kimi-code — three built-ins only), resolve the role to a built-in via `gsd_run query resolve-dispatch-type --requested <role> --raw`. On named-dispatch runtimes (Claude/OpenCode/…) the role is returned unchanged; on kimi-code it maps to `coder`/`explore`/`plan` by role-suffix. The persona rides `${AGENT_SKILLS_<ROLE>}` (Phase 3) regardless. See @gsd-core/references/runtime-aware-dispatch.md.
|
|
115
115
|
|
|
116
|
-
**Pattern A:** init_agent_tracking → capture `EXPECTED_BASE=$(git rev-parse HEAD)` → print `Spawning executor agent (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)` → spawn Agent(subagent_type="gsd-executor", model=executor_model) with prompt: execute plan at [path], autonomous, all tasks + SUMMARY + commit, follow deviation/auth rules, report: plan name, tasks, SUMMARY path, commit hash → track agent_id → wait → update tracking → report. **Include `isolation="worktree"` only if `workflow.use_worktrees` is not `false`** (read via `config-get workflow.use_worktrees`)
|
|
116
|
+
**Pattern A:** init_agent_tracking → capture `EXPECTED_BASE=$(git rev-parse HEAD)` → **before spawning, run the #2649 pre-dispatch worktree base-check** (mirrors execute-phase #683/#1369 and quick #1941): if `workflow.use_worktrees` is not `false`, run `gsd_run query worktree.base-check --pick shouldDegrade`; if it returns `true`, print its `--pick message` to stderr, emit the `⚠ [#2649] Worktree fork base diverged from orchestrator HEAD — auto-degrading to sequential mode for this plan to avoid a base-mismatch halt.` warning, and treat worktrees as disabled for this dispatch (spawn WITHOUT `isolation="worktree"`). Claude Code's `isolation="worktree"` forks from `origin/HEAD`, not live local HEAD; without this gate a plan whose commit advanced local HEAD past a stale `origin/HEAD` hits the verify-only guard's `exit 42` mid-execution with no auto-degrade. → print `Spawning executor agent (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)` → spawn Agent(subagent_type="gsd-executor", model=executor_model) with prompt: execute plan at [path], autonomous, all tasks + SUMMARY + commit, follow deviation/auth rules, report: plan name, tasks, SUMMARY path, commit hash → track agent_id → wait → update tracking → report. **Include `isolation="worktree"` only if `workflow.use_worktrees` is not `false`** (read via `config-get workflow.use_worktrees`) **and the #2649 base-check did not degrade**. **When using `isolation="worktree"`, embed the `<worktree_branch_check>` block from `gsd-core/references/worktree-branch-check.md` into the prompt, substituting `{EXPECTED_BASE}` with the captured base SHA.** That guard is **verify-only and fail-closed** (#48) and stays active as a backstop whether or not the base-check degraded: it asserts a per-agent `agent-*` / `worktree-agent-*` branch and the exact base, forbids `git update-ref` self-recovery (#2924), and on any mismatch prints `FATAL:` and `exit 42` so the orchestrator can recover — the sub-agent never rewrites a worktree it did not create. This supersedes the former self-recovery (#2015), whose destructive base rewrite could fail silently under a deny rule; the base-drift it addressed affects all platforms, and base correction is now the orchestrator's responsibility.
|
|
117
117
|
|
|
118
118
|
**Pattern B:** Execute segment-by-segment. Autonomous segments: spawn subagent for assigned tasks only (no SUMMARY/commit). Checkpoints: main context. After all segments: aggregate, create SUMMARY, commit. See segment_execution.
|
|
119
119
|
|
|
@@ -105,7 +105,7 @@ Usage: `/gsd:discuss-phase 2`
|
|
|
105
105
|
Usage: `/gsd:discuss-phase 2 --batch`
|
|
106
106
|
Usage: `/gsd:discuss-phase 2 --batch=3`
|
|
107
107
|
|
|
108
|
-
**`/gsd:plan-phase <number> [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--prd <file>] [--ingest <path-or-glob>] [--ingest-format <auto|nygard|madr|narrative>] [--reviews] [--text] [--tdd] [--mvp] [--no-tracer] [--no-reversibility-gates]`**
|
|
108
|
+
**`/gsd:plan-phase <number> [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--skip-ui] [--prd <file>] [--ingest <path-or-glob>] [--ingest-format <auto|nygard|madr|narrative>] [--reviews] [--text] [--bounce] [--skip-bounce] [--chunked] [--tdd] [--mvp] [--granularity <coarse|standard|fine>] [--no-tracer] [--no-reversibility-gates]`**
|
|
109
109
|
Create detailed execution plan for a specific phase.
|
|
110
110
|
|
|
111
111
|
- `--skip-research` — bypass the research subagent
|
|
@@ -113,10 +113,15 @@ Create detailed execution plan for a specific phase.
|
|
|
113
113
|
- Modifiers: `--research` forces refresh (re-spawn researcher). `--view` prints existing `RESEARCH.md` to stdout without spawning. With neither, auto-uses an existing `RESEARCH.md` (one-line notice, then clean exit).
|
|
114
114
|
- `--gaps` — focus only on closing gaps from a prior plan-check
|
|
115
115
|
- `--skip-verify` — skip the post-plan verifier loop
|
|
116
|
+
- `--skip-ui` — skip the UI-SPEC gate for a detected frontend phase (not recommended for frontend phases)
|
|
116
117
|
- `--ingest <path-or-glob>` — pre-ingest external ADRs/PRDs/SPECs before planning (see *PRD Express Path* below)
|
|
117
118
|
- `--ingest-format <auto|nygard|madr|narrative>` — hint the ADR ingester's parser when `--ingest` is set; defaults to `auto`
|
|
119
|
+
- `--bounce` — run the optional external plan-refinement pass (or set `workflow.plan_bounce: true` to activate by default); requires `workflow.plan_bounce_script`
|
|
120
|
+
- `--skip-bounce` — disable the plan-refinement pass even when `workflow.plan_bounce` config enables it
|
|
121
|
+
- `--chunked` — split the planner run into a short outline pass plus one short per-plan pass each (~3–5 min), committing each plan individually for crash resilience; re-running `--chunked` resumes from the last committed plan (or set `workflow.plan_chunked: true` to activate by default)
|
|
118
122
|
- `--tdd` — plan in test-driven order (tests before code)
|
|
119
123
|
- `--mvp` — MVP enrichment (user story + Walking Skeleton) on top of the default tracer-first ordering (see also `/gsd:mvp-phase`)
|
|
124
|
+
- `--granularity <coarse|standard|fine>` — override the resolved plan granularity for this run (wins over per-phase/top-level config and project defaults)
|
|
120
125
|
- `--no-tracer` — opt out of the default tracer-first slice and plan horizontal layers (legacy default)
|
|
121
126
|
- `--no-reversibility-gates` — suppress the `checkpoint:decision` a `one-way`-door decision normally earns, for intentionally-unattended runs (ratings are still recorded)
|
|
122
127
|
|
|
@@ -84,9 +84,10 @@ git init
|
|
|
84
84
|
- execution_context path `/.codex/` → `RUNTIME=codex`
|
|
85
85
|
- `/.gemini/` → `RUNTIME=gemini`
|
|
86
86
|
- `/.opencode/` or `/.config/opencode/` → `RUNTIME=opencode`
|
|
87
|
+
- `/.trae/` → `RUNTIME=trae`
|
|
87
88
|
- else → `RUNTIME=claude`
|
|
88
89
|
|
|
89
|
-
Fall back to env vars (`CODEX_HOME`, `GEMINI_CONFIG_DIR`, `OPENCODE_CONFIG_DIR`) if execution_context is unavailable.
|
|
90
|
+
Fall back to env vars (`CODEX_HOME`, `GEMINI_CONFIG_DIR`, `OPENCODE_CONFIG_DIR`, `TRAE_CONFIG_DIR`) if execution_context is unavailable.
|
|
90
91
|
|
|
91
92
|
</step>
|
|
92
93
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
**Part A — milestone-state write (skip when a workstream is active).** Skip Part A if `GSD_WS` is non-empty (parsed in Step 1). The active workstream's own `.planning/workstreams/<name>/STATE.md`/`ROADMAP.md`/`REQUIREMENTS.md` already carry this milestone's state. Writing a `## Current Milestone` heading here would clobber the shared file, and with parallel milestones across workstreams, whichever workstream runs `new-milestone` last would silently win the shared heading (#2308). In flat mode (`GSD_WS` empty), run Part A exactly as before:
|
|
2
|
+
|
|
3
|
+
Add/update:
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
## Current Milestone: v[X.Y] [Name]
|
|
7
|
+
|
|
8
|
+
**Goal:** [One sentence describing milestone focus]
|
|
9
|
+
|
|
10
|
+
**Target features:**
|
|
11
|
+
- [Feature 1]
|
|
12
|
+
- [Feature 2]
|
|
13
|
+
- [Feature 3]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Update Active requirements section and "Last updated" footer.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## 7.5 Reset-phase safety (only when `--reset-phase-numbers`)
|
|
2
|
+
|
|
3
|
+
If `--reset-phase-numbers` is active:
|
|
4
|
+
|
|
5
|
+
1. Set starting phase number to `1` for the upcoming roadmap.
|
|
6
|
+
2. If `phase_dir_count > 0`, archive the old phase directories before roadmapping so new `01-*` / `02-*` directories cannot collide with stale milestone directories.
|
|
7
|
+
|
|
8
|
+
If `phase_dir_count > 0` and `phase_archive_path` is available:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
mkdir -p "${phase_archive_path}"
|
|
12
|
+
find .planning/phases -mindepth 1 -maxdepth 1 -type d -exec mv {} "${phase_archive_path}/" \;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then verify `.planning/phases/` no longer contains old milestone directories before continuing.
|
|
16
|
+
|
|
17
|
+
If `phase_dir_count > 0` but `phase_archive_path` is missing:
|
|
18
|
+
- Stop and explain that reset numbering is unsafe without a completed milestone archive target.
|
|
19
|
+
- Tell the user to complete/archive the previous milestone first, then rerun `/gsd:new-milestone --reset-phase-numbers ${GSD_WS}`.
|