Commit Graph

117 Commits

Author SHA1 Message Date
YeonGyu-Kim cad63c97bd Merge pull request #4052 from PeterPonyu/fix/3505-attach-retry-until-session-ready
fix(tmux-subagent): wait for session readiness before spawning attach pane
2026-05-21 00:45:15 +09:00
YeonGyu-Kim e824115a2f Merge pull request #4063 from PeterPonyu/fix/3963-server-url-port-zero
fix(team-mode): surface port-0 fallback and silent layout skip (#3963)
2026-05-21 00:42:20 +09:00
Sami Jawhar e8a7e2a94d fix(tmux): skip layout enforcement when closing isolated container pane 2026-05-19 12:24:59 +00:00
ZeyuFu ced95c4bfa fix(team-mode): surface port-0 fallback and silent layout skip (#3963)
When ctx.serverUrl had a port string of "0", TmuxSessionManager
silently replaced it with the localhost:4096 fallback and
createTeamLayout subsequently skipped pane creation without any
user-visible signal. The two-step silent failure made team_mode
tmux_visualization look broken in default TUI mode.

Surface the failure path:

- TmuxSessionManager now retains ctx.serverUrl on the instance and
  exposes it via getCtxServerUrl(), and emits a structured warning
  log on the port-0 fallback branch naming both the discarded URL
  and the fallback it landed on.
- createTeamLayout's "opencode server not reachable" log is
  upgraded to a structured warning including ctxServerUrl and a
  hint to launch with --port N + OPENCODE_PORT=N.

No behavior change to the fallback resolution itself - only the
silence. Existing port-0 fallback tests still pass; two new tests
assert the warning fires on port 0 and is absent for real ports.
2026-05-16 01:23:25 -04:00
YeonGyu-Kim e63c5b9a22 fix(tmux): require explicit active isolated window 2026-05-16 00:26:44 +09:00
YeonGyu-Kim 1ff59f44ce test(tmux): align pane-state runner format 2026-05-16 00:22:52 +09:00
YeonGyu-Kim 54a7256a71 test(tmux): align placeholder command expectations 2026-05-16 00:14:06 +09:00
Disaster-Terminator 0c8e546c57 fix(tmux): support manager-scoped isolated session names 2026-05-16 00:06:58 +09:00
Disaster-Terminator 4e3684eb2a fix(tmux): gate isolated pane activation on visible client focus 2026-05-16 00:05:02 +09:00
Disaster-Terminator c63108d55b fix(tmux): track placeholder panes before attach readiness 2026-05-16 00:02:02 +09:00
Disaster-Terminator 688bb551b2 fix(tmux): defer subagent attach until pane focus 2026-05-15 23:57:07 +09:00
PeterPonyu 58681f6d00 test(tmux-subagent): assert waitForSessionReady gates executeActions
The regression test for the pane-creation race (PR #4052 / issue #3505)
previously didn't enforce the readiness-then-spawn ordering: mocks
resolved synchronously and the assertion only checked the final
behavior, not the sequencing. A future code change reintroducing the
race could slip past this test silently.

Rewrites the test to explicitly assert call ordering:
waitForSessionReady must complete before executeActions is invoked.
A failure case is added where waitForSessionReady remains pending
when executeActions would otherwise fire; the test asserts the spawn
is correctly deferred.

Addresses cubic-dev-ai's review on PR #4052 (severity 5/10,
test quality).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 10:33:24 -04:00
Momentum96 e90ff8058e fix(tmux): treat busy sessions as attachable 2026-05-15 23:12:56 +09:00
PeterPonyu 0465562fa4 fix(tmux-subagent): wait for session readiness before spawning attach pane
`opencode attach` was invoked inside a freshly-split tmux pane before the
child session appeared in the opencode server's status map.  The process
exited immediately (session not found), tmux auto-closed the pane, and the
subagent ran invisibly in the background — the race documented in #3505.

Fix: call `waitForSessionReady` *before* `executeActions` in
`session-created-handler.ts`, mirroring the guard already present in
`TmuxSessionManager.ensureSessionReadyBeforeSpawn()`.  If the session does
not become attachable within the timeout the handler returns early without
spawning a pane at all, eliminating the transient-pane and silent-close
failure modes.  The now-unreachable post-spawn readiness-check / pane-close
cleanup branch is removed.

Adds a regression test suite (session-created-handler.test.ts) covering:
- not-ready session → no pane spawned, no polling started
- duplicate session.created → idempotent
- non session.created event type → no action
- already-tracked session → idempotent

Closes #3505

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 07:54:52 -04:00
YeonGyu-Kim 8dcbccf063 fix(tmux): inject pane action dependencies 2026-05-15 17:54:43 +09:00
YeonGyu-Kim d8f52aae7f test: run suite without split runner 2026-05-15 16:26:57 +09:00
YeonGyu-Kim 9f6d0d2281 docs(agents-md): refresh hierarchical knowledge base for v4.1.2
- Bump root AGENTS.md header: 2026-05-14 → 2026-05-15, commit 5ffbe0e2453a740636, release v4.1.1 → v4.1.2
- Update file counts: 2034 (1337+697) → 2041 (1340+701), LOC ~292k → ~294k
- Fix STRUCTURE: openclaw lives at src/openclaw/ (not src/features/); list more accurate feature modules in the parenthetical
- Clarify interactive_bash gate: tmux binary on PATH via isInteractiveBashEnabled() (not 'tmux enabled')
- Fix docs/reference/features.md hook counts: Tool Guard 14→16, Total base 52→54, total with team-mode 59→61
- Bump 'Generated' date on all 43 subdir AGENTS.md files to 2026-05-15
- Preserve promptAsync injection cautions verbatim (per request)
2026-05-15 13:48:11 +09:00
YeonGyu-Kim 1e7a7600a2 docs(agents-md): regenerate hierarchical AGENTS.md knowledge base for v4.1.1
Refresh all AGENTS.md files to reflect codebase state at 5ffbe0e24 (was cd31d2a1a, 197 commits behind).

Key drift corrections across 45 modified + 1 new file:

Root AGENTS.md:
- TS file counts: 1967 -> 2034 in src/ (1337 source + 697 test)
- LOC: 278k -> 292k
- Barrel index.ts: 120 -> 122
- Hook tier composition: 52/59 -> 54/61 (base/with team-mode)
- Tool Guard hooks: 14 -> 16 (add fsync-skip-warning, bash-file-read-guard)
- Add boulder feature, agent-ordering schema, .agents/ directory, v4.1.1 release tag
- Add generated/ directory entry

src/AGENTS.md:
- Subsystem inventory: agents 96->102, hooks 570->581, tools 306->314,
  features 389->400, shared 258->278, cli 150->158, plugin 55->56
- LOC totals refreshed for every subsystem
- Schema files: 32 -> 30

src/hooks/AGENTS.md:
- Tier 2 (Tool Guard): 14 -> 16 hooks, add fsyncSkipWarning row
- Total: 52 base / 59 team-mode -> 54 base / 61 team-mode
- zauc-mocks count: 7 -> 5

src/features/AGENTS.md:
- background-agent: 47 -> 57 files, mention archive fallback
- opencode-skill-loader: 33 -> 30
- tmux-subagent: 34 -> 32

src/plugin/AGENTS.md:
- Tool Guard composer count: 14 -> 16
- Aggregator total: 43 -> 45

src/cli/AGENTS.md:
- Add new boulder subcommand (BoulderState inspector)
- Command count: 6 -> 7

NEW: src/features/boulder-state/AGENTS.md
- Document the new Boulder work tracking feature
- Schema v2 with BoulderState/BoulderWorkState/TaskSessionState
- Lifecycle, storage, integration points with atlas/ralph-loop hooks

All other AGENTS.md files: Generated date 2026-05-08 -> 2026-05-14.
2026-05-14 12:57:46 +09:00
YeonGyu-Kim d5fbada13d test: make unsafe test coercion explicit
Move test coercion out of a hidden global and require each test to import the helper so review tools and runtime scripts can see the unsafe boundary.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-12 15:51:31 +09:00
YeonGyu-Kim 11b3638493 test(features): remove unsafe test assertions
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-12 15:41:17 +09:00
YeonGyu-Kim 4da48555ee fix(plugin): normalize event session ids
Handle OpenCode session events that carry the session ID under properties.info.id or properties.info.sessionID so background tasks and continuation hooks do not miss idle/error/delete events.

Add regression coverage for nested session.idle events completing background tasks and waking continuation hooks.
2026-05-12 12:32:26 +09:00
YeonGyu-Kim 1bb36314bd feat(tmux-subagent): add event handlers for session lifecycle 2026-05-08 17:44:19 +09:00
YeonGyu-Kim c7d6a4a2ce fix: remove dead-code files accidentally resurrected by previous commit
The previous commit (2dfa6336f) used 'git add -A' which swept up files that
prior commits had intentionally deleted but were still present untracked in
the local workspace. This commit re-deletes them to match the upstream intent.

Files removed (each was previously deleted in the cited commit):

- drafts/gpt-5-5/{README,deep,hephaestus,oracle,sisyphus-junior,sisyphus}.md
  (deleted in 40ded422c chore(drafts): remove stale gpt-5.5 prompt drafts)
- src/plugin-dispose.{ts,test.ts}
  (deleted in e2f5c0d36 refactor(plugin): remove orphaned createPluginDispose)
- src/features/tmux-subagent/{cleanup,session-created-handler,session-deleted-handler}.ts
  (deleted in 7a7926f22 chore(tmux-subagent): remove dead event-handler modules)
- src/tools/delegate-task/{model-string-parser,resolve-call-id,resolve-call-id.test}.ts
  (model-string-parser deleted in db056346d; resolve-call-id was scratch)
- src/__debug-test.test.ts (debug scratch never intended for git)

Typecheck + model-requirements tests still pass. The legitimate metis +
AGENTS.md edits from the previous commit remain on dev.
2026-05-08 13:08:16 +09:00
YeonGyu-Kim 2dfa6336f5 fix(metis): switch primary model to claude-sonnet-4-6 + correct AGENTS.md inaccuracies
Source code change:
- src/shared/model-requirements.ts: prepend claude-sonnet-4-6 to metis fallback
  chain so Sonnet becomes the default. Opus 4.7 max remains as the immediate
  fallback for callers who want extra reasoning.
- src/shared/model-requirements.test.ts: update assertion to expect Sonnet
  primary + Opus secondary.

AGENTS.md accuracy fixes (verified against source):
- Agent modes: Sisyphus/Hephaestus are 'primary' (not 'all'); Sisyphus-Junior
  is 'subagent' (not 'all'). Confirmed via 'const MODE: AgentMode = ...' in
  each agent file. Also clarified Prometheus has no agentSources factory and
  is built via buildPrometheusAgentConfig.
- Sisyphus fallback chain: corrected order to kimi-k2.6 → k2p5 → kimi-k2.5
  → gpt-5.5 medium → glm-5 → big-pickle (was missing kimi-k2.5).
- Librarian/Explore: added missing minimax-m2.7 step between -highspeed and
  claude-haiku-4-5.
- Metis chain: removed fictitious gemini-3.1-pro entry.
- Sisyphus-Junior chain: spelled out the actual fallback (was 'user-configurable').
- Temperatures: Sisyphus/Hephaestus do not set explicit temperature (model
  default); Sisyphus-Junior is 0.1 via SISYPHUS_JUNIOR_DEFAULTS.
- Quick category default: gpt-5.4-mini (not gpt-5.4-mini-fast).

Team-mode corrections:
- Eligibility registry has 3 verdicts: eligible (sisyphus, atlas, sisyphus-junior),
  conditional (hephaestus — needs D-36 teammate permission), hard-reject
  (oracle, librarian, explore, multimodal-looker, metis, momus, prometheus).
- Schema has 11 fields, not 4: added max_messages_per_run, max_wall_clock_minutes,
  max_member_turns, base_dir, message_payload_max_bytes, recipient_unread_max_bytes,
  mailbox_poll_interval_ms.
- Hooks: 'team-session-events' is 4 sub-handlers in src/plugin/event.ts
  (team-idle-wake-hint, team-lead-orphan-handler, team-member-error-handler,
  team-member-status-handler), not a single Continuation-tier hook.
- Tier counts now show base + team-mode: ToolGuard 14/15, Transform 5/7.
- Total: 52 base hooks, 59 with team-mode.

Doc cascade for the Metis change:
- docs/guide/orchestration.md, agent-model-matching.md, installation.md
- docs/reference/configuration.md, features.md
2026-05-08 13:06:34 +09:00
YeonGyu-Kim 838b5ae216 docs(agents): refresh hierarchical AGENTS.md with team-mode coverage
Update root + 43 directory-level AGENTS.md files to reflect current state:
- Root AGENTS.md rewritten with accurate counts (1967 TS files, 1304 source +
  663 test, 278k LOC, 120 barrel index.ts), 7-step init flow, 5-tier hook
  composition, and full Team Mode section (12 team_* tools, eligibility,
  storage layout, config gate)
- src/AGENTS.md adds team-mode init step, current per-subdir file/LOC table
- src/tools/AGENTS.md documents conditional gates (team-mode +12, task
  system +4, hashline +1, interactive_bash +1, look_at +1) with always-on
  baseline of 20
- src/hooks/AGENTS.md splits into 5 tiers + 4 conditional team-mode hooks
- src/features/team-mode/AGENTS.md surfaces 12 tools, eligible agents,
  spawn-race-safe invariants, and integration points
- src/features/builtin-skills/AGENTS.md tracks 10 skills incl. team-mode
- src/agents/AGENTS.md, src/plugin/AGENTS.md, src/config/AGENTS.md updated
  for team-mode awareness, accurate counts, and current schema field list
- All other AGENTS.md files refreshed to 2026-05-08 generation date
2026-05-08 12:08:42 +09:00
YeonGyu-Kim ee938aa097 fix full-suite isolation regressions 2026-05-07 18:36:03 +09:00
YeonGyu-Kim d7d956468c docs: add AGENTS.md for team-mode and tmux-subagent features 2026-05-06 14:19:39 +09:00
YeonGyu-Kim 5e4ae8815e test(tmux-subagent): expand zombie-pane test coverage 2026-05-06 14:19:38 +09:00
YeonGyu-Kim 49bb5dd81a test(tmux-subagent): add pane-state-querier runner tests 2026-05-06 14:19:38 +09:00
YeonGyu-Kim 8d3d882578 test(tmux-subagent): add manager project-directory resolution tests 2026-05-06 14:19:38 +09:00
YeonGyu-Kim 77655a7c30 test(tmux-subagent): expand manager test coverage 2026-05-06 14:19:38 +09:00
YeonGyu-Kim 680927d0fd test(tmux-subagent): expand polling-manager test coverage 2026-05-06 14:19:38 +09:00
YeonGyu-Kim b6dcf05d45 test(tmux-subagent): expand action-executor test coverage 2026-05-06 14:19:38 +09:00
YeonGyu-Kim c8b225099c refactor(tmux-subagent): stabilize polling, execution and session lifecycle with runner 2026-05-06 14:19:38 +09:00
YeonGyu-Kim 3ddc757b15 fix(bun-spawn-shim): eliminate globalThis.Bun top-level destructures for Electron/Node compat
Root cause: bun build --target bun inlines top-level
  var { spawn } = globalThis.Bun;
for every file that contains 'import { spawn } from "bun"'. On Node/Electron
where globalThis.Bun is undefined, this crashes with
  Cannot destructure property 'spawn' of 'globalThis.Bun' as it is undefined.
26 source files had this import; the bundled output had 25 top-level destructures.

Fix:
- Add src/shared/bun-spawn-shim.ts: a thin wrapper that
  - delegates to Bun.spawn/spawnSync when globalThis.Bun is present (real Bun)
  - falls back to static ESM imports of node:child_process otherwise
  - uses static 'import { spawn } from "node:child_process"' so Bun bundler
    does NOT emit any globalThis.Bun destructures for this module
- Replace all 26 'from "bun"' spawn/spawnSync imports with relative paths to shim
- Replace 4 direct Bun.spawn() call sites with shim's spawn()
- Remove src/electron-compat.ts and script/prepend-electron-shim.ts (no longer needed)
- Update src/electron-compat.test.ts to assert 0 top-level globalThis.Bun destructures

Verification: grep -c '} = globalThis.Bun;' dist/index.js → 0 (was 25)
All 5921 tests pass (1 pre-existing timeout failure unrelated to this change).

Fixes #3797
2026-05-05 22:41:45 +09:00
YeonGyu-Kim acf293de96 fix(tmux): validate fallback port
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-27 14:24:42 +09:00
YeonGyu-Kim c65f90ee09 fix(tmux): preserve configured fallback port
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-27 13:51:16 +09:00
YeonGyu-Kim f1353cd9a8 fix(tmux): use stable fallback server URL
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-27 13:24:50 +09:00
YeonGyu-Kim 913fac05f5 fix(tmux-subagent): retry stale sweep if first attempt throws
Oracle flagged: staleSweepCompleted was set to true BEFORE
sweepStaleOmoAgentSessions() ran, so any throw from the first
invocation would permanently disable stale cleanup for the rest
of the process lifetime.

Fix:
- Move staleSweepCompleted=true into the try-block success branch.
- Add staleSweepInProgress guard so concurrent onSessionCreated calls
  do not invoke sweep twice in parallel (sweep is idempotent, but the
  guard prevents doubled log noise).
- finally{} clears the inProgress flag regardless of outcome.
- cleanup() resets both flags.

Two new tests cover: retry after a thrown first attempt, and single
invocation when subsequent spawns follow a successful first sweep.
2026-04-18 20:45:21 +09:00
YeonGyu-Kim 859d67f41e fix(tmux-subagent): revert session.error cleanup (recoverable-error regression)
Oracle flagged a regression introduced in PR #3507 commit 21554be8:
event.ts routed session.error through tmux pane cleanup BEFORE the
existing session-recovery / model-fallback logic ran.

Problem: when session.error was recoverable (context window limit,
quota rate limit, provider fallback), the recovery/fallback code would
successfully continue the SAME session - but by then its tmux pane had
already been destroyed. User-visible symptom is exactly the original
complaint - 'screen appears but streaming stops working' after an
auto-retry.

Fix is the minimal revert: remove the onSessionError funnel from
event.ts and drop onSessionError from the manager. Fatal errors that
actually end a session still fire session.deleted, which continues to
trigger cleanup correctly. Non-fatal error streams stay attached to
the surviving pane.
2026-04-18 20:37:49 +09:00
YeonGyu-Kim 3dce19d173 fix(tmux-subagent): move 'cleanup complete' log back to cleanup() method
The log line was misplaced at the end of sweepStaleIsolatedSessionsOnce
where it said 'cleanup complete' after the stale sweep, which was
misleading. Per Oracle review.
2026-04-18 20:27:48 +09:00
YeonGyu-Kim 104523051d feat(tmux): sweep stale omo-agents-<pid> sessions on first spawn
Follow-up to PR #3507 addressing the Oracle-noted operational limitation:
per-PID isolated session names (getIsolatedSessionName(process.pid)) mean
that when an opencode process is SIGKILL'd (or the machine hard-reboots),
the old omo-agents-<old-pid> tmux session survives forever because nothing
is around to kill it.

Added sweepStaleOmoAgentSessions() that:
1. Lists tmux sessions matching /^omo-agents-(\d+)$/
2. For each, checks process.kill(pid, 0) to detect a dead PID
3. Skips our own PID
4. Calls killTmuxSessionIfExists for every session whose owner process is gone

Wired into TmuxSessionManager.onSessionCreated() as a one-shot (guarded by
staleSweepCompleted flag) so it runs lazily on the first subagent spawn when
isolation="session". The flag is reset in cleanup() so subsequent process
restarts re-run the sweep.

6 new tests cover: outside-tmux no-op, no matching sessions, multiple dead
PIDs, current PID skip, live PID skip, list-sessions failure.

Manual E2E verified on real tmux:
- Created omo-agents-99999, sweep killed it
- Spawned our own omo-agents-<pid>, closeTmuxPane returned true even after
  pane auto-destroy from Ctrl+C
- Final tmux list-sessions shows zero omo-agents-* orphans
2026-04-18 20:22:00 +09:00
YeonGyu-Kim 257b6cf951 fix(tmux): scope isolated session name per plugin instance (Oracle review)
Oracle flagged the previous commit: "omo-agents" was a shared constant,
so when two plugin instances ran in the same tmux server they wrote into
the same session. One instance's cleanup would then kill-session on the
shared name and tear down the other instance's live attached panes.

Replace the const ISOLATED_SESSION_NAME with getIsolatedSessionName(pid)
which defaults to process.pid, so every opencode process owns its own
"omo-agents-<pid>" session. spawnTmuxSession and cleanup both resolve
the name through this helper. Discovery is straightforward from the
host tmux via 'tmux list-sessions | grep omo-agents-'.

Manager test covers two concurrent managers and asserts each kills a
per-pid session name, proving they no longer collide on a global name.
2026-04-18 19:47:36 +09:00
YeonGyu-Kim 21554be870 fix(tmux-subagent): tighten serve/attach cleanup paths so panes and sessions are torn down reliably
Three defects observed with tmux.isolation="session" where the omo-agents
session was left with orphan fish panes after subagents finished:

1. cleanup() never ran 'tmux kill-session -t omo-agents'. If any pane
   lingered (for example because opencode attach stayed blocked on SSE),
   the isolated session survived process shutdown. Now we explicitly kill
   the shared session through killTmuxSessionIfExists when isolation is
   "session".

2. session.error events bypassed tmux cleanup entirely. Only session.deleted
   closed panes, so any provider error that did not escalate into a delete
   left the pane behind. Added onSessionError on TmuxSessionManager, wired
   from plugin/event.ts, which funnels through the same onSessionDeleted
   close path for tracked sessions only.

3. retryPendingCloses() only ran when a new session was created. If the
   main process went idle after a failed close, the pending session stayed
   pending forever. TmuxPollingManager now accepts the retry callback and
   fires it on every tick, alongside the existing stability-based close
   sweep.

Manager tests cover isolation=session kill invocation, inline/window
isolation skipping the kill, the onSessionError happy + untracked paths,
and an isolated-session kill failure that must not break cleanup.
2026-04-18 19:31:45 +09:00
YeonGyu-Kim 7a7926f222 chore(tmux-subagent): remove dead event-handler modules
Drop cleanup.ts, session-created-handler.ts, and session-deleted-handler.ts
which were never wired up; the lifecycle logic they contained lives inline
in TmuxSessionManager. Barrels trimmed to match.
2026-04-18 19:30:44 +09:00
YeonGyu-Kim c9c1c58c2c fix(tmux-subagent): track pane without blocking on session readiness
waitForSessionReady polled session.status for up to 10s before the pane was registered, but session.status only becomes visible after promptAsync starts. Blocking pane tracking on that signal caused the attach client to see an empty session and render a blank TUI.

Track the pane immediately after spawn, and run the readiness probe in the background purely for observability.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-18 17:22:01 +09:00
YeonGyu-Kim 0c5cd3a1c4 chore(agents): update all AGENTS.md generation dates to 2026-04-11
🤖 Generated with OhMyOpenCode assistance
2026-04-11 22:33:22 +09:00
YeonGyu-Kim 4180a0ba0a test(features): update background agent, MCP loader, and tmux tests
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-10 15:53:30 +09:00
GeonWoo Jeon (Jay) ade57474be fix(merge): resolve dev conflicts for openclaw branch 2026-04-09 12:23:38 +09:00
GeonWoo Jeon (Jay) 687e7bb243 fix(test): align zombie pane tmux mocks 2026-04-09 12:09:09 +09:00