oh-my-codex 0.11.12 → 0.11.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +23 -0
  4. package/README.vi.md +144 -185
  5. package/crates/omx-runtime-core/src/engine.rs +122 -4
  6. package/crates/omx-runtime-core/src/lib.rs +17 -0
  7. package/dist/cli/__tests__/autoresearch.test.js +11 -0
  8. package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
  9. package/dist/cli/__tests__/cleanup.test.js +117 -4
  10. package/dist/cli/__tests__/cleanup.test.js.map +1 -1
  11. package/dist/cli/__tests__/error-handling-warnings.test.js +13 -0
  12. package/dist/cli/__tests__/error-handling-warnings.test.js.map +1 -1
  13. package/dist/cli/__tests__/exec.test.js +6 -0
  14. package/dist/cli/__tests__/exec.test.js.map +1 -1
  15. package/dist/cli/__tests__/index.test.js +94 -1
  16. package/dist/cli/__tests__/index.test.js.map +1 -1
  17. package/dist/cli/__tests__/launch-fallback.test.js +3 -0
  18. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  19. package/dist/cli/__tests__/package-bin-contract.test.js +10 -0
  20. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  21. package/dist/cli/__tests__/packaged-script-resolution.test.js +4 -3
  22. package/dist/cli/__tests__/packaged-script-resolution.test.js.map +1 -1
  23. package/dist/cli/__tests__/resume.test.js +6 -0
  24. package/dist/cli/__tests__/resume.test.js.map +1 -1
  25. package/dist/cli/__tests__/setup-refresh.test.js +29 -12
  26. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  27. package/dist/cli/__tests__/star-prompt.test.js +16 -0
  28. package/dist/cli/__tests__/star-prompt.test.js.map +1 -1
  29. package/dist/cli/__tests__/uninstall.test.js +112 -1
  30. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  31. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts +2 -0
  32. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts.map +1 -0
  33. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +30 -0
  34. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -0
  35. package/dist/cli/cleanup.d.ts +2 -0
  36. package/dist/cli/cleanup.d.ts.map +1 -1
  37. package/dist/cli/cleanup.js +26 -1
  38. package/dist/cli/cleanup.js.map +1 -1
  39. package/dist/cli/index.d.ts +7 -0
  40. package/dist/cli/index.d.ts.map +1 -1
  41. package/dist/cli/index.js +161 -50
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/cli/setup.d.ts.map +1 -1
  44. package/dist/cli/setup.js +15 -14
  45. package/dist/cli/setup.js.map +1 -1
  46. package/dist/cli/star-prompt.d.ts.map +1 -1
  47. package/dist/cli/star-prompt.js +1 -0
  48. package/dist/cli/star-prompt.js.map +1 -1
  49. package/dist/cli/team.d.ts.map +1 -1
  50. package/dist/cli/team.js +5 -1
  51. package/dist/cli/team.js.map +1 -1
  52. package/dist/cli/uninstall.d.ts.map +1 -1
  53. package/dist/cli/uninstall.js +26 -0
  54. package/dist/cli/uninstall.js.map +1 -1
  55. package/dist/cli/update.d.ts.map +1 -1
  56. package/dist/cli/update.js +1 -0
  57. package/dist/cli/update.js.map +1 -1
  58. package/dist/config/__tests__/generator-idempotent.test.js +4 -4
  59. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  60. package/dist/config/__tests__/mcp-registry.test.js +13 -16
  61. package/dist/config/__tests__/mcp-registry.test.js.map +1 -1
  62. package/dist/config/mcp-registry.d.ts +1 -0
  63. package/dist/config/mcp-registry.d.ts.map +1 -1
  64. package/dist/config/mcp-registry.js +4 -4
  65. package/dist/config/mcp-registry.js.map +1 -1
  66. package/dist/config/models.d.ts +1 -0
  67. package/dist/config/models.d.ts.map +1 -1
  68. package/dist/config/models.js +39 -1
  69. package/dist/config/models.js.map +1 -1
  70. package/dist/hooks/__tests__/keyword-detector.test.js +12 -1
  71. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  72. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +499 -17
  73. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  74. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +140 -14
  75. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  76. package/dist/hooks/__tests__/notify-hook-modules.test.js +5 -0
  77. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
  78. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts +2 -0
  79. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts.map +1 -0
  80. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +597 -0
  81. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -0
  82. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +15 -1
  83. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
  84. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +73 -53
  85. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  86. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +193 -2
  87. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  88. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +183 -0
  89. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  90. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +255 -97
  91. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  92. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
  93. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  94. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +46 -0
  95. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  96. package/dist/hooks/keyword-detector.d.ts +1 -0
  97. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  98. package/dist/hooks/keyword-detector.js +48 -0
  99. package/dist/hooks/keyword-detector.js.map +1 -1
  100. package/dist/hooks/session.d.ts.map +1 -1
  101. package/dist/hooks/session.js +1 -0
  102. package/dist/hooks/session.js.map +1 -1
  103. package/dist/hud/__tests__/state.test.js +70 -1
  104. package/dist/hud/__tests__/state.test.js.map +1 -1
  105. package/dist/hud/state.d.ts.map +1 -1
  106. package/dist/hud/state.js +10 -37
  107. package/dist/hud/state.js.map +1 -1
  108. package/dist/mcp/state-server.d.ts.map +1 -1
  109. package/dist/mcp/state-server.js +5 -0
  110. package/dist/mcp/state-server.js.map +1 -1
  111. package/dist/modes/__tests__/base-session-scope.test.js +46 -0
  112. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  113. package/dist/modes/base.d.ts.map +1 -1
  114. package/dist/modes/base.js +4 -0
  115. package/dist/modes/base.js.map +1 -1
  116. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts +2 -0
  117. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts.map +1 -0
  118. package/dist/notifications/__tests__/custom-alias-enablement.test.js +84 -0
  119. package/dist/notifications/__tests__/custom-alias-enablement.test.js.map +1 -0
  120. package/dist/notifications/__tests__/idle-cooldown.test.js +55 -0
  121. package/dist/notifications/__tests__/idle-cooldown.test.js.map +1 -1
  122. package/dist/notifications/idle-cooldown.d.ts +8 -6
  123. package/dist/notifications/idle-cooldown.d.ts.map +1 -1
  124. package/dist/notifications/idle-cooldown.js +53 -22
  125. package/dist/notifications/idle-cooldown.js.map +1 -1
  126. package/dist/notifications/notifier.js +1 -1
  127. package/dist/notifications/notifier.js.map +1 -1
  128. package/dist/notifications/reply-listener.d.ts.map +1 -1
  129. package/dist/notifications/reply-listener.js +1 -0
  130. package/dist/notifications/reply-listener.js.map +1 -1
  131. package/dist/openclaw/config.js +2 -2
  132. package/dist/openclaw/config.js.map +1 -1
  133. package/dist/runtime/bridge.d.ts +1 -0
  134. package/dist/runtime/bridge.d.ts.map +1 -1
  135. package/dist/runtime/bridge.js +2 -6
  136. package/dist/runtime/bridge.js.map +1 -1
  137. package/dist/scripts/notify-fallback-watcher.js +97 -59
  138. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  139. package/dist/scripts/notify-hook/auto-nudge.d.ts +2 -1
  140. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  141. package/dist/scripts/notify-hook/auto-nudge.js +72 -238
  142. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  143. package/dist/scripts/notify-hook/managed-tmux.d.ts +19 -0
  144. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -0
  145. package/dist/scripts/notify-hook/managed-tmux.js +320 -0
  146. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -0
  147. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +22 -0
  148. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -0
  149. package/dist/scripts/notify-hook/ralph-session-resume.js +277 -0
  150. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -0
  151. package/dist/scripts/notify-hook/state-io.d.ts +1 -1
  152. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  153. package/dist/scripts/notify-hook/state-io.js +2 -10
  154. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  155. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  156. package/dist/scripts/notify-hook/team-dispatch.js +60 -59
  157. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  158. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -1
  159. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  160. package/dist/scripts/notify-hook/team-leader-nudge.js +13 -5
  161. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  162. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  163. package/dist/scripts/notify-hook/team-tmux-guard.js +1 -19
  164. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  165. package/dist/scripts/notify-hook/team-worker.js +4 -4
  166. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  167. package/dist/scripts/notify-hook/tmux-injection.d.ts +1 -1
  168. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  169. package/dist/scripts/notify-hook/tmux-injection.js +102 -35
  170. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  171. package/dist/scripts/notify-hook.js +144 -20
  172. package/dist/scripts/notify-hook.js.map +1 -1
  173. package/dist/scripts/tmux-hook-engine.d.ts +1 -0
  174. package/dist/scripts/tmux-hook-engine.d.ts.map +1 -1
  175. package/dist/scripts/tmux-hook-engine.js +3 -0
  176. package/dist/scripts/tmux-hook-engine.js.map +1 -1
  177. package/dist/team/__tests__/api-interop.test.js +96 -4
  178. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  179. package/dist/team/__tests__/leader-activity.test.js +107 -2
  180. package/dist/team/__tests__/leader-activity.test.js.map +1 -1
  181. package/dist/team/__tests__/runtime-cli.test.js +32 -0
  182. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  183. package/dist/team/__tests__/runtime.test.js +148 -0
  184. package/dist/team/__tests__/runtime.test.js.map +1 -1
  185. package/dist/team/__tests__/shutdown-fallback.test.js +13 -0
  186. package/dist/team/__tests__/shutdown-fallback.test.js.map +1 -1
  187. package/dist/team/__tests__/state-root.test.js +11 -1
  188. package/dist/team/__tests__/state-root.test.js.map +1 -1
  189. package/dist/team/__tests__/state.test.js +16 -5
  190. package/dist/team/__tests__/state.test.js.map +1 -1
  191. package/dist/team/__tests__/tmux-session.test.js +460 -2
  192. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  193. package/dist/team/api-interop.d.ts.map +1 -1
  194. package/dist/team/api-interop.js +34 -7
  195. package/dist/team/api-interop.js.map +1 -1
  196. package/dist/team/commit-hygiene.d.ts +60 -0
  197. package/dist/team/commit-hygiene.d.ts.map +1 -0
  198. package/dist/team/commit-hygiene.js +232 -0
  199. package/dist/team/commit-hygiene.js.map +1 -0
  200. package/dist/team/leader-activity.d.ts.map +1 -1
  201. package/dist/team/leader-activity.js +17 -35
  202. package/dist/team/leader-activity.js.map +1 -1
  203. package/dist/team/runtime-cli.d.ts +9 -1
  204. package/dist/team/runtime-cli.d.ts.map +1 -1
  205. package/dist/team/runtime-cli.js +15 -6
  206. package/dist/team/runtime-cli.js.map +1 -1
  207. package/dist/team/runtime.d.ts +7 -2
  208. package/dist/team/runtime.d.ts.map +1 -1
  209. package/dist/team/runtime.js +391 -63
  210. package/dist/team/runtime.js.map +1 -1
  211. package/dist/team/state/dispatch.js +1 -1
  212. package/dist/team/state/dispatch.js.map +1 -1
  213. package/dist/team/state/mailbox.d.ts +1 -0
  214. package/dist/team/state/mailbox.d.ts.map +1 -1
  215. package/dist/team/state/mailbox.js +54 -8
  216. package/dist/team/state/mailbox.js.map +1 -1
  217. package/dist/team/state-root.d.ts +1 -1
  218. package/dist/team/state-root.d.ts.map +1 -1
  219. package/dist/team/state-root.js +8 -3
  220. package/dist/team/state-root.js.map +1 -1
  221. package/dist/team/state.d.ts.map +1 -1
  222. package/dist/team/state.js +66 -3
  223. package/dist/team/state.js.map +1 -1
  224. package/dist/team/tmux-session.d.ts.map +1 -1
  225. package/dist/team/tmux-session.js +69 -27
  226. package/dist/team/tmux-session.js.map +1 -1
  227. package/dist/utils/__tests__/platform-command.test.js +101 -2
  228. package/dist/utils/__tests__/platform-command.test.js.map +1 -1
  229. package/dist/utils/git-layout.d.ts +8 -0
  230. package/dist/utils/git-layout.d.ts.map +1 -0
  231. package/dist/utils/git-layout.js +58 -0
  232. package/dist/utils/git-layout.js.map +1 -0
  233. package/dist/utils/platform-command.d.ts.map +1 -1
  234. package/dist/utils/platform-command.js +32 -1
  235. package/dist/utils/platform-command.js.map +1 -1
  236. package/package.json +6 -6
  237. package/src/scripts/notify-fallback-watcher.ts +96 -58
  238. package/src/scripts/notify-hook/auto-nudge.ts +75 -230
  239. package/src/scripts/notify-hook/managed-tmux.ts +324 -0
  240. package/src/scripts/notify-hook/ralph-session-resume.ts +337 -0
  241. package/src/scripts/notify-hook/state-io.ts +2 -10
  242. package/src/scripts/notify-hook/team-dispatch.ts +70 -54
  243. package/src/scripts/notify-hook/team-leader-nudge.ts +19 -5
  244. package/src/scripts/notify-hook/team-tmux-guard.ts +0 -20
  245. package/src/scripts/notify-hook/team-worker.ts +4 -4
  246. package/src/scripts/notify-hook/tmux-injection.ts +103 -33
  247. package/src/scripts/notify-hook.ts +150 -21
  248. package/src/scripts/tmux-hook-engine.ts +4 -0
@@ -1,9 +1,11 @@
1
1
  import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { spawnSync } from 'node:child_process';
4
3
  import { chmod, mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
4
+ import { readFileSync } from 'node:fs';
5
5
  import { tmpdir } from 'node:os';
6
6
  import { join } from 'node:path';
7
+ import { buildTmuxSessionName } from '../../cli/index.js';
8
+ import { handleTmuxInjection } from '../../scripts/notify-hook/tmux-injection.js';
7
9
  const NOTIFY_HOOK_SCRIPT = new URL('../../../dist/scripts/notify-hook.js', import.meta.url);
8
10
  async function withTempWorkingDir(run) {
9
11
  const cwd = await mkdtemp(join(tmpdir(), 'omx-notify-tmux-heal-'));
@@ -20,6 +22,44 @@ async function writeJson(path, value) {
20
22
  async function readJson(path) {
21
23
  return JSON.parse(await readFile(path, 'utf-8'));
22
24
  }
25
+ function readLinuxStartTicks(pid) {
26
+ try {
27
+ const stat = readFileSync(`/proc/${pid}/stat`, 'utf-8');
28
+ const commandEnd = stat.lastIndexOf(')');
29
+ if (commandEnd === -1)
30
+ return null;
31
+ const remainder = stat.slice(commandEnd + 1).trim();
32
+ const fields = remainder.split(/\s+/);
33
+ if (fields.length <= 19)
34
+ return null;
35
+ const startTicks = Number(fields[19]);
36
+ return Number.isFinite(startTicks) ? startTicks : null;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ function readLinuxCmdline(pid) {
43
+ try {
44
+ const raw = readFileSync(`/proc/${pid}/cmdline`);
45
+ const text = raw.toString('utf-8').replace(/\0+/g, ' ').trim();
46
+ return text.length > 0 ? text : null;
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ async function writeManagedSessionState(stateDir, cwd, sessionId) {
53
+ await writeJson(join(stateDir, 'session.json'), {
54
+ session_id: sessionId,
55
+ started_at: new Date().toISOString(),
56
+ cwd,
57
+ pid: process.pid,
58
+ platform: process.platform,
59
+ pid_start_ticks: readLinuxStartTicks(process.pid),
60
+ pid_cmdline: readLinuxCmdline(process.pid),
61
+ });
62
+ }
23
63
  describe('notify-hook tmux target healing', () => {
24
64
  it('falls back to global mode state when scoped session has no allowed active mode', async () => {
25
65
  await withTempWorkingDir(async (cwd) => {
@@ -30,12 +70,13 @@ describe('notify-hook tmux target healing', () => {
30
70
  const sessionStateDir = join(stateDir, 'sessions', sessionId);
31
71
  const fakeBinDir = join(cwd, 'fake-bin');
32
72
  const fakeTmuxPath = join(fakeBinDir, 'tmux');
73
+ const managedSessionName = buildTmuxSessionName(cwd, sessionId);
33
74
  const configPath = join(omxDir, 'tmux-hook.json');
34
75
  const hookStatePath = join(stateDir, 'tmux-hook-state.json');
35
76
  await mkdir(sessionStateDir, { recursive: true });
36
77
  await mkdir(logsDir, { recursive: true });
37
78
  await mkdir(fakeBinDir, { recursive: true });
38
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
79
+ await writeManagedSessionState(stateDir, cwd, sessionId);
39
80
  await writeJson(join(sessionStateDir, 'team-state.json'), { active: true, current_phase: 'team-exec' });
40
81
  await writeJson(join(stateDir, 'ralph-state.json'), { active: true, iteration: 0 });
41
82
  await writeJson(configPath, {
@@ -71,6 +112,10 @@ if [[ "$cmd" == "display-message" ]]; then
71
112
  echo "codex"
72
113
  exit 0
73
114
  fi
115
+ if [[ "$format" == "#S" && "$target" == "%42" ]]; then
116
+ echo "${managedSessionName}"
117
+ exit 0
118
+ fi
74
119
  if [[ "$format" == "#{pane_in_mode}" && "$target" == "%42" ]]; then
75
120
  echo "0"
76
121
  exit 0
@@ -95,15 +140,24 @@ exit 1
95
140
  'input-messages': ['no marker here'],
96
141
  'last-assistant-message': 'output',
97
142
  };
98
- const result = spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
99
- encoding: 'utf8',
100
- env: {
101
- ...process.env,
102
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
103
- OMX_TEAM_WORKER: '',
104
- },
105
- });
106
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
143
+ const previousPath = process.env.PATH;
144
+ const previousTeamWorker = process.env.OMX_TEAM_WORKER;
145
+ try {
146
+ process.env.PATH = `${fakeBinDir}:${process.env.PATH || ''}`;
147
+ process.env.OMX_TEAM_WORKER = '';
148
+ delete process.env.TMUX_PANE;
149
+ await handleTmuxInjection({ payload, cwd, stateDir, logsDir });
150
+ }
151
+ finally {
152
+ if (typeof previousPath === 'string')
153
+ process.env.PATH = previousPath;
154
+ else
155
+ delete process.env.PATH;
156
+ if (typeof previousTeamWorker === 'string')
157
+ process.env.OMX_TEAM_WORKER = previousTeamWorker;
158
+ else
159
+ delete process.env.OMX_TEAM_WORKER;
160
+ }
107
161
  const hookState = await readJson(hookStatePath);
108
162
  assert.equal(hookState.last_reason, 'injection_sent');
109
163
  assert.equal(hookState.total_injections, 1);
@@ -118,12 +172,13 @@ exit 1
118
172
  const sessionStateDir = join(stateDir, 'sessions', sessionId);
119
173
  const fakeBinDir = join(cwd, 'fake-bin');
120
174
  const fakeTmuxPath = join(fakeBinDir, 'tmux');
175
+ const managedSessionName = buildTmuxSessionName(cwd, sessionId);
121
176
  const configPath = join(omxDir, 'tmux-hook.json');
122
177
  const hookStatePath = join(stateDir, 'tmux-hook-state.json');
123
178
  await mkdir(sessionStateDir, { recursive: true });
124
179
  await mkdir(logsDir, { recursive: true });
125
180
  await mkdir(fakeBinDir, { recursive: true });
126
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
181
+ await writeManagedSessionState(stateDir, cwd, sessionId);
127
182
  await writeJson(join(sessionStateDir, 'ralph-state.json'), { active: true, iteration: 0 });
128
183
  await writeJson(configPath, {
129
184
  enabled: true,
@@ -148,7 +203,7 @@ if [[ "$cmd" == "list-panes" ]]; then
148
203
  *) shift ;;
149
204
  esac
150
205
  done
151
- if [[ "$target" == "devsess" ]]; then
206
+ if [[ "$target" == "${managedSessionName}" ]]; then
152
207
  echo "%42 1"
153
208
  exit 0
154
209
  fi
@@ -190,7 +245,7 @@ if [[ "$cmd" == "display-message" ]]; then
190
245
  exit 0
191
246
  fi
192
247
  if [[ "$format" == "#S" && "$target" == "%42" ]]; then
193
- echo "devsess"
248
+ echo "${managedSessionName}"
194
249
  exit 0
195
250
  fi
196
251
  echo "bad display target: $target / $format" >&2
@@ -207,21 +262,35 @@ exit 1
207
262
  const payload = {
208
263
  cwd,
209
264
  type: 'agent-turn-complete',
265
+ session_id: sessionId,
210
266
  'thread-id': 'thread-test',
211
267
  'turn-id': 'turn-test',
212
268
  'input-messages': ['no marker here'],
213
269
  'last-assistant-message': 'output',
214
270
  };
215
- const result = spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
216
- encoding: 'utf8',
217
- env: {
218
- ...process.env,
219
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
220
- OMX_TEAM_WORKER: '',
221
- TMUX_PANE: '%42',
222
- },
223
- });
224
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
271
+ const previousPath = process.env.PATH;
272
+ const previousTeamWorker = process.env.OMX_TEAM_WORKER;
273
+ const previousTmuxPane = process.env.TMUX_PANE;
274
+ try {
275
+ process.env.PATH = `${fakeBinDir}:${process.env.PATH || ''}`;
276
+ process.env.OMX_TEAM_WORKER = '';
277
+ process.env.TMUX_PANE = '%42';
278
+ await handleTmuxInjection({ payload, cwd, stateDir, logsDir });
279
+ }
280
+ finally {
281
+ if (typeof previousPath === 'string')
282
+ process.env.PATH = previousPath;
283
+ else
284
+ delete process.env.PATH;
285
+ if (typeof previousTeamWorker === 'string')
286
+ process.env.OMX_TEAM_WORKER = previousTeamWorker;
287
+ else
288
+ delete process.env.OMX_TEAM_WORKER;
289
+ if (typeof previousTmuxPane === 'string')
290
+ process.env.TMUX_PANE = previousTmuxPane;
291
+ else
292
+ delete process.env.TMUX_PANE;
293
+ }
225
294
  const hookState = await readJson(hookStatePath);
226
295
  assert.equal(hookState.last_reason, 'injection_sent');
227
296
  assert.equal(hookState.total_injections, 1);
@@ -239,12 +308,13 @@ exit 1
239
308
  const sessionStateDir = join(stateDir, 'sessions', sessionId);
240
309
  const fakeBinDir = join(cwd, 'fake-bin');
241
310
  const fakeTmuxPath = join(fakeBinDir, 'tmux');
311
+ const managedSessionName = buildTmuxSessionName(cwd, sessionId);
242
312
  const configPath = join(omxDir, 'tmux-hook.json');
243
313
  const hookStatePath = join(stateDir, 'tmux-hook-state.json');
244
314
  await mkdir(sessionStateDir, { recursive: true });
245
315
  await mkdir(logsDir, { recursive: true });
246
316
  await mkdir(fakeBinDir, { recursive: true });
247
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
317
+ await writeManagedSessionState(stateDir, cwd, sessionId);
248
318
  await writeJson(join(sessionStateDir, 'ralph-state.json'), { active: true, iteration: 0 });
249
319
  await writeJson(configPath, {
250
320
  enabled: true,
@@ -269,7 +339,7 @@ if [[ "$cmd" == "list-panes" ]]; then
269
339
  *) shift ;;
270
340
  esac
271
341
  done
272
- if [[ "$target" == "devsess" ]]; then
342
+ if [[ "$target" == "${managedSessionName}" ]]; then
273
343
  echo "%42 1"
274
344
  exit 0
275
345
  fi
@@ -311,7 +381,7 @@ if [[ "$cmd" == "display-message" ]]; then
311
381
  exit 0
312
382
  fi
313
383
  if [[ "$format" == "#S" && "$target" == "%42" ]]; then
314
- echo "devsess"
384
+ echo "${managedSessionName}"
315
385
  exit 0
316
386
  fi
317
387
  echo "bad display target: $target / $format" >&2
@@ -328,27 +398,41 @@ exit 1
328
398
  const payload = {
329
399
  cwd,
330
400
  type: 'agent-turn-complete',
401
+ session_id: sessionId,
331
402
  'thread-id': 'thread-test-2',
332
403
  'turn-id': 'turn-test-2',
333
404
  'input-messages': ['no marker here'],
334
405
  'last-assistant-message': 'output',
335
406
  };
336
- const result = spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
337
- encoding: 'utf8',
338
- env: {
339
- ...process.env,
340
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
341
- OMX_TEAM_WORKER: '',
342
- TMUX_PANE: '%42',
343
- },
344
- });
345
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
407
+ const previousPath = process.env.PATH;
408
+ const previousTeamWorker = process.env.OMX_TEAM_WORKER;
409
+ const previousTmuxPane = process.env.TMUX_PANE;
410
+ try {
411
+ process.env.PATH = `${fakeBinDir}:${process.env.PATH || ''}`;
412
+ process.env.OMX_TEAM_WORKER = '';
413
+ process.env.TMUX_PANE = '%42';
414
+ await handleTmuxInjection({ payload, cwd, stateDir, logsDir });
415
+ }
416
+ finally {
417
+ if (typeof previousPath === 'string')
418
+ process.env.PATH = previousPath;
419
+ else
420
+ delete process.env.PATH;
421
+ if (typeof previousTeamWorker === 'string')
422
+ process.env.OMX_TEAM_WORKER = previousTeamWorker;
423
+ else
424
+ delete process.env.OMX_TEAM_WORKER;
425
+ if (typeof previousTmuxPane === 'string')
426
+ process.env.TMUX_PANE = previousTmuxPane;
427
+ else
428
+ delete process.env.TMUX_PANE;
429
+ }
346
430
  const hookState = await readJson(hookStatePath);
347
431
  assert.equal(hookState.last_reason, 'pane_cwd_mismatch');
348
432
  assert.equal(hookState.total_injections, 0);
349
433
  });
350
434
  });
351
- it('does not guess a pane by shared cwd when canonical codex pane is unavailable', async () => {
435
+ it('resolves the explicit managed session target without shared-cwd guessing', async () => {
352
436
  await withTempWorkingDir(async (cwd) => {
353
437
  const omxDir = join(cwd, '.omx');
354
438
  const stateDir = join(omxDir, 'state');
@@ -357,12 +441,13 @@ exit 1
357
441
  const sessionStateDir = join(stateDir, 'sessions', sessionId);
358
442
  const fakeBinDir = join(cwd, 'fake-bin');
359
443
  const fakeTmuxPath = join(fakeBinDir, 'tmux');
444
+ const managedSessionName = buildTmuxSessionName(cwd, sessionId);
360
445
  const configPath = join(omxDir, 'tmux-hook.json');
361
446
  const hookStatePath = join(stateDir, 'tmux-hook-state.json');
362
447
  await mkdir(sessionStateDir, { recursive: true });
363
448
  await mkdir(logsDir, { recursive: true });
364
449
  await mkdir(fakeBinDir, { recursive: true });
365
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
450
+ await writeManagedSessionState(stateDir, cwd, sessionId);
366
451
  await writeJson(join(sessionStateDir, 'ralph-state.json'), { active: true, iteration: 0 });
367
452
  await writeJson(configPath, {
368
453
  enabled: true,
@@ -394,7 +479,7 @@ if [[ "$cmd" == "list-panes" ]]; then
394
479
  echo "%42\t${cwd}\t1\tdevsess"
395
480
  exit 0
396
481
  fi
397
- if [[ "$target" == "devsess" ]]; then
482
+ if [[ "$target" == "${managedSessionName}" ]]; then
398
483
  echo "%42 1"
399
484
  exit 0
400
485
  fi
@@ -416,7 +501,7 @@ if [[ "$cmd" == "display-message" ]]; then
416
501
  exit 0
417
502
  fi
418
503
  if [[ "$format" == "#S" && "$target" == "%42" ]]; then
419
- echo "devsess"
504
+ echo "${managedSessionName}"
420
505
  exit 0
421
506
  fi
422
507
  if [[ "$format" == "#{pane_current_path}" && "$target" == "%42" ]]; then
@@ -437,23 +522,33 @@ exit 1
437
522
  const payload = {
438
523
  cwd,
439
524
  type: 'agent-turn-complete',
525
+ session_id: sessionId,
440
526
  'thread-id': 'thread-test-3',
441
527
  'turn-id': 'turn-test-3',
442
528
  'input-messages': ['no marker here'],
443
529
  'last-assistant-message': 'output',
444
530
  };
445
- const result = spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
446
- encoding: 'utf8',
447
- env: {
448
- ...process.env,
449
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
450
- OMX_TEAM_WORKER: '',
451
- },
452
- });
453
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
531
+ const previousPath = process.env.PATH;
532
+ const previousTeamWorker = process.env.OMX_TEAM_WORKER;
533
+ try {
534
+ process.env.PATH = `${fakeBinDir}:${process.env.PATH || ''}`;
535
+ process.env.OMX_TEAM_WORKER = '';
536
+ delete process.env.TMUX_PANE;
537
+ await handleTmuxInjection({ payload, cwd, stateDir, logsDir });
538
+ }
539
+ finally {
540
+ if (typeof previousPath === 'string')
541
+ process.env.PATH = previousPath;
542
+ else
543
+ delete process.env.PATH;
544
+ if (typeof previousTeamWorker === 'string')
545
+ process.env.OMX_TEAM_WORKER = previousTeamWorker;
546
+ else
547
+ delete process.env.OMX_TEAM_WORKER;
548
+ }
454
549
  const hookState = await readJson(hookStatePath);
455
- assert.equal(hookState.last_reason, 'target_not_found');
456
- assert.equal(hookState.total_injections ?? 0, 0);
550
+ assert.equal(hookState.last_reason, 'injection_sent');
551
+ assert.equal(hookState.total_injections, 1);
457
552
  });
458
553
  });
459
554
  it('heals a stale HUD pane target back to the canonical codex pane', async () => {
@@ -465,12 +560,13 @@ exit 1
465
560
  const sessionStateDir = join(stateDir, 'sessions', sessionId);
466
561
  const fakeBinDir = join(cwd, 'fake-bin');
467
562
  const fakeTmuxPath = join(fakeBinDir, 'tmux');
563
+ const managedSessionName = buildTmuxSessionName(cwd, sessionId);
468
564
  const configPath = join(omxDir, 'tmux-hook.json');
469
565
  const hookStatePath = join(stateDir, 'tmux-hook-state.json');
470
566
  await mkdir(sessionStateDir, { recursive: true });
471
567
  await mkdir(logsDir, { recursive: true });
472
568
  await mkdir(fakeBinDir, { recursive: true });
473
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
569
+ await writeManagedSessionState(stateDir, cwd, sessionId);
474
570
  await writeJson(join(sessionStateDir, 'ralph-state.json'), { active: true, iteration: 0 });
475
571
  await writeJson(configPath, {
476
572
  enabled: true,
@@ -510,7 +606,7 @@ if [[ "$cmd" == "display-message" ]]; then
510
606
  exit 0
511
607
  fi
512
608
  if [[ "$format" == "#S" && "$target" == "%77" ]]; then
513
- echo "devsess"
609
+ echo "${managedSessionName}"
514
610
  exit 0
515
611
  fi
516
612
  if [[ "$format" == "#{pane_current_path}" && "$target" == "%99" ]]; then
@@ -522,7 +618,7 @@ if [[ "$cmd" == "display-message" ]]; then
522
618
  exit 0
523
619
  fi
524
620
  if [[ "$format" == "#S" && "$target" == "%99" ]]; then
525
- echo "devsess"
621
+ echo "${managedSessionName}"
526
622
  exit 0
527
623
  fi
528
624
  if [[ "$format" == "#{pane_in_mode}" && "$target" == "%99" ]]; then
@@ -531,6 +627,20 @@ if [[ "$cmd" == "display-message" ]]; then
531
627
  fi
532
628
  exit 1
533
629
  fi
630
+ if [[ "$cmd" == "list-panes" ]]; then
631
+ target=""
632
+ while (($#)); do
633
+ case "$1" in
634
+ -t) target="$2"; shift 2 ;;
635
+ *) shift ;;
636
+ esac
637
+ done
638
+ if [[ "$target" == "${managedSessionName}" ]]; then
639
+ printf "%%77\t1\tnode\tnode dist/cli/omx.js hud --watch\n%%99\t0\tcodex\tcodex\n"
640
+ exit 0
641
+ fi
642
+ exit 1
643
+ fi
534
644
  if [[ "$cmd" == "send-keys" ]]; then
535
645
  exit 0
536
646
  fi
@@ -547,16 +657,29 @@ exit 1
547
657
  'input-messages': ['no marker here'],
548
658
  'last-assistant-message': 'output',
549
659
  };
550
- const result = spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
551
- encoding: 'utf8',
552
- env: {
553
- ...process.env,
554
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
555
- OMX_TEAM_WORKER: '',
556
- TMUX_PANE: '%99',
557
- },
558
- });
559
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
660
+ const previousPath = process.env.PATH;
661
+ const previousTeamWorker = process.env.OMX_TEAM_WORKER;
662
+ const previousTmuxPane = process.env.TMUX_PANE;
663
+ try {
664
+ process.env.PATH = `${fakeBinDir}:${process.env.PATH || ''}`;
665
+ process.env.OMX_TEAM_WORKER = '';
666
+ process.env.TMUX_PANE = '%99';
667
+ await handleTmuxInjection({ payload, cwd, stateDir, logsDir });
668
+ }
669
+ finally {
670
+ if (typeof previousPath === 'string')
671
+ process.env.PATH = previousPath;
672
+ else
673
+ delete process.env.PATH;
674
+ if (typeof previousTeamWorker === 'string')
675
+ process.env.OMX_TEAM_WORKER = previousTeamWorker;
676
+ else
677
+ delete process.env.OMX_TEAM_WORKER;
678
+ if (typeof previousTmuxPane === 'string')
679
+ process.env.TMUX_PANE = previousTmuxPane;
680
+ else
681
+ delete process.env.TMUX_PANE;
682
+ }
560
683
  const hookState = await readJson(hookStatePath);
561
684
  assert.equal(hookState.last_reason, 'injection_sent');
562
685
  assert.equal(hookState.last_target, '%99');
@@ -574,12 +697,13 @@ exit 1
574
697
  const sessionStateDir = join(stateDir, 'sessions', sessionId);
575
698
  const fakeBinDir = join(cwd, 'fake-bin');
576
699
  const fakeTmuxPath = join(fakeBinDir, 'tmux');
700
+ const managedSessionName = buildTmuxSessionName(cwd, sessionId);
577
701
  const configPath = join(omxDir, 'tmux-hook.json');
578
702
  const hookStatePath = join(stateDir, 'tmux-hook-state.json');
579
703
  await mkdir(sessionStateDir, { recursive: true });
580
704
  await mkdir(logsDir, { recursive: true });
581
705
  await mkdir(fakeBinDir, { recursive: true });
582
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
706
+ await writeManagedSessionState(stateDir, cwd, sessionId);
583
707
  await writeJson(join(sessionStateDir, 'ralph-state.json'), {
584
708
  active: true,
585
709
  iteration: 0,
@@ -619,7 +743,7 @@ if [[ "$cmd" == "display-message" ]]; then
619
743
  exit 0
620
744
  fi
621
745
  if [[ "$format" == "#S" && "$target" == "%99" ]]; then
622
- echo "devsess"
746
+ echo "${managedSessionName}"
623
747
  exit 0
624
748
  fi
625
749
  echo "bad display target: $target / $format" >&2
@@ -640,20 +764,30 @@ exit 1
640
764
  const payload = {
641
765
  cwd,
642
766
  type: 'agent-turn-complete',
767
+ session_id: sessionId,
643
768
  'thread-id': 'thread-test-4',
644
769
  'turn-id': 'turn-test-4',
645
770
  'input-messages': ['no marker here'],
646
771
  'last-assistant-message': 'output',
647
772
  };
648
- const result = spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
649
- encoding: 'utf8',
650
- env: {
651
- ...process.env,
652
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
653
- OMX_TEAM_WORKER: '',
654
- },
655
- });
656
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
773
+ const previousPath = process.env.PATH;
774
+ const previousTeamWorker = process.env.OMX_TEAM_WORKER;
775
+ try {
776
+ process.env.PATH = `${fakeBinDir}:${process.env.PATH || ''}`;
777
+ process.env.OMX_TEAM_WORKER = '';
778
+ delete process.env.TMUX_PANE;
779
+ await handleTmuxInjection({ payload, cwd, stateDir, logsDir });
780
+ }
781
+ finally {
782
+ if (typeof previousPath === 'string')
783
+ process.env.PATH = previousPath;
784
+ else
785
+ delete process.env.PATH;
786
+ if (typeof previousTeamWorker === 'string')
787
+ process.env.OMX_TEAM_WORKER = previousTeamWorker;
788
+ else
789
+ delete process.env.OMX_TEAM_WORKER;
790
+ }
657
791
  const hookState = await readJson(hookStatePath);
658
792
  assert.equal(hookState.last_reason, 'injection_sent');
659
793
  assert.equal(hookState.total_injections, 1);
@@ -671,12 +805,13 @@ exit 1
671
805
  const sessionStateDir = join(stateDir, 'sessions', sessionId);
672
806
  const fakeBinDir = join(cwd, 'fake-bin');
673
807
  const fakeTmuxPath = join(fakeBinDir, 'tmux');
808
+ const managedSessionName = buildTmuxSessionName(cwd, sessionId);
674
809
  const configPath = join(omxDir, 'tmux-hook.json');
675
810
  const hookStatePath = join(stateDir, 'tmux-hook-state.json');
676
811
  await mkdir(sessionStateDir, { recursive: true });
677
812
  await mkdir(logsDir, { recursive: true });
678
813
  await mkdir(fakeBinDir, { recursive: true });
679
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
814
+ await writeManagedSessionState(stateDir, cwd, sessionId);
680
815
  await writeJson(join(sessionStateDir, 'ralph-state.json'), {
681
816
  active: true,
682
817
  iteration: 0,
@@ -721,7 +856,7 @@ if [[ "$cmd" == "display-message" ]]; then
721
856
  exit 0
722
857
  fi
723
858
  if [[ "$format" == "#S" && "$target" == "%99" ]]; then
724
- echo "devsess"
859
+ echo "${managedSessionName}"
725
860
  exit 0
726
861
  fi
727
862
  if [[ "$format" == "#{pane_current_command}" && "$target" == "%99" ]]; then
@@ -756,15 +891,24 @@ exit 1
756
891
  'input-messages': ['no marker here'],
757
892
  'last-assistant-message': 'output',
758
893
  };
759
- const result = spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
760
- encoding: 'utf8',
761
- env: {
762
- ...process.env,
763
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
764
- OMX_TEAM_WORKER: '',
765
- },
766
- });
767
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
894
+ const previousPath = process.env.PATH;
895
+ const previousTeamWorker = process.env.OMX_TEAM_WORKER;
896
+ try {
897
+ process.env.PATH = `${fakeBinDir}:${process.env.PATH || ''}`;
898
+ process.env.OMX_TEAM_WORKER = '';
899
+ delete process.env.TMUX_PANE;
900
+ await handleTmuxInjection({ payload, cwd, stateDir, logsDir });
901
+ }
902
+ finally {
903
+ if (typeof previousPath === 'string')
904
+ process.env.PATH = previousPath;
905
+ else
906
+ delete process.env.PATH;
907
+ if (typeof previousTeamWorker === 'string')
908
+ process.env.OMX_TEAM_WORKER = previousTeamWorker;
909
+ else
910
+ delete process.env.OMX_TEAM_WORKER;
911
+ }
768
912
  const hookState = await readJson(hookStatePath);
769
913
  assert.equal(hookState.last_reason, 'injection_sent');
770
914
  assert.equal(hookState.total_injections, 1);
@@ -782,12 +926,13 @@ exit 1
782
926
  const sessionStateDir = join(stateDir, 'sessions', sessionId);
783
927
  const fakeBinDir = join(cwd, 'fake-bin');
784
928
  const fakeTmuxPath = join(fakeBinDir, 'tmux');
929
+ const managedSessionName = buildTmuxSessionName(cwd, sessionId);
785
930
  const configPath = join(omxDir, 'tmux-hook.json');
786
931
  const hookStatePath = join(stateDir, 'tmux-hook-state.json');
787
932
  await mkdir(sessionStateDir, { recursive: true });
788
933
  await mkdir(logsDir, { recursive: true });
789
934
  await mkdir(fakeBinDir, { recursive: true });
790
- await writeJson(join(stateDir, 'session.json'), { session_id: sessionId });
935
+ await writeManagedSessionState(stateDir, cwd, sessionId);
791
936
  await writeJson(join(sessionStateDir, 'ralph-state.json'), { active: true, iteration: 0, tmux_pane_id: '%42' });
792
937
  await writeJson(configPath, {
793
938
  enabled: true,
@@ -822,6 +967,10 @@ if [[ "$cmd" == "display-message" ]]; then
822
967
  echo "codex"
823
968
  exit 0
824
969
  fi
970
+ if [[ "$format" == "#S" && "$target" == "%42" ]]; then
971
+ echo "${managedSessionName}"
972
+ exit 0
973
+ fi
825
974
  if [[ "$format" == "#{pane_in_mode}" && "$target" == "%42" ]]; then
826
975
  echo "0"
827
976
  exit 0
@@ -854,15 +1003,24 @@ exit 1
854
1003
  'input-messages': ['no marker here'],
855
1004
  'last-assistant-message': 'output',
856
1005
  };
857
- const result = spawnSync(process.execPath, [NOTIFY_HOOK_SCRIPT.pathname, JSON.stringify(payload)], {
858
- encoding: 'utf8',
859
- env: {
860
- ...process.env,
861
- PATH: `${fakeBinDir}:${process.env.PATH || ''}`,
862
- OMX_TEAM_WORKER: '',
863
- },
864
- });
865
- assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1006
+ const previousPath = process.env.PATH;
1007
+ const previousTeamWorker = process.env.OMX_TEAM_WORKER;
1008
+ try {
1009
+ process.env.PATH = `${fakeBinDir}:${process.env.PATH || ''}`;
1010
+ process.env.OMX_TEAM_WORKER = '';
1011
+ delete process.env.TMUX_PANE;
1012
+ await handleTmuxInjection({ payload, cwd, stateDir, logsDir });
1013
+ }
1014
+ finally {
1015
+ if (typeof previousPath === 'string')
1016
+ process.env.PATH = previousPath;
1017
+ else
1018
+ delete process.env.PATH;
1019
+ if (typeof previousTeamWorker === 'string')
1020
+ process.env.OMX_TEAM_WORKER = previousTeamWorker;
1021
+ else
1022
+ delete process.env.OMX_TEAM_WORKER;
1023
+ }
866
1024
  const hookState = await readJson(hookStatePath);
867
1025
  assert.equal(hookState.last_reason, 'pane_has_active_task');
868
1026
  assert.equal(hookState.total_injections ?? 0, 0);