From 2b9fa009d318acbbedc8df0c17b95f503a8094f5 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Wed, 27 May 2026 20:21:05 -0400 Subject: [PATCH] fix(#373): replace unquoted $GSD_SDK with space-safe gsd_run launcher (#379) * fix(#373): replace unquoted $GSD_SDK with space-safe gsd_run launcher Workflow bash blocks resolved the runtime as GSD_SDK="node $GSD_TOOLS" and invoked it unquoted ($GSD_SDK query ...). On install paths containing spaces (e.g. /Volumes/Mini Me/...) the unquoted expansion word-split into `node /Volumes/Mini gsd-tools.cjs ...`, failing with "Cannot find module '/Volumes/Mini'" and getting masked by `2>/dev/null || echo "{}"` into a silent empty state. Replace the string variable with a single-line shell launcher that defines a gsd_run function, invokes the runtime with a fully-quoted path and "$@", and preserves the local-cjs / installed-gsd-tools-on-PATH fallback (#3668) plus the loud not-found error and install hint. The launcher uses _GSD_SHIM_NAME indirection so no workflow emits the /gsd-tools substring that the do.md dispatcher-parity scanner would misread, and is single-line to stay within the per-file progressive-disclosure line budgets (#2551). The canonical launcher lives in get-shit-done/workflows/_runtime-launcher.snippet.sh, is propagated once per file by scripts/sync-runtime-launcher.cjs, and is locked by tests/runtime-launcher-parity.test.cjs (fails CI on drift, on a reappearing $GSD_SDK token, or on a /gsd-tools substring). Dependent workflow-assertion tests are updated from $GSD_SDK to gsd_run, and the runtime launcher is registered in CONTEXT.md. Fixes #373 Co-Authored-By: Claude Opus 4.7 (1M context) * ci(#373): add changeset fragment and allow-test-rule for parity guard The runtime-launcher parity test is a structural drift guard that reads workflow markdown to assert the canonical launcher is present and the retired $GSD_SDK / /gsd-tools tokens are absent; annotate it with allow-test-rule per the no-source-grep lint escape hatch. Add the required .changeset fragment for this user-facing fix. Co-Authored-By: Claude Opus 4.7 (1M context) * test(#373): make parity PATH-fallback assertion cross-platform (Windows) Subtest (E) compared GSD_TOOLS against the Node-side absolute temp path, but the value originates from git-bash which reports the POSIX form, so the prefix comparison failed on windows-latest while the launcher itself worked (the installed stub was invoked). Assert the resolved binary by normalized suffix (/bin/gsd-tools, not .cjs) instead of the absolute prefix; the behavioral stub-invocation assertion is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- .changeset/jolly-cranes-chatter.md | 5 + CONTEXT.md | 3 + .../workflows/_runtime-launcher.snippet.sh | 1 + get-shit-done/workflows/add-backlog.md | 21 +- get-shit-done/workflows/add-phase.md | 17 +- get-shit-done/workflows/add-tests.md | 17 +- get-shit-done/workflows/add-todo.md | 19 +- .../workflows/ai-integration-phase.md | 27 +- get-shit-done/workflows/audit-fix.md | 17 +- get-shit-done/workflows/audit-milestone.md | 27 +- get-shit-done/workflows/audit-uat.md | 15 +- get-shit-done/workflows/autonomous.md | 41 +- get-shit-done/workflows/check-todos.md | 17 +- get-shit-done/workflows/cleanup.md | 15 +- get-shit-done/workflows/code-review-fix.md | 19 +- get-shit-done/workflows/code-review.md | 29 +- get-shit-done/workflows/complete-milestone.md | 29 +- get-shit-done/workflows/debug.md | 19 +- get-shit-done/workflows/diagnose-issues.md | 19 +- .../workflows/discuss-phase-assumptions.md | 31 +- get-shit-done/workflows/discuss-phase.md | 14 +- .../workflows/discuss-phase/modes/advisor.md | 3 +- .../workflows/discuss-phase/modes/auto.md | 3 +- .../workflows/discuss-phase/modes/chain.md | 7 +- get-shit-done/workflows/do.md | 16 +- get-shit-done/workflows/docs-update.md | 19 +- get-shit-done/workflows/edit-phase.md | 23 +- get-shit-done/workflows/eval-review.md | 17 +- get-shit-done/workflows/execute-phase.md | 95 ++--- .../steps/codebase-drift-gate.md | 3 +- .../execute-phase/steps/post-merge-gate.md | 5 +- get-shit-done/workflows/execute-plan.md | 43 +- get-shit-done/workflows/explore.md | 15 +- get-shit-done/workflows/extract-learnings.md | 17 +- get-shit-done/workflows/forensics.md | 15 +- get-shit-done/workflows/graduation.md | 19 +- get-shit-done/workflows/health.md | 19 +- get-shit-done/workflows/import.md | 17 +- get-shit-done/workflows/insert-phase.md | 21 +- get-shit-done/workflows/list-workspaces.md | 15 +- get-shit-done/workflows/manager.md | 17 +- get-shit-done/workflows/map-codebase.md | 19 +- get-shit-done/workflows/milestone-summary.md | 19 +- get-shit-done/workflows/mvp-phase.md | 23 +- get-shit-done/workflows/new-milestone.md | 33 +- get-shit-done/workflows/new-project.md | 41 +- get-shit-done/workflows/new-workspace.md | 15 +- get-shit-done/workflows/next.md | 17 +- get-shit-done/workflows/pause-work.md | 19 +- .../workflows/plan-milestone-gaps.md | 19 +- get-shit-done/workflows/plan-phase.md | 85 ++-- .../workflows/plan-review-convergence.md | 15 +- get-shit-done/workflows/plant-seed.md | 17 +- get-shit-done/workflows/profile-user.md | 29 +- get-shit-done/workflows/progress.md | 31 +- get-shit-done/workflows/quick.md | 39 +- get-shit-done/workflows/remove-phase.md | 21 +- get-shit-done/workflows/remove-workspace.md | 15 +- get-shit-done/workflows/resume-project.md | 15 +- get-shit-done/workflows/review.md | 57 +-- get-shit-done/workflows/scan.md | 15 +- get-shit-done/workflows/secure-phase.md | 23 +- get-shit-done/workflows/settings-advanced.md | 33 +- .../workflows/settings-integrations.md | 37 +- get-shit-done/workflows/settings.md | 17 +- get-shit-done/workflows/ship.md | 31 +- get-shit-done/workflows/sketch-wrap-up.md | 17 +- get-shit-done/workflows/sketch.md | 17 +- get-shit-done/workflows/spike-wrap-up.md | 17 +- get-shit-done/workflows/spike.md | 19 +- get-shit-done/workflows/stats.md | 17 +- get-shit-done/workflows/thread.md | 29 +- get-shit-done/workflows/transition.md | 25 +- get-shit-done/workflows/ui-phase.md | 31 +- get-shit-done/workflows/ui-review.md | 21 +- get-shit-done/workflows/ultraplan-phase.md | 15 +- get-shit-done/workflows/update.md | 1 - get-shit-done/workflows/validate-phase.md | 23 +- get-shit-done/workflows/verify-phase.md | 33 +- get-shit-done/workflows/verify-work.md | 35 +- package.json | 1 + scripts/sync-runtime-launcher.cjs | 402 ++++++++++++++++++ ...ug-2384-post-merge-deletion-audit.test.cjs | 4 +- tests/bug-2661-roadmap-sync-parallel.test.cjs | 12 +- ...ummary-rescue-gitignored-planning.test.cjs | 2 +- ...360-codex-execute-phase-worktrees.test.cjs | 4 +- .../bug-3381-verify-work-workstream.test.cjs | 8 +- tests/bug-3521-quick-cleanup-cwd-pin.test.cjs | 8 +- ...-3668-workflow-runtime-resolution.test.cjs | 92 +++- tests/enh-2433-todo-phase-linking.test.cjs | 4 +- tests/enh-2792-namespace-skills.test.cjs | 6 +- tests/runtime-launcher-parity.test.cjs | 385 +++++++++++++++++ tests/ultraplan-phase.test.cjs | 6 +- tests/worktree-cleanup.test.cjs | 20 +- 94 files changed, 1410 insertions(+), 1320 deletions(-) create mode 100644 .changeset/jolly-cranes-chatter.md create mode 100644 get-shit-done/workflows/_runtime-launcher.snippet.sh create mode 100644 scripts/sync-runtime-launcher.cjs create mode 100644 tests/runtime-launcher-parity.test.cjs diff --git a/.changeset/jolly-cranes-chatter.md b/.changeset/jolly-cranes-chatter.md new file mode 100644 index 000000000..cdb7b7da1 --- /dev/null +++ b/.changeset/jolly-cranes-chatter.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 379 +--- +**Workflow runtime launcher no longer breaks on install paths containing spaces** — workflow bash blocks resolved the runtime via an unquoted shell string variable (`GSD_SDK="node $GSD_TOOLS"`, invoked as `$GSD_SDK query …`), which word-split on paths like `/Volumes/Mini Me/…` and was silently masked into empty `{}` state. Replaced with a single-line, space-safe `gsd_run` shell launcher (quoted path + `"$@"`), propagated once per workflow file from one canonical snippet and enforced by a parity test. The local-`.cjs` / installed-`gsd-tools`-on-PATH fallback (#3668) and the loud not-found error are preserved. Fixes #373. diff --git a/CONTEXT.md b/CONTEXT.md index 824111f0f..f0e2f69e6 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -64,6 +64,9 @@ Single dispatch seam (`get-shit-done/bin/lib/command-routing-hub.cjs`) that cent ### Runtime Source Layout Module Single-runtime seam layout for this repository after SDK retirement. Runtime execution paths live under `get-shit-done/bin/lib/` and are grouped by seam concern (dispatch, manifest, handlers, runtime, observability, installer). ADR-0174 preserves the seam vocabulary and defines the canonical long-term shape as a seam-aligned TypeScript `src/` tree (`src/dispatch/`, `src/handlers/`, `src/errors/`, `src/manifest/`, `src/config/`, `src/state/`, `src/workstream/`, `src/runtime/`, `src/cli/`, `src/observability/`) compiled to CJS. +### Runtime Launcher Module +Canonical space-safe shell preamble (`gsd_run`) used by every workflow bash block to invoke the GSD runtime CLI. Resolves `get-shit-done/bin/gsd-tools.cjs` via `node` when present, falls back to a `gsd-tools` binary on PATH, else errors. Single source of truth: `get-shit-done/workflows/_runtime-launcher.snippet.sh`; propagated by `scripts/sync-runtime-launcher.cjs`; enforced by `tests/runtime-launcher-parity.test.cjs`. Replaced the retired unquoted `$GSD_SDK` variable (#373). + ### Dispatch Observability Module Module owning dispatch-event creation, redaction, and logger behavior for the Command Routing Hub. Core files: `get-shit-done/bin/lib/observability/event.cjs`, `get-shit-done/bin/lib/observability/logger.cjs`, `get-shit-done/bin/lib/observability/redaction.cjs`. Contract: silent on success by default, structured JSON to stderr on error, and opt-in audit trail at `.planning/.gsd-trace.jsonl` via `GSD_AUDIT=1` or config (`audit.enabled`). Each dispatch carries a `traceId`; composed dispatches set `parentTraceId` for correlation. diff --git a/get-shit-done/workflows/_runtime-launcher.snippet.sh b/get-shit-done/workflows/_runtime-launcher.snippet.sh new file mode 100644 index 000000000..091f60dfd --- /dev/null +++ b/get-shit-done/workflows/_runtime-launcher.snippet.sh @@ -0,0 +1 @@ +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi diff --git a/get-shit-done/workflows/add-backlog.md b/get-shit-done/workflows/add-backlog.md index ed7c30869..0bf1b6e02 100644 --- a/get-shit-done/workflows/add-backlog.md +++ b/get-shit-done/workflows/add-backlog.md @@ -19,19 +19,8 @@ cat .planning/ROADMAP.md ## Step 2: Find next backlog number ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -NEXT=$($GSD_SDK query phase.next-decimal 999 --raw) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +NEXT=$(gsd_run query phase.next-decimal 999 --raw) ``` If no 999.x phases exist yet, `phase.next-decimal` returns `999.1`. Sparse numbering @@ -64,8 +53,8 @@ Plans: Apply the `project_code` prefix (if set in `.planning/config.json`) so the backlog directory name is consistent with all other phase-creation paths: ```bash -SLUG=$($GSD_SDK query generate-slug "$ARGUMENTS" --raw) -PROJECT_CODE=$($GSD_SDK query config-get project_code --raw 2>/dev/null || echo "") +SLUG=$(gsd_run query generate-slug "$ARGUMENTS" --raw) +PROJECT_CODE=$(gsd_run query config-get project_code --raw 2>/dev/null || echo "") PREFIX=$([ -n "$PROJECT_CODE" ] && echo "${PROJECT_CODE}-" || echo "") PHASE_DIR=".planning/phases/${PREFIX}${NEXT}-${SLUG}" mkdir -p "${PHASE_DIR}" @@ -75,7 +64,7 @@ touch "${PHASE_DIR}/.gitkeep" ## Step 5: Commit ```bash -$GSD_SDK query commit "docs: add backlog item ${NEXT} — ${ARGUMENTS}" --files .planning/ROADMAP.md "${PHASE_DIR}/.gitkeep" +gsd_run query commit "docs: add backlog item ${NEXT} — ${ARGUMENTS}" --files .planning/ROADMAP.md "${PHASE_DIR}/.gitkeep" ``` ## Step 6: Report diff --git a/get-shit-done/workflows/add-phase.md b/get-shit-done/workflows/add-phase.md index afd6090b1..124720d2e 100644 --- a/get-shit-done/workflows/add-phase.md +++ b/get-shit-done/workflows/add-phase.md @@ -29,19 +29,8 @@ Exit. Load phase operation context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "0") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "0") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -57,7 +46,7 @@ Exit. **Delegate the phase addition to `gsd-tools.cjs query phase.add`:** ```bash -RESULT=$($GSD_SDK query phase.add "${description}") +RESULT=$(gsd_run query phase.add "${description}") ``` The CLI handles: diff --git a/get-shit-done/workflows/add-tests.md b/get-shit-done/workflows/add-tests.md index dd68f3f23..7480ad239 100644 --- a/get-shit-done/workflows/add-tests.md +++ b/get-shit-done/workflows/add-tests.md @@ -33,19 +33,8 @@ Exit. Load phase operation context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -312,7 +301,7 @@ Create a test coverage report and present to user: Record test generation in project state: ```bash -$GSD_SDK query state-snapshot +gsd_run query state-snapshot ``` If there are passing tests to commit: diff --git a/get-shit-done/workflows/add-todo.md b/get-shit-done/workflows/add-todo.md index 3fe2a9d1e..287c62a7b 100644 --- a/get-shit-done/workflows/add-todo.md +++ b/get-shit-done/workflows/add-todo.md @@ -12,19 +12,8 @@ Read all files referenced by the invoking prompt's execution_context before star Load todo context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.todos) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.todos) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -98,7 +87,7 @@ Use values from init context: `timestamp` and `date` are already available. Generate slug for the title: ```bash -slug=$($GSD_SDK query generate-slug "$title" --raw) +slug=$(gsd_run query generate-slug "$title" --raw) ``` Write to `.planning/todos/pending/${date}-${slug}.md`: @@ -133,7 +122,7 @@ If `.planning/STATE.md` exists: Commit the todo and any updated state: ```bash -$GSD_SDK query commit "docs: capture todo - [title]" --files .planning/todos/pending/[filename] .planning/STATE.md +gsd_run query commit "docs: capture todo - [title]" --files .planning/todos/pending/[filename] .planning/STATE.md ``` Tool respects `commit_docs` config and gitignore automatically. diff --git a/get-shit-done/workflows/ai-integration-phase.md b/get-shit-done/workflows/ai-integration-phase.md index 4c6cdd409..afd018f75 100644 --- a/get-shit-done/workflows/ai-integration-phase.md +++ b/get-shit-done/workflows/ai-integration-phase.md @@ -20,19 +20,8 @@ This prevents the two most common AI development failures: choosing the wrong fr ## 1. Initialize ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.plan-phase "$PHASE") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.plan-phase "$PHASE") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -42,15 +31,15 @@ Parse JSON for: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded Resolve agent models: ```bash -SELECTOR_MODEL=$($GSD_SDK query resolve-model gsd-framework-selector 2>/dev/null | jq -r '.model' 2>/dev/null || true) -RESEARCHER_MODEL=$($GSD_SDK query resolve-model gsd-ai-researcher 2>/dev/null | jq -r '.model' 2>/dev/null || true) -DOMAIN_MODEL=$($GSD_SDK query resolve-model gsd-domain-researcher 2>/dev/null | jq -r '.model' 2>/dev/null || true) -PLANNER_MODEL=$($GSD_SDK query resolve-model gsd-eval-planner 2>/dev/null | jq -r '.model' 2>/dev/null || true) +SELECTOR_MODEL=$(gsd_run query resolve-model gsd-framework-selector 2>/dev/null | jq -r '.model' 2>/dev/null || true) +RESEARCHER_MODEL=$(gsd_run query resolve-model gsd-ai-researcher 2>/dev/null | jq -r '.model' 2>/dev/null || true) +DOMAIN_MODEL=$(gsd_run query resolve-model gsd-domain-researcher 2>/dev/null | jq -r '.model' 2>/dev/null || true) +PLANNER_MODEL=$(gsd_run query resolve-model gsd-eval-planner 2>/dev/null | jq -r '.model' 2>/dev/null || true) ``` Check config: ```bash -AI_PHASE_ENABLED=$($GSD_SDK query config-get workflow.ai_integration_phase 2>/dev/null || echo "true") +AI_PHASE_ENABLED=$(gsd_run query config-get workflow.ai_integration_phase 2>/dev/null || echo "true") ``` **If `AI_PHASE_ENABLED` is `false`:** @@ -66,7 +55,7 @@ Exit workflow. Extract phase number from $ARGUMENTS. If not provided, detect next unplanned phase. ```bash -PHASE_INFO=$($GSD_SDK query roadmap.get-phase "${PHASE}") +PHASE_INFO=$(gsd_run query roadmap.get-phase "${PHASE}") ``` **If `found` is false:** Error with available phases. diff --git a/get-shit-done/workflows/audit-fix.md b/get-shit-done/workflows/audit-fix.md index c7a19b0c1..73adb91cb 100644 --- a/get-shit-done/workflows/audit-fix.md +++ b/get-shit-done/workflows/audit-fix.md @@ -32,19 +32,8 @@ Invoke the source audit command and capture output. For `audit-uat` source: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query audit-uat 2>/dev/null || echo "{}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query audit-uat 2>/dev/null || echo "{}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -117,7 +106,7 @@ Agent( **b. Run tests:** ```bash -AUDIT_TEST_CMD=$($GSD_SDK query config-get workflow.test_command --default "" 2>/dev/null || true) +AUDIT_TEST_CMD=$(gsd_run query config-get workflow.test_command --default "" 2>/dev/null || true) if [ -z "$AUDIT_TEST_CMD" ]; then if [ -f "Makefile" ] && grep -q "^test:" Makefile; then AUDIT_TEST_CMD="make test" diff --git a/get-shit-done/workflows/audit-milestone.md b/get-shit-done/workflows/audit-milestone.md index b94094041..44414e6b7 100644 --- a/get-shit-done/workflows/audit-milestone.md +++ b/get-shit-done/workflows/audit-milestone.md @@ -16,35 +16,24 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo ## 0. Initialize Milestone Context ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.milestone-op) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.milestone-op) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_CHECKER=$($GSD_SDK query agent-skills gsd-integration-checker) +AGENT_SKILLS_CHECKER=$(gsd_run query agent-skills gsd-integration-checker) ``` Extract from init JSON: `milestone_version`, `milestone_name`, `phase_count`, `completed_phases`, `commit_docs`. Resolve integration checker model: ```bash -integration_checker_model=$($GSD_SDK query resolve-model gsd-integration-checker --raw) +integration_checker_model=$(gsd_run query resolve-model gsd-integration-checker --raw) ``` ## 1. Determine Milestone Scope ```bash # Get phases in milestone (sorted numerically, handles decimals) -$GSD_SDK query phases.list +gsd_run query phases.list ``` - Parse version from arguments or detect current from ROADMAP.md @@ -58,7 +47,7 @@ For each phase directory, read the VERIFICATION.md: ```bash # For each phase, use find-phase to resolve the directory (handles archived phases) -PHASE_INFO=$($GSD_SDK query find-phase 01 --raw) +PHASE_INFO=$(gsd_run query find-phase 01 --raw) # Extract directory from JSON, then read VERIFICATION.md from that directory # Repeat for each phase number from ROADMAP.md ``` @@ -127,7 +116,7 @@ For each phase's SUMMARY.md, extract `requirements-completed` from YAML frontmat ```bash for summary in .planning/phases/*-*/*-SUMMARY.md; do [ -e "$summary" ] || continue - $GSD_SDK query summary-extract "$summary" --fields requirements_completed --pick requirements_completed + gsd_run query summary-extract "$summary" --fields requirements_completed --pick requirements_completed done ``` @@ -155,7 +144,7 @@ For each REQ-ID, determine status using all three sources: Skip if `workflow.nyquist_validation` is explicitly `false` (absent = enabled). ```bash -NYQUIST_CONFIG=$($GSD_SDK query config-get workflow.nyquist_validation --raw 2>/dev/null) +NYQUIST_CONFIG=$(gsd_run query config-get workflow.nyquist_validation --raw 2>/dev/null) ``` If `false`: skip entirely. diff --git a/get-shit-done/workflows/audit-uat.md b/get-shit-done/workflows/audit-uat.md index db17476c9..bf6e867bc 100644 --- a/get-shit-done/workflows/audit-uat.md +++ b/get-shit-done/workflows/audit-uat.md @@ -8,19 +8,8 @@ Cross-phase audit of all UAT and verification files. Finds every outstanding ite Run the CLI audit: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -AUDIT=$($GSD_SDK query audit-uat --raw) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +AUDIT=$(gsd_run query audit-uat --raw) ``` Parse JSON for `results` array and `summary` object. diff --git a/get-shit-done/workflows/autonomous.md b/get-shit-done/workflows/autonomous.md index 2c32281db..3ddf8f353 100644 --- a/get-shit-done/workflows/autonomous.md +++ b/get-shit-done/workflows/autonomous.md @@ -48,19 +48,8 @@ When `--interactive` is set, discuss runs inline with questions (not auto-answer Bootstrap via milestone-level init: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.milestone-op) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.milestone-op) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -94,7 +83,7 @@ If `INTERACTIVE` is set, display: `Mode: Interactive (discuss inline, plan+execu Run phase discovery: ```bash -ROADMAP=$($GSD_SDK query roadmap.analyze) +ROADMAP=$(gsd_run query roadmap.analyze) ``` Parse the JSON `phases` array. @@ -153,7 +142,7 @@ Exit cleanly. **Fetch details for each phase:** ```bash -DETAIL=$($GSD_SDK query roadmap.get-phase ${PHASE_NUM}) +DETAIL=$(gsd_run query roadmap.get-phase ${PHASE_NUM}) ``` Extract `phase_name`, `goal`, `success_criteria` from each. Store for use in execute_phase and transition messages. @@ -181,7 +170,7 @@ Where N = current phase number (from the ROADMAP, e.g., 63), T = total milestone Check if CONTEXT.md already exists for this phase: ```bash -PHASE_STATE=$($GSD_SDK query init.phase-op ${PHASE_NUM}) +PHASE_STATE=$(gsd_run query init.phase-op ${PHASE_NUM}) ``` Parse `has_context` from JSON. @@ -197,7 +186,7 @@ Proceed to 3b. **If has_context is false:** Check if discuss is disabled via settings: ```bash -SKIP_DISCUSS=$($GSD_SDK query config-get workflow.skip_discuss 2>/dev/null || echo "false") +SKIP_DISCUSS=$(gsd_run query config-get workflow.skip_discuss 2>/dev/null || echo "false") ``` **If SKIP_DISCUSS is `true`:** Skip discuss entirely — the ROADMAP phase description is the spec. Display: @@ -209,7 +198,7 @@ Phase ${PHASE_NUM}: Discuss skipped (workflow.skip_discuss=true) — using ROADM Write a minimal CONTEXT.md so downstream plan-phase has valid input. Get phase details: ```bash -DETAIL=$($GSD_SDK query roadmap.get-phase ${PHASE_NUM}) +DETAIL=$(gsd_run query roadmap.get-phase ${PHASE_NUM}) ``` Extract `goal` and `requirements` from JSON. Write `${phase_dir}/${padded_phase}-CONTEXT.md` with: @@ -261,7 +250,7 @@ None — discuss phase skipped. Commit the minimal context: ```bash -$GSD_SDK query commit "docs(${PADDED_PHASE}): auto-generated context (discuss skipped)" --files "${phase_dir}/${padded_phase}-CONTEXT.md" +gsd_run query commit "docs(${PADDED_PHASE}): auto-generated context (discuss skipped)" --files "${phase_dir}/${padded_phase}-CONTEXT.md" ``` Proceed to 3b. @@ -282,7 +271,7 @@ Skill(skill="gsd-discuss-phase", args="${PHASE_NUM}") After discuss completes (either mode), verify context was written: ```bash -PHASE_STATE=$($GSD_SDK query init.phase-op ${PHASE_NUM}) +PHASE_STATE=$(gsd_run query init.phase-op ${PHASE_NUM}) ``` Check `has_context`. If false → go to handle_blocker: "Discuss for phase ${PHASE_NUM} did not produce CONTEXT.md." @@ -292,7 +281,7 @@ Check `has_context`. If false → go to handle_blocker: "Discuss for phase ${PHA Check if this phase has frontend indicators and whether a UI-SPEC already exists: ```bash -PHASE_SECTION=$($GSD_SDK query roadmap.get-phase ${PHASE_NUM} 2>/dev/null) +PHASE_SECTION=$(gsd_run query roadmap.get-phase ${PHASE_NUM} 2>/dev/null) # Shell-free word-boundary gate (#3718): Node.js helper — no locale env-var dependency. # Reads via stdin to avoid OS ARG_MAX limits on large phase text. # Path anchored to repo root; falls back to CWD if git is unavailable @@ -306,7 +295,7 @@ UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1) Check if UI phase workflow is enabled: ```bash -UI_PHASE_CFG=$($GSD_SDK query config-get workflow.ui_phase 2>/dev/null || echo "true") +UI_PHASE_CFG=$(gsd_run query config-get workflow.ui_phase 2>/dev/null || echo "true") ``` **If `HAS_UI` is 0 (frontend indicators found) AND `UI_SPEC_FILE` is empty (no UI-SPEC exists) AND `UI_PHASE_CFG` is not `false`:** @@ -379,7 +368,7 @@ Auto-invoke code review and fix chain. Autonomous mode chains both review and fi **Config gate:** ```bash -CODE_REVIEW_ENABLED=$($GSD_SDK query config-get workflow.code_review 2>/dev/null || echo "true") +CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true") ``` If `"false"`: display "Code review skipped (workflow.code_review=false)" and proceed to 3d. @@ -407,7 +396,7 @@ VERIFY_STATUS=$(grep "^status:" "${PHASE_DIR}"/*-VERIFICATION.md 2>/dev/null | h Where `PHASE_DIR` comes from the `init phase-op` call already made in step 3a. If the variable is not in scope, re-fetch: ```bash -PHASE_STATE=$($GSD_SDK query init.phase-op ${PHASE_NUM}) +PHASE_STATE=$(gsd_run query init.phase-op ${PHASE_NUM}) ``` Parse `phase_dir` from the JSON. @@ -503,7 +492,7 @@ UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1) Check if UI review is enabled: ```bash -UI_REVIEW_CFG=$($GSD_SDK query config-get workflow.ui_review 2>/dev/null || echo "true") +UI_REVIEW_CFG=$(gsd_run query config-get workflow.ui_review 2>/dev/null || echo "true") ``` **If `UI_SPEC_FILE` is not empty AND `UI_REVIEW_CFG` is not `false`:** @@ -562,7 +551,7 @@ Proceed directly to lifecycle step (which handles partial completion — skips a **Otherwise:** After each phase completes, re-read ROADMAP.md to catch phases inserted mid-execution (decimal phases like 5.1): ```bash -ROADMAP=$($GSD_SDK query roadmap.analyze) +ROADMAP=$(gsd_run query roadmap.analyze) ``` Re-filter incomplete phases using the same logic as discover_phases: diff --git a/get-shit-done/workflows/check-todos.md b/get-shit-done/workflows/check-todos.md index fae118996..23964168b 100644 --- a/get-shit-done/workflows/check-todos.md +++ b/get-shit-done/workflows/check-todos.md @@ -12,19 +12,8 @@ Read all files referenced by the invoking prompt's execution_context before star Load todo context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.todos) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.todos) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -169,7 +158,7 @@ If todo was moved to done/, commit the change: ```bash git rm --cached .planning/todos/pending/[filename] 2>/dev/null || true -$GSD_SDK query commit "docs: start work on todo - [title]" --files .planning/todos/completed/[filename] .planning/STATE.md +gsd_run query commit "docs: start work on todo - [title]" --files .planning/todos/completed/[filename] .planning/STATE.md ``` Tool respects `commit_docs` config and gitignore automatically. diff --git a/get-shit-done/workflows/cleanup.md b/get-shit-done/workflows/cleanup.md index ea2e63ee1..460b7626a 100644 --- a/get-shit-done/workflows/cleanup.md +++ b/get-shit-done/workflows/cleanup.md @@ -124,19 +124,8 @@ Repeat for all milestones in the cleanup set. Commit the changes: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query commit "chore: archive phase directories from completed milestones" --files .planning/milestones/ .planning/phases/ +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query commit "chore: archive phase directories from completed milestones" --files .planning/milestones/ .planning/phases/ ``` diff --git a/get-shit-done/workflows/code-review-fix.md b/get-shit-done/workflows/code-review-fix.md index 36ad90f44..e950fdc0e 100644 --- a/get-shit-done/workflows/code-review-fix.md +++ b/get-shit-done/workflows/code-review-fix.md @@ -17,20 +17,9 @@ Read all files referenced by the invoking prompt's execution_context before star Parse arguments and load project state: ```bash +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi PHASE_ARG="${1}" -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -86,7 +75,7 @@ FIX_REPORT_PATH="${PHASE_DIR}/${PADDED_PHASE}-REVIEW-FIX.md" Check if code review is enabled via config: ```bash -CODE_REVIEW_ENABLED=$($GSD_SDK query config-get workflow.code_review 2>/dev/null || echo "true") +CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true") ``` If CODE_REVIEW_ENABLED is "false": @@ -375,7 +364,7 @@ if [ -f "${FIX_REPORT_PATH}" ]; then echo "REVIEW-FIX.md created at ${FIX_REPORT_PATH}" if [ "$COMMIT_DOCS" = "true" ]; then - $GSD_SDK query commit \ + gsd_run query commit \ "docs(${PADDED_PHASE}): add code review fix report" \ --files "${FIX_REPORT_PATH}" fi diff --git a/get-shit-done/workflows/code-review.md b/get-shit-done/workflows/code-review.md index 4afc50973..5e13c7691 100644 --- a/get-shit-done/workflows/code-review.md +++ b/get-shit-done/workflows/code-review.md @@ -17,20 +17,9 @@ Read all files referenced by the invoking prompt's execution_context before star Parse arguments and load project state: ```bash +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi PHASE_ARG="${1}" -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -86,7 +75,7 @@ fi Check if code review is enabled via config: ```bash -CODE_REVIEW_ENABLED=$($GSD_SDK query config-get workflow.code_review 2>/dev/null || echo "true") +CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true") ``` If CODE_REVIEW_ENABLED is "false": @@ -109,7 +98,7 @@ Determine review depth with priority order: if [ -n "$DEPTH_OVERRIDE" ]; then REVIEW_DEPTH="$DEPTH_OVERRIDE" else - CONFIG_DEPTH=$($GSD_SDK query config-get workflow.code_review_depth 2>/dev/null || echo "") + CONFIG_DEPTH=$(gsd_run query config-get workflow.code_review_depth 2>/dev/null || echo "") REVIEW_DEPTH="${CONFIG_DEPTH:-standard}" fi ``` @@ -335,10 +324,10 @@ Optional structural cross-module pass powered by fallow. Read fallow config gates: ```bash -FALLOW_ENABLED=$($GSD_SDK query config-get code_quality.fallow.enabled 2>/dev/null || echo "false") -FALLOW_SCOPE=$($GSD_SDK query config-get code_quality.fallow.scope 2>/dev/null || echo "phase") -FALLOW_PROFILE=$($GSD_SDK query config-get code_quality.fallow.profile 2>/dev/null || echo "standard") -FALLOW_MCP=$($GSD_SDK query config-get code_quality.fallow.mcp 2>/dev/null || echo "false") +FALLOW_ENABLED=$(gsd_run query config-get code_quality.fallow.enabled 2>/dev/null || echo "false") +FALLOW_SCOPE=$(gsd_run query config-get code_quality.fallow.scope 2>/dev/null || echo "phase") +FALLOW_PROFILE=$(gsd_run query config-get code_quality.fallow.profile 2>/dev/null || echo "standard") +FALLOW_MCP=$(gsd_run query config-get code_quality.fallow.mcp 2>/dev/null || echo "false") ``` Defaults are fail-closed and opt-in: @@ -505,7 +494,7 @@ if [ -f "${REVIEW_PATH}" ]; then echo "REVIEW.md created at ${REVIEW_PATH}" if [ "$COMMIT_DOCS" = "true" ]; then - $GSD_SDK query commit \ + gsd_run query commit \ "docs(${PADDED_PHASE}): add code review report" \ --files "${REVIEW_PATH}" fi diff --git a/get-shit-done/workflows/complete-milestone.md b/get-shit-done/workflows/complete-milestone.md index 5160401a8..95f1d6766 100644 --- a/get-shit-done/workflows/complete-milestone.md +++ b/get-shit-done/workflows/complete-milestone.md @@ -41,19 +41,8 @@ When a milestone completes: Before proceeding with milestone close, run the comprehensive open artifact audit. ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query audit-open +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query audit-open ``` If the output contains open items (any section with count > 0): @@ -96,7 +85,7 @@ SECURITY: Audit JSON output is structured data from the `audit-open` query handl **Use `roadmap analyze` for comprehensive readiness check:** ```bash -ROADMAP=$($GSD_SDK query roadmap.analyze) +ROADMAP=$(gsd_run query roadmap.analyze) ``` This returns all phases with plan/summary counts and disk status. Use this to verify: @@ -211,7 +200,7 @@ Extract one-liners from SUMMARY.md files using summary-extract: # For each phase in milestone, extract one-liner for summary in .planning/phases/*-*/*-SUMMARY.md; do [ -e "$summary" ] || continue - $GSD_SDK query summary-extract "$summary" --fields one_liner --pick one_liner + gsd_run query summary-extract "$summary" --fields one_liner --pick one_liner done ``` @@ -424,7 +413,7 @@ Update `.planning/ROADMAP.md` — group completed milestone phases: **Delegate archival to `gsd-tools.cjs query milestone.complete`:** ```bash -ARCHIVE=$($GSD_SDK query milestone.complete "v[X.Y]" --name "[Milestone Name]") +ARCHIVE=$(gsd_run query milestone.complete "v[X.Y]" --name "[Milestone Name]") ``` The CLI handles: @@ -506,7 +495,7 @@ Append the extracted Backlog content verbatim to the end of the newly written RO **Safety commit — commit archive files BEFORE deleting any originals:** ```bash -$GSD_SDK query commit "chore: archive v[X.Y] milestone files" --files .planning/milestones/v[X.Y]-ROADMAP.md .planning/milestones/v[X.Y]-REQUIREMENTS.md .planning/milestones/v[X.Y]-MILESTONE-AUDIT.md .planning/MILESTONES.md .planning/PROJECT.md .planning/STATE.md .planning/ROADMAP.md +gsd_run query commit "chore: archive v[X.Y] milestone files" --files .planning/milestones/v[X.Y]-ROADMAP.md .planning/milestones/v[X.Y]-REQUIREMENTS.md .planning/milestones/v[X.Y]-MILESTONE-AUDIT.md .planning/MILESTONES.md .planning/PROJECT.md .planning/STATE.md .planning/ROADMAP.md ``` This creates a durable checkpoint in git history. If anything fails after this point, the working tree can be reconstructed from git. @@ -575,7 +564,7 @@ If the "## Cross-Milestone Trends" section exists, update the tables with new da **Commit:** ```bash -$GSD_SDK query commit "docs: update retrospective for v${VERSION}" --files .planning/RETROSPECTIVE.md +gsd_run query commit "docs: update retrospective for v${VERSION}" --files .planning/RETROSPECTIVE.md ``` @@ -609,7 +598,7 @@ Check branching strategy and offer merge options. Use `init milestone-op` for context, or load config directly: ```bash -INIT=$($GSD_SDK query init.execute-phase "1") +INIT=$(gsd_run query init.execute-phase "1") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -617,7 +606,7 @@ Extract `branching_strategy`, `phase_branch_template`, `milestone_branch_templat Detect base branch: ```bash -BASE_BRANCH=$($GSD_SDK query config-get git.base_branch 2>/dev/null || echo "") +BASE_BRANCH=$(gsd_run query config-get git.base_branch 2>/dev/null || echo "") if [ -z "$BASE_BRANCH" ] || [ "$BASE_BRANCH" = "null" ]; then BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||') BASE_BRANCH="${BASE_BRANCH:-main}" diff --git a/get-shit-done/workflows/debug.md b/get-shit-done/workflows/debug.md index ac49a5842..7ec494063 100644 --- a/get-shit-done/workflows/debug.md +++ b/get-shit-done/workflows/debug.md @@ -16,30 +16,19 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo ## 0. Initialize Context ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query state.load) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query state.load) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` Extract `commit_docs` from init JSON. Resolve debugger model: ```bash -debugger_model=$($GSD_SDK query resolve-model gsd-debugger 2>/dev/null | jq -r '.model' 2>/dev/null || true) +debugger_model=$(gsd_run query resolve-model gsd-debugger 2>/dev/null | jq -r '.model' 2>/dev/null || true) ``` Read TDD mode from config: ```bash -TDD_MODE=$($GSD_SDK query config-get workflow.tdd_mode 2>/dev/null | jq -r 'if type == "boolean" then tostring else . end' 2>/dev/null || echo "false") +TDD_MODE=$(gsd_run query config-get workflow.tdd_mode 2>/dev/null | jq -r 'if type == "boolean" then tostring else . end' 2>/dev/null || echo "false") ``` ## 1a. LIST subcommand diff --git a/get-shit-done/workflows/diagnose-issues.md b/get-shit-done/workflows/diagnose-issues.md index 9ba890050..0f24f4758 100644 --- a/get-shit-done/workflows/diagnose-issues.md +++ b/get-shit-done/workflows/diagnose-issues.md @@ -58,19 +58,8 @@ gaps = [ **Read worktree config:** ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -USE_WORKTREES=$($GSD_SDK query config-get workflow.use_worktrees 2>/dev/null || echo "true") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +USE_WORKTREES=$(gsd_run query config-get workflow.use_worktrees 2>/dev/null || echo "true") ``` **Report diagnosis plan to user:** @@ -99,7 +88,7 @@ This runs in parallel - all gaps investigated simultaneously. **Load agent skills:** ```bash -AGENT_SKILLS_DEBUGGER=$($GSD_SDK query agent-skills gsd-debugger) +AGENT_SKILLS_DEBUGGER=$(gsd_run query agent-skills gsd-debugger) EXPECTED_BASE=$(git rev-parse HEAD) ``` @@ -191,7 +180,7 @@ Update status in frontmatter to "diagnosed". Commit the updated UAT.md: ```bash -$GSD_SDK query commit "docs({phase_num}): add root causes from diagnosis" --files ".planning/phases/XX-name/{phase_num}-UAT.md" +gsd_run query commit "docs({phase_num}): add root causes from diagnosis" --files ".planning/phases/XX-name/{phase_num}-UAT.md" ``` diff --git a/get-shit-done/workflows/discuss-phase-assumptions.md b/get-shit-done/workflows/discuss-phase-assumptions.md index effe2f3ad..30040d7ca 100644 --- a/get-shit-done/workflows/discuss-phase-assumptions.md +++ b/get-shit-done/workflows/discuss-phase-assumptions.md @@ -64,21 +64,10 @@ plain-text numbered list and ask the user to type their choice number. Phase number from argument (required). ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_ANALYZER=$($GSD_SDK query agent-skills gsd-assumptions-analyzer) +AGENT_SKILLS_ANALYZER=$(gsd_run query agent-skills gsd-assumptions-analyzer) ``` Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, @@ -183,7 +172,7 @@ Structure the extracted information for use in assumption generation. Check if any pending todos are relevant to this phase's scope. ```bash -TODO_MATCHES=$($GSD_SDK query todo.match-phase "${PHASE_NUMBER}") +TODO_MATCHES=$(gsd_run query todo.match-phase "${PHASE_NUMBER}") ``` Parse JSON for: `todo_count`, `matches[]`. @@ -564,7 +553,7 @@ Write file. Commit phase context and discussion log: ```bash -$GSD_SDK query commit "docs(${padded_phase}): capture phase context (assumptions mode)" --files "${phase_dir}/${padded_phase}-CONTEXT.md" "${phase_dir}/${padded_phase}-DISCUSSION-LOG.md" +gsd_run query commit "docs(${padded_phase}): capture phase context (assumptions mode)" --files "${phase_dir}/${padded_phase}-CONTEXT.md" "${phase_dir}/${padded_phase}-DISCUSSION-LOG.md" ``` Confirm: "Committed: docs(${padded_phase}): capture phase context (assumptions mode)" @@ -574,7 +563,7 @@ Confirm: "Committed: docs(${padded_phase}): capture phase context (assumptions m Update STATE.md with session info: ```bash -$GSD_SDK query state.record-session \ +gsd_run query state.record-session \ --stopped-at "Phase ${PHASE} context gathered (assumptions mode)" \ --resume-file "${phase_dir}/${padded_phase}-CONTEXT.md" ``` @@ -582,7 +571,7 @@ $GSD_SDK query state.record-session \ Commit STATE.md: ```bash -$GSD_SDK query commit "docs(state): record phase ${PHASE} context session" --files .planning/STATE.md +gsd_run query commit "docs(state): record phase ${PHASE} context session" --files .planning/STATE.md ``` @@ -635,17 +624,17 @@ Check for auto-advance trigger: 2. Sync chain flag: ```bash if [[ ! "$ARGUMENTS" =~ --auto ]]; then - $GSD_SDK query config-set workflow._auto_chain_active false || true + gsd_run query config-set workflow._auto_chain_active false || true fi ``` 3. Read consolidated auto-mode (`active` = chain flag OR user preference): ```bash - AUTO_MODE=$($GSD_SDK query check auto-mode --pick active 2>/dev/null || echo "false") + AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null || echo "false") ``` **If `--auto` flag present AND `AUTO_MODE` is not true:** ```bash -$GSD_SDK query config-set workflow._auto_chain_active true +gsd_run query config-set workflow._auto_chain_active true ``` **If `--auto` flag present OR `AUTO_MODE` is true:** diff --git a/get-shit-done/workflows/discuss-phase.md b/get-shit-done/workflows/discuss-phase.md index 52e72d96a..6ed8780a5 100644 --- a/get-shit-done/workflows/discuss-phase.md +++ b/get-shit-done/workflows/discuss-phase.md @@ -109,9 +109,9 @@ Phase: "API documentation" → Structure/navigation, Code examples depth, Phase number from argument (required). ```bash -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs"; if [ -f "$GSD_TOOLS" ]; then GSD_SDK="node $GSD_TOOLS"; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; GSD_SDK="$GSD_TOOLS"; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2; exit 1; fi -INIT=$($GSD_SDK query init.phase-op "${PHASE}"); [[ "$INIT" == @file:* ]] && INIT=$(cat "${INIT#@file:}") -AGENT_SKILLS_ADVISOR=$($GSD_SDK query agent-skills gsd-advisor-researcher) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE}"); [[ "$INIT" == @file:* ]] && INIT=$(cat "${INIT#@file:}") +AGENT_SKILLS_ADVISOR=$(gsd_run query agent-skills gsd-advisor-researcher) ``` Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`, `plan_count`, `roadmap_exists`, `planning_exists`, `response_language`. @@ -265,7 +265,7 @@ Build internal `` with sections for Project-Level (from PROJECT Check pending todos for matches with this phase's scope. ```bash -TODO_MATCHES=$($GSD_SDK query todo.match-phase "${PHASE_NUMBER}") +TODO_MATCHES=$(gsd_run query todo.match-phase "${PHASE_NUMBER}") ``` Parse JSON for: `todo_count`, `matches[]` (each with `file`, `title`, `area`, `score`, `reasons`). @@ -447,7 +447,7 @@ rm -f "${phase_dir}/${padded_phase}-DISCUSS-CHECKPOINT.json" Commit phase context and discussion log: ```bash -$GSD_SDK query commit "docs(${padded_phase}): capture phase context" --files "${phase_dir}/${padded_phase}-CONTEXT.md" "${phase_dir}/${padded_phase}-DISCUSSION-LOG.md" +gsd_run query commit "docs(${padded_phase}): capture phase context" --files "${phase_dir}/${padded_phase}-CONTEXT.md" "${phase_dir}/${padded_phase}-DISCUSSION-LOG.md" ``` Confirm: "Committed: docs(${padded_phase}): capture phase context" @@ -457,11 +457,11 @@ Confirm: "Committed: docs(${padded_phase}): capture phase context" Update STATE.md with session info: ```bash -$GSD_SDK query state.record-session \ +gsd_run query state.record-session \ --stopped-at "Phase ${PHASE} context gathered" \ --resume-file "${phase_dir}/${padded_phase}-CONTEXT.md" -$GSD_SDK query commit "docs(state): record phase ${PHASE} context session" --files .planning/STATE.md +gsd_run query commit "docs(state): record phase ${PHASE} context session" --files .planning/STATE.md ``` diff --git a/get-shit-done/workflows/discuss-phase/modes/advisor.md b/get-shit-done/workflows/discuss-phase/modes/advisor.md index a2b71f2da..b9d901c71 100644 --- a/get-shit-done/workflows/discuss-phase/modes/advisor.md +++ b/get-shit-done/workflows/discuss-phase/modes/advisor.md @@ -37,7 +37,8 @@ Map to calibration tier: Resolve advisor model: ```bash -ADVISOR_MODEL=$($GSD_SDK query resolve-model gsd-advisor-researcher --raw) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +ADVISOR_MODEL=$(gsd_run query resolve-model gsd-advisor-researcher --raw) ``` ## Non-technical owner detection diff --git a/get-shit-done/workflows/discuss-phase/modes/auto.md b/get-shit-done/workflows/discuss-phase/modes/auto.md index bf0bbb063..0266e08b7 100644 --- a/get-shit-done/workflows/discuss-phase/modes/auto.md +++ b/get-shit-done/workflows/discuss-phase/modes/auto.md @@ -40,7 +40,8 @@ that the next pass treats as gaps, consuming unbounded time and resources. Check the pass cap from config: ```bash -MAX_PASSES=$($GSD_SDK query config-get workflow.max_discuss_passes 2>/dev/null || echo "3") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +MAX_PASSES=$(gsd_run query config-get workflow.max_discuss_passes 2>/dev/null || echo "3") ``` If you have already written and committed CONTEXT.md, the discuss step is diff --git a/get-shit-done/workflows/discuss-phase/modes/chain.md b/get-shit-done/workflows/discuss-phase/modes/chain.md index f9dc808b6..d727d4b90 100644 --- a/get-shit-done/workflows/discuss-phase/modes/chain.md +++ b/get-shit-done/workflows/discuss-phase/modes/chain.md @@ -25,20 +25,21 @@ interrupted `--auto` chain. This does NOT touch `workflow.auto_advance` (the user's persistent settings preference): ```bash +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi if [[ ! "$ARGUMENTS" =~ --auto ]] && [[ ! "$ARGUMENTS" =~ --chain ]]; then - $GSD_SDK query config-set workflow._auto_chain_active false || true + gsd_run query config-set workflow._auto_chain_active false || true fi ``` 3. Read consolidated auto-mode (`active` = chain flag OR user preference): ```bash - AUTO_MODE=$($GSD_SDK query check auto-mode --pick active 2>/dev/null || echo "false") + AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null || echo "false") ``` 4. **If `--auto` or `--chain` flag present AND `AUTO_MODE` is not true:** Persist chain flag to config (handles direct usage without new-project): ```bash - $GSD_SDK query config-set workflow._auto_chain_active true + gsd_run query config-set workflow._auto_chain_active true ``` 5. **If `--auto` flag present OR `--chain` flag present OR `AUTO_MODE` is diff --git a/get-shit-done/workflows/do.md b/get-shit-done/workflows/do.md index 04fa4e587..998eb6c3f 100644 --- a/get-shit-done/workflows/do.md +++ b/get-shit-done/workflows/do.md @@ -26,20 +26,8 @@ Wait for response before continuing. **Check if project exists.** ```bash -# SDK resolution: prefer local node shim, fall back to installed gsd-tools (#3668) -_GSD_SHIM_NAME="gsd-tools.cjs" -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query state.load 2>/dev/null) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query state.load 2>/dev/null) ``` Track whether `.planning/` exists — some routes require it, others don't. diff --git a/get-shit-done/workflows/docs-update.md b/get-shit-done/workflows/docs-update.md index 3e26adde2..025fb8ac8 100644 --- a/get-shit-done/workflows/docs-update.md +++ b/get-shit-done/workflows/docs-update.md @@ -14,21 +14,10 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo Load docs-update context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query docs-init) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query docs-init) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS=$($GSD_SDK query agent-skills gsd-doc-writer) +AGENT_SKILLS=$(gsd_run query agent-skills gsd-doc-writer) ``` Extract from init JSON: @@ -1072,7 +1061,7 @@ Only run this step if `commit_docs` is `true` from the init JSON. If `commit_doc Assemble the list of files that were actually generated (do not include files that failed or were skipped): ```bash -$GSD_SDK query commit "docs: generate project documentation" \ +gsd_run query commit "docs: generate project documentation" \ --files README.md docs/ARCHITECTURE.md docs/CONFIGURATION.md docs/GETTING-STARTED.md docs/DEVELOPMENT.md docs/TESTING.md # Append any conditional docs that were generated: # --files ... docs/API.md docs/DEPLOYMENT.md CONTRIBUTING.md diff --git a/get-shit-done/workflows/edit-phase.md b/get-shit-done/workflows/edit-phase.md index 23ac9a2a5..f16c038d6 100644 --- a/get-shit-done/workflows/edit-phase.md +++ b/get-shit-done/workflows/edit-phase.md @@ -34,19 +34,8 @@ Exit. Load phase operation context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${target}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${target}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -62,7 +51,7 @@ Exit. Read the current phase section from ROADMAP.md: ```bash -PHASE_DATA=$($GSD_SDK query roadmap get-phase "${target}") +PHASE_DATA=$(gsd_run query roadmap get-phase "${target}") ``` Parse the JSON result. If `found` is false: @@ -90,7 +79,7 @@ Also parse the full section text to extract additional fields not in the SDK res Determine the phase status from disk. Compare against STATE.md current phase: ```bash -ANALYZE=$($GSD_SDK query roadmap analyze) +ANALYZE=$(gsd_run query roadmap analyze) ``` Find the phase entry in the `phases` array. Extract `disk_status`. @@ -192,7 +181,7 @@ Wait for user input. Use the clarified intent to rewrite all fields: If `depends_on` is being updated (or preserved as non-empty), validate that every referenced phase number exists in ROADMAP.md: ```bash -ALL_PHASES=$($GSD_SDK query roadmap analyze) +ALL_PHASES=$(gsd_run query roadmap analyze) ``` Parse the `phases` array to get all valid phase numbers. @@ -251,7 +240,7 @@ Read the full ROADMAP.md content, locate the phase section by its header (`## Ph After writing ROADMAP.md, update STATE.md Roadmap Evolution: ```bash -$GSD_SDK query state.add-roadmap-evolution \ +gsd_run query state.add-roadmap-evolution \ --phase {target} \ --action edited \ --note "edited fields: {changed_field_list}" diff --git a/get-shit-done/workflows/eval-review.md b/get-shit-done/workflows/eval-review.md index 220246cf9..21735efd0 100644 --- a/get-shit-done/workflows/eval-review.md +++ b/get-shit-done/workflows/eval-review.md @@ -13,26 +13,15 @@ Use after /gsd:execute-phase to verify that the evaluation strategy from AI-SPEC ## 0. Initialize ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `commit_docs`. ```bash -AUDITOR_MODEL=$($GSD_SDK query resolve-model gsd-eval-auditor 2>/dev/null | jq -r '.model' 2>/dev/null || true) +AUDITOR_MODEL=$(gsd_run query resolve-model gsd-eval-auditor 2>/dev/null | jq -r '.model' 2>/dev/null || true) ``` Display banner: diff --git a/get-shit-done/workflows/execute-phase.md b/get-shit-done/workflows/execute-phase.md index bc5ab6902..13c684243 100644 --- a/get-shit-done/workflows/execute-phase.md +++ b/get-shit-done/workflows/execute-phase.md @@ -66,21 +66,10 @@ If `--wave` is absent, preserve the current behavior of executing all incomplete Load all context in one call: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.execute-phase "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.execute-phase "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS=$($GSD_SDK query agent-skills gsd-executor) +AGENT_SKILLS=$(gsd_run query agent-skills gsd-executor) ``` 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`. @@ -92,17 +81,17 @@ Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelizat Read runtime/worktree config and fail closed before any executor dispatch: ```bash -RUNTIME=$($GSD_SDK query config-get runtime --default claude 2>/dev/null || echo "claude") -USE_WORKTREES=$($GSD_SDK query config-get workflow.use_worktrees 2>/dev/null || echo "true") -EXECUTOR_STALL_INTERVAL_MINUTES=$($GSD_SDK query config-get executor.stall_detect_interval_minutes 2>/dev/null || echo "5") -EXECUTOR_STALL_THRESHOLD_MINUTES=$($GSD_SDK query config-get executor.stall_threshold_minutes 2>/dev/null || echo "10") +RUNTIME=$(gsd_run query config-get runtime --default claude 2>/dev/null || echo "claude") +USE_WORKTREES=$(gsd_run query config-get workflow.use_worktrees 2>/dev/null || echo "true") +EXECUTOR_STALL_INTERVAL_MINUTES=$(gsd_run query config-get executor.stall_detect_interval_minutes 2>/dev/null || echo "5") +EXECUTOR_STALL_THRESHOLD_MINUTES=$(gsd_run query config-get executor.stall_threshold_minutes 2>/dev/null || echo "10") if [ "$RUNTIME" = "codex" ] && [ "$USE_WORKTREES" != "false" ]; then echo "FATAL: Codex execute-phase worktree isolation is unsupported. Set workflow.use_worktrees=false or use a runtime with Agent isolation=\"worktree\" support." >&2 exit 1 fi # Sweep orphaned locked worktrees from prior crashed sessions before spawning executors (#3707). -[ "$USE_WORKTREES" != "false" ] && $GSD_SDK query worktree.reap-orphans 2>/dev/null || true +[ "$USE_WORKTREES" != "false" ] && gsd_run query worktree.reap-orphans 2>/dev/null || true ``` Codex maps subagents to `spawn_agent`, which has no direct Codex mapping for Claude Code's `isolation="worktree"` parameter. Failing closed prevents main-checkout edits while the workflow believes agents are isolated. @@ -125,7 +114,7 @@ When `USE_WORKTREES` (project-level) is `false`, all executor agents run without Read context window size for adaptive prompt enrichment: ```bash -CONTEXT_WINDOW=$($GSD_SDK query config-get context_window 2>/dev/null || echo "200000") +CONTEXT_WINDOW=$(gsd_run query config-get context_window 2>/dev/null || echo "200000") ``` When `CONTEXT_WINDOW >= 500000` (1M-class models), subagent prompts include richer context: @@ -157,7 +146,7 @@ inline path for each plan. ```bash # REQUIRED: prevents stale auto-chain from previous --auto runs if [[ ! "$ARGUMENTS" =~ --auto ]]; then - $GSD_SDK query config-set workflow._auto_chain_active false || true + gsd_run query config-set workflow._auto_chain_active false || true fi ``` @@ -165,8 +154,8 @@ Resolve `MVP_MODE` once via the centralized `phase.mvp-mode` query verb (precede ```bash MVP_FLAG_ARG="" if [[ "$ARGUMENTS" =~ (^|[[:space:]])--mvp([[:space:]]|$) ]]; then MVP_FLAG_ARG="--cli-flag"; fi -MVP_MODE=$($GSD_SDK query phase.mvp-mode "${PHASE_NUMBER}" $MVP_FLAG_ARG --pick active) -TDD_MODE=$($GSD_SDK query config-get workflow.tdd_mode 2>/dev/null || echo "false") +MVP_MODE=$(gsd_run query phase.mvp-mode "${PHASE_NUMBER}" $MVP_FLAG_ARG --pick active) +TDD_MODE=$(gsd_run query config-get workflow.tdd_mode 2>/dev/null || echo "false") ``` @@ -188,11 +177,11 @@ Offer these recovery options: **MVP+TDD gate.** Task-scoped enforcement runs inside plan execution (immediately before each implementation step), where `TASK_FILE`, `PLAN_ID`, and `TASK_ID` are defined. Keep the same predicate and RED-commit contract: ```bash if [ "$MVP_MODE" = "true" ] && [ "$TDD_MODE" = "true" ]; then - IS_BEHAVIOR_ADDING=$($GSD_SDK query task.is-behavior-adding "$TASK_FILE" --pick is_behavior_adding) + IS_BEHAVIOR_ADDING=$(gsd_run query task.is-behavior-adding "$TASK_FILE" --pick is_behavior_adding) if [ "$IS_BEHAVIOR_ADDING" = "true" ]; then RED_COMMIT=$(git log --oneline --grep="^test(${PHASE_NUMBER}-${PLAN_ID}):" -- "**/*.test.*" "**/*.spec.*" "tests/" | head -1) if [ -z "$RED_COMMIT" ]; then - $GSD_SDK query state.update last_gate_trip "${PLAN_ID}/${TASK_ID}" || true + gsd_run query state.update last_gate_trip "${PLAN_ID}/${TASK_ID}" || true echo "MVP+TDD GATE TRIPPED: missing RED commit for ${PLAN_ID}/${TASK_ID}" exit 1 fi @@ -318,7 +307,7 @@ Report: "Found {plan_count} plans in {phase_dir} ({incomplete_count} incomplete) **Update STATE.md for phase start:** ```bash -$GSD_SDK query state.begin-phase --phase "${PHASE_NUMBER}" --name "${PHASE_NAME}" --plans "${PLAN_COUNT}" +gsd_run query state.begin-phase --phase "${PHASE_NUMBER}" --name "${PHASE_NAME}" --plans "${PLAN_COUNT}" ``` This updates Status, Last Activity, Current focus, Current Position, and plan counts in STATE.md so frontmatter and body text reflect the active phase immediately. @@ -327,7 +316,7 @@ This updates Status, Last Activity, Current focus, Current Position, and plan co Load plan inventory with wave grouping in one call: ```bash -PLAN_INDEX=$($GSD_SDK query phase-plan-index "${PHASE_NUMBER}") +PLAN_INDEX=$(gsd_run query phase-plan-index "${PHASE_NUMBER}") ``` 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`. @@ -369,9 +358,9 @@ executor skips them. `workflow.cross_ai_execution` is `true`. Plans matching both conditions are marked for cross-AI. ```bash -CROSS_AI_ENABLED=$($GSD_SDK query config-get workflow.cross_ai_execution 2>/dev/null || echo "false") -CROSS_AI_CMD=$($GSD_SDK query config-get workflow.cross_ai_command 2>/dev/null || echo "") -CROSS_AI_TIMEOUT=$($GSD_SDK query config-get workflow.cross_ai_timeout 2>/dev/null || echo "300") +CROSS_AI_ENABLED=$(gsd_run query config-get workflow.cross_ai_execution 2>/dev/null || echo "false") +CROSS_AI_CMD=$(gsd_run query config-get workflow.cross_ai_command 2>/dev/null || echo "") +CROSS_AI_TIMEOUT=$(gsd_run query config-get workflow.cross_ai_timeout 2>/dev/null || echo "300") ``` **If no plans are marked for cross-AI:** Skip to execute_waves. @@ -731,7 +720,7 @@ increases monotonically across waves. `{status}` is `complete` (success), 5. **Post-wave hook validation (parallel mode only):** Hooks run on every executor commit by default (#2924); this post-wave run only fires when `workflow.worktree_skip_hooks=true` opted out of per-commit hooks: ```bash - SKIP_HOOKS=$($GSD_SDK query config-get workflow.worktree_skip_hooks 2>/dev/null || echo "false") + SKIP_HOOKS=$(gsd_run query config-get workflow.worktree_skip_hooks 2>/dev/null || echo "false") if [ "$SKIP_HOOKS" = "true" ]; then # Stash uncommitted changes under a named ref so we always pop (bare `git stash` strands them on hook/script failure). #3542: `refs/stash` is shared across worktrees, so this helper runs ONLY in the orchestrator's main checkout after all wave worktrees have been merged + removed; executors are forbidden from running any `git stash` subcommand (see `` in `agents/gsd-executor.md`). STASHED=false @@ -774,7 +763,7 @@ increases monotonically across waves. `{status}` is `complete` (success), [ -z "${EXPECTED_BRANCH:-}" ] || [ "$ORCH_BRANCH" = "$EXPECTED_BRANCH" ] || { echo "FATAL: orchestrator on '$ORCH_BRANCH' but expected '$EXPECTED_BRANCH' before worktree cleanup — refusing to merge (#3174-class drift)" >&2; exit 1; } # Fail closed: SDK refusal (safety guard #3174/#3384) must surface — do not swallow exit 1. - $GSD_SDK query worktree.cleanup-wave --manifest "$WAVE_WORKTREE_MANIFEST" || exit 1 + gsd_run query worktree.cleanup-wave --manifest "$WAVE_WORKTREE_MANIFEST" || exit 1 ``` **Cleanup-tail snippet (use after any wave whose merges did not flow through the templated path above):** @@ -847,12 +836,12 @@ increases monotonically across waves. `{status}` is `complete` (success), if [ "${TEST_EXIT}" -eq 0 ]; then # Update ROADMAP plan progress for each completed plan in this wave for plan_id in {completed_plan_ids}; do - $GSD_SDK query roadmap.update-plan-progress "${PHASE_NUMBER}" "${plan_id}" "complete" + gsd_run query roadmap.update-plan-progress "${PHASE_NUMBER}" "${plan_id}" "complete" done # Only commit tracking files if they actually changed if ! git diff --quiet .planning/ROADMAP.md .planning/STATE.md 2>/dev/null; then - $GSD_SDK query commit "docs(phase-${PHASE_NUMBER}): update tracking after wave ${N}" --files .planning/ROADMAP.md .planning/STATE.md + gsd_run query commit "docs(phase-${PHASE_NUMBER}): update tracking after wave ${N}" --files .planning/ROADMAP.md .planning/STATE.md fi elif [ "${TEST_EXIT}" -eq 124 ]; then echo "⚠ Skipping tracking update — test suite timed out. Plans remain in-progress. Run tests manually to confirm." @@ -928,7 +917,7 @@ increases monotonically across waves. `{status}` is `complete` (success), 7. **Handle failures:** **Step 7.0 — classify before branching (#3095):** ```bash - CLASS_JSON=$($GSD_SDK query agent.classify-failure -- "$AGENT_RETURN_BODY") + CLASS_JSON=$(gsd_run query agent.classify-failure -- "$AGENT_RETURN_BODY") CLASS=$(echo "$CLASS_JSON" | jq -r '.class') SENTINEL=$(echo "$CLASS_JSON" | jq -r '.sentinel // empty') RETRY_AFTER=$(echo "$CLASS_JSON" | jq -r '.retryAfterSeconds // empty') @@ -967,7 +956,7 @@ Plans with `autonomous: false` require user interaction. **Auto-mode checkpoint handling:** Read auto-advance config (chain flag OR user preference — same boolean as `check.auto-mode`): ```bash -AUTO_MODE=$($GSD_SDK query check auto-mode --pick active 2>/dev/null || echo "false") +AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null || echo "false") ``` When executor returns a checkpoint AND `AUTO_MODE` is `true`: @@ -1028,7 +1017,7 @@ After all waves: **Security gate check:** ```bash -SECURITY_CFG=$($GSD_SDK query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true") +SECURITY_CFG=$(gsd_run query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true") SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1) ``` @@ -1052,7 +1041,7 @@ If `SECURITY_CFG` is `true` AND SECURITY.md exists: check frontmatter `threats_o **Optional step — TDD collaborative review.** ```bash -TDD_MODE=$($GSD_SDK query config-get workflow.tdd_mode 2>/dev/null || echo "false") +TDD_MODE=$(gsd_run query config-get workflow.tdd_mode 2>/dev/null || echo "false") ``` **Skip if `TDD_MODE` is `false`.** @@ -1105,7 +1094,7 @@ The verifier agent (step `verify_phase_goal`) still checks TDD discipline in bot If `WAVE_FILTER` was used, re-run plan discovery after execution: ```bash -POST_PLAN_INDEX=$($GSD_SDK query phase-plan-index "${PHASE_NUMBER}") +POST_PLAN_INDEX=$(gsd_run query phase-plan-index "${PHASE_NUMBER}") ``` Apply the same "incomplete" filtering rules as earlier: @@ -1137,7 +1126,7 @@ Selected wave finished successfully. This phase still has incomplete plans, so p **Config gate:** ```bash -CODE_REVIEW_ENABLED=$($GSD_SDK query config-get workflow.code_review 2>/dev/null || echo "true") +CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true") ``` If `CODE_REVIEW_ENABLED` is `"false"`: display "Code review skipped (workflow.code_review=false)" and proceed to next step. @@ -1180,7 +1169,7 @@ fi **2. Find parent UAT file:** ```bash -PARENT_INFO=$($GSD_SDK query find-phase "${PARENT_PHASE}" --raw) +PARENT_INFO=$(gsd_run query find-phase "${PARENT_PHASE}" --raw) # Extract directory from PARENT_INFO JSON, then find UAT file in that directory ``` @@ -1211,7 +1200,7 @@ mv .planning/debug/{slug}.md .planning/debug/resolved/ **6. Commit updated artifacts:** ```bash -$GSD_SDK 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 +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 ``` @@ -1239,7 +1228,7 @@ Collect all unique test file paths into `REGRESSION_FILES`. ```bash # Resolve test command: project config > Makefile > language sniff -REG_TEST_CMD=$($GSD_SDK query config-get workflow.test_command --default "" 2>/dev/null || true) +REG_TEST_CMD=$(gsd_run query config-get workflow.test_command --default "" 2>/dev/null || true) if [ -z "$REG_TEST_CMD" ]; then if [ -f "Makefile" ] && grep -q "^test:" Makefile; then REG_TEST_CMD="make test" @@ -1295,7 +1284,7 @@ build/types pass because TypeScript types come from config, not the live databas **Run after execution completes but BEFORE verification marks success.** ```bash -SCHEMA_DRIFT=$($GSD_SDK query verify.schema-drift "${PHASE_NUMBER}" 2>/dev/null) +SCHEMA_DRIFT=$(gsd_run query verify.schema-drift "${PHASE_NUMBER}" 2>/dev/null) ``` Parse JSON result for: `drift_detected`, `blocking`, `schema_files`, `orms`, `unpushed_orms`, `message`. @@ -1369,7 +1358,7 @@ spawn template, and the two `workflow.drift_*` config keys. Verify phase achieved its GOAL, not just completed tasks. ```bash -VERIFIER_SKILLS=$($GSD_SDK query agent-skills gsd-verifier) +VERIFIER_SKILLS=$(gsd_run query agent-skills gsd-verifier) ``` ``` @@ -1454,7 +1443,7 @@ blocked: 0 Commit the file: ```bash -$GSD_SDK query commit "test({phase_num}): persist human verification items as UAT" --files "{phase_dir}/{phase_num}-HUMAN-UAT.md" +gsd_run query commit "test({phase_num}): persist human verification items as UAT" --files "{phase_dir}/{phase_num}-HUMAN-UAT.md" ``` **Step B: Present to user:** @@ -1503,7 +1492,7 @@ Gap closure cycle: `/gsd:plan-phase {X} --gaps ${GSD_WS}` reads VERIFICATION.md **Mark phase complete and update all tracking files:** ```bash -COMPLETION=$($GSD_SDK query phase.complete "${PHASE_NUMBER}") +COMPLETION=$(gsd_run query phase.complete "${PHASE_NUMBER}") ``` The CLI handles: @@ -1526,7 +1515,7 @@ These items are tracked and will appear in `/gsd:progress` and `/gsd:audit-uat`. ``` ```bash -$GSD_SDK query commit "docs(phase-{X}): complete phase execution" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md {phase_dir}/*-VERIFICATION.md +gsd_run query commit "docs(phase-{X}): complete phase execution" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md {phase_dir}/*-VERIFICATION.md ``` @@ -1538,7 +1527,7 @@ entries from the completed phase to the global learnings store at `~/.gsd/knowle **Check config gate:** ```bash -GL_ENABLED=$($GSD_SDK query config-get features.global_learnings --raw 2>/dev/null || echo "false") +GL_ENABLED=$(gsd_run query config-get features.global_learnings --raw 2>/dev/null || echo "false") ``` **If `GL_ENABLED` is not `true`:** Skip this step entirely (feature disabled by default). @@ -1548,7 +1537,7 @@ GL_ENABLED=$($GSD_SDK query config-get features.global_learnings --raw 2>/dev/nu 1. Check if LEARNINGS.md exists in the phase directory (use the `phase_dir` value from init context) 2. If found, copy to global store: ```bash -$GSD_SDK query learnings.copy 2>/dev/null || echo "⚠ Learnings copy failed — continuing" +gsd_run query learnings.copy 2>/dev/null || echo "⚠ Learnings copy failed — continuing" ``` Copy failure must NOT block phase completion. @@ -1576,7 +1565,7 @@ for TODO_FILE in "$PENDING_DIR"/*.md; do done if [ ${#CLOSED[@]} -gt 0 ]; then - $GSD_SDK query commit "docs(phase-${PHASE_NUMBER}): auto-close ${#CLOSED[@]} todo(s) resolved by this phase" --files .planning/todos/completed/ .planning/STATE.md|| true + gsd_run query commit "docs(phase-${PHASE_NUMBER}): auto-close ${#CLOSED[@]} todo(s) resolved by this phase" --files .planning/todos/completed/ .planning/STATE.md|| true echo "◆ Closed ${#CLOSED[@]} todo(s) resolved by Phase ${PHASE_NUMBER}:" for f in "${CLOSED[@]}"; do echo " ✓ $f"; done fi @@ -1601,7 +1590,7 @@ PROJECT.md falls behind silently over multiple phases. 5. Commit the change: ```bash -$GSD_SDK query commit "docs(phase-{X}): evolve PROJECT.md after phase completion" --files .planning/PROJECT.md +gsd_run query commit "docs(phase-{X}): evolve PROJECT.md after phase completion" --files .planning/PROJECT.md ``` **Skip this step if** `.planning/PROJECT.md` does not exist. @@ -1639,7 +1628,7 @@ STOP. Do not proceed to auto-advance or transition. 1. Parse `--auto` flag from $ARGUMENTS 2. Read consolidated auto-mode (`active` = chain flag OR user preference; chain flag already synced in init step): ```bash - AUTO_MODE=$($GSD_SDK query check auto-mode --pick active 2>/dev/null || echo "false") + AUTO_MODE=$(gsd_run query check auto-mode --pick active 2>/dev/null || echo "false") ``` **If `--auto` flag present OR `AUTO_MODE` is true (AND verification passed with no gaps):** diff --git a/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md b/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md index a3568e36a..be559f34c 100644 --- a/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md +++ b/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md @@ -45,7 +45,8 @@ First load the mapper agent's skill bundle (the executor's `AGENT_SKILLS` from step `init_context` is for `gsd-executor`, not the mapper): ```bash -AGENT_SKILLS_MAPPER=$($GSD_SDK query agent-skills gsd-codebase-mapper) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +AGENT_SKILLS_MAPPER=$(gsd_run query agent-skills gsd-codebase-mapper) ``` Then spawn `gsd-codebase-mapper` agents with the `--paths` hint: diff --git a/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md b/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md index 668e7c60c..9362d6679 100644 --- a/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md +++ b/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md @@ -8,8 +8,9 @@ detect. **Step A — Build gate:** ```bash +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi # Resolve build command: project config > Xcode > Makefile > language sniff -BUILD_CMD=$($GSD_SDK query config-get workflow.build_command --default "" 2>/dev/null || true) +BUILD_CMD=$(gsd_run query config-get workflow.build_command --default "" 2>/dev/null || true) if [ -z "$BUILD_CMD" ]; then XCODEPROJ=$(find . -maxdepth 2 -name "*.xcodeproj" -not -path "*/node_modules/*" 2>/dev/null | head -1) if [ -n "$XCODEPROJ" ]; then @@ -63,7 +64,7 @@ fi ```bash # Resolve test command: project config > Xcode > Makefile > language sniff -TEST_CMD=$($GSD_SDK query config-get workflow.test_command --default "" 2>/dev/null || true) +TEST_CMD=$(gsd_run query config-get workflow.test_command --default "" 2>/dev/null || true) if [ -z "$TEST_CMD" ]; then XCODEPROJ=$(find . -maxdepth 2 -name "*.xcodeproj" -not -path "*/node_modules/*" 2>/dev/null | head -1) if [ -n "$XCODEPROJ" ]; then diff --git a/get-shit-done/workflows/execute-plan.md b/get-shit-done/workflows/execute-plan.md index bea9405fc..08eac0930 100644 --- a/get-shit-done/workflows/execute-plan.md +++ b/get-shit-done/workflows/execute-plan.md @@ -30,19 +30,8 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo Load execution context (paths only to minimize orchestrator context): ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.execute-phase "${PHASE}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.execute-phase "${PHASE}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -85,7 +74,7 @@ PLAN_START_EPOCH=$(date +%s) ```bash # Count tasks — match ]' .planning/phases/XX-name/{phase}-{plan}-PLAN.md 2>/dev/null || echo "0") -INLINE_THRESHOLD=$($GSD_SDK query config-get workflow.inline_plan_threshold 2>/dev/null || echo "2") +INLINE_THRESHOLD=$(gsd_run query config-get workflow.inline_plan_threshold 2>/dev/null || echo "2") grep -n "type=\"checkpoint" .planning/phases/XX-name/{phase}-{plan}-PLAN.md ``` @@ -169,7 +158,7 @@ This IS the execution instructions. Follow exactly. If plan references CONTEXT.m ```bash -$GSD_SDK query phases.list --type summaries --raw +gsd_run query phases.list --type summaries --raw # Extract the second-to-last summary from the JSON result ``` @@ -323,7 +312,7 @@ If verification fails: **Check if node repair is enabled** (default: on): ```bash -NODE_REPAIR=$($GSD_SDK query config-get workflow.node_repair 2>/dev/null || echo "true") +NODE_REPAIR=$(gsd_run query config-get workflow.node_repair 2>/dev/null || echo "true") ``` If `NODE_REPAIR` is `true`: invoke `@./.claude/get-shit-done/workflows/node-repair.md` with: @@ -396,13 +385,13 @@ IS_WORKTREE=$([ -f .git ] && echo "true" || echo "false") # Skip in parallel mode — orchestrator handles STATE.md centrally if [ "$IS_WORKTREE" != "true" ]; then # Advance plan counter (handles last-plan edge case) - $GSD_SDK query state.advance-plan + gsd_run query state.advance-plan # Recalculate progress bar from disk state - $GSD_SDK query state.update-progress + gsd_run query state.update-progress # Record execution metrics - $GSD_SDK query state.record-metric \ + gsd_run query state.record-metric \ --phase "${PHASE}" --plan "${PLAN}" --duration "${DURATION}" \ --tasks "${TASK_COUNT}" --files "${FILE_COUNT}" fi @@ -415,11 +404,11 @@ From SUMMARY: Extract decisions and add to STATE.md: ```bash # Add each decision from SUMMARY key-decisions # Prefer file inputs for shell-safe text (preserves `$`, `*`, etc. exactly) -$GSD_SDK query state.add-decision \ +gsd_run query state.add-decision \ --phase "${PHASE}" --summary-file "${DECISION_TEXT_FILE}" --rationale-file "${RATIONALE_FILE}" # Add blockers if any found -$GSD_SDK query state.add-blocker --text-file "${BLOCKER_TEXT_FILE}" +gsd_run query state.add-blocker --text-file "${BLOCKER_TEXT_FILE}" ``` @@ -427,7 +416,7 @@ $GSD_SDK query state.add-blocker --text-file "${BLOCKER_TEXT_FILE}" Update session info using gsd-tools.cjs query (or legacy gsd-tools): ```bash -$GSD_SDK query state.record-session \ +gsd_run query state.record-session \ --stopped-at "Completed ${PHASE}-${PLAN}-PLAN.md" \ --resume-file "None" ``` @@ -453,7 +442,7 @@ IS_WORKTREE=$([ -f .git ] && echo "true" || echo "false") if [ "$IS_WORKTREE" != "true" ]; then # use_worktrees: false → this handler is the sole post-plan sync point (#2661) - $GSD_SDK query roadmap.update-plan-progress "${PHASE}" + gsd_run query roadmap.update-plan-progress "${PHASE}" fi ``` Counts PLAN vs SUMMARY files on disk. Updates progress table row with correct count and status (`In Progress` or `Complete` with date). @@ -463,7 +452,7 @@ Counts PLAN vs SUMMARY files on disk. Updates progress table row with correct co Mark completed requirements from the PLAN.md frontmatter `requirements:` field: ```bash -$GSD_SDK query requirements.mark-complete ${REQ_IDS} +gsd_run query requirements.mark-complete ${REQ_IDS} ``` Extract requirement IDs from the plan's frontmatter (e.g., `requirements: [AUTH-01, AUTH-02]`). If no requirements field, skip. @@ -483,9 +472,9 @@ IS_WORKTREE=$([ -f .git ] && echo "true" || echo "false") # In parallel mode: exclude STATE.md and ROADMAP.md (orchestrator commits these) if [ "$IS_WORKTREE" = "true" ]; then - $GSD_SDK query commit "docs({phase}-{plan}): complete [plan-name] plan" --files .planning/phases/XX-name/{phase}-{plan}-SUMMARY.md .planning/REQUIREMENTS.md + gsd_run query commit "docs({phase}-{plan}): complete [plan-name] plan" --files .planning/phases/XX-name/{phase}-{plan}-SUMMARY.md .planning/REQUIREMENTS.md else - $GSD_SDK query commit "docs({phase}-{plan}): complete [plan-name] plan" --files .planning/phases/XX-name/{phase}-{plan}-SUMMARY.md .planning/STATE.md .planning/ROADMAP.md .planning/REQUIREMENTS.md + gsd_run query commit "docs({phase}-{plan}): complete [plan-name] plan" --files .planning/phases/XX-name/{phase}-{plan}-SUMMARY.md .planning/STATE.md .planning/ROADMAP.md .planning/REQUIREMENTS.md fi ``` @@ -501,7 +490,7 @@ git diff --name-only ${FIRST_TASK}^..HEAD 2>/dev/null || true Update only structural changes: new src/ dir → STRUCTURE.md | deps → STACK.md | file pattern → CONVENTIONS.md | API client → INTEGRATIONS.md | config → STACK.md | renamed → update paths. Skip code-only/bugfix/content changes. ```bash -$GSD_SDK query commit "" --files .planning/codebase/*.md --amend +gsd_run query commit "" --files .planning/codebase/*.md --amend ``` diff --git a/get-shit-done/workflows/explore.md b/get-shit-done/workflows/explore.md index 81eabf4ba..f7e8a1adb 100644 --- a/get-shit-done/workflows/explore.md +++ b/get-shit-done/workflows/explore.md @@ -115,19 +115,8 @@ For each selected output, write the file: Commit if `commit_docs` is enabled: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query commit "docs: capture exploration — {topic_slug}" --files {file_list} +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query commit "docs: capture exploration — {topic_slug}" --files {file_list} ``` ## Step 6: Close diff --git a/get-shit-done/workflows/extract-learnings.md b/get-shit-done/workflows/extract-learnings.md index c69ddcc9f..0f59a3bbe 100644 --- a/get-shit-done/workflows/extract-learnings.md +++ b/get-shit-done/workflows/extract-learnings.md @@ -16,19 +16,8 @@ Analyze completed phase artifacts (PLAN.md, SUMMARY.md, VERIFICATION.md, UAT.md, Parse arguments and load project state: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -201,7 +190,7 @@ The body follows this structure: Update STATE.md to reflect the learning extraction: ```bash -$GSD_SDK query state.update "Last Activity" "$(date +%Y-%m-%d)" +gsd_run query state.update "Last Activity" "$(date +%Y-%m-%d)" ``` diff --git a/get-shit-done/workflows/forensics.md b/get-shit-done/workflows/forensics.md index a9a154ed1..2192ceece 100644 --- a/get-shit-done/workflows/forensics.md +++ b/get-shit-done/workflows/forensics.md @@ -272,19 +272,8 @@ gh issue create \ ## Step 8: Update STATE.md ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query state.record-session "" \ +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query state.record-session "" \ "Forensic investigation complete" \ ".planning/forensics/report-{timestamp}.md" ``` diff --git a/get-shit-done/workflows/graduation.md b/get-shit-done/workflows/graduation.md index dab59c6c6..dec046d04 100644 --- a/get-shit-done/workflows/graduation.md +++ b/get-shit-done/workflows/graduation.md @@ -21,21 +21,10 @@ Read from project config (`config.json`): ## Step 1: Guard Checks ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -GRADUATION_ENABLED=$($GSD_SDK query config-get features.graduation 2>/dev/null || echo "true") -GRADUATION_WINDOW=$($GSD_SDK query config-get features.graduation_window 2>/dev/null || echo "5") -GRADUATION_THRESHOLD=$($GSD_SDK query config-get features.graduation_threshold 2>/dev/null || echo "3") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +GRADUATION_ENABLED=$(gsd_run query config-get features.graduation 2>/dev/null || echo "true") +GRADUATION_WINDOW=$(gsd_run query config-get features.graduation_window 2>/dev/null || echo "5") +GRADUATION_THRESHOLD=$(gsd_run query config-get features.graduation_threshold 2>/dev/null || echo "3") ``` **Skip silently (print nothing) if:** diff --git a/get-shit-done/workflows/health.md b/get-shit-done/workflows/health.md index 258489c4e..9e188efb6 100644 --- a/get-shit-done/workflows/health.md +++ b/get-shit-done/workflows/health.md @@ -49,19 +49,8 @@ available — replace the prompt with a plain-text two-question sequence plain text from the user's response. ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query validate.context \ +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query validate.context \ --tokens-used "$TOKENS_USED" \ --context-window "$CONTEXT_WINDOW" ``` @@ -76,7 +65,7 @@ health output, the two modes are independent diagnostics. **Run health validation:** ```bash -$GSD_SDK query validate.health $REPAIR_FLAG $BACKFILL_FLAG +gsd_run query validate.health $REPAIR_FLAG $BACKFILL_FLAG ``` Parse JSON output: @@ -163,7 +152,7 @@ If yes, re-run with --repair flag and display results. Re-run health check without --repair to confirm issues are resolved: ```bash -$GSD_SDK query validate.health +gsd_run query validate.health ``` Report final status. diff --git a/get-shit-done/workflows/import.md b/get-shit-done/workflows/import.md index 5a3bac439..6170dc785 100644 --- a/get-shit-done/workflows/import.md +++ b/get-shit-done/workflows/import.md @@ -176,19 +176,8 @@ Apply GSD naming convention for the output filename: Determine the target directory by querying `init.phase-op` for the phase number extracted in `plan_read_input`. This ensures the `project_code` prefix from `.planning/config.json` is applied: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "{NN}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "{NN}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi expected_phase_dir=$(echo "$INIT" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).expected_phase_dir)") ``` @@ -237,7 +226,7 @@ Update `.planning/STATE.md` if appropriate (e.g., increment total plan count). Commit the imported plan and updated files: ```bash -$GSD_SDK query commit "docs({phase}): import plan from {basename FILEPATH}" --files .planning/phases/{phase}/{plan}-PLAN.md .planning/ROADMAP.md +gsd_run query commit "docs({phase}): import plan from {basename FILEPATH}" --files .planning/phases/{phase}/{plan}-PLAN.md .planning/ROADMAP.md ``` Display completion: diff --git a/get-shit-done/workflows/insert-phase.md b/get-shit-done/workflows/insert-phase.md index b68602c74..486262c5b 100644 --- a/get-shit-done/workflows/insert-phase.md +++ b/get-shit-done/workflows/insert-phase.md @@ -34,19 +34,8 @@ Validate first argument is an integer. Load phase operation context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${after_phase}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${after_phase}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -61,7 +50,7 @@ Exit. **Delegate the phase insertion to `gsd-tools.cjs query phase.insert`:** ```bash -RESULT=$($GSD_SDK query phase.insert "${after_phase}" "${description}") +RESULT=$(gsd_run query phase.insert "${after_phase}" "${description}") ``` The CLI handles: @@ -83,7 +72,7 @@ blocks direct STATE.md writes): `{decimal_phase}`: ```bash - $GSD_SDK query state.patch '{"Current Phase":"{decimal_phase}","Next recommended run":"/gsd:plan-phase {decimal_phase}"}' + gsd_run query state.patch '{"Current Phase":"{decimal_phase}","Next recommended run":"/gsd:plan-phase {decimal_phase}"}' ``` (Adjust field names to whatever pointers STATE.md exposes — the handler @@ -94,7 +83,7 @@ blocks direct STATE.md writes): and dedupes identical entries: ```bash - $GSD_SDK query state.add-roadmap-evolution \ + gsd_run query state.add-roadmap-evolution \ --phase {decimal_phase} \ --action inserted \ --after {after_phase} \ diff --git a/get-shit-done/workflows/list-workspaces.md b/get-shit-done/workflows/list-workspaces.md index 152399f65..6b6f475cf 100644 --- a/get-shit-done/workflows/list-workspaces.md +++ b/get-shit-done/workflows/list-workspaces.md @@ -11,19 +11,8 @@ Read all files referenced by the invoking prompt's execution_context before star ## 1. Setup ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.list-workspaces) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.list-workspaces) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` diff --git a/get-shit-done/workflows/manager.md b/get-shit-done/workflows/manager.md index 885a56176..3f5941515 100644 --- a/get-shit-done/workflows/manager.md +++ b/get-shit-done/workflows/manager.md @@ -19,19 +19,8 @@ Read all files referenced by the invoking prompt's execution_context before star Bootstrap via manager init: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.manager) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.manager) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -72,7 +61,7 @@ Proceed to dashboard step. **Every time this step is reached**, re-read state from disk to pick up changes from background agents: ```bash -INIT=$($GSD_SDK query init.manager) +INIT=$(gsd_run query init.manager) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` diff --git a/get-shit-done/workflows/map-codebase.md b/get-shit-done/workflows/map-codebase.md index b6b3c5e9a..06f183cf4 100644 --- a/get-shit-done/workflows/map-codebase.md +++ b/get-shit-done/workflows/map-codebase.md @@ -69,21 +69,10 @@ documents refreshed. Load codebase mapping context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.map-codebase) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.map-codebase) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_MAPPER=$($GSD_SDK query agent-skills gsd-codebase-mapper) +AGENT_SKILLS_MAPPER=$(gsd_run query agent-skills gsd-codebase-mapper) ``` Extract from init JSON: `mapper_model`, `commit_docs`, `codebase_dir`, `existing_maps`, `has_maps`, `codebase_dir_exists`, `subagent_timeout`, `date`. @@ -390,7 +379,7 @@ Continue to commit_codebase_map. Commit the codebase map: ```bash -$GSD_SDK query commit "docs: map existing codebase" --files .planning/codebase/*.md +gsd_run query commit "docs: map existing codebase" --files .planning/codebase/*.md ``` Continue to offer_next. diff --git a/get-shit-done/workflows/milestone-summary.md b/get-shit-done/workflows/milestone-summary.md index b4ae69f3b..b4b224f2b 100644 --- a/get-shit-done/workflows/milestone-summary.md +++ b/get-shit-done/workflows/milestone-summary.md @@ -53,19 +53,8 @@ Read all files that exist. Missing files are fine — the summary adapts to what Find all phase directories: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query init.progress +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query init.progress ``` This returns phase metadata. For each phase in the milestone scope: @@ -201,7 +190,7 @@ mkdir -p .planning/reports Write the summary, then commit: ```bash -$GSD_SDK query commit "docs(v${VERSION}): generate milestone summary for onboarding" --files \ +gsd_run query commit "docs(v${VERSION}): generate milestone summary for onboarding" --files \ ".planning/reports/MILESTONE_SUMMARY-v${VERSION}.md" ``` @@ -229,7 +218,7 @@ If the user is done: ## Step 9: Update STATE.md ```bash -$GSD_SDK query state.record-session "" \ +gsd_run query state.record-session "" \ "Milestone v${VERSION} summary generated" \ ".planning/reports/MILESTONE_SUMMARY-v${VERSION}.md" ``` diff --git a/get-shit-done/workflows/mvp-phase.md b/get-shit-done/workflows/mvp-phase.md index 856528a37..4d04b5ba4 100644 --- a/get-shit-done/workflows/mvp-phase.md +++ b/get-shit-done/workflows/mvp-phase.md @@ -34,26 +34,15 @@ Normalize per `@~/.claude/get-shit-done/references/phase-argument-parsing.md` (z ## 2. Validate phase exists and check status ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -PHASE_INFO=$($GSD_SDK query roadmap.get-phase "${PHASE}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +PHASE_INFO=$(gsd_run query roadmap.get-phase "${PHASE}") PHASE_FOUND=$(echo "$PHASE_INFO" | jq -r '.found') PHASE_NAME=$(echo "$PHASE_INFO" | jq -r '.phase_name') PHASE_GOAL=$(echo "$PHASE_INFO" | jq -r '.goal') PHASE_MODE=$(echo "$PHASE_INFO" | jq -r '.mode // ""') PHASE_COMPLETE=$(echo "$PHASE_INFO" | jq -r '.roadmap_complete // false') -ANALYZE=$($GSD_SDK query roadmap.analyze) +ANALYZE=$(gsd_run query roadmap.analyze) if [[ "$ANALYZE" == @file:* ]]; then ANALYZE=$(cat "${ANALYZE#@file:}"); fi DISK_STATUS=$(echo "$ANALYZE" | jq -r --arg p "$PHASE" '.phases[] | select((.phase_number|tostring)==$p) | .disk_status' | head -1) if [[ "$DISK_STATUS" == "complete" || "$PHASE_COMPLETE" == "true" ]]; then @@ -110,7 +99,7 @@ If any of the three answers is empty or whitespace-only, error and re-prompt tha **Validate via the centralized User Story validator.** The verb owns the canonical regex `/^As a .+, I want to .+, so that .+\.$/` and surfaces per-error guidance: ```bash -USER_STORY_RESULT=$($GSD_SDK query user-story.validate --story "$USER_STORY") +USER_STORY_RESULT=$(gsd_run query user-story.validate --story "$USER_STORY") if [ "$(echo "$USER_STORY_RESULT" | jq -r '.valid')" != "true" ]; then echo "$USER_STORY_RESULT" | jq -r '.errors[]' >&2 # Re-prompt the offending field(s) per surfaced errors, then re-run validation. @@ -195,8 +184,8 @@ On Apply, write the updated `ROADMAP.md` atomically (read-edit-write). ## 6. Verify the write ```bash -NEW_MODE=$($GSD_SDK query roadmap.get-phase "${PHASE}" --pick mode) -NEW_GOAL=$($GSD_SDK query roadmap.get-phase "${PHASE}" --pick goal) +NEW_MODE=$(gsd_run query roadmap.get-phase "${PHASE}" --pick mode) +NEW_GOAL=$(gsd_run query roadmap.get-phase "${PHASE}" --pick goal) ``` Assert: diff --git a/get-shit-done/workflows/new-milestone.md b/get-shit-done/workflows/new-milestone.md index 111981d00..6b66cbc44 100644 --- a/get-shit-done/workflows/new-milestone.md +++ b/get-shit-done/workflows/new-milestone.md @@ -181,19 +181,8 @@ blockers, todos) is preserved across the switch — symmetric with `milestone.complete`. ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query state.milestone-switch --milestone "v[X.Y]" --name "[Name]" +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query state.milestone-switch --milestone "v[X.Y]" --name "[Name]" ``` The resulting Current Position section looks like: @@ -220,21 +209,21 @@ Delete MILESTONE-CONTEXT.md if exists (consumed). Clear leftover phase directories from the previous milestone: ```bash -$GSD_SDK query phases.clear --confirm +gsd_run query phases.clear --confirm ``` ```bash -$GSD_SDK query commit "docs: start milestone v[X.Y] [Name]" --files .planning/PROJECT.md .planning/STATE.md +gsd_run query commit "docs: start milestone v[X.Y] [Name]" --files .planning/PROJECT.md .planning/STATE.md ``` ## 7. Load Context and Resolve Models ```bash -INIT=$($GSD_SDK query init.new-milestone) +INIT=$(gsd_run query init.new-milestone) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_RESEARCHER=$($GSD_SDK query agent-skills gsd-project-researcher) -AGENT_SKILLS_SYNTHESIZER=$($GSD_SDK query agent-skills gsd-research-synthesizer) -AGENT_SKILLS_ROADMAPPER=$($GSD_SDK query agent-skills gsd-roadmapper) +AGENT_SKILLS_RESEARCHER=$(gsd_run query agent-skills gsd-project-researcher) +AGENT_SKILLS_SYNTHESIZER=$(gsd_run query agent-skills gsd-research-synthesizer) +AGENT_SKILLS_ROADMAPPER=$(gsd_run query agent-skills gsd-roadmapper) ``` Extract from init JSON: `researcher_model`, `synthesizer_model`, `roadmapper_model`, `commit_docs`, `research_enabled`, `current_milestone`, `project_exists`, `roadmap_exists`, `latest_completed_milestone`, `phase_dir_count`, `phase_archive_path`, `agents_installed`, `missing_agents`. @@ -456,7 +445,7 @@ If "adjust": Return to scoping. **Commit requirements:** ```bash -$GSD_SDK query commit "docs: define milestone v[X.Y] requirements" --files .planning/REQUIREMENTS.md +gsd_run query commit "docs: define milestone v[X.Y] requirements" --files .planning/REQUIREMENTS.md ``` ## 10. Create Roadmap @@ -542,7 +531,7 @@ Success criteria: **Commit roadmap** (after approval): ```bash -$GSD_SDK query commit "docs: create milestone v[X.Y] roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md +gsd_run query commit "docs: create milestone v[X.Y] roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md ``` ## 10.5. Link Pending Todos to Roadmap Phases @@ -585,7 +574,7 @@ files: [existing] **If any todos were linked:** ```bash -$GSD_SDK query commit "docs: tag [count] pending todos with resolves_phase after milestone v[X.Y] roadmap" --files .planning/todos/pending/*.md +gsd_run query commit "docs: tag [count] pending todos with resolves_phase after milestone v[X.Y] roadmap" --files .planning/todos/pending/*.md ``` Print a summary: diff --git a/get-shit-done/workflows/new-project.md b/get-shit-done/workflows/new-project.md index af2ad3e71..a92fd6719 100644 --- a/get-shit-done/workflows/new-project.md +++ b/get-shit-done/workflows/new-project.md @@ -57,23 +57,12 @@ The document should describe what you want to build. **MANDATORY FIRST STEP — Execute these checks before ANY user interaction:** ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.new-project) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.new-project) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_RESEARCHER=$($GSD_SDK query agent-skills gsd-project-researcher) -AGENT_SKILLS_SYNTHESIZER=$($GSD_SDK query agent-skills gsd-research-synthesizer) -AGENT_SKILLS_ROADMAPPER=$($GSD_SDK query agent-skills gsd-roadmapper) +AGENT_SKILLS_RESEARCHER=$(gsd_run query agent-skills gsd-project-researcher) +AGENT_SKILLS_SYNTHESIZER=$(gsd_run query agent-skills gsd-research-synthesizer) +AGENT_SKILLS_ROADMAPPER=$(gsd_run query agent-skills gsd-roadmapper) ``` Parse JSON for: `researcher_model`, `synthesizer_model`, `roadmapper_model`, `commit_docs`, `project_exists`, `has_codebase_map`, `planning_exists`, `has_existing_code`, `has_package_file`, `is_brownfield`, `needs_codebase_map`, `has_git`, `git_worktree_root`, `in_nested_subdir`, `project_path`, `agents_installed`, `missing_agents`, `agent_runtime`, `agents_dir`, `required_agents`, `required_agents_installed`, `missing_required_agents`, `agent_skill_payloads_available`, `agent_skill_payload_agents`. @@ -275,7 +264,7 @@ Create `.planning/config.json` with all settings (CLI fills in remaining default ```bash mkdir -p .planning -$GSD_SDK query config-new-project '{"mode":"yolo","granularity":"[selected]","parallelization":true|false,"commit_docs":true|false,"model_profile":"quality|balanced|budget|inherit","workflow":{"research":true|false,"plan_check":true|false,"verifier":true|false,"nyquist_validation":true|false,"auto_advance":true},"ship":{"pr_body_sections":[{"heading":"User Stories & Acceptance Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria","fallback":"- Acceptance criteria are covered by the linked requirements and verification evidence."},{"heading":"Risks & Dependencies","enabled":true|false,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."},{"heading":"Success Metrics & Release Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria","fallback":"- Release when automated verification and required manual checks pass."},{"heading":"Stakeholder Review & Approval","enabled":true|false,"template":"- Product owner approval pending for {phase_name}."}]}}' +gsd_run query config-new-project '{"mode":"yolo","granularity":"[selected]","parallelization":true|false,"commit_docs":true|false,"model_profile":"quality|balanced|budget|inherit","workflow":{"research":true|false,"plan_check":true|false,"verifier":true|false,"nyquist_validation":true|false,"auto_advance":true},"ship":{"pr_body_sections":[{"heading":"User Stories & Acceptance Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria","fallback":"- Acceptance criteria are covered by the linked requirements and verification evidence."},{"heading":"Risks & Dependencies","enabled":true|false,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."},{"heading":"Success Metrics & Release Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria","fallback":"- Release when automated verification and required manual checks pass."},{"heading":"Stakeholder Review & Approval","enabled":true|false,"template":"- Product owner approval pending for {phase_name}."}]}}' ``` **If commit_docs = No:** Add `.planning/` to `.gitignore`. @@ -284,13 +273,13 @@ $GSD_SDK query config-new-project '{"mode":"yolo","granularity":"[selected]","pa ```bash mkdir -p .planning -$GSD_SDK query commit "chore: add project config" --files .planning/config.json +gsd_run query commit "chore: add project config" --files .planning/config.json ``` **Persist auto-advance chain flag to config (survives context compaction):** ```bash -$GSD_SDK query config-set workflow._auto_chain_active true +gsd_run query config-set workflow._auto_chain_active true ``` Proceed to Step 4 (skip Steps 3 and 5). @@ -495,7 +484,7 @@ Do not compress. Capture everything gathered. ```bash mkdir -p .planning -$GSD_SDK query commit "docs: initialize project" --files .planning/PROJECT.md +gsd_run query commit "docs: initialize project" --files .planning/PROJECT.md ``` ## 5. Workflow Preferences @@ -756,7 +745,7 @@ Create `.planning/config.json` with all settings (CLI fills in remaining default ```bash mkdir -p .planning -$GSD_SDK query config-new-project '{"mode":"[yolo|interactive]","granularity":"[selected]","parallelization":true|false,"commit_docs":true|false,"model_profile":"quality|balanced|budget|inherit","workflow":{"research":true|false,"plan_check":true|false,"verifier":true|false,"nyquist_validation":[false if granularity=coarse, true otherwise]},"ship":{"pr_body_sections":[{"heading":"User Stories & Acceptance Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria","fallback":"- Acceptance criteria are covered by the linked requirements and verification evidence."},{"heading":"Risks & Dependencies","enabled":true|false,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."},{"heading":"Success Metrics & Release Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria","fallback":"- Release when automated verification and required manual checks pass."},{"heading":"Stakeholder Review & Approval","enabled":true|false,"template":"- Product owner approval pending for {phase_name}."}]}}' +gsd_run query config-new-project '{"mode":"[yolo|interactive]","granularity":"[selected]","parallelization":true|false,"commit_docs":true|false,"model_profile":"quality|balanced|budget|inherit","workflow":{"research":true|false,"plan_check":true|false,"verifier":true|false,"nyquist_validation":[false if granularity=coarse, true otherwise]},"ship":{"pr_body_sections":[{"heading":"User Stories & Acceptance Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## User Stories || REQUIREMENTS.md ## Acceptance Criteria","fallback":"- Acceptance criteria are covered by the linked requirements and verification evidence."},{"heading":"Risks & Dependencies","enabled":true|false,"source":"PLAN.md ## Risks || PLAN.md ## Dependencies","fallback":"- No known high-risk rollout dependencies."},{"heading":"Success Metrics & Release Criteria","enabled":true|false,"source":"REQUIREMENTS.md ## Definition of Done || VERIFICATION.md ## Release Criteria","fallback":"- Release when automated verification and required manual checks pass."},{"heading":"Stakeholder Review & Approval","enabled":true|false,"template":"- Product owner approval pending for {phase_name}."}]}}' ``` **Note:** Run `/gsd:settings` anytime to update model profile, workflow agents, branching strategy, and other preferences. @@ -773,7 +762,7 @@ $GSD_SDK query config-new-project '{"mode":"[yolo|interactive]","granularity":"[ **Commit config.json:** ```bash -$GSD_SDK query commit "chore: add project config" --files .planning/config.json +gsd_run query commit "chore: add project config" --files .planning/config.json ``` ## 5.1. Sub-Repo Detection @@ -1221,7 +1210,7 @@ If "adjust": Return to scoping. **Commit requirements:** ```bash -$GSD_SDK query commit "docs: define v1 requirements" --files .planning/REQUIREMENTS.md +gsd_run query commit "docs: define v1 requirements" --files .planning/REQUIREMENTS.md ``` ## 7.5. Project Structure Mode @@ -1397,7 +1386,7 @@ Use AskUserQuestion: **Generate or refresh project instruction file before final commit:** ```bash -$GSD_SDK query generate-claude-md --output "$INSTRUCTION_FILE" +gsd_run query generate-claude-md --output "$INSTRUCTION_FILE" ``` This ensures new projects get the default GSD workflow-enforcement guidance and current project context in `$INSTRUCTION_FILE`. @@ -1405,7 +1394,7 @@ This ensures new projects get the default GSD workflow-enforcement guidance and **Commit roadmap (after approval or auto mode):** ```bash -$GSD_SDK query commit "docs: create roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md "$INSTRUCTION_FILE" +gsd_run query commit "docs: create roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md "$INSTRUCTION_FILE" ``` ## 9. Done @@ -1446,7 +1435,7 @@ Exit skill and invoke SlashCommand("/gsd:discuss-phase 1 --auto") Check if Phase 1 has UI indicators (look for `**UI hint**: yes` in Phase 1 detail section of ROADMAP.md): ```bash -PHASE1_SECTION=$($GSD_SDK query roadmap.get-phase 1 2>/dev/null) +PHASE1_SECTION=$(gsd_run query roadmap.get-phase 1 2>/dev/null) PHASE1_HAS_UI=$(echo "$PHASE1_SECTION" | grep -qi "UI hint.*yes" && echo "true" || echo "false") ``` diff --git a/get-shit-done/workflows/new-workspace.md b/get-shit-done/workflows/new-workspace.md index cfe8ef960..521ab8fb7 100644 --- a/get-shit-done/workflows/new-workspace.md +++ b/get-shit-done/workflows/new-workspace.md @@ -13,19 +13,8 @@ Read all files referenced by the invoking prompt's execution_context before star **MANDATORY FIRST STEP — Execute init command:** ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.new-workspace) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.new-workspace) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` diff --git a/get-shit-done/workflows/next.md b/get-shit-done/workflows/next.md index 54224794a..c002129f2 100644 --- a/get-shit-done/workflows/next.md +++ b/get-shit-done/workflows/next.md @@ -13,20 +13,9 @@ Read all files referenced by the invoking prompt's execution_context before star Read project state to determine current position: ```bash +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi # Get state snapshot -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query state.json 2>/dev/null || echo "{}" +gsd_run query state.json 2>/dev/null || echo "{}" ``` Also read: @@ -139,7 +128,7 @@ Choice [S]: ``` 2. Commit the deferral record: ```bash -$GSD_SDK query commit "docs: defer incomplete Phase {src} items to backlog" +gsd_run query commit "docs: defer incomplete Phase {src} items to backlog" ``` 3. Continue routing to `determine_next_action` immediately — no second prompt. diff --git a/get-shit-done/workflows/pause-work.md b/get-shit-done/workflows/pause-work.md index 13bb0dd3c..6b3bfa81c 100644 --- a/get-shit-done/workflows/pause-work.md +++ b/get-shit-done/workflows/pause-work.md @@ -66,19 +66,8 @@ Report any summaries with placeholder content as incomplete items. **Write structured handoff to `.planning/HANDOFF.json`:** ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -timestamp=$($GSD_SDK query current-timestamp full --raw) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +timestamp=$(gsd_run query current-timestamp full --raw) ``` ```json @@ -213,13 +202,13 @@ Be specific enough for a fresh Claude to understand immediately. Use `current-timestamp` for last_updated field. You can use init todos (which provides timestamps) or call directly: ```bash -timestamp=$($GSD_SDK query current-timestamp full --raw) +timestamp=$(gsd_run query current-timestamp full --raw) ``` ```bash -$GSD_SDK query commit "wip: [context-name] paused at [X]/[Y]" --files [handoff-path] .planning/HANDOFF.json +gsd_run query commit "wip: [context-name] paused at [X]/[Y]" --files [handoff-path] .planning/HANDOFF.json ``` diff --git a/get-shit-done/workflows/plan-milestone-gaps.md b/get-shit-done/workflows/plan-milestone-gaps.md index 40cb7e318..488541d30 100644 --- a/get-shit-done/workflows/plan-milestone-gaps.md +++ b/get-shit-done/workflows/plan-milestone-gaps.md @@ -64,20 +64,9 @@ Gap: Flow "View dashboard" broken at data fetch Find highest existing phase: ```bash +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi # Get sorted phase list, extract last one -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -HIGHEST=$($GSD_SDK query phases.list --pick directories[-1]) +HIGHEST=$(gsd_run query phases.list --pick directories[-1]) ``` New phases continue from there: @@ -154,7 +143,7 @@ grep -c "Pending" .planning/REQUIREMENTS.md For each new phase (N, N+1, …), resolve the directory name via `init.phase-op` so the `project_code` prefix is honoured: ```bash -INIT=$($GSD_SDK query init.phase-op "{NN}") +INIT=$(gsd_run query init.phase-op "{NN}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi expected_phase_dir=$(echo "$INIT" | node -e "process.stdout.write(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).expected_phase_dir)") mkdir -p "${expected_phase_dir}" @@ -165,7 +154,7 @@ Repeat for each gap-closure phase number. This produces `{CODE}-{NN}-{slug}/` wh ## 9. Commit Roadmap and Requirements Update ```bash -$GSD_SDK query commit "docs(roadmap): add gap closure phases {N}-{M}" --files .planning/ROADMAP.md .planning/REQUIREMENTS.md +gsd_run query commit "docs(roadmap): add gap closure phases {N}-{M}" --files .planning/ROADMAP.md .planning/REQUIREMENTS.md ``` ## 10. Offer Next Steps diff --git a/get-shit-done/workflows/plan-phase.md b/get-shit-done/workflows/plan-phase.md index 8b01b65a5..7e3ef322c 100644 --- a/get-shit-done/workflows/plan-phase.md +++ b/get-shit-done/workflows/plan-phase.md @@ -31,26 +31,15 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo Load all context in one call (paths only to minimize orchestrator context): ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.plan-phase "$PHASE") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.plan-phase "$PHASE") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_RESEARCHER=$($GSD_SDK query agent-skills gsd-phase-researcher) -AGENT_SKILLS_PLANNER=$($GSD_SDK query agent-skills gsd-planner) -AGENT_SKILLS_CHECKER=$($GSD_SDK query agent-skills gsd-plan-checker) -CONTEXT_WINDOW=$($GSD_SDK query config-get context_window 2>/dev/null || echo "200000") -TDD_MODE=$($GSD_SDK query config-get workflow.tdd_mode 2>/dev/null || echo "false") -MVP_MODE_CFG=$($GSD_SDK query config-get workflow.mvp_mode 2>/dev/null || echo "false") +AGENT_SKILLS_RESEARCHER=$(gsd_run query agent-skills gsd-phase-researcher) +AGENT_SKILLS_PLANNER=$(gsd_run query agent-skills gsd-planner) +AGENT_SKILLS_CHECKER=$(gsd_run query agent-skills gsd-plan-checker) +CONTEXT_WINDOW=$(gsd_run query config-get context_window 2>/dev/null || echo "200000") +TDD_MODE=$(gsd_run query config-get workflow.tdd_mode 2>/dev/null || echo "false") +MVP_MODE_CFG=$(gsd_run query config-get workflow.mvp_mode 2>/dev/null || echo "false") ``` When `TDD_MODE` is `true`, the planner agent is instructed to apply `type: tdd` to eligible tasks using heuristics from `references/tdd.md`. The planner's `` is extended to include `@~/.claude/get-shit-done/references/tdd.md` so gate enforcement rules are available during planning. @@ -148,7 +137,7 @@ The verb returns `true|false`. Full result also exposes `source` (`cli_flag` | ` ```bash WALKING_SKELETON=false if [ "$MVP_MODE" = "true" ] && [ "$padded_phase" = "01" ]; then - PRIOR_SUMMARIES=$($GSD_SDK query phases.list --pick summaries_total 2>/dev/null || echo "0") + PRIOR_SUMMARIES=$(gsd_run query phases.list --pick summaries_total 2>/dev/null || echo "0") if [ "$PRIOR_SUMMARIES" = "0" ]; then WALKING_SKELETON=true; fi fi ``` @@ -177,7 +166,7 @@ Set `phase_dir="${expected_phase_dir}"` after creation. Set `CHUNKED_MODE` from flag or config: ```bash -CHUNKED_CFG=$($GSD_SDK query config-get workflow.plan_chunked 2>/dev/null || echo "false") +CHUNKED_CFG=$(gsd_run query config-get workflow.plan_chunked 2>/dev/null || echo "false") CHUNKED_MODE=false if [[ "$ARGUMENTS" =~ --chunked ]] || [[ "$CHUNKED_CFG" == "true" ]]; then CHUNKED_MODE=true @@ -205,14 +194,14 @@ Exit workflow. ## 3. Validate Phase ```bash -PHASE_INFO=$($GSD_SDK query roadmap.get-phase "${PHASE}") +PHASE_INFO=$(gsd_run query roadmap.get-phase "${PHASE}") ``` **If `found` is false:** Error with available phases. **If `found` is true:** Extract `phase_number`, `phase_name`, `goal` from JSON. Now that `PHASE` is finalized, resolve MVP mode: ```bash -MVP_MODE=$($GSD_SDK query phase.mvp-mode "${PHASE}" $MVP_FLAG_ARG --pick active) +MVP_MODE=$(gsd_run query phase.mvp-mode "${PHASE}" $MVP_FLAG_ARG --pick active) ``` ## 3.5. Handle PRD Express Path @@ -312,7 +301,7 @@ Use full relative paths. Group by topic area.] 5. Commit: ```bash -$GSD_SDK query commit "docs(${padded_phase}): generate context from PRD" --files "${phase_dir}/${padded_phase}-CONTEXT.md" +gsd_run query commit "docs(${padded_phase}): generate context from PRD" --files "${phase_dir}/${padded_phase}-CONTEXT.md" ``` 6. Set `context_content` to the generated CONTEXT.md content and continue to step 5 (Handle Research). @@ -346,7 +335,7 @@ If `context_path` is not null, display: `Using phase context from: ${context_pat Read discuss mode for context gate label: ```bash -DISCUSS_MODE=$($GSD_SDK query config-get workflow.discuss_mode 2>/dev/null || echo "discuss") +DISCUSS_MODE=$(gsd_run query config-get workflow.discuss_mode 2>/dev/null || echo "discuss") ``` If `TEXT_MODE` is true, present as a plain-text numbered list: @@ -390,7 +379,7 @@ If "Run discuss-phase first": ```bash AI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-AI-SPEC.md 2>/dev/null | head -1) -AI_PHASE_CFG=$($GSD_SDK query config-get workflow.ai_integration_phase 2>/dev/null || echo "true") +AI_PHASE_CFG=$(gsd_run query config-get workflow.ai_integration_phase 2>/dev/null || echo "true") ``` **Skip if `AI_PHASE_CFG` is `false`.** @@ -497,7 +486,7 @@ Display banner: ### Spawn gsd-phase-researcher ```bash -PHASE_DESC=$($GSD_SDK query roadmap.get-phase "${PHASE}" --pick section) +PHASE_DESC=$(gsd_run query roadmap.get-phase "${PHASE}" --pick section) ``` Research prompt: @@ -598,9 +587,9 @@ test -f "${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md" && echo "VALIDATION_CREATED > Skip if `workflow.security_enforcement` is explicitly `false`. Absent = enabled. ```bash -SECURITY_CFG=$($GSD_SDK query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true") -SECURITY_ASVS=$($GSD_SDK query config-get workflow.security_asvs_level --raw 2>/dev/null || echo "1") -SECURITY_BLOCK=$($GSD_SDK query config-get workflow.security_block_on --raw 2>/dev/null || echo "high") +SECURITY_CFG=$(gsd_run query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true") +SECURITY_ASVS=$(gsd_run query config-get workflow.security_asvs_level --raw 2>/dev/null || echo "1") +SECURITY_BLOCK=$(gsd_run query config-get workflow.security_block_on --raw 2>/dev/null || echo "high") ``` **If `SECURITY_CFG` is `false`:** Skip to step 5.6. @@ -624,8 +613,8 @@ Continue to step 5.6. Security config is passed to the planner in step 8. > Skip if `workflow.ui_phase` is explicitly `false` AND `workflow.ui_safety_gate` is explicitly `false` in `.planning/config.json`. If keys are absent, treat as enabled. ```bash -UI_PHASE_CFG=$($GSD_SDK query config-get workflow.ui_phase 2>/dev/null || echo "true") -UI_GATE_CFG=$($GSD_SDK query config-get workflow.ui_safety_gate 2>/dev/null || echo "true") +UI_PHASE_CFG=$(gsd_run query config-get workflow.ui_phase 2>/dev/null || echo "true") +UI_GATE_CFG=$(gsd_run query config-get workflow.ui_safety_gate 2>/dev/null || echo "true") ``` **If both are `false`:** Skip to step 6. @@ -633,7 +622,7 @@ UI_GATE_CFG=$($GSD_SDK query config-get workflow.ui_safety_gate 2>/dev/null || e Check if phase has frontend indicators: ```bash -PHASE_SECTION=$($GSD_SDK query roadmap.get-phase "${PHASE}" 2>/dev/null) +PHASE_SECTION=$(gsd_run query roadmap.get-phase "${PHASE}" 2>/dev/null) # Shell-free word-boundary gate (#3718): Node.js helper — no locale env-var dependency. # Reads via stdin to avoid OS ARG_MAX limits on large phase text. # Path anchored to repo root; falls back to CWD if git is unavailable @@ -658,7 +647,7 @@ UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1) Read ephemeral chain flag (same field as `check.auto-mode` → `auto_chain_active`): ```bash -AUTO_CHAIN=$($GSD_SDK query check auto-mode --pick auto_chain_active 2>/dev/null || echo "false") +AUTO_CHAIN=$(gsd_run query check auto-mode --pick auto_chain_active 2>/dev/null || echo "false") ``` **If `AUTO_CHAIN` is `true` (running inside a `--chain` or `--auto` pipeline):** @@ -698,7 +687,7 @@ Also available: Check if any files in the phase scope match schema patterns: ```bash -PHASE_SECTION=$($GSD_SDK query roadmap.get-phase "${PHASE}" --pick section 2>/dev/null) +PHASE_SECTION=$(gsd_run query roadmap.get-phase "${PHASE}" --pick section 2>/dev/null) ``` Scan `PHASE_SECTION`, `CONTEXT.md` (if loaded), and `RESEARCH.md` (if exists) for file paths matching these ORM patterns: @@ -813,7 +802,7 @@ Proceed to Step 7.8 (or Step 8 if pattern mapper is disabled) only if user selec Check config: ```bash -PATTERN_MAPPER_CFG=$($GSD_SDK query config-get workflow.pattern_mapper 2>/dev/null || echo "true") +PATTERN_MAPPER_CFG=$(gsd_run query config-get workflow.pattern_mapper 2>/dev/null || echo "true") ``` **If `PATTERN_MAPPER_CFG` is `false`:** Skip to step 8. @@ -1106,7 +1095,7 @@ For each plan entry extracted from `PLAN-OUTLINE.md`: 5. **Commit per-plan:** ```bash - $GSD_SDK query commit "docs(${PADDED_PHASE}): plan ${plan_id} (chunked)" --files "${PHASE_DIR}/${plan_id}-PLAN.md" + gsd_run query commit "docs(${PADDED_PHASE}): plan ${plan_id} (chunked)" --files "${PHASE_DIR}/${plan_id}-PLAN.md" ``` After all N plans are written and committed, treat this as `## PLANNING COMPLETE` and continue @@ -1398,8 +1387,8 @@ Skipping bounce step. **Read pass count:** ```bash -BOUNCE_PASSES=$($GSD_SDK query config-get workflow.plan_bounce_passes 2>/dev/null || echo "2") -BOUNCE_SCRIPT=$($GSD_SDK query config-get workflow.plan_bounce_script 2>/dev/null | jq -r '.' 2>/dev/null || true) +BOUNCE_PASSES=$(gsd_run query config-get workflow.plan_bounce_passes 2>/dev/null || echo "2") +BOUNCE_SCRIPT=$(gsd_run query config-get workflow.plan_bounce_script 2>/dev/null | jq -r '.' 2>/dev/null || true) ``` Display banner: @@ -1444,7 +1433,7 @@ After the script returns, check that the bounced file still has valid YAML front 6. **Commit surviving bounced plans:** If at least one plan survived both the frontmatter validation and the checker re-run, commit the changes: ```bash -$GSD_SDK query commit "refactor(${padded_phase}): bounce plans through external refinement" --files "${PHASE_DIR}/*-PLAN.md" +gsd_run query commit "refactor(${padded_phase}): bounce plans through external refinement" --files "${PHASE_DIR}/*-PLAN.md" ``` Display summary: @@ -1518,9 +1507,9 @@ silently dropped on the way into the plans. (nothing to translate) or if its `` block is empty. ```bash -GATE_CFG=$($GSD_SDK query config-get workflow.context_coverage_gate 2>/dev/null || echo "true") +GATE_CFG=$(gsd_run query config-get workflow.context_coverage_gate 2>/dev/null || echo "true") if [ "$GATE_CFG" != "false" ]; then - GATE_RESULT=$($GSD_SDK query check.decision-coverage-plan "${PHASE_DIR}" "${CONTEXT_PATH}") + GATE_RESULT=$(gsd_run query check.decision-coverage-plan "${PHASE_DIR}" "${CONTEXT_PATH}") # BLOCKING: refuse to mark phase planned when a trackable decision is uncovered. # `passed: true` covers both real-pass and skipped cases (gate disabled / no CONTEXT.md / # no trackable decisions). Verify-phase counterpart deliberately omits this exit-1 — that @@ -1576,7 +1565,7 @@ after thousands of dollars of execution. After plans pass all gates, record that planning is complete so STATE.md reflects the new phase status: ```bash -$GSD_SDK query state.planned-phase --phase "${PHASE_NUMBER}" --name "${PHASE_NAME}" --plans "${PLAN_COUNT}" +gsd_run query state.planned-phase --phase "${PHASE_NUMBER}" --name "${PHASE_NAME}" --plans "${PLAN_COUNT}" ``` This updates STATUS to "Ready to execute", sets the correct plan count, and timestamps Last Activity. @@ -1590,7 +1579,7 @@ After plans are finalized, annotate the ROADMAP.md plan list for this phase with This step is derived entirely from existing PLAN frontmatter — no extra LLM pass is required. ```bash -$GSD_SDK query roadmap.annotate-dependencies "${PHASE_NUMBER}" +gsd_run query roadmap.annotate-dependencies "${PHASE_NUMBER}" ``` This operation is idempotent: if wave headers or cross-cutting constraints already exist in the ROADMAP phase section, the command returns without modifying the file. Skip this step if `plan_count` is 0. @@ -1600,7 +1589,7 @@ This operation is idempotent: if wave headers or cross-cutting constraints alrea If `commit_docs` is true (from the init JSON parsed in step 1), commit the generated plan artifacts (including any ROADMAP.md annotations from step 13c): ```bash -$GSD_SDK query commit "docs(${PADDED_PHASE}): create phase plan" --files "${PHASE_DIR}"/*-PLAN.md .planning/STATE.md .planning/ROADMAP.md +gsd_run query commit "docs(${PADDED_PHASE}): create phase plan" --files "${PHASE_DIR}"/*-PLAN.md .planning/STATE.md .planning/ROADMAP.md ``` This commits all PLAN.md files for the phase plus the updated STATE.md and ROADMAP.md to version-control the planning artifacts. Skip this step if `commit_docs` is false. @@ -1617,7 +1606,7 @@ one place before execution begins. **Skip if:** `workflow.post_planning_gaps` is `false`. Default is `true`. ```bash -POST_PLANNING_GAPS=$($GSD_SDK query config-get workflow.post_planning_gaps --default true 2>/dev/null || echo true) +POST_PLANNING_GAPS=$(gsd_run query config-get workflow.post_planning_gaps --default true 2>/dev/null || echo true) if [ "$POST_PLANNING_GAPS" = "true" ]; then node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" gap-analysis --phase-dir "${PHASE_DIR}" fi @@ -1665,7 +1654,7 @@ Check for auto-advance trigger using values already loaded in step 1: 3. **Sync chain flag with intent** — if user invoked manually (no `--auto` and no `--chain`), clear the ephemeral chain flag from any previous interrupted `--auto` chain. This does NOT touch `workflow.auto_advance` (the user's persistent settings preference): ```bash if [[ ! "$ARGUMENTS" =~ --auto ]] && [[ ! "$ARGUMENTS" =~ --chain ]]; then - $GSD_SDK query config-set workflow._auto_chain_active false || true + gsd_run query config-set workflow._auto_chain_active false || true fi ``` @@ -1676,7 +1665,7 @@ Set local variables from INIT (parsed once in step 1): **If `--auto` or `--chain` flag present AND `AUTO_CHAIN` is not true:** Persist chain flag to config (handles direct invocation without prior discuss-phase): ```bash if ([[ "$ARGUMENTS" =~ --auto ]] || [[ "$ARGUMENTS" =~ --chain ]]) && [[ "$AUTO_CHAIN" != "true" ]]; then - $GSD_SDK query config-set workflow._auto_chain_active true + gsd_run query config-set workflow._auto_chain_active true fi ``` diff --git a/get-shit-done/workflows/plan-review-convergence.md b/get-shit-done/workflows/plan-review-convergence.md index c03123b98..43b05565e 100644 --- a/get-shit-done/workflows/plan-review-convergence.md +++ b/get-shit-done/workflows/plan-review-convergence.md @@ -43,19 +43,8 @@ echo "$ARGUMENTS" | grep -qE '\-\-ws\s+\S+' && GSD_WS=$(echo "$ARGUMENTS" | grep ## 1.5. Config Gate (feature disabled by default) ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -CONVERGENCE_ENABLED=$($GSD_SDK query config-get workflow.plan_review_convergence 2>/dev/null || echo "false") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +CONVERGENCE_ENABLED=$(gsd_run query config-get workflow.plan_review_convergence 2>/dev/null || echo "false") ``` **If `CONVERGENCE_ENABLED` is not `"true"`:** Display and exit: diff --git a/get-shit-done/workflows/plant-seed.md b/get-shit-done/workflows/plant-seed.md index d7f83d3c9..fdf8eff18 100644 --- a/get-shit-done/workflows/plant-seed.md +++ b/get-shit-done/workflows/plant-seed.md @@ -135,19 +135,8 @@ Store relevant file paths as `$BREADCRUMBS`. ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query commit "docs: plant seed — {$IDEA}" --files .planning/seeds/SEED-{PADDED}-{slug}.md +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query commit "docs: plant seed — {$IDEA}" --files .planning/seeds/SEED-{PADDED}-{slug}.md ``` @@ -218,7 +207,7 @@ Update the seed file's frontmatter and sections with the gathered values: Commit the update: ```bash -$GSD_SDK query commit "docs: enrich seed ${SEED_ID} — trigger + why + scope" --files "$SEED_FILE" +gsd_run query commit "docs: enrich seed ${SEED_ID} — trigger + why + scope" --files "$SEED_FILE" ``` Confirm: diff --git a/get-shit-done/workflows/profile-user.md b/get-shit-done/workflows/profile-user.md index bcefa8485..83d1967e8 100644 --- a/get-shit-done/workflows/profile-user.md +++ b/get-shit-done/workflows/profile-user.md @@ -130,19 +130,8 @@ Display: "◆ Scanning sessions..." Run session scan: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -SCAN_RESULT=$($GSD_SDK query scan-sessions --json 2>/dev/null) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +SCAN_RESULT=$(gsd_run query scan-sessions --json 2>/dev/null) ``` Parse the JSON output to get session count and project count. @@ -162,7 +151,7 @@ Display: "◆ Sampling messages..." Run profile sampling: ```bash -SAMPLE_RESULT=$($GSD_SDK query profile-sample --json 2>/dev/null) +SAMPLE_RESULT=$(gsd_run query profile-sample --json 2>/dev/null) ``` Parse the JSON output to get the temp directory path and message count. @@ -213,7 +202,7 @@ Display: "Using questionnaire to build your profile." **Get questions:** ```bash -QUESTIONS=$($GSD_SDK query profile-questionnaire --json 2>/dev/null) +QUESTIONS=$(gsd_run query profile-questionnaire --json 2>/dev/null) ``` Parse the questions JSON. It contains 8 questions, one per dimension. @@ -236,7 +225,7 @@ Write the answers JSON to `$ANSWERS_PATH`. **Convert answers to analysis:** ```bash -ANALYSIS_RESULT=$($GSD_SDK query profile-questionnaire --answers "$ANSWERS_PATH" --json 2>/dev/null) +ANALYSIS_RESULT=$(gsd_run query profile-questionnaire --answers "$ANSWERS_PATH" --json 2>/dev/null) ``` Parse the analysis JSON from the result. @@ -283,7 +272,7 @@ Write updated analysis JSON back to `$ANALYSIS_PATH`. Display: "◆ Writing profile..." ```bash -$GSD_SDK query write-profile --input "$ANALYSIS_PATH" --json +gsd_run query write-profile --input "$ANALYSIS_PATH" --json ``` Display: "✓ Profile written to $HOME/.claude/get-shit-done/USER-PROFILE.md" @@ -362,7 +351,7 @@ Generate selected artifacts sequentially (file I/O is fast, no benefit from para **For /gsd-dev-preferences (if selected):** ```bash -$GSD_SDK query generate-dev-preferences --analysis "$ANALYSIS_PATH" --json +gsd_run query generate-dev-preferences --analysis "$ANALYSIS_PATH" --json ``` Display: "✓ Generated /gsd-dev-preferences at $HOME/.claude/skills/gsd-dev-preferences/SKILL.md" @@ -370,7 +359,7 @@ Display: "✓ Generated /gsd-dev-preferences at $HOME/.claude/skills/gsd-dev-pre **For CLAUDE.md profile section (if selected):** ```bash -$GSD_SDK query generate-claude-profile --analysis "$ANALYSIS_PATH" --json +gsd_run query generate-claude-profile --analysis "$ANALYSIS_PATH" --json ``` Display: "✓ Added profile section to CLAUDE.md" @@ -378,7 +367,7 @@ Display: "✓ Added profile section to CLAUDE.md" **For Global CLAUDE.md (if selected):** ```bash -$GSD_SDK query generate-claude-profile --analysis "$ANALYSIS_PATH" --global --json +gsd_run query generate-claude-profile --analysis "$ANALYSIS_PATH" --global --json ``` Display: "✓ Added profile section to $HOME/.claude/CLAUDE.md" diff --git a/get-shit-done/workflows/progress.md b/get-shit-done/workflows/progress.md index a7f071352..4a8251c16 100644 --- a/get-shit-done/workflows/progress.md +++ b/get-shit-done/workflows/progress.md @@ -12,26 +12,15 @@ Read all files referenced by the invoking prompt's execution_context before star **Load progress context (paths only):** ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.progress) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.progress) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` Extract from init JSON: `project_exists`, `roadmap_exists`, `state_exists`, `phases`, `current_phase`, `next_phase`, `milestone_version`, `completed_count`, `phase_count`, `paused_at`, `state_path`, `roadmap_path`, `project_path`, `config_path`. ```bash -DISCUSS_MODE=$($GSD_SDK query config-get workflow.discuss_mode 2>/dev/null || echo "discuss") +DISCUSS_MODE=$(gsd_run query config-get workflow.discuss_mode 2>/dev/null || echo "discuss") ``` If `project_exists` is false (no `.planning/` directory): @@ -67,7 +56,7 @@ This minimizes orchestrator context usage. **Get comprehensive roadmap analysis (replaces manual parsing):** ```bash -ROADMAP=$($GSD_SDK query roadmap.analyze) +ROADMAP=$(gsd_run query roadmap.analyze) ``` This returns structured JSON with: @@ -86,7 +75,7 @@ Use this instead of manually reading/parsing ROADMAP.md. - Find the 2-3 most recent SUMMARY.md files - Use `summary-extract` for efficient parsing: ```bash - $GSD_SDK query summary-extract --fields one_liner + gsd_run query summary-extract --fields one_liner ``` - This shows "what we've been working on" @@ -110,7 +99,7 @@ Use this instead of manually reading/parsing ROADMAP.md. ```bash # Get formatted progress bar -PROGRESS_BAR=$($GSD_SDK query progress.bar --raw) +PROGRESS_BAR=$(gsd_run query progress.bar --raw) ``` Present: @@ -158,7 +147,7 @@ CONTEXT: [✓ if has_context | - if not] Resolve `MVP_MODE` per phase via the centralized resolver. progress has no `--mvp` CLI flag (mode is inherited from the planned phase), so we omit `--cli-flag`: ```bash -MVP_MODE=$($GSD_SDK query phase.mvp-mode "${PHASE_NUMBER}" --pick active) +MVP_MODE=$(gsd_run query phase.mvp-mode "${PHASE_NUMBER}" --pick active) ``` When `MVP_MODE=true`, the per-phase progress block adds a **user-flow status** sub-block sourced from the phase's PLAN.md task names. Each task whose name reads like a user-visible capability (e.g., "Register flow", "Login flow", "Password reset") is rendered as a status line: @@ -210,7 +199,7 @@ Track: Scan ALL phases in the current milestone for outstanding verification debt using the CLI (which respects milestone boundaries via `getMilestonePhaseFilter`): ```bash -DEBT=$($GSD_SDK query audit-uat --raw 2>/dev/null) +DEBT=$(gsd_run query audit-uat --raw 2>/dev/null) ``` Parse JSON for `summary.total_items` and `summary.total_files`. @@ -273,7 +262,7 @@ Check if `{phase_num}-CONTEXT.md` exists in phase directory. Check if current phase has UI indicators: ```bash -PHASE_SECTION=$($GSD_SDK query roadmap.get-phase "${CURRENT_PHASE}" 2>/dev/null) +PHASE_SECTION=$(gsd_run query roadmap.get-phase "${CURRENT_PHASE}" 2>/dev/null) PHASE_HAS_UI=$(echo "$PHASE_SECTION" | grep -qi "UI hint.*yes" && echo "true" || echo "false") ``` @@ -419,7 +408,7 @@ Read ROADMAP.md to get the next phase's name and goal. Check if next phase has UI indicators: ```bash -NEXT_PHASE_SECTION=$($GSD_SDK query roadmap.get-phase "$((Z+1))" 2>/dev/null) +NEXT_PHASE_SECTION=$(gsd_run query roadmap.get-phase "$((Z+1))" 2>/dev/null) NEXT_HAS_UI=$(echo "$NEXT_PHASE_SECTION" | grep -qi "UI hint.*yes" && echo "true" || echo "false") ``` diff --git a/get-shit-done/workflows/quick.md b/get-shit-done/workflows/quick.md index 08a7fb3f7..6173f097c 100644 --- a/get-shit-done/workflows/quick.md +++ b/get-shit-done/workflows/quick.md @@ -125,37 +125,26 @@ If `$VALIDATE_MODE` only: **Step 2: Initialize** ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.quick "$DESCRIPTION") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.quick "$DESCRIPTION") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_PLANNER=$($GSD_SDK query agent-skills gsd-planner) -AGENT_SKILLS_EXECUTOR=$($GSD_SDK query agent-skills gsd-executor) -AGENT_SKILLS_CHECKER=$($GSD_SDK query agent-skills gsd-plan-checker) -AGENT_SKILLS_VERIFIER=$($GSD_SDK query agent-skills gsd-verifier) +AGENT_SKILLS_PLANNER=$(gsd_run query agent-skills gsd-planner) +AGENT_SKILLS_EXECUTOR=$(gsd_run query agent-skills gsd-executor) +AGENT_SKILLS_CHECKER=$(gsd_run query agent-skills gsd-plan-checker) +AGENT_SKILLS_VERIFIER=$(gsd_run query agent-skills gsd-verifier) ``` Parse JSON for: `planner_model`, `executor_model`, `checker_model`, `verifier_model`, `commit_docs`, `branch_name`, `quick_id`, `slug`, `date`, `timestamp`, `quick_dir`, `task_dir`, `roadmap_exists`, `planning_exists`. ```bash -USE_WORKTREES=$($GSD_SDK query config-get workflow.use_worktrees 2>/dev/null || echo "true") +USE_WORKTREES=$(gsd_run query config-get workflow.use_worktrees 2>/dev/null || echo "true") ``` If `USE_WORKTREES` is not `"false"`, run a startup orphan sweep before spawning any executors. This reaps locked worktrees whose lock-owner process is dead, whose branch is merged into the default branch, and whose lock file mtime is older than 5 minutes. Running it at startup prevents accumulation of orphaned worktrees from prior sessions that exited without cleanup (#3707). ```bash if [ "$USE_WORKTREES" != "false" ]; then - $GSD_SDK query worktree.reap-orphans 2>/dev/null || true + gsd_run query worktree.reap-orphans 2>/dev/null || true fi ``` @@ -641,7 +630,7 @@ Skip this step entirely if `USE_WORKTREES === "false"` (non-worktree mode: PLAN. ```bash if [ "${USE_WORKTREES}" != "false" ]; then - COMMIT_DOCS=$($GSD_SDK query config-get commit_docs 2>/dev/null || echo "true") + COMMIT_DOCS=$(gsd_run query config-get commit_docs 2>/dev/null || echo "true") if [ "$COMMIT_DOCS" != "false" ]; then git add "${QUICK_DIR}/${quick_id}-PLAN.md" # No-op skip if nothing actually staged (idempotent re-runs). @@ -650,7 +639,7 @@ if [ "${USE_WORKTREES}" != "false" ]; then else # Run hooks normally (#2924). If a project opts out via # workflow.worktree_skip_hooks=true, honor that opt-in only. - SKIP_HOOKS=$($GSD_SDK query config-get workflow.worktree_skip_hooks 2>/dev/null || echo "false") + SKIP_HOOKS=$(gsd_run query config-get workflow.worktree_skip_hooks 2>/dev/null || echo "false") if [ "$SKIP_HOOKS" = "true" ]; then git commit --no-verify -m "docs(${quick_id}): pre-dispatch plan for ${DESCRIPTION}" -- "${QUICK_DIR}/${quick_id}-PLAN.md" \ || { echo "ERROR: pre-dispatch PLAN.md commit failed (--no-verify path). Aborting before executor dispatch." >&2; exit 1; } @@ -790,7 +779,7 @@ After executor returns: # base, deletion diffs, merge result, and worktree removal before branch # deletion. If it blocks, resolve the reported manifest entry and rerun. # Fail closed: SDK refusal (safety guard #3174/#3384) must surface — do not swallow exit 1. - $GSD_SDK query worktree.cleanup-wave --manifest "$QUICK_WORKTREE_MANIFEST" || exit 1 + gsd_run query worktree.cleanup-wave --manifest "$QUICK_WORKTREE_MANIFEST" || exit 1 ``` If `workflow.use_worktrees` is `false`, skip this step. 2. Verify summary exists at `${QUICK_DIR}/${quick_id}-SUMMARY.md` @@ -811,7 +800,7 @@ Skip this step entirely if `$FULL_MODE` is false. **Config gate:** ```bash -CODE_REVIEW_ENABLED=$($GSD_SDK query config-get workflow.code_review 2>/dev/null || echo "true") +CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true") ``` If `"false"`, skip with message "Code review skipped (workflow.code_review=false)". @@ -977,14 +966,14 @@ Build file list: # Explicitly stage all artifacts before commit — PLAN.md may be untracked # if the executor ran without worktree isolation and committed docs early # Filter .planning/ files from staging if commit_docs is disabled (#1783) -COMMIT_DOCS=$($GSD_SDK query config-get commit_docs 2>/dev/null || echo "true") +COMMIT_DOCS=$(gsd_run query config-get commit_docs 2>/dev/null || echo "true") if [ "$COMMIT_DOCS" = "false" ]; then file_list_filtered=$(echo "${file_list}" | tr ' ' '\n' | grep -v '^\.planning/' | tr '\n' ' ') git add ${file_list_filtered} 2>/dev/null else git add ${file_list} 2>/dev/null fi -$GSD_SDK query commit "docs(quick-${quick_id}): ${DESCRIPTION}" --files ${file_list} +gsd_run query commit "docs(quick-${quick_id}): ${DESCRIPTION}" --files ${file_list} ``` Get final commit hash: diff --git a/get-shit-done/workflows/remove-phase.md b/get-shit-done/workflows/remove-phase.md index f001daa63..6866f80f2 100644 --- a/get-shit-done/workflows/remove-phase.md +++ b/get-shit-done/workflows/remove-phase.md @@ -29,19 +29,8 @@ Exit. Load phase operation context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${target}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${target}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -92,13 +81,13 @@ Wait for confirmation. **Delegate the entire removal operation to `gsd-tools.cjs query phase.remove`:** ```bash -RESULT=$($GSD_SDK query phase.remove "${target}") +RESULT=$(gsd_run query phase.remove "${target}") ``` If the phase has executed plans (SUMMARY.md files), the CLI will error. Use `--force` only if the user confirms: ```bash -RESULT=$($GSD_SDK query phase.remove "${target}" --force) +RESULT=$(gsd_run query phase.remove "${target}" --force) ``` The CLI handles: @@ -115,7 +104,7 @@ Extract from result: `removed`, `directory_deleted`, `renamed_directories`, `ren Stage and commit the removal: ```bash -$GSD_SDK query commit "chore: remove phase {target} ({original-phase-name})" --files .planning/ +gsd_run query commit "chore: remove phase {target} ({original-phase-name})" --files .planning/ ``` The commit message preserves the historical record of what was removed. diff --git a/get-shit-done/workflows/remove-workspace.md b/get-shit-done/workflows/remove-workspace.md index 7c01c1d5d..043df1f31 100644 --- a/get-shit-done/workflows/remove-workspace.md +++ b/get-shit-done/workflows/remove-workspace.md @@ -13,19 +13,8 @@ Read all files referenced by the invoking prompt's execution_context before star Extract workspace name from $ARGUMENTS. ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.remove-workspace "$WORKSPACE_NAME") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.remove-workspace "$WORKSPACE_NAME") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` diff --git a/get-shit-done/workflows/resume-project.md b/get-shit-done/workflows/resume-project.md index 6c14a2009..ddcdf5d29 100644 --- a/get-shit-done/workflows/resume-project.md +++ b/get-shit-done/workflows/resume-project.md @@ -20,19 +20,8 @@ Instantly restore full project context so "Where were we?" has an immediate, com Load all context in one call: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.resume) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.resume) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` diff --git a/get-shit-done/workflows/review.md b/get-shit-done/workflows/review.md index 4315cc931..51f3e7466 100644 --- a/get-shit-done/workflows/review.md +++ b/get-shit-done/workflows/review.md @@ -14,6 +14,7 @@ A plan that survives review from 2-3 independent AI systems is more robust. Check which AI CLIs are available on the system: ```bash +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi # Check each CLI command -v gemini >/dev/null 2>&1 && echo "gemini:available" || echo "gemini:missing" command -v claude >/dev/null 2>&1 && echo "claude:available" || echo "claude:missing" @@ -24,27 +25,15 @@ command -v qwen >/dev/null 2>&1 && echo "qwen:available" || echo "qwen:missing" command -v cursor >/dev/null 2>&1 && echo "cursor:available" || echo "cursor:missing" # Check local model servers (OpenAI-compatible HTTP API — no CLI binary required) -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -OLLAMA_HOST=$($GSD_SDK query config-get review.ollama_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +OLLAMA_HOST=$(gsd_run query config-get review.ollama_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$OLLAMA_HOST" ] || [ "$OLLAMA_HOST" = "null" ]; then OLLAMA_HOST="http://localhost:11434"; fi curl -s --max-time 2 "${OLLAMA_HOST}/v1/models" >/dev/null 2>&1 && echo "ollama:available" || echo "ollama:missing" -LM_STUDIO_HOST=$($GSD_SDK query config-get review.lm_studio_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +LM_STUDIO_HOST=$(gsd_run query config-get review.lm_studio_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$LM_STUDIO_HOST" ] || [ "$LM_STUDIO_HOST" = "null" ]; then LM_STUDIO_HOST="http://localhost:1234"; fi curl -s --max-time 2 "${LM_STUDIO_HOST}/v1/models" >/dev/null 2>&1 && echo "lm_studio:available" || echo "lm_studio:missing" -LLAMA_CPP_HOST=$($GSD_SDK query config-get review.llama_cpp_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +LLAMA_CPP_HOST=$(gsd_run query config-get review.llama_cpp_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$LLAMA_CPP_HOST" ] || [ "$LLAMA_CPP_HOST" = "null" ]; then LLAMA_CPP_HOST="http://localhost:8080"; fi curl -s --max-time 2 "${LLAMA_CPP_HOST}/v1/models" >/dev/null 2>&1 && echo "llama_cpp:available" || echo "llama_cpp:missing" ``` @@ -120,7 +109,7 @@ Rules: Collect phase artifacts for the review prompt: ```bash -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -225,10 +214,10 @@ Read model preferences from planning config. Null/missing values fall back to CL ```bash # JSON scalars from gsd-tools.cjs query; use jq -r to strip JSON string quotes (install jq if missing) -GEMINI_MODEL=$($GSD_SDK query config-get review.models.gemini 2>/dev/null | jq -r '.' 2>/dev/null || true) -CLAUDE_MODEL=$($GSD_SDK query config-get review.models.claude 2>/dev/null | jq -r '.' 2>/dev/null || true) -CODEX_MODEL=$($GSD_SDK query config-get review.models.codex 2>/dev/null | jq -r '.' 2>/dev/null || true) -OPENCODE_MODEL=$($GSD_SDK query config-get review.models.opencode 2>/dev/null | jq -r '.' 2>/dev/null || true) +GEMINI_MODEL=$(gsd_run query config-get review.models.gemini 2>/dev/null | jq -r '.' 2>/dev/null || true) +CLAUDE_MODEL=$(gsd_run query config-get review.models.claude 2>/dev/null | jq -r '.' 2>/dev/null || true) +CODEX_MODEL=$(gsd_run query config-get review.models.codex 2>/dev/null | jq -r '.' 2>/dev/null || true) +OPENCODE_MODEL=$(gsd_run query config-get review.models.opencode 2>/dev/null | jq -r '.' 2>/dev/null || true) ``` For each selected CLI, invoke in sequence (not parallel — avoid rate limits): @@ -325,7 +314,7 @@ prepare_trimmed_prompt_for_reviewer() { REQUIREMENTS_ARG="" [ -f "/tmp/gsd-review-{phase}-requirements.md" ] && REQUIREMENTS_ARG="--requirements-file /tmp/gsd-review-{phase}-requirements.md" - $GSD_SDK query prompt-budget \ + gsd_run query prompt-budget \ --budget "$REVIEWER_BUDGET" \ --instructions-file "/tmp/gsd-review-{phase}-instructions.md" \ --roadmap-file "/tmp/gsd-review-{phase}-roadmap.md" \ @@ -336,9 +325,9 @@ prepare_trimmed_prompt_for_reviewer() { } # Resolve prompt budget for Ollama: per-reviewer override > global default > null -OLLAMA_REVIEWER_BUDGET=$($GSD_SDK query config-get review.max_prompt_tokens_per_reviewer.ollama 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") +OLLAMA_REVIEWER_BUDGET=$(gsd_run query config-get review.max_prompt_tokens_per_reviewer.ollama 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") if [ -z "$OLLAMA_REVIEWER_BUDGET" ] || [ "$OLLAMA_REVIEWER_BUDGET" = "null" ]; then - OLLAMA_REVIEWER_BUDGET=$($GSD_SDK query config-get review.max_prompt_tokens 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") + OLLAMA_REVIEWER_BUDGET=$(gsd_run query config-get review.max_prompt_tokens 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") fi # Apply budget trim for Ollama if a budget is configured @@ -362,9 +351,9 @@ if [ -n "$OLLAMA_REVIEWER_BUDGET" ] && [ "$OLLAMA_REVIEWER_BUDGET" != "null" ] & fi if [ "$OLLAMA_SKIP" != "1" ]; then -OLLAMA_HOST=$($GSD_SDK query config-get review.ollama_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +OLLAMA_HOST=$(gsd_run query config-get review.ollama_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$OLLAMA_HOST" ] || [ "$OLLAMA_HOST" = "null" ]; then OLLAMA_HOST="http://localhost:11434"; fi -OLLAMA_MODEL=$($GSD_SDK query config-get review.models.ollama 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +OLLAMA_MODEL=$(gsd_run query config-get review.models.ollama 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$OLLAMA_MODEL" ] || [ "$OLLAMA_MODEL" = "null" ]; then OLLAMA_MODEL=$(curl -s --max-time 2 "${OLLAMA_HOST}/v1/models" 2>/dev/null | jq -r '.data[0].id // "llama3"' 2>/dev/null || echo "llama3") fi @@ -384,9 +373,9 @@ fi **LM Studio (local, OpenAI-compatible):** ```bash # Resolve prompt budget for LM Studio: per-reviewer override > global default > null -LM_STUDIO_REVIEWER_BUDGET=$($GSD_SDK query config-get review.max_prompt_tokens_per_reviewer.lm_studio 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") +LM_STUDIO_REVIEWER_BUDGET=$(gsd_run query config-get review.max_prompt_tokens_per_reviewer.lm_studio 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") if [ -z "$LM_STUDIO_REVIEWER_BUDGET" ] || [ "$LM_STUDIO_REVIEWER_BUDGET" = "null" ]; then - LM_STUDIO_REVIEWER_BUDGET=$($GSD_SDK query config-get review.max_prompt_tokens 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") + LM_STUDIO_REVIEWER_BUDGET=$(gsd_run query config-get review.max_prompt_tokens 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") fi # Apply budget trim for LM Studio if a budget is configured @@ -410,9 +399,9 @@ if [ -n "$LM_STUDIO_REVIEWER_BUDGET" ] && [ "$LM_STUDIO_REVIEWER_BUDGET" != "nul fi if [ "$LM_STUDIO_SKIP" != "1" ]; then -LM_STUDIO_HOST=$($GSD_SDK query config-get review.lm_studio_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +LM_STUDIO_HOST=$(gsd_run query config-get review.lm_studio_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$LM_STUDIO_HOST" ] || [ "$LM_STUDIO_HOST" = "null" ]; then LM_STUDIO_HOST="http://localhost:1234"; fi -LM_STUDIO_MODEL=$($GSD_SDK query config-get review.models.lm_studio 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +LM_STUDIO_MODEL=$(gsd_run query config-get review.models.lm_studio 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$LM_STUDIO_MODEL" ] || [ "$LM_STUDIO_MODEL" = "null" ]; then LM_STUDIO_MODEL=$(curl -s --max-time 2 "${LM_STUDIO_HOST}/v1/models" 2>/dev/null | jq -r '.data[0].id // "local-model"' 2>/dev/null || echo "local-model") fi @@ -437,9 +426,9 @@ fi **llama.cpp (local, OpenAI-compatible):** ```bash # Resolve prompt budget for llama.cpp: per-reviewer override > global default > null -LLAMA_CPP_REVIEWER_BUDGET=$($GSD_SDK query config-get review.max_prompt_tokens_per_reviewer.llama_cpp 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") +LLAMA_CPP_REVIEWER_BUDGET=$(gsd_run query config-get review.max_prompt_tokens_per_reviewer.llama_cpp 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") if [ -z "$LLAMA_CPP_REVIEWER_BUDGET" ] || [ "$LLAMA_CPP_REVIEWER_BUDGET" = "null" ]; then - LLAMA_CPP_REVIEWER_BUDGET=$($GSD_SDK query config-get review.max_prompt_tokens 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") + LLAMA_CPP_REVIEWER_BUDGET=$(gsd_run query config-get review.max_prompt_tokens 2>/dev/null | jq -r '.' 2>/dev/null || echo "null") fi # Apply budget trim for llama.cpp if a budget is configured @@ -463,9 +452,9 @@ if [ -n "$LLAMA_CPP_REVIEWER_BUDGET" ] && [ "$LLAMA_CPP_REVIEWER_BUDGET" != "nul fi if [ "$LLAMA_CPP_SKIP" != "1" ]; then -LLAMA_CPP_HOST=$($GSD_SDK query config-get review.llama_cpp_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +LLAMA_CPP_HOST=$(gsd_run query config-get review.llama_cpp_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$LLAMA_CPP_HOST" ] || [ "$LLAMA_CPP_HOST" = "null" ]; then LLAMA_CPP_HOST="http://localhost:8080"; fi -LLAMA_CPP_MODEL=$($GSD_SDK query config-get review.models.llama_cpp 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +LLAMA_CPP_MODEL=$(gsd_run query config-get review.models.llama_cpp 2>/dev/null | jq -r '.' 2>/dev/null || echo "") if [ -z "$LLAMA_CPP_MODEL" ] || [ "$LLAMA_CPP_MODEL" = "null" ]; then LLAMA_CPP_MODEL=$(curl -s --max-time 2 "${LLAMA_CPP_HOST}/v1/models" 2>/dev/null | jq -r '.data[0].id // "local-model"' 2>/dev/null || echo "local-model") fi @@ -597,7 +586,7 @@ trimmed_reviewers: # only present if at least one reviewer was trimmed Commit: ```bash -$GSD_SDK query commit "docs: cross-AI review for phase {N}" --files {phase_dir}/{padded_phase}-REVIEWS.md +gsd_run query commit "docs: cross-AI review for phase {N}" --files {phase_dir}/{padded_phase}-REVIEWS.md ``` diff --git a/get-shit-done/workflows/scan.md b/get-shit-done/workflows/scan.md index e82862d01..4a73c485d 100644 --- a/get-shit-done/workflows/scan.md +++ b/get-shit-done/workflows/scan.md @@ -39,19 +39,8 @@ Exit. ## Step 2: Check for existing documents ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.map-codebase 2>/dev/null || echo "{}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.map-codebase 2>/dev/null || echo "{}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` diff --git a/get-shit-done/workflows/secure-phase.md b/get-shit-done/workflows/secure-phase.md index 4977f433e..c5d7192f2 100644 --- a/get-shit-done/workflows/secure-phase.md +++ b/get-shit-done/workflows/secure-phase.md @@ -16,28 +16,17 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo ## 0. Initialize ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_AUDITOR=$($GSD_SDK query agent-skills gsd-security-auditor) +AGENT_SKILLS_AUDITOR=$(gsd_run query agent-skills gsd-security-auditor) ``` Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`. ```bash -AUDITOR_MODEL=$($GSD_SDK query resolve-model gsd-security-auditor --raw) -SECURITY_CFG=$($GSD_SDK query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true") +AUDITOR_MODEL=$(gsd_run query resolve-model gsd-security-auditor --raw) +SECURITY_CFG=$(gsd_run query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true") ``` If `SECURITY_CFG` is `false`: exit with "Security enforcement disabled. Enable via /gsd:settings." @@ -158,7 +147,7 @@ Do NOT emit next-phase routing. Stop here. ## 7. Commit ```bash -$GSD_SDK query commit "docs(phase-${PHASE}): add/update security threat verification" +gsd_run query commit "docs(phase-${PHASE}): add/update security threat verification" ``` ## 8. Results + Routing diff --git a/get-shit-done/workflows/settings-advanced.md b/get-shit-done/workflows/settings-advanced.md index 4d23d0dfa..986a4ac5e 100644 --- a/get-shit-done/workflows/settings-advanced.md +++ b/get-shit-done/workflows/settings-advanced.md @@ -20,19 +20,8 @@ Read all files referenced by the invoking prompt's execution_context before star Ensure config exists and resolve the workstream-aware config path (mirrors `settings.md`): ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query config-ensure-section +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query config-ensure-section if [[ -z "${GSD_CONFIG_PATH:-}" ]]; then if [[ -f .planning/active-workstream ]]; then WS=$(tr -d '\n\r' < .planning/active-workstream) @@ -476,12 +465,12 @@ AskUserQuestion([ For each tier where the user chose "Enter model ID": ```bash -$GSD_SDK query config-set model_profile_overrides.. "" +gsd_run query config-set model_profile_overrides.. "" ``` For each tier where the user chose "Clear override", remove the key by setting it to null: ```bash -$GSD_SDK query config-set model_profile_overrides.. null +gsd_run query config-set model_profile_overrides.. null ``` "Keep current" selections are skipped entirely. Never write a key the user did not explicitly @@ -499,14 +488,14 @@ keys and sibling sub-objects. ```bash # Example — only write keys the user changed. "Keep current" selections are skipped. -$GSD_SDK query config-set workflow.plan_bounce_passes 5 -$GSD_SDK query config-set workflow.subagent_timeout 900 -$GSD_SDK query config-set git.base_branch main -$GSD_SDK query config-set context_window 1000000 +gsd_run query config-set workflow.plan_bounce_passes 5 +gsd_run query config-set workflow.subagent_timeout 900 +gsd_run query config-set git.base_branch main +gsd_run query config-set context_window 1000000 # Runtime model tier examples: -$GSD_SDK query config-set runtime gemini -$GSD_SDK query config-set model_profile_overrides.gemini.opus gemini-3-ultra -$GSD_SDK query config-set model_profile_overrides.gemini.haiku null +gsd_run query config-set runtime gemini +gsd_run query config-set model_profile_overrides.gemini.opus gemini-3-ultra +gsd_run query config-set model_profile_overrides.gemini.haiku null ``` Conceptual shape after merge (unchanged top-level keys like `model_profile`, diff --git a/get-shit-done/workflows/settings-integrations.md b/get-shit-done/workflows/settings-integrations.md index 43b6bb594..c0d439b2d 100644 --- a/get-shit-done/workflows/settings-integrations.md +++ b/get-shit-done/workflows/settings-integrations.md @@ -42,19 +42,8 @@ Read all files referenced by the invoking prompt's execution_context before star Ensure config exists and resolve the active config path (flat vs workstream, #2282): ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query config-ensure-section +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query config-ensure-section if [[ -z "${GSD_CONFIG_PATH:-}" ]]; then if [[ -f .planning/active-workstream ]]; then WS=$(tr -d '\n\r' < .planning/active-workstream) @@ -77,10 +66,10 @@ integration field, compute one of: - `` — non-secret routing/skill string, shown as-is ```bash -BRAVE=$($GSD_SDK query config-get brave_search --default null) -FIRECRAWL=$($GSD_SDK query config-get firecrawl --default null) -EXA=$($GSD_SDK query config-get exa_search --default null) -SEARCH_GITIGNORED=$($GSD_SDK query config-get search_gitignored --default false) +BRAVE=$(gsd_run query config-get brave_search --default null) +FIRECRAWL=$(gsd_run query config-get firecrawl --default null) +EXA=$(gsd_run query config-get exa_search --default null) +SEARCH_GITIGNORED=$(gsd_run query config-get search_gitignored --default false) ``` For each secret key (`brave_search`, `firecrawl`, `exa_search`) the displayed @@ -141,16 +130,16 @@ key value. **The answer must not be echoed back** in subsequent question descriptions or confirmation text. Write the value via: ```bash -$GSD_SDK query config-set brave_search "" # masked in output -$GSD_SDK query config-set firecrawl "" # masked in output -$GSD_SDK query config-set exa_search "" # masked in output -$GSD_SDK query config-set search_gitignored true|false +gsd_run query config-set brave_search "" # masked in output +gsd_run query config-set firecrawl "" # masked in output +gsd_run query config-set exa_search "" # masked in output +gsd_run query config-set search_gitignored true|false ``` For "Clear", write `null`: ```bash -$GSD_SDK query config-set brave_search null +gsd_run query config-set brave_search null ``` @@ -197,7 +186,7 @@ Leave / Replace / Clear, followed by a text-input prompt for the new command string. Write via: ```bash -$GSD_SDK query config-set review.models. "" +gsd_run query config-set review.models. "" ``` After each update, return to the "Review model CLI mapping — what next?" question. @@ -261,7 +250,7 @@ For a selected slug, prompt for the comma-separated skill list (text input). Show the current value if any, offer Leave / Replace / Clear. Write via: ```bash -$GSD_SDK query config-set agent_skills. "" +gsd_run query config-set agent_skills. "" ``` After each update, return to the "Agent skills mapping — what next?" question. diff --git a/get-shit-done/workflows/settings.md b/get-shit-done/workflows/settings.md index 8f0cc78e1..236704a71 100644 --- a/get-shit-done/workflows/settings.md +++ b/get-shit-done/workflows/settings.md @@ -12,20 +12,9 @@ Read all files referenced by the invoking prompt's execution_context before star Ensure config exists and load current state: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -$GSD_SDK query config-ensure-section -INIT=$($GSD_SDK query state.load) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +gsd_run query config-ensure-section +INIT=$(gsd_run query state.load) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi # `state.load` returns STATE frontmatter JSON from the SDK — it does not include `config_path`. Orchestrators may set `GSD_CONFIG_PATH` from init phase-op JSON; otherwise resolve the same path gsd-tools uses for flat vs active workstream (#2282). if [[ -z "${GSD_CONFIG_PATH:-}" ]]; then diff --git a/get-shit-done/workflows/ship.md b/get-shit-done/workflows/ship.md index 308d3988e..48fb6389b 100644 --- a/get-shit-done/workflows/ship.md +++ b/get-shit-done/workflows/ship.md @@ -12,19 +12,8 @@ Read all files referenced by the invoking prompt's execution_context before star Parse arguments and load project state: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -32,14 +21,14 @@ Parse from init JSON: `phase_found`, `phase_dir`, `phase_number`, `phase_name`, Also load config for branching strategy: ```bash -CONFIG=$($GSD_SDK query state.load) +CONFIG=$(gsd_run query state.load) ``` Extract: `branching_strategy`, `branch_name`. Detect base branch for PRs and merges: ```bash -BASE_BRANCH=$($GSD_SDK query config-get git.base_branch 2>/dev/null || echo "") +BASE_BRANCH=$(gsd_run query config-get git.base_branch 2>/dev/null || echo "") if [ -z "$BASE_BRANCH" ] || [ "$BASE_BRANCH" = "null" ]; then BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||') BASE_BRANCH="${BASE_BRANCH:-main}" @@ -158,7 +147,7 @@ For each SUMMARY.md in the phase directory: Read append-only project-specific PRD/PR body sections from config: ```bash -CUSTOM_PR_SECTIONS=$($GSD_SDK query config-get ship.pr_body_sections --default '[]' 2>/dev/null || echo '[]') +CUSTOM_PR_SECTIONS=$(gsd_run query config-get ship.pr_body_sections --default '[]' 2>/dev/null || echo '[]') ``` `ship.pr_body_sections` is an onboarding-time extension point for teams that need extra PRD-style sections such as `User Stories & Acceptance Criteria`, `Risks & Dependencies`, `Success Metrics`, `Release Criteria`, or `Stakeholder Review & Approval`. @@ -230,7 +219,7 @@ Report: "PR #{number} created: {url}" Before prompting the user, check if an external review command is configured: ```bash -REVIEW_CMD=$($GSD_SDK query config-get workflow.code_review_command 2>/dev/null | jq -r '.' 2>/dev/null || echo "") +REVIEW_CMD=$(gsd_run query config-get workflow.code_review_command 2>/dev/null | jq -r '.' 2>/dev/null || echo "") ``` If `REVIEW_CMD` is non-empty and not `"null"`, run the external review: @@ -243,7 +232,7 @@ If `REVIEW_CMD` is non-empty and not `"null"`, run the external review: 2. **Load phase context from STATE.md:** ```bash - STATE_STATUS=$($GSD_SDK query state.load 2>/dev/null | head -20) + STATE_STATUS=$(gsd_run query state.load 2>/dev/null | head -20) ``` 3. **Build review prompt and pipe to command via stdin:** @@ -316,13 +305,13 @@ Report the PR URL and suggest: "Review the diff at {url}/files" Update STATE.md to reflect the shipping action: ```bash -$GSD_SDK query state.update "Last Activity" "$(date +%Y-%m-%d)" -$GSD_SDK query state.update "Status" "Phase ${PHASE_NUMBER} shipped — PR #${PR_NUMBER}" +gsd_run query state.update "Last Activity" "$(date +%Y-%m-%d)" +gsd_run query state.update "Status" "Phase ${PHASE_NUMBER} shipped — PR #${PR_NUMBER}" ``` If `commit_docs` is true: ```bash -$GSD_SDK query commit "docs(${padded_phase}): ship phase ${PHASE_NUMBER} — PR #${PR_NUMBER}" --files .planning/STATE.md +gsd_run query commit "docs(${padded_phase}): ship phase ${PHASE_NUMBER} — PR #${PR_NUMBER}" --files .planning/STATE.md ``` diff --git a/get-shit-done/workflows/sketch-wrap-up.md b/get-shit-done/workflows/sketch-wrap-up.md index ad4364db2..07785a1e6 100644 --- a/get-shit-done/workflows/sketch-wrap-up.md +++ b/get-shit-done/workflows/sketch-wrap-up.md @@ -37,19 +37,8 @@ Exit. Check `commit_docs` config: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -COMMIT_DOCS=$($GSD_SDK query config-get commit_docs 2>/dev/null || echo "true") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +COMMIT_DOCS=$(gsd_run query config-get commit_docs 2>/dev/null || echo "true") ``` @@ -244,7 +233,7 @@ If this routing line already exists (append mode), leave it as-is. Commit all artifacts (if `COMMIT_DOCS` is true): ```bash -$GSD_SDK query commit "docs(sketch-wrap-up): package [N] sketch findings into project skill" --files .planning/sketches/WRAP-UP-SUMMARY.md +gsd_run query commit "docs(sketch-wrap-up): package [N] sketch findings into project skill" --files .planning/sketches/WRAP-UP-SUMMARY.md ``` diff --git a/get-shit-done/workflows/sketch.md b/get-shit-done/workflows/sketch.md index abe0494b4..b32535c57 100644 --- a/get-shit-done/workflows/sketch.md +++ b/get-shit-done/workflows/sketch.md @@ -99,19 +99,8 @@ ls -d .planning/sketches/[0-9][0-9][0-9]-* 2>/dev/null | sort | tail -1 Check `commit_docs` config: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -COMMIT_DOCS=$($GSD_SDK query config-get commit_docs 2>/dev/null || echo "true") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +COMMIT_DOCS=$(gsd_run query config-get commit_docs 2>/dev/null || echo "true") ``` @@ -308,7 +297,7 @@ Iterate until satisfied. **h.** Commit (if `COMMIT_DOCS` is true): ```bash -$GSD_SDK query commit "docs(sketch-NNN): [winning direction] — [key visual insight]" --files .planning/sketches/NNN-descriptive-name/ .planning/sketches/MANIFEST.md +gsd_run query commit "docs(sketch-NNN): [winning direction] — [key visual insight]" --files .planning/sketches/NNN-descriptive-name/ .planning/sketches/MANIFEST.md ``` **i.** Report: diff --git a/get-shit-done/workflows/spike-wrap-up.md b/get-shit-done/workflows/spike-wrap-up.md index 50b3b1691..725d41930 100644 --- a/get-shit-done/workflows/spike-wrap-up.md +++ b/get-shit-done/workflows/spike-wrap-up.md @@ -37,19 +37,8 @@ Exit. Check `commit_docs` config: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -COMMIT_DOCS=$($GSD_SDK query config-get commit_docs 2>/dev/null || echo "true") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +COMMIT_DOCS=$(gsd_run query config-get commit_docs 2>/dev/null || echo "true") ``` @@ -258,7 +247,7 @@ Patterns and stack choices established across spike sessions. New spikes follow Commit all artifacts (if `COMMIT_DOCS` is true): ```bash -$GSD_SDK query commit "docs(spike-wrap-up): package [N] spike findings into project skill" --files .planning/spikes/WRAP-UP-SUMMARY.md .planning/spikes/CONVENTIONS.md +gsd_run query commit "docs(spike-wrap-up): package [N] spike findings into project skill" --files .planning/spikes/WRAP-UP-SUMMARY.md .planning/spikes/CONVENTIONS.md ``` diff --git a/get-shit-done/workflows/spike.md b/get-shit-done/workflows/spike.md index ebb72a620..e6dd6b41b 100644 --- a/get-shit-done/workflows/spike.md +++ b/get-shit-done/workflows/spike.md @@ -96,19 +96,8 @@ ls -d .planning/spikes/[0-9][0-9][0-9]-* 2>/dev/null | sort | tail -1 Check `commit_docs` config: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -COMMIT_DOCS=$($GSD_SDK query config-get commit_docs 2>/dev/null || echo "true") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +COMMIT_DOCS=$(gsd_run query config-get commit_docs 2>/dev/null || echo "true") ``` @@ -346,7 +335,7 @@ tags: [tag1, tag2] **i.** Commit (if `COMMIT_DOCS` is true): ```bash -$GSD_SDK query commit "docs(spike-NNN): [VERDICT] — [key finding]" --files .planning/spikes/NNN-descriptive-name/ .planning/spikes/MANIFEST.md +gsd_run query commit "docs(spike-NNN): [VERDICT] — [key finding]" --files .planning/spikes/NNN-descriptive-name/ .planning/spikes/MANIFEST.md ``` **j.** Report: @@ -400,7 +389,7 @@ Only include patterns that repeated across 2+ spikes or were explicitly chosen b Commit (if `COMMIT_DOCS` is true): ```bash -$GSD_SDK query commit "docs(spikes): update conventions" --files .planning/spikes/CONVENTIONS.md +gsd_run query commit "docs(spikes): update conventions" --files .planning/spikes/CONVENTIONS.md ``` diff --git a/get-shit-done/workflows/stats.md b/get-shit-done/workflows/stats.md index 7ca2f4731..70097f973 100644 --- a/get-shit-done/workflows/stats.md +++ b/get-shit-done/workflows/stats.md @@ -12,19 +12,8 @@ Read all files referenced by the invoking prompt's execution_context before star Gather project statistics: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -STATS=$($GSD_SDK query stats.json) +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +STATS=$(gsd_run query stats.json) if [[ "$STATS" == @file:* ]]; then STATS=$(cat "${STATS#@file:}"); fi ``` @@ -67,7 +56,7 @@ If no `.planning/` directory exists, inform the user to run `/gsd:new-project` f **MVP phase summary.** Read all phases via `gsd-tools.cjs query roadmap.analyze` (Phase 1's `cmdRoadmapAnalyze` surfaces a `mode` field per phase). Count phases by mode: ```bash -ANALYZE=$($GSD_SDK query roadmap.analyze) +ANALYZE=$(gsd_run query roadmap.analyze) if [[ "$ANALYZE" == @file:* ]]; then ANALYZE=$(cat "${ANALYZE#@file:}"); fi MVP_COUNT=$(echo "$ANALYZE" | jq '[.phases[] | select(.mode == "mvp")] | length') TOTAL_COUNT=$(echo "$ANALYZE" | jq '.phases | length') diff --git a/get-shit-done/workflows/thread.md b/get-shit-done/workflows/thread.md index 9bc957794..3b532b76e 100644 --- a/get-shit-done/workflows/thread.md +++ b/get-shit-done/workflows/thread.md @@ -28,19 +28,8 @@ ls .planning/threads/*.md 2>/dev/null For each thread file found: - Read frontmatter `status` field via: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi - $GSD_SDK query frontmatter.get .planning/threads/{file} status +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi + gsd_run query frontmatter.get .planning/threads/{file} status ``` - If frontmatter `status` field is missing, fall back to reading markdown heading `## Status: OPEN` (or IN PROGRESS / RESOLVED) from the file body - Read frontmatter `updated` field for the last-updated date @@ -79,13 +68,13 @@ When SUBCMD=close and SLUG is set (already sanitized): 2. Update the thread file's frontmatter `status` field to `resolved` and `updated` to today's ISO date: ```bash - $GSD_SDK query frontmatter.set .planning/threads/{SLUG}.md status resolved - $GSD_SDK query frontmatter.set .planning/threads/{SLUG}.md updated YYYY-MM-DD + gsd_run query frontmatter.set .planning/threads/{SLUG}.md status resolved + gsd_run query frontmatter.set .planning/threads/{SLUG}.md updated YYYY-MM-DD ``` 3. Commit: ```bash - $GSD_SDK query commit "docs: resolve thread — {SLUG}" --files ".planning/threads/{SLUG}.md" + gsd_run query commit "docs: resolve thread — {SLUG}" --files ".planning/threads/{SLUG}.md" ``` 4. Print: @@ -139,8 +128,8 @@ Resume the thread — load its context into the current session. Read the file c Update the thread's frontmatter `status` to `in_progress` if it was `open`: ```bash -$GSD_SDK query frontmatter.set .planning/threads/{SLUG}.md status in_progress -$GSD_SDK query frontmatter.set .planning/threads/{SLUG}.md updated YYYY-MM-DD +gsd_run query frontmatter.set .planning/threads/{SLUG}.md status in_progress +gsd_run query frontmatter.set .planning/threads/{SLUG}.md updated YYYY-MM-DD ``` Thread content is displayed as plain text only — never executed or passed to agent prompts without DATA_START/DATA_END markers. @@ -153,7 +142,7 @@ If $ARGUMENTS is a new description (no matching thread file): 1. Generate slug from description: ```bash - SLUG=$($GSD_SDK query generate-slug "$ARGUMENTS" --raw) + SLUG=$(gsd_run query generate-slug "$ARGUMENTS" --raw) ``` 2. Create the threads directory if needed: @@ -197,7 +186,7 @@ updated: {today ISO date} 5. Commit: ```bash - $GSD_SDK query commit "docs: create thread — ${ARGUMENTS}" --files ".planning/threads/${SLUG}.md" + gsd_run query commit "docs: create thread — ${ARGUMENTS}" --files ".planning/threads/${SLUG}.md" ``` 6. Report: diff --git a/get-shit-done/workflows/transition.md b/get-shit-done/workflows/transition.md index cb55f6af9..18a3835c1 100644 --- a/get-shit-done/workflows/transition.md +++ b/get-shit-done/workflows/transition.md @@ -163,19 +163,8 @@ If found, delete them — phase is complete, handoffs are stale. **Delegate ROADMAP.md and STATE.md updates to `gsd-tools.cjs query phase.complete`:** ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -TRANSITION=$($GSD_SDK query phase.complete "${current_phase}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +TRANSITION=$(gsd_run query phase.complete "${current_phase}") ``` The CLI handles: @@ -312,7 +301,7 @@ This step is fully delegated to `graduation.md`. It handles guard checks (featur Verify the updates are correct by reading STATE.md. If the progress bar needs updating, use: ```bash -PROGRESS=$($GSD_SDK query progress.bar --raw) +PROGRESS=$(gsd_run query progress.bar --raw) ``` Update the progress bar line in STATE.md with the result. @@ -421,7 +410,7 @@ The `next_phase` and `next_phase_name` fields give you the next phase details. If you need additional context, use: ```bash -ROADMAP=$($GSD_SDK query roadmap.analyze) +ROADMAP=$(gsd_run query roadmap.analyze) ``` This returns all phases with goals, disk status, and completion info. @@ -440,7 +429,7 @@ In flat mode, go directly to **Route B**. ```bash # Only check if we're in workstream mode if [ -n "$GSD_WORKSTREAM" ]; then - WS_LIST=$($GSD_SDK query workstream.list --raw) + WS_LIST=$(gsd_run query workstream.list --raw) fi ``` @@ -560,7 +549,7 @@ to the next milestone — other workstreams are still working. **Clear auto-advance chain flag** — workstream boundary is the natural stopping point: ```bash -$GSD_SDK query config-set workflow._auto_chain_active false +gsd_run query config-set workflow._auto_chain_active false ``` @@ -614,7 +603,7 @@ Do NOT auto-invoke any further slash commands. **Clear auto-advance chain flag** — milestone boundary is the natural stopping point: ```bash -$GSD_SDK query config-set workflow._auto_chain_active false +gsd_run query config-set workflow._auto_chain_active false ``` diff --git a/get-shit-done/workflows/ui-phase.md b/get-shit-done/workflows/ui-phase.md index 4dbfa407b..be44ba402 100644 --- a/get-shit-done/workflows/ui-phase.md +++ b/get-shit-done/workflows/ui-phase.md @@ -19,22 +19,11 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo ## 1. Initialize ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.plan-phase "$PHASE") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.plan-phase "$PHASE") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_UI=$($GSD_SDK query agent-skills gsd-ui-researcher) -AGENT_SKILLS_UI_CHECKER=$($GSD_SDK query agent-skills gsd-ui-checker) +AGENT_SKILLS_UI=$(gsd_run query agent-skills gsd-ui-researcher) +AGENT_SKILLS_UI_CHECKER=$(gsd_run query agent-skills gsd-ui-checker) ``` Parse JSON for: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_context`, `has_research`, `commit_docs`. @@ -49,14 +38,14 @@ SKETCH_FINDINGS_PATH=$(ls ./.claude/skills/sketch-findings-*/SKILL.md 2>/dev/nul Resolve UI agent models: ```bash -UI_RESEARCHER_MODEL=$($GSD_SDK query resolve-model gsd-ui-researcher --raw) -UI_CHECKER_MODEL=$($GSD_SDK query resolve-model gsd-ui-checker --raw) +UI_RESEARCHER_MODEL=$(gsd_run query resolve-model gsd-ui-researcher --raw) +UI_CHECKER_MODEL=$(gsd_run query resolve-model gsd-ui-checker --raw) ``` Check config: ```bash -UI_ENABLED=$($GSD_SDK query config-get workflow.ui_phase 2>/dev/null || echo "true") +UI_ENABLED=$(gsd_run query config-get workflow.ui_phase 2>/dev/null || echo "true") ``` **If `UI_ENABLED` is `false`:** @@ -72,7 +61,7 @@ Exit workflow. Extract phase number from $ARGUMENTS. If not provided, detect next unplanned phase. ```bash -PHASE_INFO=$($GSD_SDK query roadmap.get-phase "${PHASE}") +PHASE_INFO=$(gsd_run query roadmap.get-phase "${PHASE}") ``` **If `found` is false:** Error with available phases. @@ -310,13 +299,13 @@ Dimensions: 6/6 passed ## 11. Commit (if configured) ```bash -$GSD_SDK query commit "docs(${padded_phase}): UI design contract" --files "${PHASE_DIR}/${PADDED_PHASE}-UI-SPEC.md" +gsd_run query commit "docs(${padded_phase}): UI design contract" --files "${PHASE_DIR}/${PADDED_PHASE}-UI-SPEC.md" ``` ## 12. Update State ```bash -$GSD_SDK query state.record-session \ +gsd_run query state.record-session \ --stopped-at "Phase ${PHASE} UI-SPEC approved" \ --resume-file "${PHASE_DIR}/${PADDED_PHASE}-UI-SPEC.md" ``` diff --git a/get-shit-done/workflows/ui-review.md b/get-shit-done/workflows/ui-review.md index 46f1c11b6..f55fc3d64 100644 --- a/get-shit-done/workflows/ui-review.md +++ b/get-shit-done/workflows/ui-review.md @@ -16,27 +16,16 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo ## 0. Initialize ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_UI_REVIEWER=$($GSD_SDK query agent-skills gsd-ui-auditor) +AGENT_SKILLS_UI_REVIEWER=$(gsd_run query agent-skills gsd-ui-auditor) ``` Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `commit_docs`. ```bash -UI_AUDITOR_MODEL=$($GSD_SDK query resolve-model gsd-ui-auditor --raw) +UI_AUDITOR_MODEL=$(gsd_run query resolve-model gsd-ui-auditor --raw) ``` Display banner: @@ -188,7 +177,7 @@ tools is detected at runtime. ## 5. Commit (if configured) ```bash -$GSD_SDK query commit "docs(${padded_phase}): UI audit review" --files "${PHASE_DIR}/${PADDED_PHASE}-UI-REVIEW.md" +gsd_run query commit "docs(${padded_phase}): UI audit review" --files "${PHASE_DIR}/${PADDED_PHASE}-UI-REVIEW.md" ``` diff --git a/get-shit-done/workflows/ultraplan-phase.md b/get-shit-done/workflows/ultraplan-phase.md index 41772a760..4a2ecefd3 100644 --- a/get-shit-done/workflows/ultraplan-phase.md +++ b/get-shit-done/workflows/ultraplan-phase.md @@ -66,19 +66,8 @@ unplanned phase from the roadmap (same logic as /gsd:plan-phase). Load GSD phase context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.plan-phase "$PHASE") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.plan-phase "$PHASE") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` diff --git a/get-shit-done/workflows/update.md b/get-shit-done/workflows/update.md index 92d3be874..3246f4f6f 100644 --- a/get-shit-done/workflows/update.md +++ b/get-shit-done/workflows/update.md @@ -483,7 +483,6 @@ inspect). Otherwise run `detect-custom-files`: ```bash -GSD_TOOLS="$RUNTIME_DIR/get-shit-done/bin/gsd-tools.cjs" CUSTOM_JSON='' if [ -f "$GSD_TOOLS" ] && [ -n "$RUNTIME_DIR" ]; then CUSTOM_JSON=$(node "$GSD_TOOLS" detect-custom-files --config-dir "$RUNTIME_DIR" 2>/dev/null) diff --git a/get-shit-done/workflows/validate-phase.md b/get-shit-done/workflows/validate-phase.md index 1f5577631..a464b6ca5 100644 --- a/get-shit-done/workflows/validate-phase.md +++ b/get-shit-done/workflows/validate-phase.md @@ -16,28 +16,17 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo ## 0. Initialize ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_AUDITOR=$($GSD_SDK query agent-skills gsd-nyquist-auditor) +AGENT_SKILLS_AUDITOR=$(gsd_run query agent-skills gsd-nyquist-auditor) ``` Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`. ```bash -AUDITOR_MODEL=$($GSD_SDK query resolve-model gsd-nyquist-auditor --raw) -NYQUIST_CFG=$($GSD_SDK query config-get workflow.nyquist_validation --raw) +AUDITOR_MODEL=$(gsd_run query resolve-model gsd-nyquist-auditor --raw) +NYQUIST_CFG=$(gsd_run query config-get workflow.nyquist_validation --raw) ``` If `NYQUIST_CFG` is `false`: exit with "Nyquist validation is disabled. Enable via /gsd:settings." @@ -151,7 +140,7 @@ Handle return: git add {test_files} git commit -m "test(phase-${PHASE}): add Nyquist validation tests" -$GSD_SDK query commit "docs(phase-${PHASE}): add/update validation strategy" +gsd_run query commit "docs(phase-${PHASE}): add/update validation strategy" ``` ## 8. Results + Routing diff --git a/get-shit-done/workflows/verify-phase.md b/get-shit-done/workflows/verify-phase.md index 08d76d05a..983017ac4 100644 --- a/get-shit-done/workflows/verify-phase.md +++ b/get-shit-done/workflows/verify-phase.md @@ -29,19 +29,8 @@ Then verify each level against the actual codebase. Load phase operation context: ```bash -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.phase-op "${PHASE_ARG}") +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi +INIT=$(gsd_run query init.phase-op "${PHASE_ARG}") if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi ``` @@ -49,14 +38,14 @@ Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`, `has_plans`, Then load phase details and list plans/summaries: ```bash -$GSD_SDK query roadmap.get-phase "${phase_number}" +gsd_run query roadmap.get-phase "${phase_number}" grep -E "^| ${phase_number}" .planning/REQUIREMENTS.md 2>/dev/null || true ls "$phase_dir"/*-SUMMARY.md "$phase_dir"/*-PLAN.md 2>/dev/null || true ``` Load full milestone phases for deferred-item filtering (Step 9b): ```bash -$GSD_SDK query roadmap.analyze +gsd_run query roadmap.analyze ``` Extract **phase goal** from ROADMAP.md (the outcome to verify, not tasks), **requirements** from REQUIREMENTS.md if it exists, and **all milestone phases** from roadmap analyze (for cross-referencing gaps against later phases). @@ -69,7 +58,7 @@ Use `gsd-tools.cjs query` verify handlers (or legacy gsd-tools) to extract must_ ```bash for plan in "$PHASE_DIR"/*-PLAN.md; do - MUST_HAVES=$($GSD_SDK query frontmatter.get "$plan" --field must_haves) + MUST_HAVES=$(gsd_run query frontmatter.get "$plan" --field must_haves) echo "=== $plan ===" && echo "$MUST_HAVES" done ``` @@ -83,7 +72,7 @@ Aggregate all must_haves across plans for phase-level verification. If no must_haves in frontmatter (MUST_HAVES returns error or empty), check for Success Criteria: ```bash -PHASE_DATA=$($GSD_SDK query roadmap.get-phase "${phase_number}" --raw) +PHASE_DATA=$(gsd_run query roadmap.get-phase "${phase_number}" --raw) ``` Parse the `success_criteria` array from the JSON output. If non-empty: @@ -119,7 +108,7 @@ Use `gsd-tools.cjs query verify.artifacts` (or legacy gsd-tools) for artifact ve ```bash for plan in "$PHASE_DIR"/*-PLAN.md; do - ARTIFACT_RESULT=$($GSD_SDK query verify.artifacts "$plan") + ARTIFACT_RESULT=$(gsd_run query verify.artifacts "$plan") echo "=== $plan ===" && echo "$ARTIFACT_RESULT" done ``` @@ -162,7 +151,7 @@ Use `gsd-tools.cjs query verify.key-links` (or legacy gsd-tools) for key link ve ```bash for plan in "$PHASE_DIR"/*-PLAN.md; do - LINKS_RESULT=$($GSD_SDK query verify.key-links "$plan") + LINKS_RESULT=$(gsd_run query verify.key-links "$plan") echo "=== $plan ===" && echo "$LINKS_RESULT" done ``` @@ -217,7 +206,7 @@ phase. no `` block. ```bash -GATE_CFG=$($GSD_SDK query config-get workflow.context_coverage_gate 2>/dev/null || echo "true") +GATE_CFG=$(gsd_run query config-get workflow.context_coverage_gate 2>/dev/null || echo "true") if [ "$GATE_CFG" != "false" ]; then # Discover the phase CONTEXT.md via glob expansion rather than `ls | head` # (review F17 / ShellCheck SC2012). Globs preserve filenames containing @@ -226,7 +215,7 @@ if [ "$GATE_CFG" != "false" ]; then for f in "${PHASE_DIR}"/*-CONTEXT.md; do [ -e "$f" ] && CONTEXT_PATH="$f" && break done - DECISION_RESULT=$($GSD_SDK query check.decision-coverage-verify "${PHASE_DIR}" "${CONTEXT_PATH}") + DECISION_RESULT=$(gsd_run query check.decision-coverage-verify "${PHASE_DIR}" "${CONTEXT_PATH}") fi ``` @@ -261,7 +250,7 @@ inspecting static artifacts. ```bash # Resolve test command: project config > Makefile > language sniff -TEST_CMD=$($GSD_SDK query config-get workflow.test_command --default "" 2>/dev/null || true) +TEST_CMD=$(gsd_run query config-get workflow.test_command --default "" 2>/dev/null || true) if [ -z "$TEST_CMD" ]; then if [ -f "Makefile" ] && grep -q "^test:" Makefile; then TEST_CMD="make test" diff --git a/get-shit-done/workflows/verify-work.md b/get-shit-done/workflows/verify-work.md index b4a78a707..934d2162a 100644 --- a/get-shit-done/workflows/verify-work.md +++ b/get-shit-done/workflows/verify-work.md @@ -30,26 +30,15 @@ No Pass/Fail buttons. No severity questions. Just: "Here's what should happen. D If $ARGUMENTS contains a phase number, load context: ```bash +_GSD_SHIM_NAME="gsd-tools.cjs"; GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then 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" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2; exit 1; fi GSD_WS="" echo "$ARGUMENTS" | grep -qE -- '--ws[[:space:]]+[^[:space:]]+' && GSD_WS=$(echo "$ARGUMENTS" | grep -oE -- '--ws[[:space:]]+[^[:space:]]+') PHASE_ARG=$(echo "$ARGUMENTS" | sed -E 's/--ws[[:space:]]+[^[:space:]]+//g' | xargs) -# SDK resolution: prefer local gsd-tools.cjs, fall back to installed gsd-tools (#3668) -GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs" -if [ -f "$GSD_TOOLS" ]; then - GSD_SDK="node $GSD_TOOLS" -elif command -v gsd-tools >/dev/null 2>&1; then - GSD_TOOLS="$(command -v gsd-tools)" - GSD_SDK="$GSD_TOOLS" -else - echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH." >&2 - echo "Run: npx -y @opengsd/get-shit-done-redux@latest --claude --local" >&2 - exit 1 -fi -INIT=$($GSD_SDK query init.verify-work "${PHASE_ARG}" ${GSD_WS}) +INIT=$(gsd_run query init.verify-work "${PHASE_ARG}" ${GSD_WS}) if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi -AGENT_SKILLS_PLANNER=$($GSD_SDK query agent-skills gsd-planner) -AGENT_SKILLS_CHECKER=$($GSD_SDK query agent-skills gsd-plan-checker) +AGENT_SKILLS_PLANNER=$(gsd_run query agent-skills gsd-planner) +AGENT_SKILLS_CHECKER=$(gsd_run query agent-skills gsd-plan-checker) ``` Parse JSON for: `planner_model`, `checker_model`, `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `has_verification`, `uat_path`. @@ -58,7 +47,7 @@ Parse JSON for: `planner_model`, `checker_model`, `commit_docs`, `phase_found`, # MVP mode detection via the centralized phase.mvp-mode resolver. # verify-work has no --mvp CLI flag (mode is inherited from the planned phase), # so we omit --cli-flag — the verb falls through roadmap → config → false. -MVP_MODE=$($GSD_SDK query phase.mvp-mode "${phase_number}" ${GSD_WS} --pick active) +MVP_MODE=$(gsd_run query phase.mvp-mode "${phase_number}" ${GSD_WS} --pick active) ``` @@ -116,7 +105,7 @@ Before running manual UAT, check whether this phase has a UI component and wheth `mcp__playwright__*` or `mcp__puppeteer__*` tools are available in the current session. ```bash -UI_PHASE_FLAG=$($GSD_SDK query config-get workflow.ui_phase --raw 2>/dev/null || echo "true") +UI_PHASE_FLAG=$(gsd_run query config-get workflow.ui_phase --raw 2>/dev/null || echo "true") UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1) ``` @@ -170,8 +159,8 @@ When `MVP_MODE=false` (mode is null, absent, or the phase has no `**Mode:**` lin **User-story format guard.** When `MVP_MODE=true`, also verify the phase's goal is in User Story format via the centralized validator: ```bash -PHASE_GOAL=$($GSD_SDK query roadmap.get-phase "${phase_number}" ${GSD_WS} --pick goal) -USER_STORY_VALID=$($GSD_SDK query user-story.validate --story "$PHASE_GOAL" --pick valid) +PHASE_GOAL=$(gsd_run query roadmap.get-phase "${phase_number}" ${GSD_WS} --pick goal) +USER_STORY_VALID=$(gsd_run query user-story.validate --story "$PHASE_GOAL" --pick valid) if [ "$USER_STORY_VALID" != "true" ]; then echo "Phase ${phase_number} has '**Mode:** mvp' in ROADMAP.md but the **Goal:** is not in user-story format." echo "Run /gsd mvp-phase ${phase_number} to set a user-story goal before verifying." @@ -279,7 +268,7 @@ Proceed to `present_test`. Render the checkpoint from the structured UAT file instead of composing it freehand: ```bash -CHECKPOINT=$($GSD_SDK query uat.render-checkpoint --file "$uat_path" --raw) +CHECKPOINT=$(gsd_run query uat.render-checkpoint --file "$uat_path" --raw) if [[ "$CHECKPOINT" == @file:* ]]; then CHECKPOINT=$(cat "${CHECKPOINT#@file:}"); fi ``` @@ -437,7 +426,7 @@ Clear Current Test section: Commit the UAT file: ```bash -$GSD_SDK query commit "test({phase_num}): complete UAT - {passed} passed, {issues} issues" --files ".planning/phases/XX-name/{phase_num}-UAT.md" +gsd_run query commit "test({phase_num}): complete UAT - {passed} passed, {issues} issues" --files ".planning/phases/XX-name/{phase_num}-UAT.md" ``` Present summary: @@ -461,7 +450,7 @@ Present summary: **If issues == 0:** ```bash -SECURITY_CFG=$($GSD_SDK query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true") +SECURITY_CFG=$(gsd_run query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true") SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1) ``` @@ -510,7 +499,7 @@ Run phase artifact scan to surface any open items before marking phase verified: `audit-open` is CJS-only until registered on `gsd-tools.cjs query`: ```bash -$GSD_SDK query audit-open --json +gsd_run query audit-open --json ``` Parse the JSON output. For the CURRENT PHASE ONLY, surface: diff --git a/package.json b/package.json index a652cb15c..1b88044ec 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "fallow": "^2.70.0" }, "scripts": { + "sync:launcher": "node scripts/sync-runtime-launcher.cjs", "check:env": "bash scripts/check-env.sh", "check:alias-drift": "node scripts/check-alias-drift.cjs", "check:integrity": "./scripts/check-npm-integrity.sh", diff --git a/scripts/sync-runtime-launcher.cjs b/scripts/sync-runtime-launcher.cjs new file mode 100644 index 000000000..173179b0b --- /dev/null +++ b/scripts/sync-runtime-launcher.cjs @@ -0,0 +1,402 @@ +'use strict'; +/** + * sync-runtime-launcher.cjs + * + * Idempotent transform: for every get-shit-done/workflows/*.md (and subdirs), + * rewrite all bash/sh/shell fenced blocks to: + * 1. Strip ALL old resolver forms from every bash block (GSD_TOOLS=, + * GSD_SDK=, the if/elif/else/fi resolver, _GSD_SHIM_NAME=, and any + * previously-inserted gsd_run preamble). + * 2. Replace $GSD_SDK tokens with gsd_run (idempotent). + * 3. Insert the canonical preamble at the TOP of ONLY the FIRST bash block + * (document order) that contains a gsd_run call. All other bash blocks + * keep their gsd_run calls with NO preamble. (Define once per file, + * use across blocks — original footprint.) + * + * Run: node scripts/sync-runtime-launcher.cjs + */ + +const fs = require('node:fs'); +const path = require('node:path'); + +const WORKFLOWS_DIR = path.join(__dirname, '..', 'get-shit-done', 'workflows'); +const SNIPPET_FILE = path.join(WORKFLOWS_DIR, '_runtime-launcher.snippet.sh'); + +// Read canonical preamble (full content of snippet file) +function loadPreamble() { + const raw = fs.readFileSync(SNIPPET_FILE, 'utf8'); + const lines = raw.split('\n'); + // Strip trailing empty line (trailing newline produces an empty last element) + const content = lines[lines.length - 1] === '' ? lines.slice(0, -1) : lines; + if (content.length < 1) { + throw new Error(`_runtime-launcher.snippet.sh is empty`); + } + return content; +} + +/** + * Collect all .md files recursively. + */ +function collectFiles(dir) { + const results = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + results.push(...collectFiles(full)); + } else if (entry.isFile() && entry.name.endsWith('.md')) { + results.push(full); + } + } + return results; +} + +/** + * Given the lines of a bash block (without fence markers), strip all resolver + * boilerplate (old and new preamble forms) and replace $GSD_SDK tokens. + * Does NOT insert preamble — that is done by the file-level transform. + * + * Returns the stripped lines array. + */ +function stripAndReplace(lines, preamble) { + let result = lines.slice(); + + // Step 1: Remove ALL resolver boilerplate lines (including existing preamble). + result = removeResolverLines(result, preamble); + + // Step 2: Replace $GSD_SDK tokens with gsd_run + result = result.map((line) => replaceGsdSdk(line)); + + return result; +} + +/** + * Remove resolver boilerplate lines from a block. + * + * Patterns to remove: + * A) Multi-line if block: + * GSD_TOOLS="...gsd-tools.cjs" (or ...${_GSD_SHIM_NAME}) + * if [ -f "$GSD_TOOLS" ]; then + * ... + * fi + * + * B) One-liner form: + * GSD_TOOLS=...; if [ -f "$GSD_TOOLS" ]; then GSD_SDK=...; elif ...; else ...; fi + * + * C) _GSD_SHIM_NAME= line + * + * D) Bare GSD_SDK= line + * + * E) The canonical preamble comment line (so we strip old inserted preambles too) + * + * F) The gsd_run() function definitions that are part of the preamble + * (so previously-inserted preambles are stripped and will be re-inserted + * exactly once at the right location) + */ +function removeResolverLines(lines, preamble) { + const result = []; + let i = 0; + + // Build a set of preamble lines for fast lookup (to strip previously-inserted preambles) + const preambleLineSet = new Set(preamble); + + while (i < lines.length) { + const line = lines[i]; + const trimmed = line.trim(); + + // B) One-liner form: GSD_TOOLS=... ; if ... GSD_SDK=... fi + if ( + /^GSD_TOOLS=.*gsd-tools\.cjs.*;\s*if\s+\[/.test(trimmed) || + /^GSD_TOOLS=.*\/\$\{_GSD_SHIM_NAME\}.*;\s*if\s+\[/.test(trimmed) + ) { + // Skip the whole one-liner, and any adjacent SDK comment above it + const lastIdx = result.length - 1; + if (lastIdx >= 0 && isSdkComment(result[lastIdx])) { + result.pop(); + } + i++; + continue; + } + + // C) _GSD_SHIM_NAME= line + if (/^_GSD_SHIM_NAME=/.test(trimmed)) { + // Check if there's a canonical preamble comment just before it + const lastIdx = result.length - 1; + if (lastIdx >= 0 && isCanonicalPreambleComment(result[lastIdx])) { + result.pop(); + } else if (lastIdx >= 0 && isSdkComment(result[lastIdx])) { + result.pop(); + } + i++; + continue; + } + + // A) Multi-line form: starts with GSD_TOOLS=...gsd-tools.cjs or GSD_TOOLS=...${_GSD_SHIM_NAME} + if ( + /^GSD_TOOLS=.*gsd-tools\.cjs"$/.test(trimmed) || + /^GSD_TOOLS=.*\/\$\{_GSD_SHIM_NAME\}"$/.test(trimmed) + ) { + // Check if there's a canonical preamble comment just before it (preamble already installed) + // or an old SDK comment — either way, remove the whole block + const lastIdx = result.length - 1; + if (lastIdx >= 0 && (isCanonicalPreambleComment(result[lastIdx]) || isSdkComment(result[lastIdx]))) { + result.pop(); + } + + // Consume the if block that follows (if it exists) + const ahead = lines[i + 1] ? lines[i + 1].trim() : ''; + if (/^if\s+\[\s+-f\s+"\$GSD_TOOLS"\s*\]/.test(ahead)) { + // Consume until matching `fi` + i += 2; // skip GSD_TOOLS= and `if [...]` + let depth = 1; + while (i < lines.length && depth > 0) { + const t = lines[i].trim(); + if (/^if\s+/.test(t)) depth++; + if (/^fi(\s|$)/.test(t)) { + depth--; + if (depth === 0) { + i++; + break; + } + } + i++; + } + // After fi, skip a blank line if present + if (i < lines.length && lines[i].trim() === '') { + i++; + } + continue; + } else { + // Just skip the GSD_TOOLS= line + i++; + continue; + } + } + + // D) Bare GSD_SDK= line (not inside an if block, defensive) + if (/^GSD_SDK=/.test(trimmed) && !/gsd_run/.test(trimmed)) { + i++; + continue; + } + + // E+F) Strip lines that are part of the canonical preamble (to remove previously-inserted preambles). + // We match the canonical preamble comment, _GSD_SHIM_NAME (handled above at C), + // and gsd_run() function definition lines. + if (isCanonicalPreambleComment(trimmed.startsWith('#') ? line : '')) { + // Start of a previously-inserted canonical preamble — skip preamble lines + // by consuming lines that match the preamble array in order. + // Check how many consecutive lines match the preamble. + let matchLen = 0; + for (let p = 0; p < preamble.length; p++) { + if (lines[i + p] === preamble[p]) { + matchLen++; + } else { + break; + } + } + if (matchLen === preamble.length) { + // Exact preamble match — skip all preamble lines + i += matchLen; + // Skip trailing blank line if present + if (i < lines.length && lines[i].trim() === '') { + i++; + } + continue; + } + // Partial match or just the comment — still remove the comment line + i++; + continue; + } + + result.push(line); + i++; + } + + return result; +} + +/** + * Returns true if the line looks like an old SDK resolver comment (to be removed). + * Must NOT match the new canonical preamble comment. + */ +function isSdkComment(line) { + // The new canonical preamble comment starts with "# Runtime launcher:" — preserve it. + if (isCanonicalPreambleComment(line)) return false; + return /^\s*#\s*SDK resolution/.test(line) || /^\s*#.*prefer local.*gsd-tools/.test(line); +} + +/** + * Returns true if the line is the new canonical preamble comment. + * This identifies the start of the new multi-line canonical preamble. + */ +function isCanonicalPreambleComment(line) { + return /^\s*#\s*Runtime launcher:.*prefer local gsd-tools\.cjs.*installed gsd-tools on PATH/.test(line); +} + +/** + * Replace all $GSD_SDK tokens with gsd_run in a line. + * Handles: $GSD_SDK, ${GSD_SDK} forms. + */ +function replaceGsdSdk(line) { + return line.replace(/\$\{?GSD_SDK\}?(?=\s|$|;|"|'|\))/g, 'gsd_run'); +} + +/** + * Ensure the canonical preamble appears at the top of the block. + * Rules: + * - Skip leading blank lines + * - Check if preamble lines 0..N-1 already match at the scan position + * - If not, insert preamble at the top (after leading blanks) + * - Idempotent: if preamble already present, do nothing + */ +function insertPreamble(lines, preamble) { + // Find insertion point: skip blanks only + let scanIdx = 0; + while (scanIdx < lines.length && lines[scanIdx].trim() === '') scanIdx++; + + // Check if preamble already present at scanIdx + let alreadyPresent = preamble.length > 0; + for (let p = 0; p < preamble.length; p++) { + if (lines[scanIdx + p] !== preamble[p]) { + alreadyPresent = false; + break; + } + } + + if (alreadyPresent) return lines; // idempotent + + // Insert preamble at scanIdx (after leading blanks) + const insertAt = scanIdx; + const before = lines.slice(0, insertAt); + const after = lines.slice(insertAt); + + return [...before, ...preamble, ...after]; +} + +/** + * Transform a single markdown file's content. + * Returns new content string, or null if no changes needed. + * + * Strategy: + * 1. Parse all shell blocks, strip resolver boilerplate from each. + * 2. Find the FIRST block (document order) that has a gsd_run call. + * 3. Insert preamble into that block only. + * 4. Reconstruct the file. + * + * Handles both column-0 fences (```bash) and indented fences ( ```bash). + */ +function transformFile(content, preamble) { + const allLines = content.split('\n'); + + // --- Pass 1: identify all shell blocks and their positions --- + // Each entry: { openIdx, closeIdx, blockLines, isShell } + // We'll reconstruct by replacing block lines in-place. + + const shellBlockRanges = []; // { openLineIdx, contentStart, contentEnd, closingLineIdx } + let i = 0; + + while (i < allLines.length) { + const line = allLines[i]; + const fenceOpen = line.match(/^(\s*)```(\w+)?\s*$/); + if (!fenceOpen) { i++; continue; } + + const indent = fenceOpen[1]; + const lang = (fenceOpen[2] || '').toLowerCase(); + const isShellBlock = ['bash', 'sh', 'shell', 'zsh', ''].includes(lang); + const closingPattern = new RegExp('^' + escapeRegExp(indent) + '```\\s*$'); + + const openLineIdx = i; + i++; + const contentStart = i; + + while (i < allLines.length && !closingPattern.test(allLines[i])) { + i++; + } + const contentEnd = i; // exclusive + const closingLineIdx = i < allLines.length ? i : -1; + if (i < allLines.length) i++; + + if (isShellBlock) { + shellBlockRanges.push({ openLineIdx, contentStart, contentEnd, closingLineIdx }); + } + } + + if (shellBlockRanges.length === 0) return null; + + // --- Pass 2: transform each block --- + // Build a new lines array by splicing in transformed block contents. + // Process ranges in reverse order so indices stay valid. + + const outputLines = allLines.slice(); + let changed = false; + let firstGsdRunBlockIdx = -1; // index into shellBlockRanges of the first gsd_run block (after strip) + + // First: strip + replace in all blocks, find first gsd_run block + const strippedBlocks = shellBlockRanges.map((range) => { + const blockLines = outputLines.slice(range.contentStart, range.contentEnd); + const stripped = stripAndReplace(blockLines, preamble); + return stripped; + }); + + // Find the first block that has a gsd_run call (after stripping) + for (let bi = 0; bi < strippedBlocks.length; bi++) { + if (strippedBlocks[bi].some((l) => /\bgsd_run\b/.test(l))) { + firstGsdRunBlockIdx = bi; + break; + } + } + + // Insert preamble into the first gsd_run block only + const finalBlocks = strippedBlocks.map((stripped, bi) => { + if (bi === firstGsdRunBlockIdx) { + return insertPreamble(stripped, preamble); + } + return stripped; + }); + + // --- Pass 3: splice back into output (reverse order to preserve indices) --- + for (let bi = shellBlockRanges.length - 1; bi >= 0; bi--) { + const range = shellBlockRanges[bi]; + const originalBlock = allLines.slice(range.contentStart, range.contentEnd); + const newBlock = finalBlocks[bi]; + + if (originalBlock.join('\n') !== newBlock.join('\n')) { + changed = true; + } + + // Replace contentStart..contentEnd with newBlock + outputLines.splice(range.contentStart, range.contentEnd - range.contentStart, ...newBlock); + } + + if (!changed) return null; + + return outputLines.join('\n'); +} + +function escapeRegExp(str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); +} + +// Main +function main() { + const preamble = loadPreamble(); + const files = collectFiles(WORKFLOWS_DIR); + + let transformedCount = 0; + let unchangedCount = 0; + + for (const f of files) { + const content = fs.readFileSync(f, 'utf8'); + const result = transformFile(content, preamble); + if (result !== null) { + fs.writeFileSync(f, result, 'utf8'); + transformedCount++; + console.log(`transformed: ${path.relative(WORKFLOWS_DIR, f)}`); + } else { + unchangedCount++; + } + } + + console.log(`\nDone. ${transformedCount} files transformed, ${unchangedCount} unchanged.`); +} + +main(); diff --git a/tests/bug-2384-post-merge-deletion-audit.test.cjs b/tests/bug-2384-post-merge-deletion-audit.test.cjs index d4705e35c..42c3db633 100644 --- a/tests/bug-2384-post-merge-deletion-audit.test.cjs +++ b/tests/bug-2384-post-merge-deletion-audit.test.cjs @@ -38,7 +38,7 @@ function parseExecutePhaseContract(filePath) { delegatesToCleanupWave: lines.some(l => l.includes('worktree.cleanup-wave')), // Does the cleanup-wave invocation use || exit 1 (fail-closed)? cleanupWaveFailClosed: lines.some( - l => /\$GSD_SDK query worktree\.cleanup-wave.*\|\| exit 1/.test(l), + l => /gsd_run query worktree\.cleanup-wave.*\|\| exit 1/.test(l), ), // Does the workflow export/reference WAVE_WORKTREE_MANIFEST for the SDK? passesWaveManifest: lines.some(l => l.includes('WAVE_WORKTREE_MANIFEST')), @@ -54,7 +54,7 @@ describe('execute-phase.md — post-merge deletion audit (#2384)', () => { // The workflow delegates to the SDK rather than duplicating the check inline. assert.ok( contract.delegatesToCleanupWave, - 'execute-phase.md must delegate to $GSD_SDK query worktree.cleanup-wave (#2384/#3797)', + 'execute-phase.md must delegate to gsd_run query worktree.cleanup-wave (#2384/#3797)', ); }); diff --git a/tests/bug-2661-roadmap-sync-parallel.test.cjs b/tests/bug-2661-roadmap-sync-parallel.test.cjs index 7e23e4a51..f0abc803e 100644 --- a/tests/bug-2661-roadmap-sync-parallel.test.cjs +++ b/tests/bug-2661-roadmap-sync-parallel.test.cjs @@ -90,18 +90,18 @@ describe('bug #2661: execute-plan.md update_roadmap gating', () => { test('update_roadmap step exists and invokes roadmap.update-plan-progress', () => { assert.ok(stepMatch, 'update_roadmap step must exist'); - // After #3797 architectural fix, callsites use $GSD_SDK — accept either form + // After #3797 architectural fix, callsites use gsd_run assert.ok( - /(?:\$GSD_SDK|gsd-sdk) query roadmap\.update-plan-progress/.test(step), + /gsd_run query roadmap\.update-plan-progress/.test(step), 'update_roadmap must still invoke roadmap.update-plan-progress' ); }); test('use_worktrees: false mode — sync call is gated to fire (the #2661 reproducer)', () => { // The non-worktree branch must contain the sync call. - // After #3797 architectural fix, callsites use $GSD_SDK — accept either form + // After #3797 architectural fix, callsites use gsd_run assert.ok( - /IS_WORKTREE.*!=.*"true"[\s\S]*?(?:\$GSD_SDK|gsd-sdk) query roadmap\.update-plan-progress/.test(step), + /IS_WORKTREE.*!=.*"true"[\s\S]*?gsd_run query roadmap\.update-plan-progress/.test(step), 'sync call must execute on the IS_WORKTREE != "true" branch (use_worktrees: false)' ); }); @@ -119,9 +119,9 @@ describe('bug #2661: execute-plan.md update_roadmap gating', () => { 'bash block must include the IS_WORKTREE worktree-detection check' ); // Sync call must appear after the guard check, not before. - // After #3797 architectural fix, callsites use $GSD_SDK — accept either form + // After #3797 architectural fix, callsites use gsd_run const guardIdx = bash.search(/if \[ "\$IS_WORKTREE" != "true" \]/); - const callIdx = bash.search(/(?:\$GSD_SDK|gsd-sdk) query roadmap\.update-plan-progress/); + const callIdx = bash.search(/gsd_run query roadmap\.update-plan-progress/); assert.ok(guardIdx >= 0, 'guard must be present'); assert.ok(callIdx > guardIdx, 'sync call must appear inside the use_worktrees: false guard, not before/outside it'); diff --git a/tests/bug-2838-summary-rescue-gitignored-planning.test.cjs b/tests/bug-2838-summary-rescue-gitignored-planning.test.cjs index b37ce958a..e65810c7d 100644 --- a/tests/bug-2838-summary-rescue-gitignored-planning.test.cjs +++ b/tests/bug-2838-summary-rescue-gitignored-planning.test.cjs @@ -41,7 +41,7 @@ function parseWorkflowContract(filePath) { delegatesToCleanupWave: lines.some(l => l.includes('worktree.cleanup-wave')), // Does the cleanup-wave invocation use || exit 1 (fail-closed)? cleanupWaveFailClosed: lines.some( - l => /\$GSD_SDK query worktree\.cleanup-wave.*\|\| exit 1/.test(l), + l => /gsd_run query worktree\.cleanup-wave.*\|\| exit 1/.test(l), ), // Does the workflow still contain the broken ls-files --exclude-standard rescue form? hasBrokenLsFilesForm: lines.some( diff --git a/tests/bug-3360-codex-execute-phase-worktrees.test.cjs b/tests/bug-3360-codex-execute-phase-worktrees.test.cjs index 041954002..db312edff 100644 --- a/tests/bug-3360-codex-execute-phase-worktrees.test.cjs +++ b/tests/bug-3360-codex-execute-phase-worktrees.test.cjs @@ -26,8 +26,8 @@ function parseWorkflowSteps(content) { const body = match[2]; return { name: match[1], - // After #3797 architectural fix, callsites use $GSD_SDK — accept either form - readsRuntimeConfig: body.includes('RUNTIME=$($GSD_SDK query config-get runtime --default claude') || body.includes('RUNTIME=$(gsd-sdk query config-get runtime --default claude'), + // After #3797 architectural fix, callsites use gsd_run + readsRuntimeConfig: body.includes('RUNTIME=$(gsd_run query config-get runtime --default claude'), codexWorktreeGuard: body.includes('Codex execute-phase worktree isolation is unsupported'), worktreeDispatchGuidance: body.includes('isolation="worktree"'), }; diff --git a/tests/bug-3381-verify-work-workstream.test.cjs b/tests/bug-3381-verify-work-workstream.test.cjs index b6f13ecb5..596d40251 100644 --- a/tests/bug-3381-verify-work-workstream.test.cjs +++ b/tests/bug-3381-verify-work-workstream.test.cjs @@ -30,20 +30,20 @@ describe('bug #3381: verify-work forwards workstream context', () => { /PHASE_ARG=\$\(echo "\$ARGUMENTS" \| sed -E 's\/--ws\[\[:space:\]\]\+\[\^\[:space:\]\]\+\/\/g' \| xargs\)/, 'verify-work must derive PHASE_ARG after removing --ws', ); - // After #3797 architectural fix, callsites use $GSD_SDK — accept either bare or $GSD_SDK form + // After #3797 architectural fix, callsites use gsd_run assert.match( workflow, - /(?:\$GSD_SDK|gsd-sdk) query init\.verify-work "\$\{PHASE_ARG\}" \$\{GSD_WS\}/, + /gsd_run query init\.verify-work "\$\{PHASE_ARG\}" \$\{GSD_WS\}/, 'init.verify-work must receive GSD_WS so phase_dir resolves in workstreams', ); assert.match( workflow, - /(?:\$GSD_SDK|gsd-sdk) query phase\.mvp-mode "\$\{phase_number\}" \$\{GSD_WS\} --pick active/, + /gsd_run query phase\.mvp-mode "\$\{phase_number\}" \$\{GSD_WS\} --pick active/, 'phase.mvp-mode must receive GSD_WS so roadmap mode is workstream-scoped', ); assert.match( workflow, - /(?:\$GSD_SDK|gsd-sdk) query roadmap\.get-phase "\$\{phase_number\}" \$\{GSD_WS\} --pick goal/, + /gsd_run query roadmap\.get-phase "\$\{phase_number\}" \$\{GSD_WS\} --pick goal/, 'roadmap.get-phase must receive GSD_WS so goals are workstream-scoped', ); }); diff --git a/tests/bug-3521-quick-cleanup-cwd-pin.test.cjs b/tests/bug-3521-quick-cleanup-cwd-pin.test.cjs index 92c117a94..49bd100ef 100644 --- a/tests/bug-3521-quick-cleanup-cwd-pin.test.cjs +++ b/tests/bug-3521-quick-cleanup-cwd-pin.test.cjs @@ -31,12 +31,12 @@ describe('bug #3521 — quick.md post-merge cleanup CWD safety (via SDK delegati test('quick.md cleanup delegates CWD-safe worktree cleanup to SDK (worktree.cleanup-wave)', () => { const content = readQuickMd(); - // After #3797: quick.md delegates to $GSD_SDK query worktree.cleanup-wave + // After #3797: quick.md delegates to gsd_run query worktree.cleanup-wave // which handles CWD pinning, STATE.md backup, deletion guards, and branch // cleanup internally. The manual shell loop has been removed. assert.ok( content.includes('worktree.cleanup-wave'), - 'quick.md must delegate cleanup to $GSD_SDK query worktree.cleanup-wave (#3797)', + 'quick.md must delegate cleanup to gsd_run query worktree.cleanup-wave (#3797)', ); }); @@ -44,11 +44,11 @@ describe('bug #3521 — quick.md post-merge cleanup CWD safety (via SDK delegati const content = readQuickMd(); // The || exit 1 enforces fail-closed: SDK safety refusals (e.g. branch // drift detection from #3174) surface immediately rather than being swallowed. - // This is the equivalent of the pre-#3797 `gsd-sdk query ... || exit 1` in the + // This is the equivalent of the pre-#3797 `gsd_run query ... || exit 1` in the // `if command -v gsd-sdk` branch. assert.match( content, - /\$GSD_SDK query worktree\.cleanup-wave.*\|\| exit 1/, + /gsd_run query worktree\.cleanup-wave.*\|\| exit 1/, 'quick.md cleanup-wave must use || exit 1 — fail-closed for safety refusals (#3521/#3797)', ); }); diff --git a/tests/bug-3668-workflow-runtime-resolution.test.cjs b/tests/bug-3668-workflow-runtime-resolution.test.cjs index db4202fac..284816af8 100644 --- a/tests/bug-3668-workflow-runtime-resolution.test.cjs +++ b/tests/bug-3668-workflow-runtime-resolution.test.cjs @@ -16,14 +16,63 @@ const { execFileSync } = require('node:child_process'); const WORKFLOW_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'next.md'); +/** + * Extract the canonical runtime resolver snippet from next.md. + * + * Supports two forms: + * - One-line form (canonical): the entire launcher is a single line starting with + * `_GSD_SHIM_NAME="gsd-tools.cjs";` — return that line directly. + * - Multi-line form (legacy): starts with a `# Runtime launcher:` comment or a + * `_GSD_SHIM_NAME=` line followed by separate GSD_TOOLS= and if/elif/else/fi + * lines — scan to the closing `fi`. + */ function extractResolverSnippet() { const content = fs.readFileSync(WORKFLOW_PATH, 'utf8'); const lines = content.split(/\r?\n/); - const start = lines.findIndex((line) => line.includes('SDK resolution: prefer local gsd-tools.cjs')); - assert.notEqual(start, -1, 'next.md must contain the SDK resolution snippet'); - const end = lines.findIndex((line, index) => index > start && line === 'fi'); - assert.notEqual(end, -1, 'SDK resolution snippet must end with fi'); + // Find the canonical preamble — prefer _GSD_SHIM_NAME= line (handles both forms) + let start = lines.findIndex((line) => /^_GSD_SHIM_NAME=/.test(line.trim())); + if (start === -1) { + // Fallback: canonical preamble comment (multi-line legacy form) + start = lines.findIndex((line) => + /^\s*#\s*Runtime launcher:.*prefer local gsd-tools\.cjs.*installed gsd-tools on PATH/.test(line) + ); + } + if (start === -1) { + // Last fallback: GSD_TOOLS= with RUNTIME_DIR + start = lines.findIndex((line) => line.includes('GSD_TOOLS="${RUNTIME_DIR:-')); + } + assert.notEqual( + start, + -1, + 'next.md must contain the canonical runtime preamble ' + + '(_GSD_SHIM_NAME= line, # Runtime launcher: comment, or GSD_TOOLS= line with RUNTIME_DIR)' + ); + + // One-line form: the entire launcher (including `if` and `fi`) is on a single line. + // Detect by checking whether the start line contains a semicolon-separated `if` and `fi`. + const startLine = lines[start].trim(); + if (/^_GSD_SHIM_NAME=.*;\s*if\s+\[.*\bfi$/.test(startLine)) { + // Single-line canonical launcher — return it as-is + return startLine; + } + + // Multi-line form: scan forward from start to the closing `fi`, tracking if-depth + let depth = 0; + let end = -1; + for (let i = start; i < lines.length; i++) { + const t = lines[i].trim(); + if (/^if\s+/.test(t)) depth++; + if (/^fi(\s|$)/.test(t)) { + depth--; + if (depth === 0) { + end = i; + break; + } + } + } + assert.notEqual(end, -1, 'runtime preamble must end with a closing `fi`'); + return lines.slice(start, end + 1).join('\n'); } @@ -36,7 +85,7 @@ function runResolver({ cwd, runtimeDir, pathDir }) { 'set -e', extractResolverSnippet(), 'printf "GSD_TOOLS=%s\\n" "$GSD_TOOLS"', - '$GSD_SDK query state.json', + 'gsd_run query state.json', ].join('\n'); return execFileSync('bash', ['-c', script], { @@ -57,18 +106,28 @@ function writeExecutable(file, content) { describe('bug-3668: workflow SDK resolver supports installed user projects', () => { test('falls back to installed gsd-tools when project-local runtime copy is absent', () => { + // Bug #3668: when a user project has no local get-shit-done/bin/gsd-tools.cjs, + // the elif branch must resolve to the gsd-tools binary on PATH. + // RUNTIME_DIR points to a dir that has no gsd-tools.cjs. const tmp = makeTempDir(); const project = path.join(tmp, 'user-project'); - const bin = path.join(tmp, 'bin'); + const runtimeNoLocal = path.join(tmp, 'runtime-no-local'); + const pathBin = path.join(tmp, 'bin'); fs.mkdirSync(project, { recursive: true }); - writeExecutable(path.join(bin, 'gsd-tools'), '#!/bin/sh\nprintf "installed:%s %s\\n" "$1" "$2"\n'); + fs.mkdirSync(runtimeNoLocal, { recursive: true }); - const output = runResolver({ cwd: project, pathDir: bin }); + // Place gsd-tools stub on PATH (installed binary) + writeExecutable( + path.join(pathBin, 'gsd-tools'), + '#!/bin/sh\nprintf "installed:%s %s\\n" "$1" "$2"\n', + ); - // Normalize separators so the assertion works on Windows (Git bash emits POSIX paths) - const norm = output.replace(/\\/g, '/'); - // subtest 1: the resolved bin is the PATH-fallback gsd-tools (suffix /bin/gsd-tools, no .cjs) - assert.match(norm, /GSD_TOOLS=\S*\/bin\/gsd-tools(?:\s|$)/m); + // NO get-shit-done/bin/gsd-tools.cjs in runtimeNoLocal + const output = runResolver({ cwd: project, runtimeDir: runtimeNoLocal, pathDir: pathBin }); + + // GSD_TOOLS must have been reassigned to the PATH binary (not the missing .cjs) + assert.match(output, /GSD_TOOLS=.+gsd-tools(?:\s|$)/m); + // The PATH stub must have been invoked assert.match(output, /installed:query state\.json/); }); @@ -78,7 +137,7 @@ describe('bug-3668: workflow SDK resolver supports installed user projects', () const runtime = path.join(tmp, 'runtime'); const pathBin = path.join(tmp, 'bin'); fs.mkdirSync(project, { recursive: true }); - writeExecutable(path.join(pathBin, 'gsd-tools'), '#!/bin/sh\nprintf "installed:%s %s\\n" "$1" "$2"\n'); + writeExecutable(path.join(pathBin, 'gsd-tools'), '#!/bin/sh\nprintf "path-installed:%s %s\\n" "$1" "$2"\n'); writeExecutable( path.join(runtime, 'get-shit-done', 'bin', 'gsd-tools.cjs'), '#!/usr/bin/env node\nconsole.log(`runtime:${process.argv[2]} ${process.argv[3]}`);\n', @@ -88,9 +147,10 @@ describe('bug-3668: workflow SDK resolver supports installed user projects', () // Normalize separators so the assertion works on Windows (Git bash emits POSIX paths) const norm = output.replace(/\\/g, '/'); - // subtest 2: the resolved bin is the RUNTIME_DIR local runtime (suffix /get-shit-done/bin/gsd-tools.cjs) - assert.match(norm, /GSD_TOOLS=\S*\/get-shit-done\/bin\/gsd-tools\.cjs(?:\s|$)/m); + // The resolved bin is the RUNTIME_DIR local runtime (suffix /get-shit-done/bin/gsd-tools.cjs) + // Use .+ instead of \S* to handle paths with spaces (e.g. /Volumes/Mini Me/...) + assert.match(norm, /GSD_TOOLS=.+\/get-shit-done\/bin\/gsd-tools\.cjs(?:\s|$)/m); assert.match(output, /runtime:query state\.json/); - assert.doesNotMatch(output, /installed:query state\.json/); + assert.doesNotMatch(output, /path-installed:query state\.json/); }); }); diff --git a/tests/enh-2433-todo-phase-linking.test.cjs b/tests/enh-2433-todo-phase-linking.test.cjs index 25ff99424..ba6651b98 100644 --- a/tests/enh-2433-todo-phase-linking.test.cjs +++ b/tests/enh-2433-todo-phase-linking.test.cjs @@ -44,8 +44,8 @@ test('new-milestone.md: todo linking is best-effort and leaves unmatched todos u }); test('new-milestone.md: step 10.5 commits tagged todos', () => { - // After #3797 architectural fix, callsites use $GSD_SDK — accept either form - assert.ok(NEW_MILESTONE.includes('$GSD_SDK query commit') || NEW_MILESTONE.includes('gsd-sdk query commit'), 'should commit tagged todos'); + // After #3797 architectural fix, callsites use gsd_run + assert.ok(NEW_MILESTONE.includes('gsd_run query commit'), 'should commit tagged todos'); assert.ok(NEW_MILESTONE.includes('resolves_phase after milestone'), 'commit message should mention resolves_phase'); }); diff --git a/tests/enh-2792-namespace-skills.test.cjs b/tests/enh-2792-namespace-skills.test.cjs index 2aaf43fdb..37e4d1a8e 100644 --- a/tests/enh-2792-namespace-skills.test.cjs +++ b/tests/enh-2792-namespace-skills.test.cjs @@ -197,11 +197,11 @@ describe('gsd-health --context flag is wired into command + workflow', () => { const stepMatch = raw.match(/([\s\S]*?)<\/step>/); assert.ok(stepMatch, 'context_check step must be a closed ... block'); const stepBody = stepMatch[1]; - // After #3797 architectural fix, callsites use $GSD_SDK — accept either form + // After #3797 architectural fix, callsites use gsd_run assert.match( stepBody, - /(?:\$GSD_SDK|gsd-sdk)\s+query\s+validate\.context/, - 'context_check must call `gsd-sdk query validate.context`', + /gsd_run\s+query\s+validate\.context/, + 'context_check must call `gsd_run query validate.context`', ); assert.match(stepBody, /--tokens-used/, 'context_check must pass --tokens-used'); assert.match(stepBody, /--context-window/, 'context_check must pass --context-window'); diff --git a/tests/runtime-launcher-parity.test.cjs b/tests/runtime-launcher-parity.test.cjs new file mode 100644 index 000000000..393b88485 --- /dev/null +++ b/tests/runtime-launcher-parity.test.cjs @@ -0,0 +1,385 @@ +'use strict'; +/** + * Parity test for bug #373: space-safe gsd_run launcher + * + * Asserts: + * (A) No retired GSD_SDK token remains in any workflow .md file. + * (B) Each workflow .md that uses gsd_run contains EXACTLY ONE canonical preamble + * (byte-equal to _runtime-launcher.snippet.sh), and it appears before the first + * gsd_run call. NOT every bash block — exactly one per file (define once, use + * across blocks — original footprint). + * (C) Space-safe behavioral: a RUNTIME_DIR path with spaces in it resolves + * and calls gsd-tools.cjs correctly (no word-split, no {}). + * (D) Loud guard behavioral: missing gsd-tools.cjs exits non-zero and emits + * "not found" to stderr. + * (E) PATH fallback behavioral: when no local gsd-tools.cjs, the elif branch + * resolves to the gsd-tools binary on PATH (#3668). + * (F) Regression locks: the snippet file contains no /gsd-tools substring; and + * no line in workflows/do.md matches /\/gsd[:-][a-z]/ (dispatcher-parity + * scanner must not read the preamble as a slash-command stub). + */ + +// allow-test-rule: structural parity/drift guard — asserts literal presence/absence of the canonical gsd_run launcher and the retired $GSD_SDK / `/gsd-tools` tokens across workflow markdown; there is no typed IR for "this source file does not contain substring X". + +const { describe, test } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const os = require('node:os'); +const { execFileSync } = require('node:child_process'); + +const WORKFLOWS_DIR = path.join(__dirname, '..', 'get-shit-done', 'workflows'); +const SNIPPET_FILE = path.join(WORKFLOWS_DIR, '_runtime-launcher.snippet.sh'); + +/** + * Read the canonical preamble from the snippet file (all lines, no trailing newline). + */ +function expectedPreamble() { + const raw = fs.readFileSync(SNIPPET_FILE, 'utf8'); + const lines = raw.split('\n'); + // Strip trailing empty element produced by a trailing newline. + const content = lines[lines.length - 1] === '' ? lines.slice(0, -1) : lines; + assert.ok(content.length >= 1, `_runtime-launcher.snippet.sh must not be empty`); + return content; // array of strings +} + +/** + * Extract all bash/sh/shell fenced blocks from markdown content. + * Returns array of { index, lines } where index is 0-based block count, + * and lines is the array of content lines (without the fence markers). + * + * Handles both column-0 fences (```bash) and indented fences ( ```bash). + */ +function extractShellBlocks(content) { + const allLines = content.split('\n'); + const blocks = []; + let inBlock = false; + let blockLang = null; + let blockLines = []; + let blockIndex = 0; + let blockIndent = ''; + let closingPattern = null; + + for (let i = 0; i < allLines.length; i++) { + const line = allLines[i]; + if (!inBlock) { + const fenceOpen = line.match(/^(\s*)```(\w+)?\s*$/); + if (fenceOpen) { + inBlock = true; + blockIndent = fenceOpen[1]; + blockLang = (fenceOpen[2] || '').toLowerCase(); + blockLines = []; + // Closing pattern: same indent prefix + ``` + closingPattern = new RegExp('^' + blockIndent.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '```\\s*$'); + continue; + } + } else { + if (closingPattern.test(line)) { + if (['bash', 'sh', 'shell', 'zsh', ''].includes(blockLang)) { + blocks.push({ index: blockIndex, lang: blockLang, lines: blockLines }); + blockIndex++; + } + inBlock = false; + blockLang = null; + blockLines = []; + blockIndent = ''; + closingPattern = null; + continue; + } + blockLines.push(line); + } + } + return blocks; +} + +/** + * Collect all workflow .md files recursively under WORKFLOWS_DIR. + * Excludes _runtime-launcher.snippet.sh (not a markdown file). + */ +function collectWorkflowFiles() { + const results = []; + function walk(dir) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + walk(full); + } else if (entry.isFile() && entry.name.endsWith('.md')) { + results.push(full); + } + } + } + walk(WORKFLOWS_DIR); + return results; +} + +describe('runtime-launcher-parity (#373)', () => { + // ─── (A) No retired GSD_SDK token ──────────────────────────────────────── + test('(A) no GSD_SDK token in any workflow .md file', () => { + const files = collectWorkflowFiles(); + assert.ok(files.length > 0, 'expected at least one workflow .md file'); + + const offending = []; + for (const f of files) { + const content = fs.readFileSync(f, 'utf8'); + if (content.includes('GSD_SDK')) { + offending.push(path.relative(WORKFLOWS_DIR, f)); + } + } + + assert.deepStrictEqual( + offending, + [], + 'Found GSD_SDK (retired token) in workflow files — run `node scripts/sync-runtime-launcher.cjs` to fix:\n' + + offending.join('\n'), + ); + }); + + // ─── (B) Exactly ONE canonical preamble per using file ─────────────────── + test('(B) each workflow .md using gsd_run contains exactly ONE canonical preamble, before the first gsd_run call', () => { + const preamble = expectedPreamble(); + const preambleStr = preamble.join('\n'); + const files = collectWorkflowFiles(); + assert.ok(files.length > 0, 'expected at least one workflow .md file'); + + const violations = []; + + for (const f of files) { + const rel = path.relative(WORKFLOWS_DIR, f); + const content = fs.readFileSync(f, 'utf8'); + const blocks = extractShellBlocks(content); + + // Collect all block lines in document order for flat analysis + const allBlockLines = []; + for (const blk of blocks) { + allBlockLines.push(...blk.lines); + } + + // Does this file use gsd_run at all? + const fileHasGsdRun = allBlockLines.some((l) => /\bgsd_run\b/.test(l)); + if (!fileHasGsdRun) continue; + + // Count preamble occurrences across all shell content of this file + // Flatten all block lines with a separator so multi-block boundary doesn't create false match + const allContent = allBlockLines.join('\n'); + let preambleCount = 0; + let searchPos = 0; + while (true) { + const idx = allContent.indexOf(preambleStr, searchPos); + if (idx === -1) break; + preambleCount++; + searchPos = idx + preambleStr.length; + } + + if (preambleCount !== 1) { + violations.push( + `${rel}: expected exactly 1 canonical preamble occurrence in bash blocks, found ${preambleCount}. ` + + `Run \`node scripts/sync-runtime-launcher.cjs\` to fix.`, + ); + continue; + } + + // Verify preamble appears BEFORE the first gsd_run call (in document order) + // Find the line index of the preamble start vs the first gsd_run call in the flat content + const preamblePos = allContent.indexOf(preambleStr); + const firstGsdRunPos = allContent.search(/\bgsd_run\b/); + + // The first gsd_run WITHIN the preamble itself (the function definition) is fine. + // We need to verify that no gsd_run CALL (i.e. gsd_run used as a command, not in a + // function definition body) appears before the preamble starts. + // Simple check: preamble starts at or before the first gsd_run occurrence + if (preamblePos > firstGsdRunPos) { + violations.push( + `${rel}: preamble appears AFTER the first gsd_run reference — it must precede all gsd_run calls.`, + ); + } + } + + assert.deepStrictEqual( + violations, + [], + 'Files with gsd_run calls have wrong preamble count or ordering:\n' + + violations.join('\n---\n'), + ); + }); + + // ─── (C) Space-safe behavioral test ────────────────────────────────────── + test('(C) gsd_run works with a RUNTIME_DIR path containing spaces', () => { + // Create temp dir whose path contains a space + const base = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd 373 ')); + try { + const binDir = path.join(base, 'get-shit-done', 'bin'); + fs.mkdirSync(binDir, { recursive: true }); + + // Stub gsd-tools.cjs that prints its argv + const stub = path.join(binDir, 'gsd-tools.cjs'); + fs.writeFileSync(stub, '#!/usr/bin/env node\nconsole.log("STUB:" + process.argv.slice(2).join(","));\n'); + fs.chmodSync(stub, 0o755); + + // Build a shell script: set RUNTIME_DIR, source preamble, run gsd_run + const snippet = fs.readFileSync(SNIPPET_FILE, 'utf8'); + const scriptContent = + `export RUNTIME_DIR=${JSON.stringify(base)}\n` + + snippet + + `\ngsd_run query state.json\n`; + + const scriptPath = path.join(base, 'test-space.sh'); + fs.writeFileSync(scriptPath, scriptContent); + + const stdout = execFileSync('bash', [scriptPath], { encoding: 'utf8' }); + assert.ok( + stdout.includes('STUB:query,state.json'), + `Expected stdout to contain "STUB:query,state.json" but got: ${stdout.trim()}`, + ); + } finally { + fs.rmSync(base, { recursive: true, force: true }); + } + }); + + // ─── (D) Loud guard: missing runtime is fatal ───────────────────────────── + test('(D) missing gsd-tools.cjs and no PATH gsd-tools causes loud non-zero exit with "not found" on stderr', () => { + // Create temp dir with a space in the name, but NO gsd-tools.cjs. + // We ensure gsd-tools is not on PATH by prepending a dir that has no + // gsd-tools binary (system binaries remain on PATH so bash/node work). + const base = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd 373 notools ')); + // Place a no-op dir first in PATH; no gsd-tools stub there. + const noToolsBin = path.join(base, 'nobin'); + fs.mkdirSync(noToolsBin, { recursive: true }); + try { + const snippet = fs.readFileSync(SNIPPET_FILE, 'utf8'); + // The script must also unset any GSD_TOOLS env var that might leak in + const scriptContent = + `unset GSD_TOOLS\n` + + `export RUNTIME_DIR=${JSON.stringify(base)}\n` + + snippet + + `\ngsd_run query state.json\n`; + + const scriptPath = path.join(base, 'test-guard.sh'); + fs.writeFileSync(scriptPath, scriptContent); + + // Build a PATH that has noToolsBin first (no gsd-tools stub there) but retains + // system paths needed for bash. Exclude any PATH entry that contains a gsd-tools binary. + const systemPaths = (process.env.PATH || '/usr/bin:/bin') + .split(path.delimiter) + .filter((p) => { + try { fs.accessSync(path.join(p, 'gsd-tools'), fs.constants.X_OK); return false; } + catch { return true; } + }); + const isolatedPath = [noToolsBin, ...systemPaths].join(path.delimiter); + + let threw = false; + let stderrOutput = ''; + try { + execFileSync('bash', [scriptPath], { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + env: { ...process.env, PATH: isolatedPath }, + }); + } catch (err) { + threw = true; + stderrOutput = err.stderr || ''; + } + + assert.ok(threw, 'Expected the script to exit non-zero when gsd-tools.cjs is missing and gsd-tools is not on PATH'); + assert.ok( + stderrOutput.includes('not found') || stderrOutput.includes('ERROR'), + `Expected stderr to contain "not found" or "ERROR", got: ${stderrOutput.trim()}`, + ); + } finally { + fs.rmSync(base, { recursive: true, force: true }); + } + }); + + // ─── (E) PATH fallback behavioral (#3668) ──────────────────────────────── + test('(E) PATH fallback: uses installed gsd-tools when no local gsd-tools.cjs present', () => { + // Create a temp dir with NO local get-shit-done/bin/gsd-tools.cjs. + // Place an executable gsd-tools stub on a dedicated PATH dir. + // RUNTIME_DIR points somewhere that has no gsd-tools.cjs. + const base = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd 373 pathfb ')); + try { + const pathBinDir = path.join(base, 'bin'); + fs.mkdirSync(pathBinDir, { recursive: true }); + + // Stub installed gsd-tools binary that prints a marker + const stubPath = path.join(pathBinDir, 'gsd-tools'); + fs.writeFileSync(stubPath, '#!/bin/sh\necho "installed:$*"\n'); + fs.chmodSync(stubPath, 0o755); + + // RUNTIME_DIR points to base — no get-shit-done/bin/gsd-tools.cjs there + const snippet = fs.readFileSync(SNIPPET_FILE, 'utf8'); + const scriptContent = + `export RUNTIME_DIR=${JSON.stringify(base)}\n` + + snippet + + `\nprintf "GSD_TOOLS=%s\\n" "$GSD_TOOLS"\n` + + `gsd_run query state.json\n`; + + const scriptPath = path.join(base, 'test-pathfb.sh'); + fs.writeFileSync(scriptPath, scriptContent); + + const stdout = execFileSync('bash', [scriptPath], { + encoding: 'utf8', + env: { ...process.env, PATH: `${pathBinDir}${path.delimiter}${process.env.PATH || ''}` }, + }); + + // The PATH fallback must have resolved GSD_TOOLS to the stub binary. + // Normalize backslashes → forward slashes so the assertion works on Windows + // (git-bash emits POSIX paths while Node's os.tmpdir() returns the Windows form). + // Assert by suffix (/bin/gsd-tools, no .cjs extension) rather than absolute prefix + // because the prefix differs between Windows and POSIX. + // Use .+ (not \S*) to tolerate paths that contain spaces. + const normStdout = stdout.replace(/\\/g, '/'); + assert.match( + normStdout, + /GSD_TOOLS=.+\/bin\/gsd-tools(?:\s|$)/m, + `Expected GSD_TOOLS to resolve to the installed PATH stub (suffix /bin/gsd-tools), got: ${stdout.trim()}`, + ); + assert.doesNotMatch( + normStdout, + /GSD_TOOLS=.+\.cjs/m, + `Expected GSD_TOOLS NOT to point to a .cjs file in PATH fallback, got: ${stdout.trim()}`, + ); + // The stub must have been invoked with the query arguments + assert.ok( + stdout.includes('installed:query state.json'), + `Expected stdout to contain "installed:query state.json" (PATH stub output), got: ${stdout.trim()}`, + ); + } finally { + fs.rmSync(base, { recursive: true, force: true }); + } + }); + + // ─── (F) Regression locks: no /gsd-tools substring; no do.md dispatcher false-positive ── + test('(F) snippet has no /gsd-tools substring; do.md has no /gsd[:-][a-z] matches', () => { + // (F1) The snippet must not contain the literal substring /gsd-tools. + // The _GSD_SHIM_NAME indirection ensures bin/${_GSD_SHIM_NAME} instead of + // bin/gsd-tools.cjs — so the do.md dispatcher regex /\/gsd[:-]([a-z]...)/ never + // misreads a preamble line as a slash-command stub. + const snippetContent = fs.readFileSync(SNIPPET_FILE, 'utf8'); + assert.ok( + !snippetContent.includes('/gsd-tools'), + `_runtime-launcher.snippet.sh must not contain the literal "/gsd-tools" substring. ` + + `Use bin/\${_GSD_SHIM_NAME} indirection to keep the /gsd[:-] scanner from ` + + `misreading it as a slash-command stub. Found in snippet:\n` + + snippetContent.split('\n').filter((l) => l.includes('/gsd-tools')).join('\n'), + ); + + // (F2) workflows/do.md must not contain the literal substring /gsd-tools + // (the specific path that leaks when _GSD_SHIM_NAME indirection is bypassed). + // The bug-2954 dispatcher scanner /\/gsd[:-]([a-z]...)/ would misread + // /gsd-tools as a slash-command stub named "tools" — which is not shipped. + // Note: /gsd:command references (with colon) in the dispatch table are + // legitimate and are NOT checked here. + const doMdPath = path.join(WORKFLOWS_DIR, 'do.md'); + const doMdContent = fs.readFileSync(doMdPath, 'utf8'); + const offendingLines = doMdContent + .split('\n') + .filter((l) => /\/gsd-tools/.test(l)); + assert.deepStrictEqual( + offendingLines, + [], + `workflows/do.md contains the literal "/gsd-tools" substring which the dispatcher-parity ` + + `scanner (bug-2954) misreads as a slash-command stub. Use \${_GSD_SHIM_NAME} indirection. ` + + `Offending lines:\n` + + offendingLines.join('\n'), + ); + }); +}); diff --git a/tests/ultraplan-phase.test.cjs b/tests/ultraplan-phase.test.cjs index 2dbd49146..37ae31ae2 100644 --- a/tests/ultraplan-phase.test.cjs +++ b/tests/ultraplan-phase.test.cjs @@ -111,10 +111,10 @@ describe('ultraplan-phase workflow initialization', () => { const content = fs.readFileSync(WF_PATH, 'utf-8'); test('loads GSD phase context via gsd-sdk query init.plan-phase', () => { - // After #3797 architectural fix, callsites use $GSD_SDK — accept either form + // After #3797 architectural fix, callsites use gsd_run assert.ok( - content.includes('$GSD_SDK query init.plan-phase') || content.includes('gsd-sdk query init.plan-phase'), - 'workflow must load phase context via gsd-sdk query init.plan-phase', + content.includes('gsd_run query init.plan-phase'), + 'workflow must load phase context via gsd_run query init.plan-phase', ); }); diff --git a/tests/worktree-cleanup.test.cjs b/tests/worktree-cleanup.test.cjs index ee44d7e1e..b767dd6ba 100644 --- a/tests/worktree-cleanup.test.cjs +++ b/tests/worktree-cleanup.test.cjs @@ -500,7 +500,7 @@ describe('worktree cleanup after executor completes (#1496)', () => { // deletion internally). The manual shell cleanup loop has been removed. assert.ok( content.includes('worktree.cleanup-wave'), - 'quick cleanup must delegate to $GSD_SDK query worktree.cleanup-wave (#3797)', + 'quick cleanup must delegate to gsd_run query worktree.cleanup-wave (#3797)', ); }); @@ -510,7 +510,7 @@ describe('worktree cleanup after executor completes (#1496)', () => { // A soft || { warn } fallback would silently swallow blocked cleanups. assert.match( content, - /\$GSD_SDK query worktree\.cleanup-wave.*\|\| exit 1/, + /gsd_run query worktree\.cleanup-wave.*\|\| exit 1/, 'quick.md cleanup-wave must use || exit 1 — SDK safety refusals must surface (#3797)', ); }); @@ -535,8 +535,8 @@ describe('worktree merge: orchestrator file protection (#1756)', () => { // worktree.cleanup-wave handles STATE.md/ROADMAP.md backup + restore internally. assert.match( content, - /\$GSD_SDK query worktree\.cleanup-wave --manifest "\$WAVE_WORKTREE_MANIFEST" \|\| exit 1/, - 'execute-phase.md must delegate to $GSD_SDK query worktree.cleanup-wave with || exit 1 (#3797)', + /gsd_run query worktree\.cleanup-wave --manifest "\$WAVE_WORKTREE_MANIFEST" \|\| exit 1/, + 'execute-phase.md must delegate to gsd_run query worktree.cleanup-wave with || exit 1 (#3797)', ); }); @@ -570,8 +570,8 @@ describe('worktree merge: orchestrator file protection (#1756)', () => { // backup code — that is handled internally by worktree.cleanup-wave. assert.match( content, - /\$GSD_SDK query worktree\.cleanup-wave --manifest "\$QUICK_WORKTREE_MANIFEST" \|\| exit 1/, - 'quick.md must delegate to $GSD_SDK query worktree.cleanup-wave with || exit 1 (#3797)', + /gsd_run query worktree\.cleanup-wave --manifest "\$QUICK_WORKTREE_MANIFEST" \|\| exit 1/, + 'quick.md must delegate to gsd_run query worktree.cleanup-wave with || exit 1 (#3797)', ); }); }); @@ -677,9 +677,9 @@ describe('bug #3384: worktree cleanup workflow contracts', () => { assert.match(content, /append its returned `\{agent_id, worktree_path, branch, expected_base\}`/); // After #3797 architectural fix: quick.md delegates entirely to the SDK's cleanup-wave // command (which handles manifest parsing internally). The shell fallback with manual - // QUICK_WORKTREE_MANIFEST node-e code is removed — the SDK call with || exit 1 is the + // QUICK_WORKTREE_MANIFEST node-e code is removed — the gsd_run call with || exit 1 is the // only cleanup path, enforcing safety-refusal semantics (#3174/#3384). - assert.match(content, /\$GSD_SDK query worktree\.cleanup-wave --manifest "\$QUICK_WORKTREE_MANIFEST" \|\| exit 1/); + assert.match(content, /gsd_run query worktree\.cleanup-wave --manifest "\$QUICK_WORKTREE_MANIFEST" \|\| exit 1/); assert.doesNotMatch(content, /done < <\(node -e 'const fs=require\("fs"\);const p=process\.env\.QUICK_WORKTREE_MANIFEST/); assert.doesNotMatch(content, /done < <\(git worktree list --porcelain \| grep "\^worktree " \| grep "\\\.claude\/worktrees\/agent-"/); }); @@ -696,8 +696,8 @@ test('#3425: helper cleanup path pins orchestrator CWD to primary worktree and c assert.match(content, /cd "\$PRIMARY_WT" \|\| \{ echo "FATAL: cannot cd to primary worktree \$PRIMARY_WT" >&2; exit 1; \}/); assert.match(content, /ORCH_BRANCH=\$\(git rev-parse --abbrev-ref HEAD\)/); assert.match(content, /FATAL: orchestrator on '\$ORCH_BRANCH' but expected '\$EXPECTED_BRANCH' before worktree cleanup — refusing to merge \(#3174-class drift\)/); - // After #3797 architectural fix, callsites use $GSD_SDK — accept either form - assert.match(content, /(?:\$GSD_SDK|gsd-sdk) query worktree\.cleanup-wave --manifest "\$WAVE_WORKTREE_MANIFEST"/); + // After #3797 architectural fix, callsites use gsd_run + assert.match(content, /gsd_run query worktree\.cleanup-wave --manifest "\$WAVE_WORKTREE_MANIFEST"/); }); test('#3425: cleanup-tail snippet carries the same primary-worktree pin before removal', () => {