oh-my-codex 0.11.11 → 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 (342) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.de.md +12 -6
  4. package/README.el.md +223 -0
  5. package/README.es.md +12 -6
  6. package/README.fr.md +11 -5
  7. package/README.it.md +12 -6
  8. package/README.ja.md +12 -6
  9. package/README.ko.md +12 -6
  10. package/README.md +56 -28
  11. package/README.pl.md +216 -0
  12. package/README.pt.md +12 -6
  13. package/README.ru.md +12 -6
  14. package/README.tr.md +12 -6
  15. package/README.vi.md +148 -183
  16. package/README.zh-TW.md +14 -17
  17. package/README.zh.md +12 -6
  18. package/crates/omx-runtime-core/src/engine.rs +122 -4
  19. package/crates/omx-runtime-core/src/lib.rs +17 -0
  20. package/dist/autoresearch/contracts.d.ts.map +1 -1
  21. package/dist/autoresearch/contracts.js +1 -0
  22. package/dist/autoresearch/contracts.js.map +1 -1
  23. package/dist/autoresearch/runtime.d.ts.map +1 -1
  24. package/dist/autoresearch/runtime.js +7 -1
  25. package/dist/autoresearch/runtime.js.map +1 -1
  26. package/dist/cli/__tests__/agents.test.js +24 -1
  27. package/dist/cli/__tests__/agents.test.js.map +1 -1
  28. package/dist/cli/__tests__/autoresearch.test.js +11 -0
  29. package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
  30. package/dist/cli/__tests__/cleanup.test.js +117 -4
  31. package/dist/cli/__tests__/cleanup.test.js.map +1 -1
  32. package/dist/cli/__tests__/doctor-warning-copy.test.js +33 -3
  33. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  34. package/dist/cli/__tests__/error-handling-warnings.test.js +13 -0
  35. package/dist/cli/__tests__/error-handling-warnings.test.js.map +1 -1
  36. package/dist/cli/__tests__/exec.test.js +6 -0
  37. package/dist/cli/__tests__/exec.test.js.map +1 -1
  38. package/dist/cli/__tests__/index.test.js +101 -1
  39. package/dist/cli/__tests__/index.test.js.map +1 -1
  40. package/dist/cli/__tests__/launch-fallback.test.js +3 -0
  41. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  42. package/dist/cli/__tests__/package-bin-contract.test.js +10 -0
  43. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  44. package/dist/cli/__tests__/packaged-script-resolution.test.js +4 -3
  45. package/dist/cli/__tests__/packaged-script-resolution.test.js.map +1 -1
  46. package/dist/cli/__tests__/resume.test.js +6 -0
  47. package/dist/cli/__tests__/resume.test.js.map +1 -1
  48. package/dist/cli/__tests__/setup-refresh.test.js +29 -12
  49. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  50. package/dist/cli/__tests__/setup-scope.test.js +1 -1
  51. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  52. package/dist/cli/__tests__/star-prompt.test.js +16 -0
  53. package/dist/cli/__tests__/star-prompt.test.js.map +1 -1
  54. package/dist/cli/__tests__/uninstall.test.js +112 -1
  55. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  56. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts +2 -0
  57. package/dist/cli/__tests__/windows-popup-loop-contract.test.d.ts.map +1 -0
  58. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +30 -0
  59. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -0
  60. package/dist/cli/agents.d.ts.map +1 -1
  61. package/dist/cli/agents.js +9 -3
  62. package/dist/cli/agents.js.map +1 -1
  63. package/dist/cli/autoresearch-guided.d.ts.map +1 -1
  64. package/dist/cli/autoresearch-guided.js +9 -3
  65. package/dist/cli/autoresearch-guided.js.map +1 -1
  66. package/dist/cli/autoresearch.d.ts.map +1 -1
  67. package/dist/cli/autoresearch.js +8 -2
  68. package/dist/cli/autoresearch.js.map +1 -1
  69. package/dist/cli/cleanup.d.ts +2 -0
  70. package/dist/cli/cleanup.d.ts.map +1 -1
  71. package/dist/cli/cleanup.js +27 -1
  72. package/dist/cli/cleanup.js.map +1 -1
  73. package/dist/cli/doctor.js +7 -0
  74. package/dist/cli/doctor.js.map +1 -1
  75. package/dist/cli/index.d.ts +9 -1
  76. package/dist/cli/index.d.ts.map +1 -1
  77. package/dist/cli/index.js +171 -55
  78. package/dist/cli/index.js.map +1 -1
  79. package/dist/cli/setup.d.ts.map +1 -1
  80. package/dist/cli/setup.js +18 -15
  81. package/dist/cli/setup.js.map +1 -1
  82. package/dist/cli/star-prompt.d.ts.map +1 -1
  83. package/dist/cli/star-prompt.js +2 -0
  84. package/dist/cli/star-prompt.js.map +1 -1
  85. package/dist/cli/team.d.ts.map +1 -1
  86. package/dist/cli/team.js +5 -1
  87. package/dist/cli/team.js.map +1 -1
  88. package/dist/cli/tmux-hook.d.ts.map +1 -1
  89. package/dist/cli/tmux-hook.js +4 -1
  90. package/dist/cli/tmux-hook.js.map +1 -1
  91. package/dist/cli/uninstall.d.ts.map +1 -1
  92. package/dist/cli/uninstall.js +26 -0
  93. package/dist/cli/uninstall.js.map +1 -1
  94. package/dist/cli/update.d.ts.map +1 -1
  95. package/dist/cli/update.js +1 -0
  96. package/dist/cli/update.js.map +1 -1
  97. package/dist/compat/__tests__/rust-runtime-compat.test.js +84 -1
  98. package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
  99. package/dist/config/__tests__/generator-idempotent.test.js +4 -4
  100. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  101. package/dist/config/__tests__/mcp-registry.test.js +13 -16
  102. package/dist/config/__tests__/mcp-registry.test.js.map +1 -1
  103. package/dist/config/mcp-registry.d.ts +1 -0
  104. package/dist/config/mcp-registry.d.ts.map +1 -1
  105. package/dist/config/mcp-registry.js +4 -4
  106. package/dist/config/mcp-registry.js.map +1 -1
  107. package/dist/config/models.d.ts +1 -0
  108. package/dist/config/models.d.ts.map +1 -1
  109. package/dist/config/models.js +39 -1
  110. package/dist/config/models.js.map +1 -1
  111. package/dist/hooks/__tests__/keyword-detector.test.js +12 -1
  112. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  113. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +554 -18
  114. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  115. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +347 -16
  116. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  117. package/dist/hooks/__tests__/notify-hook-modules.test.js +5 -0
  118. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
  119. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts +2 -0
  120. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.d.ts.map +1 -0
  121. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +597 -0
  122. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -0
  123. package/dist/hooks/__tests__/notify-hook-regression-205.test.js +19 -1
  124. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
  125. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +73 -53
  126. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  127. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +193 -2
  128. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  129. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +183 -0
  130. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  131. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +255 -97
  132. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  133. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
  134. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  135. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +46 -0
  136. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  137. package/dist/hooks/__tests__/prompt-team-routing.test.js +34 -0
  138. package/dist/hooks/__tests__/prompt-team-routing.test.js.map +1 -1
  139. package/dist/hooks/__tests__/tmux-hook-engine.test.js +32 -1
  140. package/dist/hooks/__tests__/tmux-hook-engine.test.js.map +1 -1
  141. package/dist/hooks/code-simplifier/index.d.ts.map +1 -1
  142. package/dist/hooks/code-simplifier/index.js +1 -0
  143. package/dist/hooks/code-simplifier/index.js.map +1 -1
  144. package/dist/hooks/codebase-map.d.ts.map +1 -1
  145. package/dist/hooks/codebase-map.js +1 -0
  146. package/dist/hooks/codebase-map.js.map +1 -1
  147. package/dist/hooks/extensibility/sdk/tmux.d.ts.map +1 -1
  148. package/dist/hooks/extensibility/sdk/tmux.js +3 -1
  149. package/dist/hooks/extensibility/sdk/tmux.js.map +1 -1
  150. package/dist/hooks/keyword-detector.d.ts +1 -0
  151. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  152. package/dist/hooks/keyword-detector.js +48 -0
  153. package/dist/hooks/keyword-detector.js.map +1 -1
  154. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  155. package/dist/hooks/prompt-guidance-contract.js +6 -0
  156. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  157. package/dist/hooks/session.d.ts.map +1 -1
  158. package/dist/hooks/session.js +1 -0
  159. package/dist/hooks/session.js.map +1 -1
  160. package/dist/hud/__tests__/state.test.js +70 -1
  161. package/dist/hud/__tests__/state.test.js.map +1 -1
  162. package/dist/hud/authority.d.ts.map +1 -1
  163. package/dist/hud/authority.js +1 -0
  164. package/dist/hud/authority.js.map +1 -1
  165. package/dist/hud/state.d.ts.map +1 -1
  166. package/dist/hud/state.js +52 -0
  167. package/dist/hud/state.js.map +1 -1
  168. package/dist/mcp/state-server.d.ts.map +1 -1
  169. package/dist/mcp/state-server.js +5 -0
  170. package/dist/mcp/state-server.js.map +1 -1
  171. package/dist/modes/__tests__/base-session-scope.test.js +46 -0
  172. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  173. package/dist/modes/base.d.ts.map +1 -1
  174. package/dist/modes/base.js +4 -0
  175. package/dist/modes/base.js.map +1 -1
  176. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts +2 -0
  177. package/dist/notifications/__tests__/custom-alias-enablement.test.d.ts.map +1 -0
  178. package/dist/notifications/__tests__/custom-alias-enablement.test.js +84 -0
  179. package/dist/notifications/__tests__/custom-alias-enablement.test.js.map +1 -0
  180. package/dist/notifications/__tests__/idle-cooldown.test.js +55 -0
  181. package/dist/notifications/__tests__/idle-cooldown.test.js.map +1 -1
  182. package/dist/notifications/idle-cooldown.d.ts +8 -6
  183. package/dist/notifications/idle-cooldown.d.ts.map +1 -1
  184. package/dist/notifications/idle-cooldown.js +53 -22
  185. package/dist/notifications/idle-cooldown.js.map +1 -1
  186. package/dist/notifications/notifier.js +1 -1
  187. package/dist/notifications/notifier.js.map +1 -1
  188. package/dist/notifications/reply-listener.d.ts.map +1 -1
  189. package/dist/notifications/reply-listener.js +1 -0
  190. package/dist/notifications/reply-listener.js.map +1 -1
  191. package/dist/notifications/tmux.d.ts.map +1 -1
  192. package/dist/notifications/tmux.js +4 -0
  193. package/dist/notifications/tmux.js.map +1 -1
  194. package/dist/openclaw/config.js +2 -2
  195. package/dist/openclaw/config.js.map +1 -1
  196. package/dist/runtime/bridge.d.ts +2 -0
  197. package/dist/runtime/bridge.d.ts.map +1 -1
  198. package/dist/runtime/bridge.js +8 -0
  199. package/dist/runtime/bridge.js.map +1 -1
  200. package/dist/scripts/notify-fallback-watcher.js +103 -53
  201. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  202. package/dist/scripts/notify-hook/auto-nudge.d.ts +2 -1
  203. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  204. package/dist/scripts/notify-hook/auto-nudge.js +90 -104
  205. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  206. package/dist/scripts/notify-hook/managed-tmux.d.ts +19 -0
  207. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -0
  208. package/dist/scripts/notify-hook/managed-tmux.js +320 -0
  209. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -0
  210. package/dist/scripts/notify-hook/operational-events.d.ts.map +1 -1
  211. package/dist/scripts/notify-hook/operational-events.js +2 -0
  212. package/dist/scripts/notify-hook/operational-events.js.map +1 -1
  213. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +22 -0
  214. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -0
  215. package/dist/scripts/notify-hook/ralph-session-resume.js +277 -0
  216. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -0
  217. package/dist/scripts/notify-hook/state-io.d.ts +1 -1
  218. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  219. package/dist/scripts/notify-hook/state-io.js +2 -10
  220. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  221. package/dist/scripts/notify-hook/team-dispatch.d.ts +1 -1
  222. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  223. package/dist/scripts/notify-hook/team-dispatch.js +123 -72
  224. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  225. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -1
  226. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  227. package/dist/scripts/notify-hook/team-leader-nudge.js +13 -5
  228. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  229. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  230. package/dist/scripts/notify-hook/team-tmux-guard.js +1 -19
  231. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  232. package/dist/scripts/notify-hook/team-worker.js +4 -4
  233. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  234. package/dist/scripts/notify-hook/tmux-injection.d.ts +1 -1
  235. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  236. package/dist/scripts/notify-hook/tmux-injection.js +102 -35
  237. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  238. package/dist/scripts/notify-hook.js +144 -20
  239. package/dist/scripts/notify-hook.js.map +1 -1
  240. package/dist/scripts/run-provider-advisor.js +2 -0
  241. package/dist/scripts/run-provider-advisor.js.map +1 -1
  242. package/dist/scripts/run-test-files.d.ts +2 -0
  243. package/dist/scripts/run-test-files.d.ts.map +1 -0
  244. package/dist/scripts/run-test-files.js +41 -0
  245. package/dist/scripts/run-test-files.js.map +1 -0
  246. package/dist/scripts/tmux-hook-engine.d.ts +2 -0
  247. package/dist/scripts/tmux-hook-engine.d.ts.map +1 -1
  248. package/dist/scripts/tmux-hook-engine.js +15 -0
  249. package/dist/scripts/tmux-hook-engine.js.map +1 -1
  250. package/dist/team/__tests__/api-interop.test.js +136 -4
  251. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  252. package/dist/team/__tests__/leader-activity.test.js +107 -2
  253. package/dist/team/__tests__/leader-activity.test.js.map +1 -1
  254. package/dist/team/__tests__/runtime-cli.test.js +32 -0
  255. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  256. package/dist/team/__tests__/runtime.test.js +148 -0
  257. package/dist/team/__tests__/runtime.test.js.map +1 -1
  258. package/dist/team/__tests__/shutdown-fallback.test.js +13 -0
  259. package/dist/team/__tests__/shutdown-fallback.test.js.map +1 -1
  260. package/dist/team/__tests__/state-root.test.js +11 -1
  261. package/dist/team/__tests__/state-root.test.js.map +1 -1
  262. package/dist/team/__tests__/state.test.js +237 -0
  263. package/dist/team/__tests__/state.test.js.map +1 -1
  264. package/dist/team/__tests__/tmux-session.test.js +521 -2
  265. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  266. package/dist/team/api-interop.d.ts.map +1 -1
  267. package/dist/team/api-interop.js +41 -31
  268. package/dist/team/api-interop.js.map +1 -1
  269. package/dist/team/commit-hygiene.d.ts +60 -0
  270. package/dist/team/commit-hygiene.d.ts.map +1 -0
  271. package/dist/team/commit-hygiene.js +232 -0
  272. package/dist/team/commit-hygiene.js.map +1 -0
  273. package/dist/team/leader-activity.d.ts.map +1 -1
  274. package/dist/team/leader-activity.js +56 -4
  275. package/dist/team/leader-activity.js.map +1 -1
  276. package/dist/team/runtime-cli.d.ts +9 -1
  277. package/dist/team/runtime-cli.d.ts.map +1 -1
  278. package/dist/team/runtime-cli.js +15 -6
  279. package/dist/team/runtime-cli.js.map +1 -1
  280. package/dist/team/runtime.d.ts +7 -2
  281. package/dist/team/runtime.d.ts.map +1 -1
  282. package/dist/team/runtime.js +392 -171
  283. package/dist/team/runtime.js.map +1 -1
  284. package/dist/team/scaling.d.ts.map +1 -1
  285. package/dist/team/scaling.js +6 -2
  286. package/dist/team/scaling.js.map +1 -1
  287. package/dist/team/state/dispatch.d.ts +2 -0
  288. package/dist/team/state/dispatch.d.ts.map +1 -1
  289. package/dist/team/state/dispatch.js +86 -40
  290. package/dist/team/state/dispatch.js.map +1 -1
  291. package/dist/team/state/mailbox.d.ts +3 -0
  292. package/dist/team/state/mailbox.d.ts.map +1 -1
  293. package/dist/team/state/mailbox.js +93 -19
  294. package/dist/team/state/mailbox.js.map +1 -1
  295. package/dist/team/state-root.d.ts +1 -1
  296. package/dist/team/state-root.d.ts.map +1 -1
  297. package/dist/team/state-root.js +8 -3
  298. package/dist/team/state-root.js.map +1 -1
  299. package/dist/team/state.d.ts.map +1 -1
  300. package/dist/team/state.js +96 -2
  301. package/dist/team/state.js.map +1 -1
  302. package/dist/team/tmux-session.d.ts.map +1 -1
  303. package/dist/team/tmux-session.js +81 -29
  304. package/dist/team/tmux-session.js.map +1 -1
  305. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  306. package/dist/team/worker-bootstrap.js +4 -0
  307. package/dist/team/worker-bootstrap.js.map +1 -1
  308. package/dist/team/worktree.d.ts.map +1 -1
  309. package/dist/team/worktree.js +9 -0
  310. package/dist/team/worktree.js.map +1 -1
  311. package/dist/utils/__tests__/paths.test.js +98 -11
  312. package/dist/utils/__tests__/paths.test.js.map +1 -1
  313. package/dist/utils/__tests__/platform-command.test.js +101 -2
  314. package/dist/utils/__tests__/platform-command.test.js.map +1 -1
  315. package/dist/utils/git-layout.d.ts +8 -0
  316. package/dist/utils/git-layout.d.ts.map +1 -0
  317. package/dist/utils/git-layout.js +58 -0
  318. package/dist/utils/git-layout.js.map +1 -0
  319. package/dist/utils/paths.d.ts +3 -0
  320. package/dist/utils/paths.d.ts.map +1 -1
  321. package/dist/utils/paths.js +14 -4
  322. package/dist/utils/paths.js.map +1 -1
  323. package/dist/utils/platform-command.d.ts.map +1 -1
  324. package/dist/utils/platform-command.js +35 -3
  325. package/dist/utils/platform-command.js.map +1 -1
  326. package/package.json +9 -5
  327. package/src/scripts/notify-fallback-watcher.ts +103 -53
  328. package/src/scripts/notify-hook/auto-nudge.ts +97 -103
  329. package/src/scripts/notify-hook/managed-tmux.ts +324 -0
  330. package/src/scripts/notify-hook/operational-events.ts +2 -0
  331. package/src/scripts/notify-hook/ralph-session-resume.ts +337 -0
  332. package/src/scripts/notify-hook/state-io.ts +2 -10
  333. package/src/scripts/notify-hook/team-dispatch.ts +131 -66
  334. package/src/scripts/notify-hook/team-leader-nudge.ts +19 -5
  335. package/src/scripts/notify-hook/team-tmux-guard.ts +0 -20
  336. package/src/scripts/notify-hook/team-worker.ts +4 -4
  337. package/src/scripts/notify-hook/tmux-injection.ts +103 -33
  338. package/src/scripts/notify-hook.ts +150 -21
  339. package/src/scripts/run-provider-advisor.ts +4 -2
  340. package/src/scripts/run-test-files.ts +48 -0
  341. package/src/scripts/tmux-hook-engine.ts +16 -0
  342. package/templates/AGENTS.md +51 -43
@@ -3,10 +3,10 @@ import assert from 'node:assert/strict';
3
3
  import fs from 'node:fs';
4
4
  import { syncBuiltinESMExports } from 'node:module';
5
5
  import { PassThrough } from 'node:stream';
6
- import { mkdtemp, readFile, rm, writeFile, chmod } from 'fs/promises';
6
+ import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'fs/promises';
7
7
  import { join } from 'path';
8
8
  import { tmpdir } from 'os';
9
- import { buildClientAttachedReconcileHookName, assertTeamWorkerCliBinaryAvailable, buildWorkerProcessLaunchSpec, buildReconcileHudResizeArgs, buildRegisterClientAttachedReconcileArgs, buildRegisterResizeHookArgs, buildResizeHookName, buildResizeHookTarget, buildScheduleDelayedHudResizeArgs, buildUnregisterClientAttachedReconcileArgs, buildUnregisterResizeHookArgs, buildWorkerStartupCommand, buildHudPaneTarget, chooseTeamLeaderPaneId, createTeamSession, enableMouseScrolling, isMsysOrGitBash, isNativeWindows, isTmuxAvailable, translatePathForMsys, isWsl2, isWorkerAlive, killWorker, killWorkerByPaneId, teardownWorkerPanes, listTeamSessions, resolveTeamWorkerCli, resolveTeamWorkerLaunchMode, resolveWorkerCliForSend, resolveTeamWorkerCliPlan, buildWorkerSubmitPlan, sanitizeTeamName, shouldAttemptAdaptiveRetry, sendToWorker, sendToWorkerStdin, sleepFractionalSeconds, translateWorkerLaunchArgsForCli, waitForWorkerReady, paneIsBootstrapping, dismissTrustPromptIfPresent, } from '../tmux-session.js';
9
+ import { buildClientAttachedReconcileHookName, assertTeamWorkerCliBinaryAvailable, buildWorkerProcessLaunchSpec, buildReconcileHudResizeArgs, buildRegisterClientAttachedReconcileArgs, buildRegisterResizeHookArgs, buildResizeHookName, buildResizeHookTarget, buildScheduleDelayedHudResizeArgs, buildUnregisterClientAttachedReconcileArgs, buildUnregisterResizeHookArgs, buildWorkerStartupCommand, buildHudPaneTarget, chooseTeamLeaderPaneId, createTeamSession, enableMouseScrolling, isMsysOrGitBash, isNativeWindows, isTmuxAvailable, restoreStandaloneHudPane, translatePathForMsys, isWsl2, isWorkerAlive, killWorker, killWorkerByPaneId, teardownWorkerPanes, listTeamSessions, resolveTeamWorkerCli, resolveTeamWorkerLaunchMode, resolveWorkerCliForSend, resolveTeamWorkerCliPlan, buildWorkerSubmitPlan, sanitizeTeamName, shouldAttemptAdaptiveRetry, sendToWorker, sendToWorkerStdin, sleepFractionalSeconds, translateWorkerLaunchArgsForCli, waitForWorkerReady, paneIsBootstrapping, dismissTrustPromptIfPresent, } from '../tmux-session.js';
10
10
  import { HUD_RESIZE_RECONCILE_DELAY_SECONDS, HUD_TMUX_TEAM_HEIGHT_LINES } from '../../hud/constants.js';
11
11
  import * as tmuxSessionModule from '../tmux-session.js';
12
12
  function withEmptyPath(fn) {
@@ -51,6 +51,17 @@ const READY_HELPER_CAPTURE = `╭───────────────
51
51
  ╰────────────────────────────────────────────╯
52
52
 
53
53
  How can I help you today?`;
54
+ const VIEWPORT_WITHOUT_VISIBLE_PROMPT_CAPTURE = `╭────────────────────────────────────────────╮
55
+ │ >_ OpenAI Codex (v0.118.0) │
56
+ │ │
57
+ │ model: gpt-5.4 high /model to change │
58
+ │ directory: ~/Workspace/demo │
59
+ ╰────────────────────────────────────────────╯
60
+
61
+ ⚠ MCP startup incomplete (failed: hf request)`;
62
+ const VIEWPORT_SCROLLBACK_READY_CAPTURE = `${VIEWPORT_WITHOUT_VISIBLE_PROMPT_CAPTURE}
63
+
64
+ › support lane on multi-image attach`;
54
65
  async function withMockTmuxFixture(dirPrefix, tmuxScript, run) {
55
66
  const fakeBinDir = await mkdtemp(join(tmpdir(), dirPrefix));
56
67
  const logPath = join(fakeBinDir, 'tmux.log');
@@ -179,6 +190,71 @@ describe('HUD resize hook command builders', () => {
179
190
  assert.equal(args.join(' ').includes('split-window'), false);
180
191
  assert.deepEqual(args, ['run-shell', `tmux resize-pane -t %7 -y ${HUD_TMUX_TEAM_HEIGHT_LINES} >/dev/null 2>&1 || true`]);
181
192
  });
193
+ it('resolves the tmux executable for win32 hook shell snippets', async () => {
194
+ const fakeBin = await mkdtemp(join(tmpdir(), 'omx-win32-hook-tmux-'));
195
+ const prevPath = process.env.PATH;
196
+ const prevPathext = process.env.PATHEXT;
197
+ const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
198
+ try {
199
+ const tmuxPath = join(fakeBin, 'tmux.exe');
200
+ await writeFile(tmuxPath, '');
201
+ process.env.PATH = fakeBin;
202
+ process.env.PATHEXT = '.EXE';
203
+ Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
204
+ const resizeArgs = buildRegisterResizeHookArgs('my-session:0', 'omx_resize_team_session_0_1', '%1');
205
+ const delayedArgs = buildScheduleDelayedHudResizeArgs('%1');
206
+ const reconcileArgs = buildReconcileHudResizeArgs('%1');
207
+ assert.match(resizeArgs[4] ?? '', new RegExp(escapeRegExp(tmuxPath)));
208
+ assert.doesNotMatch(resizeArgs[4] ?? '', /^run-shell -b 'tmux resize-pane/);
209
+ assert.match(delayedArgs[2] ?? '', new RegExp(escapeRegExp(tmuxPath)));
210
+ assert.doesNotMatch(delayedArgs[2] ?? '', /sleep \d+; tmux resize-pane/);
211
+ assert.match(reconcileArgs[1] ?? '', new RegExp(escapeRegExp(tmuxPath)));
212
+ assert.doesNotMatch(reconcileArgs[1] ?? '', /^tmux resize-pane/);
213
+ }
214
+ finally {
215
+ if (origPlatform)
216
+ Object.defineProperty(process, 'platform', origPlatform);
217
+ if (typeof prevPath === 'string')
218
+ process.env.PATH = prevPath;
219
+ else
220
+ delete process.env.PATH;
221
+ if (typeof prevPathext === 'string')
222
+ process.env.PATHEXT = prevPathext;
223
+ else
224
+ delete process.env.PATHEXT;
225
+ await rm(fakeBin, { recursive: true, force: true });
226
+ }
227
+ });
228
+ it('resolves the tmux executable twice for win32 client-attached one-shot hooks', async () => {
229
+ const fakeBin = await mkdtemp(join(tmpdir(), 'omx-win32-attached-hook-'));
230
+ const prevPath = process.env.PATH;
231
+ const prevPathext = process.env.PATHEXT;
232
+ const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
233
+ try {
234
+ const tmuxPath = join(fakeBin, 'tmux.exe');
235
+ await writeFile(tmuxPath, '');
236
+ process.env.PATH = fakeBin;
237
+ process.env.PATHEXT = '.EXE';
238
+ Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
239
+ const args = buildRegisterClientAttachedReconcileArgs('my-session:0', 'omx_attached_team_session_0_1', '%1');
240
+ const matches = (args[4] ?? '').match(new RegExp(escapeRegExp(tmuxPath), 'g')) || [];
241
+ assert.equal(matches.length, 2, 'client-attached hook should resolve tmux for both resize and unregister commands');
242
+ assert.doesNotMatch(args[4] ?? '', /; tmux set-hook -u -t my-session:0 client-attached/);
243
+ }
244
+ finally {
245
+ if (origPlatform)
246
+ Object.defineProperty(process, 'platform', origPlatform);
247
+ if (typeof prevPath === 'string')
248
+ process.env.PATH = prevPath;
249
+ else
250
+ delete process.env.PATH;
251
+ if (typeof prevPathext === 'string')
252
+ process.env.PATHEXT = prevPathext;
253
+ else
254
+ delete process.env.PATHEXT;
255
+ await rm(fakeBin, { recursive: true, force: true });
256
+ }
257
+ });
182
258
  });
183
259
  describe('sendToWorker validation', () => {
184
260
  it('rejects text over 200 chars', async () => {
@@ -1105,6 +1181,212 @@ describe('team worker launch mode helpers', () => {
1105
1181
  delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1106
1182
  }
1107
1183
  });
1184
+ it('buildWorkerProcessLaunchSpec injects the active provider env_key from CODEX_HOME config.toml', async () => {
1185
+ const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1186
+ const prevCodexHome = process.env.CODEX_HOME;
1187
+ const prevProviderEnv = process.env.CUSTOM_PROVIDER_API_KEY;
1188
+ const codexHome = await mkdtemp(join(tmpdir(), 'omx-team-provider-env-'));
1189
+ process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1190
+ process.env.CODEX_HOME = codexHome;
1191
+ process.env.CUSTOM_PROVIDER_API_KEY = 'test-secret';
1192
+ try {
1193
+ await writeFile(join(codexHome, 'config.toml'), [
1194
+ 'model_provider = "custom_provider"',
1195
+ '',
1196
+ '[model_providers.custom_provider]',
1197
+ 'name = "custom_provider"',
1198
+ 'base_url = "http://localhost:3000/v1"',
1199
+ 'wire_api = "responses"',
1200
+ 'requires_openai_auth = true',
1201
+ 'env_key = "CUSTOM_PROVIDER_API_KEY"',
1202
+ '',
1203
+ ].join('\n'));
1204
+ const spec = buildWorkerProcessLaunchSpec('gamma-team', 1, [], '/tmp/workspace', {}, 'codex');
1205
+ assert.equal(spec.env.CUSTOM_PROVIDER_API_KEY, 'test-secret');
1206
+ }
1207
+ finally {
1208
+ if (typeof prevBypass === 'string')
1209
+ process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1210
+ else
1211
+ delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1212
+ if (typeof prevCodexHome === 'string')
1213
+ process.env.CODEX_HOME = prevCodexHome;
1214
+ else
1215
+ delete process.env.CODEX_HOME;
1216
+ if (typeof prevProviderEnv === 'string')
1217
+ process.env.CUSTOM_PROVIDER_API_KEY = prevProviderEnv;
1218
+ else
1219
+ delete process.env.CUSTOM_PROVIDER_API_KEY;
1220
+ await rm(codexHome, { recursive: true, force: true });
1221
+ }
1222
+ });
1223
+ it('buildWorkerProcessLaunchSpec does not inject the active provider env_key for non-codex workers', async () => {
1224
+ const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1225
+ const prevCodexHome = process.env.CODEX_HOME;
1226
+ const prevProviderEnv = process.env.CUSTOM_PROVIDER_API_KEY;
1227
+ const codexHome = await mkdtemp(join(tmpdir(), 'omx-team-provider-env-'));
1228
+ process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1229
+ process.env.CODEX_HOME = codexHome;
1230
+ process.env.CUSTOM_PROVIDER_API_KEY = 'test-secret';
1231
+ try {
1232
+ await writeFile(join(codexHome, 'config.toml'), [
1233
+ 'model_provider = "custom_provider"',
1234
+ '',
1235
+ '[model_providers.custom_provider]',
1236
+ 'name = "custom_provider"',
1237
+ 'base_url = "http://localhost:3000/v1"',
1238
+ 'wire_api = "responses"',
1239
+ 'requires_openai_auth = true',
1240
+ 'env_key = "CUSTOM_PROVIDER_API_KEY"',
1241
+ '',
1242
+ ].join('\n'));
1243
+ const spec = buildWorkerProcessLaunchSpec('delta-team', 1, [], '/tmp/workspace', {}, 'claude');
1244
+ assert.equal(spec.workerCli, 'claude');
1245
+ assert.equal(spec.env.CUSTOM_PROVIDER_API_KEY, undefined);
1246
+ }
1247
+ finally {
1248
+ if (typeof prevBypass === 'string')
1249
+ process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1250
+ else
1251
+ delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1252
+ if (typeof prevCodexHome === 'string')
1253
+ process.env.CODEX_HOME = prevCodexHome;
1254
+ else
1255
+ delete process.env.CODEX_HOME;
1256
+ if (typeof prevProviderEnv === 'string')
1257
+ process.env.CUSTOM_PROVIDER_API_KEY = prevProviderEnv;
1258
+ else
1259
+ delete process.env.CUSTOM_PROVIDER_API_KEY;
1260
+ await rm(codexHome, { recursive: true, force: true });
1261
+ }
1262
+ });
1263
+ it('buildWorkerProcessLaunchSpec reads provider env from worker CODEX_HOME override', async () => {
1264
+ const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1265
+ const prevCodexHome = process.env.CODEX_HOME;
1266
+ const prevPrimaryProviderEnv = process.env.PRIMARY_PROVIDER_API_KEY;
1267
+ const prevWorkerProviderEnv = process.env.WORKER_PROVIDER_API_KEY;
1268
+ const leaderCodexHome = await mkdtemp(join(tmpdir(), 'omx-team-provider-env-leader-'));
1269
+ const workerCodexHome = await mkdtemp(join(tmpdir(), 'omx-team-provider-env-worker-'));
1270
+ process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1271
+ process.env.CODEX_HOME = leaderCodexHome;
1272
+ process.env.PRIMARY_PROVIDER_API_KEY = 'leader-secret';
1273
+ process.env.WORKER_PROVIDER_API_KEY = 'worker-secret';
1274
+ try {
1275
+ await writeFile(join(leaderCodexHome, 'config.toml'), [
1276
+ 'model_provider = "primary_provider"',
1277
+ '',
1278
+ '[model_providers.primary_provider]',
1279
+ 'name = "primary_provider"',
1280
+ 'base_url = "http://localhost:3000/v1"',
1281
+ 'wire_api = "responses"',
1282
+ 'requires_openai_auth = true',
1283
+ 'env_key = "PRIMARY_PROVIDER_API_KEY"',
1284
+ '',
1285
+ ].join('\n'));
1286
+ await writeFile(join(workerCodexHome, 'config.toml'), [
1287
+ 'model_provider = "worker_provider"',
1288
+ '',
1289
+ '[model_providers.worker_provider]',
1290
+ 'name = "worker_provider"',
1291
+ 'base_url = "http://localhost:4000/v1"',
1292
+ 'wire_api = "responses"',
1293
+ 'requires_openai_auth = true',
1294
+ 'env_key = "WORKER_PROVIDER_API_KEY"',
1295
+ '',
1296
+ ].join('\n'));
1297
+ const spec = buildWorkerProcessLaunchSpec('epsilon-team', 1, [], '/tmp/workspace', { CODEX_HOME: workerCodexHome }, 'codex');
1298
+ assert.equal(spec.env.CODEX_HOME, workerCodexHome);
1299
+ assert.equal(spec.env.WORKER_PROVIDER_API_KEY, 'worker-secret');
1300
+ assert.equal(spec.env.PRIMARY_PROVIDER_API_KEY, undefined);
1301
+ }
1302
+ finally {
1303
+ if (typeof prevBypass === 'string')
1304
+ process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1305
+ else
1306
+ delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1307
+ if (typeof prevCodexHome === 'string')
1308
+ process.env.CODEX_HOME = prevCodexHome;
1309
+ else
1310
+ delete process.env.CODEX_HOME;
1311
+ if (typeof prevPrimaryProviderEnv === 'string')
1312
+ process.env.PRIMARY_PROVIDER_API_KEY = prevPrimaryProviderEnv;
1313
+ else
1314
+ delete process.env.PRIMARY_PROVIDER_API_KEY;
1315
+ if (typeof prevWorkerProviderEnv === 'string')
1316
+ process.env.WORKER_PROVIDER_API_KEY = prevWorkerProviderEnv;
1317
+ else
1318
+ delete process.env.WORKER_PROVIDER_API_KEY;
1319
+ await rm(leaderCodexHome, { recursive: true, force: true });
1320
+ await rm(workerCodexHome, { recursive: true, force: true });
1321
+ }
1322
+ });
1323
+ it('buildWorkerProcessLaunchSpec resolves relative worker CODEX_HOME against the worker cwd', async () => {
1324
+ const prevBypass = process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1325
+ const prevCodexHome = process.env.CODEX_HOME;
1326
+ const prevLeaderProviderEnv = process.env.LEADER_PROVIDER_API_KEY;
1327
+ const prevWorkerProviderEnv = process.env.WORKER_PROVIDER_API_KEY;
1328
+ const originalCwd = process.cwd();
1329
+ const leaderCwd = await mkdtemp(join(tmpdir(), 'omx-team-provider-relative-leader-'));
1330
+ const workerCwd = await mkdtemp(join(tmpdir(), 'omx-team-provider-relative-worker-'));
1331
+ const leaderCodexHome = join(leaderCwd, '.codex');
1332
+ const workerCodexHome = join(workerCwd, '.codex');
1333
+ process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = '0';
1334
+ process.env.CODEX_HOME = leaderCodexHome;
1335
+ process.env.LEADER_PROVIDER_API_KEY = 'leader-secret';
1336
+ process.env.WORKER_PROVIDER_API_KEY = 'worker-secret';
1337
+ try {
1338
+ await mkdir(leaderCodexHome, { recursive: true });
1339
+ await mkdir(workerCodexHome, { recursive: true });
1340
+ await writeFile(join(leaderCodexHome, 'config.toml'), [
1341
+ 'model_provider = "leader_provider"',
1342
+ '',
1343
+ '[model_providers.leader_provider]',
1344
+ 'name = "leader_provider"',
1345
+ 'base_url = "http://localhost:3000/v1"',
1346
+ 'wire_api = "responses"',
1347
+ 'requires_openai_auth = true',
1348
+ 'env_key = "LEADER_PROVIDER_API_KEY"',
1349
+ '',
1350
+ ].join('\n'));
1351
+ await writeFile(join(workerCodexHome, 'config.toml'), [
1352
+ 'model_provider = "worker_provider"',
1353
+ '',
1354
+ '[model_providers.worker_provider]',
1355
+ 'name = "worker_provider"',
1356
+ 'base_url = "http://localhost:4000/v1"',
1357
+ 'wire_api = "responses"',
1358
+ 'requires_openai_auth = true',
1359
+ 'env_key = "WORKER_PROVIDER_API_KEY"',
1360
+ '',
1361
+ ].join('\n'));
1362
+ process.chdir(leaderCwd);
1363
+ const spec = buildWorkerProcessLaunchSpec('zeta-team', 1, [], workerCwd, { CODEX_HOME: '.codex' }, 'codex');
1364
+ assert.equal(spec.env.CODEX_HOME, '.codex');
1365
+ assert.equal(spec.env.WORKER_PROVIDER_API_KEY, 'worker-secret');
1366
+ assert.equal(spec.env.LEADER_PROVIDER_API_KEY, undefined);
1367
+ }
1368
+ finally {
1369
+ process.chdir(originalCwd);
1370
+ if (typeof prevBypass === 'string')
1371
+ process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT = prevBypass;
1372
+ else
1373
+ delete process.env.OMX_BYPASS_DEFAULT_SYSTEM_PROMPT;
1374
+ if (typeof prevCodexHome === 'string')
1375
+ process.env.CODEX_HOME = prevCodexHome;
1376
+ else
1377
+ delete process.env.CODEX_HOME;
1378
+ if (typeof prevLeaderProviderEnv === 'string')
1379
+ process.env.LEADER_PROVIDER_API_KEY = prevLeaderProviderEnv;
1380
+ else
1381
+ delete process.env.LEADER_PROVIDER_API_KEY;
1382
+ if (typeof prevWorkerProviderEnv === 'string')
1383
+ process.env.WORKER_PROVIDER_API_KEY = prevWorkerProviderEnv;
1384
+ else
1385
+ delete process.env.WORKER_PROVIDER_API_KEY;
1386
+ await rm(leaderCwd, { recursive: true, force: true });
1387
+ await rm(workerCwd, { recursive: true, force: true });
1388
+ }
1389
+ });
1108
1390
  });
1109
1391
  describe('sendToWorkerStdin', () => {
1110
1392
  it('writes a newline-terminated trigger message to worker stdin', () => {
@@ -1186,6 +1468,56 @@ esac
1186
1468
  assert.equal(waitForWorkerReady('omx-team-x', 1, 1_000), true);
1187
1469
  });
1188
1470
  });
1471
+ it('waitForWorkerReady falls back to recent scrollback when a live Codex viewport pushes the prompt below the visible slice', async () => {
1472
+ await withMockTmuxFixture('omx-tmux-worker-ready-scrollback-fallback-', (logPath) => `#!/bin/sh
1473
+ set -eu
1474
+ printf '%s\n' "$*" >> "${logPath}"
1475
+ case "$1" in
1476
+ capture-pane)
1477
+ if printf '%s\n' "$*" | grep -q -- ' -S -80'; then
1478
+ cat <<'EOF'
1479
+ ${VIEWPORT_SCROLLBACK_READY_CAPTURE}
1480
+ EOF
1481
+ else
1482
+ cat <<'EOF'
1483
+ ${VIEWPORT_WITHOUT_VISIBLE_PROMPT_CAPTURE}
1484
+ EOF
1485
+ fi
1486
+ exit 0
1487
+ ;;
1488
+ *)
1489
+ exit 0
1490
+ ;;
1491
+ esac
1492
+ `, async ({ logPath }) => {
1493
+ assert.equal(waitForWorkerReady('omx-team-x', 1, 1_000), true);
1494
+ const log = await readFile(logPath, 'utf-8');
1495
+ assert.match(log, /capture-pane -t omx-team-x:1 -p/);
1496
+ assert.match(log, /capture-pane -t omx-team-x:1 -p -S -80/);
1497
+ });
1498
+ });
1499
+ it('waitForWorkerReady does not consult scrollback when the visible slice is only status text', async () => {
1500
+ await withMockTmuxFixture('omx-tmux-worker-ready-no-scrollback-status-', (logPath) => `#!/bin/sh
1501
+ set -eu
1502
+ printf '%s\n' "$*" >> "${logPath}"
1503
+ case "$1" in
1504
+ capture-pane)
1505
+ cat <<'EOF'
1506
+ gpt-5 50% left
1507
+ EOF
1508
+ exit 0
1509
+ ;;
1510
+ *)
1511
+ exit 0
1512
+ ;;
1513
+ esac
1514
+ `, async ({ logPath }) => {
1515
+ assert.equal(waitForWorkerReady('omx-team-x', 1, 250), false);
1516
+ const log = await readFile(logPath, 'utf-8');
1517
+ assert.match(log, /capture-pane -t omx-team-x:1 -p/);
1518
+ assert.doesNotMatch(log, /capture-pane -t omx-team-x:1 -p -S -80/);
1519
+ });
1520
+ });
1189
1521
  it('waitForWorkerReady auto-accepts the Claude bypass prompt', async () => {
1190
1522
  await withMockTmuxFixture('omx-tmux-claude-bypass-ready-', (logPath) => `#!/bin/sh
1191
1523
  set -eu
@@ -1259,6 +1591,193 @@ esac
1259
1591
  });
1260
1592
  });
1261
1593
  });
1594
+ describe('native Windows HUD reconciliation', () => {
1595
+ it('avoids nested tmux run-shell hooks during team HUD startup on native Windows', async () => {
1596
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-team-win32-hud-'));
1597
+ const prevTmux = process.env.TMUX;
1598
+ const prevTmuxPane = process.env.TMUX_PANE;
1599
+ const prevWorkerCli = process.env.OMX_TEAM_WORKER_CLI;
1600
+ const prevMsystem = process.env.MSYSTEM;
1601
+ const prevOstype = process.env.OSTYPE;
1602
+ const prevWsl = process.env.WSL_DISTRO_NAME;
1603
+ const prevWslInterop = process.env.WSL_INTEROP;
1604
+ const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1605
+ try {
1606
+ await withMockTmuxFixture('omx-tmux-win32-hud-reconcile-', (logPath) => `#!/bin/sh
1607
+ set -eu
1608
+ printf '%s\\n' "$*" >> "${logPath}"
1609
+ case "\${1:-}" in
1610
+ -V)
1611
+ echo "tmux 3.4"
1612
+ exit 0
1613
+ ;;
1614
+ display-message)
1615
+ case "$*" in
1616
+ *"#{window_width}"*)
1617
+ echo "120"
1618
+ ;;
1619
+ *)
1620
+ echo "leader:0 %1"
1621
+ ;;
1622
+ esac
1623
+ exit 0
1624
+ ;;
1625
+ list-panes)
1626
+ printf "%%1\\tnode\\t'codex'\\n"
1627
+ exit 0
1628
+ ;;
1629
+ split-window)
1630
+ case "$*" in
1631
+ *" -h "*)
1632
+ echo "%2"
1633
+ ;;
1634
+ *)
1635
+ echo "%3"
1636
+ ;;
1637
+ esac
1638
+ exit 0
1639
+ ;;
1640
+ resize-pane|select-layout|set-window-option|select-pane|kill-pane)
1641
+ exit 0
1642
+ ;;
1643
+ set-hook|run-shell)
1644
+ exit 0
1645
+ ;;
1646
+ *)
1647
+ exit 0
1648
+ ;;
1649
+ esac
1650
+ `, async ({ logPath }) => {
1651
+ const fakeBinDir = join(logPath, '..');
1652
+ const geminiPath = join(fakeBinDir, 'gemini');
1653
+ await writeFile(geminiPath, '#!/bin/sh\nexit 0\n');
1654
+ await chmod(geminiPath, 0o755);
1655
+ process.env.TMUX = 'leader-session,stub,0';
1656
+ process.env.TMUX_PANE = '%1';
1657
+ process.env.OMX_TEAM_WORKER_CLI = 'gemini';
1658
+ delete process.env.MSYSTEM;
1659
+ delete process.env.OSTYPE;
1660
+ delete process.env.WSL_DISTRO_NAME;
1661
+ delete process.env.WSL_INTEROP;
1662
+ Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1663
+ const session = createTeamSession('Windows Team', 1, cwd);
1664
+ assert.equal(session.hudPaneId, '%3');
1665
+ assert.equal(session.resizeHookName, null);
1666
+ assert.equal(session.resizeHookTarget, null);
1667
+ const tmuxLog = await readFile(logPath, 'utf-8');
1668
+ assert.match(tmuxLog, new RegExp(`resize-pane -t %3 -y ${HUD_TMUX_TEAM_HEIGHT_LINES}`));
1669
+ assert.doesNotMatch(tmuxLog, /set-hook -t leader:0 client-resized\[\d+\]/);
1670
+ assert.doesNotMatch(tmuxLog, /set-hook -t leader:0 client-attached\[\d+\]/);
1671
+ assert.doesNotMatch(tmuxLog, /run-shell -b sleep \d+; tmux resize-pane -t %3 -y \d+ >/);
1672
+ assert.doesNotMatch(tmuxLog, /run-shell tmux resize-pane -t %3 -y \d+ >/);
1673
+ });
1674
+ }
1675
+ finally {
1676
+ if (origPlatform)
1677
+ Object.defineProperty(process, 'platform', origPlatform);
1678
+ if (typeof prevTmux === 'string')
1679
+ process.env.TMUX = prevTmux;
1680
+ else
1681
+ delete process.env.TMUX;
1682
+ if (typeof prevTmuxPane === 'string')
1683
+ process.env.TMUX_PANE = prevTmuxPane;
1684
+ else
1685
+ delete process.env.TMUX_PANE;
1686
+ if (typeof prevWorkerCli === 'string')
1687
+ process.env.OMX_TEAM_WORKER_CLI = prevWorkerCli;
1688
+ else
1689
+ delete process.env.OMX_TEAM_WORKER_CLI;
1690
+ if (typeof prevMsystem === 'string')
1691
+ process.env.MSYSTEM = prevMsystem;
1692
+ else
1693
+ delete process.env.MSYSTEM;
1694
+ if (typeof prevOstype === 'string')
1695
+ process.env.OSTYPE = prevOstype;
1696
+ else
1697
+ delete process.env.OSTYPE;
1698
+ if (typeof prevWsl === 'string')
1699
+ process.env.WSL_DISTRO_NAME = prevWsl;
1700
+ else
1701
+ delete process.env.WSL_DISTRO_NAME;
1702
+ if (typeof prevWslInterop === 'string')
1703
+ process.env.WSL_INTEROP = prevWslInterop;
1704
+ else
1705
+ delete process.env.WSL_INTEROP;
1706
+ await rm(cwd, { recursive: true, force: true });
1707
+ }
1708
+ });
1709
+ it('restores standalone HUD panes with direct resize on native Windows', async () => {
1710
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-standalone-win32-hud-'));
1711
+ const prevLeaderNodePath = process.env.OMX_LEADER_NODE_PATH;
1712
+ const prevMsystem = process.env.MSYSTEM;
1713
+ const prevOstype = process.env.OSTYPE;
1714
+ const prevWsl = process.env.WSL_DISTRO_NAME;
1715
+ const prevWslInterop = process.env.WSL_INTEROP;
1716
+ const origPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
1717
+ try {
1718
+ await withMockTmuxFixture('omx-tmux-win32-standalone-hud-', (logPath) => `#!/bin/sh
1719
+ set -eu
1720
+ printf '%s\\n' "$*" >> "${logPath}"
1721
+ case "\${1:-}" in
1722
+ split-window)
1723
+ echo "%44"
1724
+ exit 0
1725
+ ;;
1726
+ resize-pane|select-pane)
1727
+ exit 0
1728
+ ;;
1729
+ set-hook|run-shell)
1730
+ exit 0
1731
+ ;;
1732
+ *)
1733
+ exit 0
1734
+ ;;
1735
+ esac
1736
+ `, async ({ logPath }) => {
1737
+ delete process.env.MSYSTEM;
1738
+ delete process.env.OSTYPE;
1739
+ delete process.env.WSL_DISTRO_NAME;
1740
+ delete process.env.WSL_INTEROP;
1741
+ process.env.OMX_LEADER_NODE_PATH = 'C:\\Program Files\\nodejs\\node.exe';
1742
+ Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
1743
+ const paneId = restoreStandaloneHudPane('%11', cwd);
1744
+ assert.equal(paneId, '%44');
1745
+ const tmuxLog = await readFile(logPath, 'utf-8');
1746
+ assert.match(tmuxLog, /'C:\\Program Files\\nodejs\\node\.exe'/);
1747
+ assert.match(tmuxLog, new RegExp(`resize-pane -t %44 -y ${HUD_TMUX_TEAM_HEIGHT_LINES}`));
1748
+ assert.match(tmuxLog, /select-pane -t %11/);
1749
+ assert.doesNotMatch(tmuxLog, /run-shell -b sleep \d+; tmux resize-pane -t %44 -y \d+ >/);
1750
+ assert.doesNotMatch(tmuxLog, /run-shell tmux resize-pane -t %44 -y \d+ >/);
1751
+ assert.doesNotMatch(tmuxLog, /set-hook -t /);
1752
+ });
1753
+ }
1754
+ finally {
1755
+ if (origPlatform)
1756
+ Object.defineProperty(process, 'platform', origPlatform);
1757
+ if (typeof prevLeaderNodePath === 'string')
1758
+ process.env.OMX_LEADER_NODE_PATH = prevLeaderNodePath;
1759
+ else
1760
+ delete process.env.OMX_LEADER_NODE_PATH;
1761
+ if (typeof prevMsystem === 'string')
1762
+ process.env.MSYSTEM = prevMsystem;
1763
+ else
1764
+ delete process.env.MSYSTEM;
1765
+ if (typeof prevOstype === 'string')
1766
+ process.env.OSTYPE = prevOstype;
1767
+ else
1768
+ delete process.env.OSTYPE;
1769
+ if (typeof prevWsl === 'string')
1770
+ process.env.WSL_DISTRO_NAME = prevWsl;
1771
+ else
1772
+ delete process.env.WSL_DISTRO_NAME;
1773
+ if (typeof prevWslInterop === 'string')
1774
+ process.env.WSL_INTEROP = prevWslInterop;
1775
+ else
1776
+ delete process.env.WSL_INTEROP;
1777
+ await rm(cwd, { recursive: true, force: true });
1778
+ }
1779
+ });
1780
+ });
1262
1781
  describe('dismissTrustPromptIfPresent capture shape', () => {
1263
1782
  it('uses visible capture-pane argv without tail flags', async () => {
1264
1783
  const previousAutoTrust = process.env.OMX_TEAM_AUTO_TRUST;