test(execute): Check 4 and Step 5 must survive a first run under zsh (red)

The Bash tool runs the user's shell; on macOS that is zsh, whose NOMATCH
option fails an unmatched session-* glob with exit 1. A first run has no
worktrees yet, so Check 4 stops every first multi-session run and every
re-run after a declined main-merge gate. Red under /bin/zsh, green under
/bin/bash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-02 16:40:05 +02:00
commit a61cde2b38
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q

View file

@ -542,6 +542,27 @@ test('Step 5 removes only what holds no work, lists every kept worktree and bran
});
});
// The Bash tool runs the user's shell, and on macOS that is zsh, whose NOMATCH
// option turns an unmatched `session-*` glob into an error (exit 1) instead of
// a literal word. A first run has no worktrees yet, so every glob loop must
// survive zsh as well as bash.
const ZSH = existsSync('/bin/zsh') ? '/bin/zsh' : null;
test('Check 4 and Step 5 pass a first run (no worktrees yet) under zsh as well as bash', { skip: ZSH ? false : 'no /bin/zsh' }, () => {
withGitRepo((root) => {
const sd = join(root, '.claude', 'trekplan-sessions', 'demo');
const env = { REPO_ROOT: root, WORKTREE_DIR: join(sd, 'worktrees'), ORDERS_DIR: join(sd, 'orders') };
const check4 = fill(bashBlock('### Check 4 —'), { slug: 'demo' });
const step5 = fill(bashBlock('### Step 5 — Cleanup'), { slug: 'demo' });
for (const shell of [BASH, ZSH]) {
for (const [name, block] of [['Check 4', check4], ['Step 5', step5]]) {
const r = spawnSync(shell, ['-c', block], { cwd: root, encoding: 'utf-8', env: { ...process.env, ...env } });
assert.equal(r.status, 0, `${name} under ${shell}: ${r.stderr}`);
assert.doesNotMatch(r.stderr, /no matches found/, `${name} under ${shell}`);
}
}
});
});
test('Step 0 resolves the main checkout and a main-relative plan path from a subdirectory, and refuses a linked worktree', () => {
withGitRepo((root) => {
const env = { CLAUDE_PLUGIN_ROOT: ROOT };