fix(tmux-terminal): D5 probe + D6 node prefix (real-tmux execution)#100
Merged
Conversation
Two bugs surfaced by exercising the implementation against a real tmux
server (test-real-tmux-smoke.mjs). Both invisible to FakeTmuxExecutor
unit tests because the fake returns configurable responses that don't
model the real defaultTmuxExecutor / tmux behavior.
D5 — isAvailable probe (tmux-backend.ts:34)
- Before: `has-session -t __pi_probe__`. The __pi_probe__ session does
not exist by default, so has-session returns exit 1.
- defaultTmuxExecutor catches non-zero exits and returns {ok: false}.
- The D1 result.ok === true check then made isAvailable always return
false, even when the tmux server was reachable.
- Fix: probe with `list-sessions` — returns 0 when the server is
reachable, regardless of session count. Correctly distinguishes
server-reachable from server-unreachable.
- Test: test-tmux-backend.mjs Group 2 test 1 args assertion updated to
["list-sessions"].
D6 — launch argv (tmux-backend.ts:52)
- Before: `["new-window", ..., "--", workerPath, manifestPath]`. tmux
tried to exec workerPath directly, but bg-worker.ts has no shebang
and is mode 644 — not executable. The window was created then
immediately destroyed (the command failed to exec); @pi_run_id and
@pi_agent_name user-options were never set; isAlive returned false.
- Fix: prepend "node" to argv — `["new-window", ..., "--", "node",
workerPath, manifestPath]`. node handles the .ts extension via
--experimental-strip-types (used elsewhere in this repo).
- Tests: test-tmux-backend.mjs Group 3 test 1 deepEqual updated to
expect "node" prefix; Group 4 test 1 workerIdx indexing updated to
workerIdx + 2 for manifestPath (intermediate "node" check added).
New: tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs +
run-real-tmux-smoke.sh
- Exercises the actual createTmuxBackend against an isolated
`tmux -L p5-smoke-<pid>` socket. Does NOT touch the user's default
tmux session. Cleans up on exit (kill-server + temp dirs).
- 11 verification steps: backend.name, isAvailable probes real tmux,
launch creates window, window visible via direct CLI, user-options
set, isAlive, list recovers runId/agentName, kill removes window,
isAlive after kill, kill idempotent.
- Skipped (exit 0) if tmux not on $PATH — opt-in by environment.
Docs:
- agents/P3_IMPLEMENTATION_SLICES.md updated with D5/D6 rationale and
the new real-tmux smoke test entry. Plan v6 should incorporate both
fixes into the canonical recipe (probe + node prefix).
Why these bugs survived the v5 review (5 rounds) + code review (1 round):
- Plan review focused on argv construction (Group 3 tests), not on
isAvailable probe semantics or worker-execution semantics.
- Code review verified argv shape against fake-recorded calls but
did not exercise real tmux.
- Unit tests use FakeTmuxExecutor which returns configurable
responses; defaultTmuxExecutor's actual return shape (always
{ok: false} for non-zero exit, no throw) was hidden behind the fake.
- The "Manual smoke: pi -e ./agents/index.ts -e ./tmux-terminal/index.ts
then /agents bg scout" criterion was listed but never executed before
merge. The new smoke test makes this criterion mechanically verified.
Verification:
- bash tmux-terminal/test-fixtures/run-p5-tests.sh: 63/63 pass + REQ-13 OK
- bash agents/test-fixtures/run-p4-4-tests.sh: green (regression intact)
- node tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs: 11/11 pass
- Mutation #1 (realpathSync → path.resolve): only testWorkerPathIsRealpathed fails
- Mutation #2 (WORKER_BASENAMES reorder): only testWorkerPathPrefersTsOverMjs fails
- Both mutations revert cleanly
lantiscooperdev
approved these changes
Jun 27, 2026
lantisprime
pushed a commit
that referenced
this pull request
Jun 27, 2026
lantiscooperdev
pushed a commit
that referenced
this pull request
Jun 27, 2026
#101) * fix(tmux-terminal): D5 probe + D6 node prefix (real-tmux execution) Two bugs surfaced by exercising the implementation against a real tmux server (test-real-tmux-smoke.mjs). Both invisible to FakeTmuxExecutor unit tests because the fake returns configurable responses that don't model the real defaultTmuxExecutor / tmux behavior. D5 — isAvailable probe (tmux-backend.ts:34) - Before: `has-session -t __pi_probe__`. The __pi_probe__ session does not exist by default, so has-session returns exit 1. - defaultTmuxExecutor catches non-zero exits and returns {ok: false}. - The D1 result.ok === true check then made isAvailable always return false, even when the tmux server was reachable. - Fix: probe with `list-sessions` — returns 0 when the server is reachable, regardless of session count. Correctly distinguishes server-reachable from server-unreachable. - Test: test-tmux-backend.mjs Group 2 test 1 args assertion updated to ["list-sessions"]. D6 — launch argv (tmux-backend.ts:52) - Before: `["new-window", ..., "--", workerPath, manifestPath]`. tmux tried to exec workerPath directly, but bg-worker.ts has no shebang and is mode 644 — not executable. The window was created then immediately destroyed (the command failed to exec); @pi_run_id and @pi_agent_name user-options were never set; isAlive returned false. - Fix: prepend "node" to argv — `["new-window", ..., "--", "node", workerPath, manifestPath]`. node handles the .ts extension via --experimental-strip-types (used elsewhere in this repo). - Tests: test-tmux-backend.mjs Group 3 test 1 deepEqual updated to expect "node" prefix; Group 4 test 1 workerIdx indexing updated to workerIdx + 2 for manifestPath (intermediate "node" check added). New: tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs + run-real-tmux-smoke.sh - Exercises the actual createTmuxBackend against an isolated `tmux -L p5-smoke-<pid>` socket. Does NOT touch the user's default tmux session. Cleans up on exit (kill-server + temp dirs). - 11 verification steps: backend.name, isAvailable probes real tmux, launch creates window, window visible via direct CLI, user-options set, isAlive, list recovers runId/agentName, kill removes window, isAlive after kill, kill idempotent. - Skipped (exit 0) if tmux not on $PATH — opt-in by environment. Docs: - agents/P3_IMPLEMENTATION_SLICES.md updated with D5/D6 rationale and the new real-tmux smoke test entry. Plan v6 should incorporate both fixes into the canonical recipe (probe + node prefix). Why these bugs survived the v5 review (5 rounds) + code review (1 round): - Plan review focused on argv construction (Group 3 tests), not on isAvailable probe semantics or worker-execution semantics. - Code review verified argv shape against fake-recorded calls but did not exercise real tmux. - Unit tests use FakeTmuxExecutor which returns configurable responses; defaultTmuxExecutor's actual return shape (always {ok: false} for non-zero exit, no throw) was hidden behind the fake. - The "Manual smoke: pi -e ./agents/index.ts -e ./tmux-terminal/index.ts then /agents bg scout" criterion was listed but never executed before merge. The new smoke test makes this criterion mechanically verified. Verification: - bash tmux-terminal/test-fixtures/run-p5-tests.sh: 63/63 pass + REQ-13 OK - bash agents/test-fixtures/run-p4-4-tests.sh: green (regression intact) - node tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs: 11/11 pass - Mutation #1 (realpathSync → path.resolve): only testWorkerPathIsRealpathed fails - Mutation #2 (WORKER_BASENAMES reorder): only testWorkerPathPrefersTsOverMjs fails - Both mutations revert cleanly * docs: sync workplan + slices to P5 D5+D6 post-merge (PR #100, 4f4339b) Three-source sync per workplan-update runbook after PR #100 merged: 1. Episodic memory (canonical-workplan): revised to new episode ID 20260627-085754-p5-fully-shipped-post-merge-fixes-d5-d6--2ee6 which supersedes 20260627-083022-p5-tmux-terminal-merged-pr-98-commit-f3b-3d0f (the pre-fix merge state). New body documents D5 + D6 fixes, the real-tmux smoke test in CI, and points at P5b (zellij/wezterm/headless) as the next natural extension. 2. WORKPLAN.md pointer refreshed to the new canonical-workplan episode. Tags include p5-pr-98, p5-pr-100, p5-d5-d6-fix. 3. agents/P3_IMPLEMENTATION_SLICES.md top-level P5 entry updated: - Added PR #100 + commit 4f4339b next to PR #98 - Branch line updated to note both p5-tmux-terminal AND fix/p5-d5-d6-real-tmux branches deleted post-merge No code changes. No agent/lib/ changes. Pattern follows PR #99 docs-only sync PR (also required because main is branch-protected). --------- Co-authored-by: Charlton D. Ho <dev@znp.pw>
lantiscooperdev
pushed a commit
that referenced
this pull request
Jun 27, 2026
…103) Three-source sync per workplan-update runbook after PR #102 merged: 1. Episodic memory (canonical-workplan): revised to new episode ID 20260627-092842-p5-fully-shipped-d5-d6-d7-fixes-merged-p-7d1e which supersedes the D5+D6-only episode. New body documents D7 (symlink-loading fix), the full D5/D6/D7 deviation timeline, lessons stored globally, and points at P5b as the next natural extension. 2. WORKPLAN.md pointer refreshed to the new canonical-workplan episode. Tags include p5-pr-98, p5-pr-100, p5-pr-102, p5-d5-d6-fix, p5-d7-fix. 3. agents/P3_IMPLEMENTATION_SLICES.md top-level P5 entry updated: - Added PR #102 + commit 6ec1b4b next to PR #100 - Branches line updated to note all 3 deleted branches No code changes. No agent/lib/ changes. Pattern follows PR #99 and #101 docs-only sync PRs (also required because main is branch-protected). Co-authored-by: Charlton D. Ho <dev@znp.pw>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes two bugs surfaced by exercising the implementation against a real tmux server (
tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs). Both bugs were invisible to the v5 unit test suite becauseFakeTmuxExecutorreturns configurable responses that don't modeldefaultTmuxExecutor's actual behavior or tmux's worker-execution semantics.The bugs
D5 —
isAvailableprobe (tmux-backend.ts:34)Before:
["has-session", "-t", "__pi_probe__"]__pi_probe__session doesn't exist by default →has-sessionreturns exit 1defaultTmuxExecutorcatches non-zero exits and returns{ok: false}result.ok === truecheck then madeisAvailablealways returnfalse, even when the tmux server was reachableFix: probe with
["list-sessions"]— returns 0 when the server is reachable, regardless of session count. Correctly distinguishes server-reachable from server-unreachable.D6 — launch argv missing
nodeprefix (tmux-backend.ts:52)Before:
["new-window", ..., "--", workerPath, manifestPath]workerPathdirectly, butbg-worker.tshas no shebang and is mode 644 (not executable)@pi_run_idand@pi_agent_nameuser-options are never setisAlivereturns false,listreturns emptyFix: prepend
"node"→["new-window", ..., "--", "node", workerPath, manifestPath]. node handles the.tsextension via--experimental-strip-types(the same mechanism used byrun-p4-4-tests.shand the other test runners in this repo).Why these bugs survived the v5 review process
isAvailableprobe semantics or worker-execution semanticsFakeTmuxExecutorreturns configurable responses;defaultTmuxExecutor's actual return shape (always{ok: false}for non-zero exit, no throw) was hidden behind the fakeThe new
test-real-tmux-smoke.mjsmakes this criterion mechanically verified in CI.New: real-tmux smoke test
tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs(222 lines) +run-real-tmux-smoke.sh(7 lines):createTmuxBackendagainst an isolatedtmux -L p5-smoke-<pid>socket (does NOT touch the user's default tmux session)Test updates
3 assertions in
test-tmux-backend.mjsupdated to match new contracts:["has-session", "-t", "__pi_probe__"]→["list-sessions"]"node"before workerPathworkerIdx + 1→workerIdx + 2for manifestPath position; added intermediate"node"checkVerification (all green)
bash tmux-terminal/test-fixtures/run-p5-tests.shbash agents/test-fixtures/run-p4-4-tests.shnode tmux-terminal/test-fixtures/test-real-tmux-smoke.mjstestWorkerPathIsRealpathedfails ✓testWorkerPathPrefersTsOverMjsfails ✓Files changed (5 files, +246/-7)
tmux-terminal/lib/tmux-backend.ts— D5 probe + D6 node prefixtmux-terminal/test-fixtures/test-tmux-backend.mjs— 3 assertion updatestmux-terminal/test-fixtures/test-real-tmux-smoke.mjs— NEW (222 lines)tmux-terminal/test-fixtures/run-real-tmux-smoke.sh— NEW (7 lines)agents/P3_IMPLEMENTATION_SLICES.md— D5/D6 + smoke test docsPlan v6 note
D5 and D6 should be incorporated into v6 of the P5 plan as canonical recipe (probe =
list-sessions, argv =[..., "--", "node", workerPath, manifestPath]). This PR ships them as post-merge fixes against v5.🤖 Generated with pi-coding-agent