Skip to content

fix: sourced libs locate themselves under zsh (#3024) - #3027

Closed
scottgigante-hubflow wants to merge 1 commit into
garrytan:mainfrom
scottgigante-hubflow:fix/zsh-sourced-self-locate
Closed

scottgigante-hubflow wants to merge 1 commit into
garrytan:mainfrom
scottgigante-hubflow:fix/zsh-sourced-self-locate

Conversation

@scottgigante-hubflow

Copy link
Copy Markdown
Contributor

Fixes #3024.

Why (in your own words)

Skill bash blocks source bin/gstack-codex-probe and bin/gstack-egress-lib.sh into whatever shell the host runs. On macOS that is zsh, including Claude Code's Bash tool. Both libraries located themselves with BASH_SOURCE, and zsh doesn't set it. Since v1.91.16.0 (#3014), the probe has resolved its model resolver as /../scripts/resolve-codex-generation-model.ts, so every Codex outside pass (/ship, /review, /codex, /autoplan, /plan-eng-review, /office-hours) reports MODEL_UNUSABLE and skips the review, even when Codex is installed, logged in and the model works. Under zsh the egress lib falls back to the caller's current directory, so _gstack_egress_home looks for gstack-state-root.sh in the user's project instead of in gstack. This is the case @akshaykalia raised on #3024.

This PR adds a zsh fallback in both places. Each one sits behind an eval so bash never has to parse zsh-only syntax:

  • probe: a new _gstack_codex_bin_dir helper, resolved when called: BASH_SOURCE under bash, functions_source under zsh. All four call sites use it (model resolver, probe cache state root, analytics state root). The file still does nothing when sourced except define functions.
  • egress lib: resolved when sourced: BASH_SOURCE, else zsh's ${(%):-%x}. The cwd fallback stays as the last resort.

Live evidence

Before (v1.91.18.0, macOS, zsh 5.9), run from a directory outside gstack:

$ zsh -c 'source ~/.claude/skills/gstack/bin/gstack-codex-probe; _gstack_codex_select_model exec'
error: Module not found "/../scripts/resolve-codex-generation-model.ts"
CODEX_MODEL: invalid — Codex outside review unavailable; missing coverage. No Codex call was made. Fix the model choice above; gstack never substitutes its default for it.

$ cd /tmp && zsh -c '. <gstack>/bin/gstack-egress-lib.sh; echo egress_dir=$_gstack_egress_lib_dir; _gstack_egress_home'
egress_dir=/tmp
<gstack state root: /tmp/gstack-state-root.sh is missing; reinstall with ./setup or /gstack-upgrade>

After, in both shells, from /tmp:

== bash
CODEX_MODEL: gpt-6-astra (exec; source: ~/.codex/config.toml model)     rc=0
CODEX_MODEL: gpt-6-astra (review; source: ~/.codex/config.toml model)   rc=0
egress_dir=<gstack>/bin
~/.gstack
== zsh
CODEX_MODEL: gpt-6-astra (exec; source: ~/.codex/config.toml model)     rc=0
CODEX_MODEL: gpt-6-astra (review; source: ~/.codex/config.toml model)   rc=0
egress_dir=<gstack>/bin
~/.gstack

Sourcing the egress lib under set -eu still works in both shells, and bash -n / zsh -n pass on the probe.

New regression test test/regression-issue3024-zsh-sourced-self-locate.test.ts. It runs each case under bash and under zsh (zsh is skipped where it isn't installed), from an unrelated cwd so the cwd fallback can't pass by accident:

without the bin/ changes:  2 pass, 4 fail  (zsh: probe dir, model resolve, egress dir; bash: helper missing)
with the fix:              6 pass, 0 fail

Related suites still pass: bun test test/codex-hardening.test.ts test/codex-model-probe.test.ts test/egress-lib.test.ts test/egress-receipt-wiring.test.ts test/aside-driver.test.ts gives 123 pass, 0 fail.

Scope

  • Changed: bin/gstack-codex-probe, bin/gstack-egress-lib.sh, one new regression test.
  • Verified live by: sourcing both libraries under bash and zsh from a directory outside gstack and resolving the configured Codex model through the real resolver (output above).
  • Did NOT test: a full paid Codex round trip through _gstack_codex_model_probe; Linux or Windows shells; zsh older than 5.9. This PR doesn't bump VERSION or add a CHANGELOG entry, since those are left to the maintainer's release wave.

Note: open PR #3025 adds a fifth ${BASH_SOURCE[0]%/*} use in bin/gstack-codex-probe (around line 138). Whichever PR merges second should switch that one to $(_gstack_codex_bin_dir) too.

Liveness proof (required for external contributors)

🤖 Generated with Claude Code

bin/gstack-codex-probe and bin/gstack-egress-lib.sh are sourced into the
host's shell by skill bash blocks. Under zsh (the macOS default, and what
Claude Code's Bash tool runs there) BASH_SOURCE is unset, so:

- the probe resolved its model resolver as
  "/../scripts/resolve-codex-generation-model.ts" and every Codex outside
  pass reported CODEX_MODEL: invalid / MODEL_UNUSABLE; the probe cache and
  analytics lookups silently found no state root.
- the egress lib fell back to the caller's cwd and looked for
  gstack-state-root.sh in whatever repo the user was working in.

Fall back to zsh's functions_source (probe, resolved at call time) and
%x prompt expansion (egress lib, resolved at source time), each behind an
eval so bash never parses zsh-only syntax.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Oct 4, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@capy-ai

capy-ai Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Thanks for this. The Oct 6 fix wave rewrote the fix on branch garrytan/fix-wave-oct6, using your diagnosis, and credits you with a Co-authored-by trailer: sourced helpers now locate themselves under zsh. The fix resolves %x at source time and adds a class test that sources every helper the skills load, under both bash and zsh (f0531a2). More review follow-ups are landing on the same branch. This PR will be closed when the wave PR merges, with a link to it.

@capy-ai

capy-ai Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Thanks for this. The fix landed in v1.91.32.0 via #3057, which rewrote it from your diagnosis and credits you with a Co-authored-by trailer on the commit. Closing in favor of #3057.

@capy-ai capy-ai Bot closed this Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant