diff --git a/.changeset/614-discuss-phase-shim-resolution.md b/.changeset/614-discuss-phase-shim-resolution.md new file mode 100644 index 000000000..72c55c139 --- /dev/null +++ b/.changeset/614-discuss-phase-shim-resolution.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 618 +--- +**`/gsd-discuss-phase` now honors `workflow.discuss_mode: assumptions` on shim-only installs** — mode routing resolves `gsd-tools` via the runtime shim instead of the bare PATH command, so a missing PATH binary no longer silently falls back to standard discuss mode. diff --git a/commands/gsd/discuss-phase.md b/commands/gsd/discuss-phase.md index d7aa4ad64..2b21790d1 100644 --- a/commands/gsd/discuss-phase.md +++ b/commands/gsd/discuss-phase.md @@ -47,7 +47,8 @@ Context files are resolved in-workflow using `init phase-op` and roadmap/state t **Mode routing:** ```bash -DISCUSS_MODE=$(gsd-tools query config-get workflow.discuss_mode 2>/dev/null || echo "discuss") +_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi +DISCUSS_MODE=$(gsd_run query config-get workflow.discuss_mode 2>/dev/null || echo "discuss") ``` If `--assumptions` is in $ARGUMENTS: diff --git a/tests/discuss-mode.test.cjs b/tests/discuss-mode.test.cjs index 8f91af26c..727bdaa8c 100644 --- a/tests/discuss-mode.test.cjs +++ b/tests/discuss-mode.test.cjs @@ -164,4 +164,25 @@ describe('workflow.discuss_mode config', () => { assert.ok(doc.includes('discuss'), 'doc should mention discuss'); assert.ok(doc.includes('config-set'), 'doc should show how to configure'); }); + + test('discuss-phase command mode-routing uses gsd_run (shim-safe) not bare gsd-tools', () => { + const command = fs.readFileSync( + path.join(__dirname, '..', 'commands', 'gsd', 'discuss-phase.md'), 'utf8' + ); + // Must contain the canonical shim probe marker + assert.ok( + command.includes('_GSD_SHIM_NAME'), + 'discuss-phase.md must define _GSD_SHIM_NAME shim probe before mode routing' + ); + // Must use gsd_run for the config lookup + assert.ok( + command.includes('gsd_run query config-get workflow.discuss_mode'), + 'discuss-phase.md must use gsd_run (not bare gsd-tools) for discuss_mode lookup' + ); + // Must NOT contain the bare footgun pattern: gsd-tools immediately before the silent default + assert.ok( + !command.includes('gsd-tools query config-get workflow.discuss_mode 2>/dev/null || echo'), + 'discuss-phase.md must NOT use bare gsd-tools binary for discuss_mode lookup (shim-only install footgun)' + ); + }); });