oh-my-codex 0.18.1 → 0.18.3

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 (310) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +4 -2
  4. package/dist/agents/__tests__/definitions.test.js +23 -0
  5. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  6. package/dist/agents/__tests__/native-config.test.js +20 -0
  7. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  8. package/dist/agents/definitions.d.ts.map +1 -1
  9. package/dist/agents/definitions.js +40 -0
  10. package/dist/agents/definitions.js.map +1 -1
  11. package/dist/agents/native-config.d.ts +1 -0
  12. package/dist/agents/native-config.d.ts.map +1 -1
  13. package/dist/agents/native-config.js +4 -0
  14. package/dist/agents/native-config.js.map +1 -1
  15. package/dist/auth/__tests__/config-sessions.test.d.ts +2 -0
  16. package/dist/auth/__tests__/config-sessions.test.d.ts.map +1 -0
  17. package/dist/auth/__tests__/config-sessions.test.js +48 -0
  18. package/dist/auth/__tests__/config-sessions.test.js.map +1 -0
  19. package/dist/auth/__tests__/quota-rotation.test.d.ts +2 -0
  20. package/dist/auth/__tests__/quota-rotation.test.d.ts.map +1 -0
  21. package/dist/auth/__tests__/quota-rotation.test.js +33 -0
  22. package/dist/auth/__tests__/quota-rotation.test.js.map +1 -0
  23. package/dist/auth/__tests__/redact.test.d.ts +2 -0
  24. package/dist/auth/__tests__/redact.test.d.ts.map +1 -0
  25. package/dist/auth/__tests__/redact.test.js +20 -0
  26. package/dist/auth/__tests__/redact.test.js.map +1 -0
  27. package/dist/auth/__tests__/storage.test.d.ts +2 -0
  28. package/dist/auth/__tests__/storage.test.d.ts.map +1 -0
  29. package/dist/auth/__tests__/storage.test.js +108 -0
  30. package/dist/auth/__tests__/storage.test.js.map +1 -0
  31. package/dist/auth/config.d.ts +9 -0
  32. package/dist/auth/config.d.ts.map +1 -0
  33. package/dist/auth/config.js +77 -0
  34. package/dist/auth/config.js.map +1 -0
  35. package/dist/auth/hotswap.d.ts +36 -0
  36. package/dist/auth/hotswap.d.ts.map +1 -0
  37. package/dist/auth/hotswap.js +159 -0
  38. package/dist/auth/hotswap.js.map +1 -0
  39. package/dist/auth/index.d.ts +8 -0
  40. package/dist/auth/index.d.ts.map +1 -0
  41. package/dist/auth/index.js +8 -0
  42. package/dist/auth/index.js.map +1 -0
  43. package/dist/auth/paths.d.ts +12 -0
  44. package/dist/auth/paths.d.ts.map +1 -0
  45. package/dist/auth/paths.js +78 -0
  46. package/dist/auth/paths.js.map +1 -0
  47. package/dist/auth/quota-detector.d.ts +10 -0
  48. package/dist/auth/quota-detector.d.ts.map +1 -0
  49. package/dist/auth/quota-detector.js +40 -0
  50. package/dist/auth/quota-detector.js.map +1 -0
  51. package/dist/auth/redact.d.ts +2 -0
  52. package/dist/auth/redact.d.ts.map +1 -0
  53. package/dist/auth/redact.js +26 -0
  54. package/dist/auth/redact.js.map +1 -0
  55. package/dist/auth/rotation.d.ts +9 -0
  56. package/dist/auth/rotation.d.ts.map +1 -0
  57. package/dist/auth/rotation.js +26 -0
  58. package/dist/auth/rotation.js.map +1 -0
  59. package/dist/auth/sessions.d.ts +15 -0
  60. package/dist/auth/sessions.d.ts.map +1 -0
  61. package/dist/auth/sessions.js +62 -0
  62. package/dist/auth/sessions.js.map +1 -0
  63. package/dist/auth/storage.d.ts +27 -0
  64. package/dist/auth/storage.d.ts.map +1 -0
  65. package/dist/auth/storage.js +111 -0
  66. package/dist/auth/storage.js.map +1 -0
  67. package/dist/catalog/__tests__/generator.test.js +4 -0
  68. package/dist/catalog/__tests__/generator.test.js.map +1 -1
  69. package/dist/cli/__tests__/auth.test.d.ts +2 -0
  70. package/dist/cli/__tests__/auth.test.d.ts.map +1 -0
  71. package/dist/cli/__tests__/auth.test.js +168 -0
  72. package/dist/cli/__tests__/auth.test.js.map +1 -0
  73. package/dist/cli/__tests__/doctor-warning-copy.test.js +112 -5
  74. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  75. package/dist/cli/__tests__/explore.test.js +20 -0
  76. package/dist/cli/__tests__/explore.test.js.map +1 -1
  77. package/dist/cli/__tests__/index.test.js +171 -21
  78. package/dist/cli/__tests__/index.test.js.map +1 -1
  79. package/dist/cli/__tests__/launch-fallback.test.js +51 -3
  80. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  81. package/dist/cli/__tests__/nested-help-routing.test.js +1 -0
  82. package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
  83. package/dist/cli/__tests__/question.test.js +2 -2
  84. package/dist/cli/__tests__/question.test.js.map +1 -1
  85. package/dist/cli/__tests__/setup-agents-overwrite.test.js +30 -1
  86. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  87. package/dist/cli/__tests__/setup-install-mode.test.js +47 -0
  88. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  89. package/dist/cli/auth.d.ts +4 -0
  90. package/dist/cli/auth.d.ts.map +1 -0
  91. package/dist/cli/auth.js +89 -0
  92. package/dist/cli/auth.js.map +1 -0
  93. package/dist/cli/doctor.d.ts.map +1 -1
  94. package/dist/cli/doctor.js +190 -7
  95. package/dist/cli/doctor.js.map +1 -1
  96. package/dist/cli/explore.d.ts.map +1 -1
  97. package/dist/cli/explore.js +12 -0
  98. package/dist/cli/explore.js.map +1 -1
  99. package/dist/cli/index.d.ts +27 -3
  100. package/dist/cli/index.d.ts.map +1 -1
  101. package/dist/cli/index.js +245 -47
  102. package/dist/cli/index.js.map +1 -1
  103. package/dist/cli/setup.d.ts.map +1 -1
  104. package/dist/cli/setup.js +11 -3
  105. package/dist/cli/setup.js.map +1 -1
  106. package/dist/config/__tests__/codex-hooks.test.js +3 -3
  107. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  108. package/dist/config/__tests__/deep-interview.test.d.ts +2 -0
  109. package/dist/config/__tests__/deep-interview.test.d.ts.map +1 -0
  110. package/dist/config/__tests__/deep-interview.test.js +239 -0
  111. package/dist/config/__tests__/deep-interview.test.js.map +1 -0
  112. package/dist/config/__tests__/generator-idempotent.test.js +123 -0
  113. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  114. package/dist/config/codex-hooks.d.ts +1 -0
  115. package/dist/config/codex-hooks.d.ts.map +1 -1
  116. package/dist/config/codex-hooks.js +2 -4
  117. package/dist/config/codex-hooks.js.map +1 -1
  118. package/dist/config/deep-interview.d.ts +22 -0
  119. package/dist/config/deep-interview.d.ts.map +1 -0
  120. package/dist/config/deep-interview.js +151 -0
  121. package/dist/config/deep-interview.js.map +1 -0
  122. package/dist/config/generator.d.ts +19 -2
  123. package/dist/config/generator.d.ts.map +1 -1
  124. package/dist/config/generator.js +198 -29
  125. package/dist/config/generator.js.map +1 -1
  126. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +21 -0
  127. package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
  128. package/dist/goal-workflows/codex-goal-snapshot.d.ts +3 -0
  129. package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
  130. package/dist/goal-workflows/codex-goal-snapshot.js +45 -2
  131. package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
  132. package/dist/hooks/__tests__/agents-overlay.test.js +2 -0
  133. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  134. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +17 -0
  135. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  136. package/dist/hooks/__tests__/explore-routing.test.js +1 -0
  137. package/dist/hooks/__tests__/explore-routing.test.js.map +1 -1
  138. package/dist/hooks/__tests__/keyword-detector.test.js +471 -15
  139. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  140. package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts +2 -0
  141. package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts.map +1 -0
  142. package/dist/hooks/__tests__/prometheus-strict-contract.test.js +320 -0
  143. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -0
  144. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +12 -0
  145. package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
  146. package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts +2 -0
  147. package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts.map +1 -0
  148. package/dist/hooks/__tests__/research-workflow-boundaries.test.js +35 -0
  149. package/dist/hooks/__tests__/research-workflow-boundaries.test.js.map +1 -0
  150. package/dist/hooks/deep-interview-config-instruction.d.ts +3 -0
  151. package/dist/hooks/deep-interview-config-instruction.d.ts.map +1 -0
  152. package/dist/hooks/deep-interview-config-instruction.js +47 -0
  153. package/dist/hooks/deep-interview-config-instruction.js.map +1 -0
  154. package/dist/hooks/explore-routing.d.ts.map +1 -1
  155. package/dist/hooks/explore-routing.js +1 -0
  156. package/dist/hooks/explore-routing.js.map +1 -1
  157. package/dist/hooks/keyword-detector.d.ts +6 -1
  158. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  159. package/dist/hooks/keyword-detector.js +80 -14
  160. package/dist/hooks/keyword-detector.js.map +1 -1
  161. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  162. package/dist/hooks/keyword-registry.js +1 -0
  163. package/dist/hooks/keyword-registry.js.map +1 -1
  164. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  165. package/dist/hooks/prompt-guidance-contract.js +11 -0
  166. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  167. package/dist/hud/__tests__/hud-tmux-injection.test.js +22 -0
  168. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
  169. package/dist/hud/__tests__/reconcile.test.js +213 -17
  170. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  171. package/dist/hud/__tests__/render.test.js +84 -0
  172. package/dist/hud/__tests__/render.test.js.map +1 -1
  173. package/dist/hud/__tests__/state.test.js +51 -1
  174. package/dist/hud/__tests__/state.test.js.map +1 -1
  175. package/dist/hud/__tests__/tmux.test.js +171 -23
  176. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  177. package/dist/hud/index.d.ts +1 -1
  178. package/dist/hud/index.d.ts.map +1 -1
  179. package/dist/hud/index.js +8 -3
  180. package/dist/hud/index.js.map +1 -1
  181. package/dist/hud/reconcile.d.ts +1 -1
  182. package/dist/hud/reconcile.d.ts.map +1 -1
  183. package/dist/hud/reconcile.js +14 -3
  184. package/dist/hud/reconcile.js.map +1 -1
  185. package/dist/hud/render.d.ts.map +1 -1
  186. package/dist/hud/render.js +26 -0
  187. package/dist/hud/render.js.map +1 -1
  188. package/dist/hud/state.d.ts +2 -1
  189. package/dist/hud/state.d.ts.map +1 -1
  190. package/dist/hud/state.js +62 -1
  191. package/dist/hud/state.js.map +1 -1
  192. package/dist/hud/tmux.d.ts +17 -3
  193. package/dist/hud/tmux.d.ts.map +1 -1
  194. package/dist/hud/tmux.js +96 -10
  195. package/dist/hud/tmux.js.map +1 -1
  196. package/dist/hud/types.d.ts +22 -0
  197. package/dist/hud/types.d.ts.map +1 -1
  198. package/dist/hud/types.js.map +1 -1
  199. package/dist/pipeline/__tests__/orchestrator.test.js +63 -1
  200. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  201. package/dist/pipeline/__tests__/stages.test.js +410 -4
  202. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  203. package/dist/pipeline/orchestrator.d.ts.map +1 -1
  204. package/dist/pipeline/orchestrator.js +29 -2
  205. package/dist/pipeline/orchestrator.js.map +1 -1
  206. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  207. package/dist/pipeline/stages/ralplan.js +41 -6
  208. package/dist/pipeline/stages/ralplan.js.map +1 -1
  209. package/dist/question/__tests__/ui.test.js +43 -10
  210. package/dist/question/__tests__/ui.test.js.map +1 -1
  211. package/dist/question/deep-interview.d.ts +2 -0
  212. package/dist/question/deep-interview.d.ts.map +1 -1
  213. package/dist/question/deep-interview.js.map +1 -1
  214. package/dist/question/ui.d.ts +12 -0
  215. package/dist/question/ui.d.ts.map +1 -1
  216. package/dist/question/ui.js +83 -46
  217. package/dist/question/ui.js.map +1 -1
  218. package/dist/ralplan/__tests__/runtime.test.js +200 -10
  219. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  220. package/dist/ralplan/consensus-gate.d.ts +23 -0
  221. package/dist/ralplan/consensus-gate.d.ts.map +1 -0
  222. package/dist/ralplan/consensus-gate.js +212 -0
  223. package/dist/ralplan/consensus-gate.js.map +1 -0
  224. package/dist/ralplan/runtime.d.ts +25 -0
  225. package/dist/ralplan/runtime.d.ts.map +1 -1
  226. package/dist/ralplan/runtime.js +144 -8
  227. package/dist/ralplan/runtime.js.map +1 -1
  228. package/dist/scripts/__tests__/codex-native-hook.test.js +1034 -28
  229. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  230. package/dist/scripts/__tests__/docs-site-contract.test.d.ts +2 -0
  231. package/dist/scripts/__tests__/docs-site-contract.test.d.ts.map +1 -0
  232. package/dist/scripts/__tests__/docs-site-contract.test.js +42 -0
  233. package/dist/scripts/__tests__/docs-site-contract.test.js.map +1 -0
  234. package/dist/scripts/__tests__/notify-dispatcher.test.js +115 -2
  235. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
  236. package/dist/scripts/__tests__/run-test-files.test.js +57 -0
  237. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  238. package/dist/scripts/__tests__/verify-native-agents.test.js +2 -2
  239. package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
  240. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  241. package/dist/scripts/codex-native-hook.js +238 -36
  242. package/dist/scripts/codex-native-hook.js.map +1 -1
  243. package/dist/scripts/notify-dispatcher.js +188 -4
  244. package/dist/scripts/notify-dispatcher.js.map +1 -1
  245. package/dist/scripts/run-test-files.js +13 -0
  246. package/dist/scripts/run-test-files.js.map +1 -1
  247. package/dist/state/__tests__/planning-gate.test.d.ts +2 -0
  248. package/dist/state/__tests__/planning-gate.test.d.ts.map +1 -0
  249. package/dist/state/__tests__/planning-gate.test.js +219 -0
  250. package/dist/state/__tests__/planning-gate.test.js.map +1 -0
  251. package/dist/state/__tests__/workflow-transition.test.js +6 -0
  252. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  253. package/dist/state/workflow-transition.d.ts +24 -1
  254. package/dist/state/workflow-transition.d.ts.map +1 -1
  255. package/dist/state/workflow-transition.js +70 -0
  256. package/dist/state/workflow-transition.js.map +1 -1
  257. package/dist/subagents/tracker.d.ts.map +1 -1
  258. package/dist/subagents/tracker.js +4 -3
  259. package/dist/subagents/tracker.js.map +1 -1
  260. package/dist/team/__tests__/runtime.test.js +36 -44
  261. package/dist/team/__tests__/runtime.test.js.map +1 -1
  262. package/dist/team/__tests__/tmux-session.test.js +144 -18
  263. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  264. package/dist/team/runtime.d.ts.map +1 -1
  265. package/dist/team/runtime.js +10 -20
  266. package/dist/team/runtime.js.map +1 -1
  267. package/dist/team/tmux-session.d.ts.map +1 -1
  268. package/dist/team/tmux-session.js +22 -6
  269. package/dist/team/tmux-session.js.map +1 -1
  270. package/dist/ultragoal/__tests__/artifacts.test.js +50 -0
  271. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  272. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  273. package/dist/ultragoal/artifacts.js +28 -2
  274. package/dist/ultragoal/artifacts.js.map +1 -1
  275. package/package.json +1 -1
  276. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  277. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +16 -4
  278. package/plugins/oh-my-codex/skills/autoresearch/SKILL.md +4 -0
  279. package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +1 -1
  280. package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +1 -1
  281. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +10 -0
  282. package/plugins/oh-my-codex/skills/pipeline/SKILL.md +1 -1
  283. package/plugins/oh-my-codex/skills/plan/SKILL.md +1 -1
  284. package/plugins/oh-my-codex/skills/prometheus-strict/README.md +35 -0
  285. package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +219 -0
  286. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +24 -5
  287. package/prompts/prometheus-strict-metis.md +274 -0
  288. package/prompts/prometheus-strict-momus.md +82 -0
  289. package/prompts/prometheus-strict-oracle.md +107 -0
  290. package/prompts/researcher.md +22 -3
  291. package/prompts/scholastic.md +11 -0
  292. package/skills/autopilot/SKILL.md +16 -4
  293. package/skills/autoresearch/SKILL.md +4 -0
  294. package/skills/autoresearch-goal/SKILL.md +1 -1
  295. package/skills/best-practice-research/SKILL.md +1 -1
  296. package/skills/deep-interview/SKILL.md +10 -0
  297. package/skills/pipeline/SKILL.md +1 -1
  298. package/skills/plan/SKILL.md +1 -1
  299. package/skills/prometheus-strict/README.md +35 -0
  300. package/skills/prometheus-strict/SKILL.md +219 -0
  301. package/skills/ralplan/SKILL.md +24 -5
  302. package/src/scripts/__tests__/codex-native-hook.test.ts +1307 -61
  303. package/src/scripts/__tests__/docs-site-contract.test.ts +47 -0
  304. package/src/scripts/__tests__/notify-dispatcher.test.ts +132 -3
  305. package/src/scripts/__tests__/run-test-files.test.ts +67 -0
  306. package/src/scripts/__tests__/verify-native-agents.test.ts +2 -2
  307. package/src/scripts/codex-native-hook.ts +260 -31
  308. package/src/scripts/notify-dispatcher.ts +202 -4
  309. package/src/scripts/run-test-files.ts +13 -0
  310. package/templates/catalog-manifest.json +27 -0
@@ -1,12 +1,12 @@
1
1
  import { afterEach, describe, it, mock } from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
  import { existsSync, mkdirSync, utimesSync } from "node:fs";
4
- import { chmod, lstat, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
4
+ import { chmod, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
5
5
  import { dirname, join } from "node:path";
6
6
  import { tmpdir } from "node:os";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { once } from "node:events";
9
- import { HELP, normalizeCodexLaunchArgs, buildTmuxShellCommand, buildTmuxPaneCommand, shouldSourceTmuxPaneShellRc, buildWindowsPromptCommand, buildTmuxSessionName, resolveCliInvocation, commandOwnsLocalHelp, resolveCodexLaunchPolicy, resolveEffectiveLeaderLaunchPolicyOverride, resolveEnvLaunchPolicyOverride, resolveLeaderLaunchPolicyOverride, classifyCodexExecFailure, resolveSignalExitCode, parseTmuxPaneSnapshot, findHudWatchPaneIds, buildHudPaneCleanupTargets, readTopLevelTomlString, upsertTopLevelTomlString, collectInheritableTeamWorkerArgs, resolveTeamWorkerLaunchArgsEnv, injectModelInstructionsBypassArgs, resolveWorkerSparkModel, resolveSetupInstallModeArg, resolveSetupMcpModeArg, resolveSetupScopeArg, resolveLaunchConfigRepairOptions, readPersistedSetupPreferences, readPersistedSetupScope, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, shouldAutoIsolateMadmaxLaunch, createMadmaxIsolatedRoot, buildMadmaxDetachedLaunchContextKey, resolveOmxRootForLaunch, resolveDisposableWorktreeOmxRootForLaunch, prepareCodexHomeForLaunch, persistProjectLaunchRuntimeAuthState, runtimeCodexHomePath, buildDetachedSessionBootstrapSteps, buildDetachedTmuxSessionName, buildDetachedSessionFinalizeSteps, buildDetachedSessionRollbackSteps, detectDetachedSessionWindowIndex, resolveNotifyTempContract, buildNotifyTempStartupMessages, buildNotifyFallbackWatcherEnv, shouldEnableNotifyFallbackWatcher, reapStaleNotifyFallbackWatcher, cleanupLaunchOrphanedMcpProcesses, reapPostLaunchOrphanedMcpProcesses, cleanupPostLaunchModeStateFiles, resolveBackgroundHelperLaunchMode, shouldDetachBackgroundHelper, resolveNotifyFallbackWatcherScript, resolveHookDerivedWatcherScript, resolveNotifyHookScript, buildDetachedWindowsBootstrapScript, acquireTmuxExtendedKeysLease, resolveNativeSessionName, releaseTmuxExtendedKeysLease, withTmuxExtendedKeys, serializeDetachedSessionParentEnv, CODEX_SQLITE_HOME_ENV, } from "../index.js";
9
+ import { HELP, normalizeCodexLaunchArgs, buildTmuxShellCommand, buildTmuxPaneCommand, shouldSourceTmuxPaneShellRc, buildWindowsPromptCommand, buildTmuxSessionName, resolveCliInvocation, commandOwnsLocalHelp, resolveCodexLaunchPolicy, resolveEffectiveLeaderLaunchPolicyOverride, resolveEnvLaunchPolicyOverride, resolveLeaderLaunchPolicyOverride, classifyCodexExecFailure, resolveSignalExitCode, parseTmuxPaneSnapshot, findHudWatchPaneIds, buildHudPaneCleanupTargets, readTopLevelTomlString, upsertTopLevelTomlString, collectInheritableTeamWorkerArgs, resolveTeamWorkerLaunchArgsEnv, injectModelInstructionsBypassArgs, resolveWorkerSparkModel, resolveSetupInstallModeArg, resolveSetupMcpModeArg, resolveSetupScopeArg, resolveLaunchConfigRepairOptions, readPersistedSetupPreferences, readPersistedSetupScope, resolveCodexConfigPathForLaunch, resolveCodexHomeForLaunch, resolveProjectLocalCodexHomeForLaunch, shouldAutoIsolateMadmaxLaunch, createMadmaxIsolatedRoot, buildMadmaxDetachedLaunchContextKey, withMadmaxDetachedContextLock, resolveOmxRootForLaunch, resolveDisposableWorktreeOmxRootForLaunch, prepareCodexHomeForLaunch, persistProjectLaunchRuntimeAuthState, persistProjectLaunchRuntimeProjectTrustState, runtimeCodexHomePath, buildDetachedSessionBootstrapSteps, buildDetachedTmuxSessionName, buildDetachedSessionFinalizeSteps, buildDetachedSessionRollbackSteps, detectDetachedSessionWindowIndex, resolveNotifyTempContract, buildNotifyTempStartupMessages, buildNotifyFallbackWatcherEnv, shouldEnableNotifyFallbackWatcher, reapStaleNotifyFallbackWatcher, cleanupLaunchOrphanedMcpProcesses, reapPostLaunchOrphanedMcpProcesses, cleanupPostLaunchModeStateFiles, resolveBackgroundHelperLaunchMode, shouldDetachBackgroundHelper, resolveNotifyFallbackWatcherScript, resolveHookDerivedWatcherScript, resolveNotifyHookScript, buildDetachedWindowsBootstrapScript, acquireTmuxExtendedKeysLease, resolveNativeSessionName, releaseTmuxExtendedKeysLease, withTmuxExtendedKeys, serializeDetachedSessionParentEnv, CODEX_SQLITE_HOME_ENV, } from "../index.js";
10
10
  import { mergeConfig, repairConfigIfNeeded } from "../../config/generator.js";
11
11
  import { ensureReusableNodeModules } from "../../utils/repo-deps.js";
12
12
  import { readAllState } from "../../hud/state.js";
@@ -64,16 +64,16 @@ describe("madmax state isolation", () => {
64
64
  const env = { OMX_RUNS_DIR: runs };
65
65
  const runDir = createMadmaxIsolatedRoot(wd, ["--madmax", "--xhigh", "--tmux"], env);
66
66
  const metadata = JSON.parse(await readFile(join(runDir, ".omxbox-run.json"), "utf-8"));
67
- const expectedContext = buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--xhigh", "--tmux"]);
67
+ const expectedContext = buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--xhigh", "--tmux"], runDir);
68
68
  assert.equal(metadata.detached_launch_context, expectedContext);
69
69
  assert.equal(env.OMX_MADMAX_DETACHED_CONTEXT, expectedContext);
70
- assert.equal(expectedContext, buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--xhigh"]), "explicit --tmux is a transport choice and must not create a second context");
71
- assert.equal(expectedContext, buildMadmaxDetachedLaunchContextKey(wd, ["--xhigh", "--madmax", "--direct"]), "argument order and transport choices must not create duplicate detached contexts");
72
- assert.notEqual(expectedContext, buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--low"]), "different launch semantics may run concurrently");
73
- assert.notEqual(buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--high", "--xhigh"]), buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--xhigh", "--high"]), "last reasoning shorthand wins, so reversed reasoning order is a distinct context");
70
+ assert.equal(buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--xhigh", "--tmux"], runDir), buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--xhigh"], runDir), "explicit --tmux is a transport choice and must not create a second context");
71
+ assert.equal(buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--xhigh", "--tmux"], runDir), buildMadmaxDetachedLaunchContextKey(wd, ["--xhigh", "--madmax", "--direct"], runDir), "argument order and transport choices must not create duplicate detached contexts");
72
+ assert.notEqual(expectedContext, buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--low"], runDir), "different launch semantics may run concurrently");
73
+ assert.notEqual(buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--high", "--xhigh"], runDir), buildMadmaxDetachedLaunchContextKey(wd, ["--madmax", "--xhigh", "--high"], runDir), "last reasoning shorthand wins, so reversed reasoning order is a distinct context");
74
74
  const otherWd = await mkdtemp(join(tmpdir(), "omx-madmax-other-source-"));
75
75
  try {
76
- assert.notEqual(expectedContext, buildMadmaxDetachedLaunchContextKey(otherWd, ["--madmax", "--xhigh"]), "different work contexts may run concurrently");
76
+ assert.notEqual(expectedContext, buildMadmaxDetachedLaunchContextKey(otherWd, ["--madmax", "--xhigh"], runDir), "different work contexts may run concurrently");
77
77
  }
78
78
  finally {
79
79
  await rm(otherWd, { recursive: true, force: true });
@@ -84,6 +84,72 @@ describe("madmax state isolation", () => {
84
84
  await rm(runs, { recursive: true, force: true });
85
85
  }
86
86
  });
87
+ it("gives independent madmax run roots distinct detached launch context locks", async () => {
88
+ const wd = await mkdtemp(join(tmpdir(), "omx-madmax-source-"));
89
+ const runs = await mkdtemp(join(tmpdir(), "omx-madmax-runs-"));
90
+ try {
91
+ const firstEnv = { OMX_RUNS_DIR: runs };
92
+ const secondEnv = { OMX_RUNS_DIR: runs };
93
+ const firstRunDir = createMadmaxIsolatedRoot(wd, ["--madmax", "--high"], firstEnv);
94
+ const secondRunDir = createMadmaxIsolatedRoot(wd, ["--madmax", "--high"], secondEnv);
95
+ assert.notEqual(firstRunDir, secondRunDir);
96
+ assert.notEqual(firstEnv.OMX_MADMAX_DETACHED_CONTEXT, secondEnv.OMX_MADMAX_DETACHED_CONTEXT, "same cwd and argv from independent boxed runs must not contend on one active-detached lock");
97
+ assert.equal(firstEnv.OMX_MADMAX_DETACHED_CONTEXT, buildMadmaxDetachedLaunchContextKey(wd, ["--high", "--madmax", "--tmux"], firstRunDir), "transport and order normalization still deduplicates within the same isolated run");
98
+ }
99
+ finally {
100
+ await rm(wd, { recursive: true, force: true });
101
+ await rm(runs, { recursive: true, force: true });
102
+ }
103
+ });
104
+ it("recovers a madmax detached context lock whose holder pid has already exited", async () => {
105
+ const runs = await mkdtemp(join(tmpdir(), "omx-madmax-lock-stale-"));
106
+ try {
107
+ const contextKey = "stale-context";
108
+ const lockPath = join(runs, "active-detached", `${contextKey}.lock`);
109
+ mkdirSync(lockPath, { recursive: true });
110
+ await writeFile(join(lockPath, "pid"), "2147483647");
111
+ let ran = false;
112
+ const result = withMadmaxDetachedContextLock(runs, contextKey, () => {
113
+ ran = true;
114
+ return "acquired";
115
+ }, { maxAttempts: 2, retryMs: 0 });
116
+ assert.equal(result, "acquired");
117
+ assert.equal(ran, true);
118
+ assert.equal(existsSync(lockPath), false);
119
+ }
120
+ finally {
121
+ await rm(runs, { recursive: true, force: true });
122
+ }
123
+ });
124
+ it("preserves a live madmax detached context lock and reports holder diagnostics on timeout", async () => {
125
+ const runs = await mkdtemp(join(tmpdir(), "omx-madmax-lock-live-"));
126
+ try {
127
+ const contextKey = "live-context";
128
+ const lockPath = join(runs, "active-detached", `${contextKey}.lock`);
129
+ mkdirSync(lockPath, { recursive: true });
130
+ await writeFile(join(lockPath, "owner.json"), `${JSON.stringify({
131
+ version: 1,
132
+ pid: process.pid,
133
+ context_key: contextKey,
134
+ acquired_at: new Date().toISOString(),
135
+ })}\n`);
136
+ await writeFile(join(lockPath, "pid"), String(process.pid));
137
+ assert.throws(() => withMadmaxDetachedContextLock(runs, contextKey, () => "should-not-run", { maxAttempts: 1, retryMs: 0 }), (err) => {
138
+ assert.ok(err instanceof Error);
139
+ assert.match(err.message, /timed out waiting for madmax detached launch context lock/);
140
+ assert.match(err.message, new RegExp(`holder pid ${process.pid} is still running`));
141
+ assert.match(err.message, /owner context live-context/);
142
+ assert.match(err.message, /Another madmax detached launch is active for this directory/);
143
+ assert.match(err.message, /close the existing madmax session or use --worktree for concurrent work/);
144
+ assert.match(err.message, /Multiple madmax sessions in one directory are unsafe/);
145
+ return true;
146
+ });
147
+ assert.equal(existsSync(lockPath), true);
148
+ }
149
+ finally {
150
+ await rm(runs, { recursive: true, force: true });
151
+ }
152
+ });
87
153
  });
88
154
  describe("resolveOmxRootForLaunch", () => {
89
155
  it("preserves POSIX absolute OMX_ROOT", () => {
@@ -986,6 +1052,7 @@ describe("commandOwnsLocalHelp", () => {
986
1052
  "question",
987
1053
  "autoresearch",
988
1054
  "deepinit",
1055
+ "explore",
989
1056
  "hooks",
990
1057
  "hud",
991
1058
  "ralph",
@@ -1357,8 +1424,10 @@ describe("project launch scope helpers", () => {
1357
1424
  assert.equal(prepared.runtimeCodexHomeForCleanup, runtimeCodexHome);
1358
1425
  assert.equal(await readFile(join(runtimeCodexHome, "config.toml"), "utf-8"), originalConfig);
1359
1426
  assert.equal(await readFile(join(runtimeCodexHome, "agents", "planner.toml"), "utf-8"), 'name = "planner"\n');
1360
- assert.equal(await readFile(join(runtimeCodexHome, "hooks.json"), "utf-8"), '{"hooks":{}}\n');
1361
- assert.equal((await lstat(join(runtimeCodexHome, "hooks.json"))).isSymbolicLink(), false);
1427
+ // GH #2470: hooks.json must NOT be mirrored into the runtime CODEX_HOME.
1428
+ // Codex still loads the canonical project .codex/hooks.json as Project
1429
+ // config; a runtime mirror would add a duplicate User config hook source.
1430
+ assert.equal(existsSync(join(runtimeCodexHome, "hooks.json")), false);
1362
1431
  assert.equal(existsSync(join(runtimeCodexHome, "state_5.sqlite")), false);
1363
1432
  assert.equal(existsSync(join(runtimeCodexHome, "state_5.sqlite-wal")), false);
1364
1433
  assert.equal(existsSync(join(runtimeCodexHome, "logs_2.sqlite-shm")), false);
@@ -1395,7 +1464,74 @@ describe("project launch scope helpers", () => {
1395
1464
  await rm(wd, { recursive: true, force: true });
1396
1465
  }
1397
1466
  });
1398
- it("rewrites setup-owned hook trust state for the runtime CODEX_HOME mirror", async () => {
1467
+ it("project-scope launch registers native hooks exactly once and persists trust state (GH #2470)", async () => {
1468
+ const wd = await mkdtemp(join(tmpdir(), "omx-issue-2470-"));
1469
+ try {
1470
+ const projectCodexHome = join(wd, ".codex");
1471
+ await mkdir(join(wd, ".omx"), { recursive: true });
1472
+ await mkdir(projectCodexHome, { recursive: true });
1473
+ await writeFile(join(wd, ".omx", "setup-scope.json"), JSON.stringify({ scope: "project" }));
1474
+ const originalProjectConfig = [
1475
+ 'model = "gpt-5.5"',
1476
+ "",
1477
+ "[features]",
1478
+ "hooks = true",
1479
+ "",
1480
+ "# OMX-owned Codex hook trust state",
1481
+ "# Trusts only setup-managed codex-native-hook.js wrappers.",
1482
+ `[hooks.state."${join(projectCodexHome, "hooks.json")}:pre_tool_use:0:0"]`,
1483
+ 'trusted_hash = "sha256:project-hooks-trusted"',
1484
+ "# End OMX-owned Codex hook trust state",
1485
+ "",
1486
+ ].join("\n");
1487
+ await writeFile(join(projectCodexHome, "config.toml"), originalProjectConfig);
1488
+ await writeFile(join(projectCodexHome, "hooks.json"), '{"hooks":{}}\n');
1489
+ const prepared = await prepareCodexHomeForLaunch(wd, "session-2470", {});
1490
+ const runtimeCodexHome = runtimeCodexHomePath(wd, "session-2470");
1491
+ // 1. Hooks register exactly once: runtime CODEX_HOME holds no hooks.json
1492
+ // mirror, so Codex only sees the canonical project .codex/hooks.json.
1493
+ assert.equal(prepared.codexHomeOverride, runtimeCodexHome);
1494
+ assert.equal(existsSync(join(runtimeCodexHome, "hooks.json")), false);
1495
+ assert.equal(existsSync(join(projectCodexHome, "hooks.json")), true);
1496
+ // Simulate Codex writing workspace trust + a new hook trust ledger
1497
+ // entry into the runtime config.toml during the session.
1498
+ const runtimeConfigPath = join(runtimeCodexHome, "config.toml");
1499
+ const runtimeConfigBefore = await readFile(runtimeConfigPath, "utf-8");
1500
+ await writeFile(runtimeConfigPath, [
1501
+ runtimeConfigBefore.replace(/\n+$/, ""),
1502
+ "",
1503
+ `[projects."${wd}"]`,
1504
+ 'trust_level = "trusted"',
1505
+ "",
1506
+ "[tui.model_availability_nux]",
1507
+ '"gpt-5.5" = 1',
1508
+ "",
1509
+ ].join("\n"));
1510
+ // 2. Workspace trust + ephemeral runtime state are persisted to the
1511
+ // project config.toml in a marker-fenced block; NUX counters and
1512
+ // other runtime-only writes are NOT leaked back to the project.
1513
+ await persistProjectLaunchRuntimeProjectTrustState(prepared.runtimeCodexHomeForCleanup, prepared.projectLocalCodexHomeForCleanup);
1514
+ const persistedProjectConfig = await readFile(join(projectCodexHome, "config.toml"), "utf-8");
1515
+ assert.ok(persistedProjectConfig.includes("# OMX-synced Codex project trust state"), "expected synced-trust marker block in project config.toml");
1516
+ assert.ok(persistedProjectConfig.includes(`[projects."${wd}"]`), "expected workspace trust entry to be persisted to project config.toml");
1517
+ assert.ok(persistedProjectConfig.includes('trust_level = "trusted"'), "expected trust_level to be persisted to project config.toml");
1518
+ assert.doesNotMatch(persistedProjectConfig, /model_availability_nux/, "NUX counters must not leak into durable project config.toml");
1519
+ assert.ok(persistedProjectConfig.includes(`[hooks.state."${join(projectCodexHome, "hooks.json")}:pre_tool_use:0:0"]`), "setup-owned project hook trust state must remain intact");
1520
+ // 3. On a subsequent launch, the runtime mirror carries the persisted
1521
+ // project trust state forward — so Codex finds the workspace as
1522
+ // already-trusted and never re-prompts.
1523
+ await rm(runtimeCodexHome, { recursive: true, force: true });
1524
+ await prepareCodexHomeForLaunch(wd, "session-2470-repeat", {});
1525
+ const nextRuntimeCodexHome = runtimeCodexHomePath(wd, "session-2470-repeat");
1526
+ const nextRuntimeConfig = await readFile(join(nextRuntimeCodexHome, "config.toml"), "utf-8");
1527
+ assert.ok(nextRuntimeConfig.includes(`[projects."${wd}"]`), "next launch must inherit the persisted workspace trust entry");
1528
+ assert.equal(existsSync(join(nextRuntimeCodexHome, "hooks.json")), false);
1529
+ }
1530
+ finally {
1531
+ await rm(wd, { recursive: true, force: true });
1532
+ }
1533
+ });
1534
+ it("keeps setup-owned hook trust state targeted at the project hooks path (GH #2470)", async () => {
1399
1535
  const wd = await mkdtemp(join(tmpdir(), "omx-launch-runtime-hook-trust-"));
1400
1536
  try {
1401
1537
  const projectCodexHome = join(wd, ".codex");
@@ -1403,23 +1539,26 @@ describe("project launch scope helpers", () => {
1403
1539
  await mkdir(projectCodexHome, { recursive: true });
1404
1540
  await writeFile(join(wd, ".omx", "setup-scope.json"), JSON.stringify({ scope: "project" }));
1405
1541
  await writeFile(join(projectCodexHome, "hooks.json"), '{"hooks":{}}\n');
1542
+ const projectHookTrustHeader = `[hooks.state."${join(projectCodexHome, "hooks.json")}:pre_tool_use:0:0"]`;
1406
1543
  await writeFile(join(projectCodexHome, "config.toml"), [
1407
1544
  "[features]",
1408
1545
  "hooks = true",
1409
1546
  "",
1410
1547
  "# OMX-owned Codex hook trust state",
1411
1548
  "# Trusts only setup-managed codex-native-hook.js wrappers.",
1412
- `[hooks.state."${join(projectCodexHome, "hooks.json")}:pre_tool_use:0:0"]`,
1413
- 'trusted_hash = "stale"',
1549
+ projectHookTrustHeader,
1550
+ 'trusted_hash = "sha256:abc"',
1414
1551
  "# End OMX-owned Codex hook trust state",
1415
1552
  "",
1416
1553
  ].join("\n"));
1417
1554
  await prepareCodexHomeForLaunch(wd, "session-trust", {});
1418
1555
  const runtimeCodexHome = runtimeCodexHomePath(wd, "session-trust");
1419
1556
  const runtimeConfig = await readFile(join(runtimeCodexHome, "config.toml"), "utf-8");
1420
- assert.match(runtimeConfig, new RegExp(`\\[hooks\\.state\\."${join(runtimeCodexHome, "hooks.json").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:pre_tool_use:0:0"\\]`));
1421
- assert.doesNotMatch(runtimeConfig, /trusted_hash = "stale"/);
1422
- assert.doesNotMatch(runtimeConfig, new RegExp(join(projectCodexHome, "hooks.json").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")));
1557
+ // Runtime CODEX_HOME no longer holds a hooks.json mirror, so the trust
1558
+ // block must continue pointing at the canonical project hooks.json path.
1559
+ assert.equal(existsSync(join(runtimeCodexHome, "hooks.json")), false);
1560
+ assert.ok(runtimeConfig.includes(projectHookTrustHeader), `expected runtime config.toml to keep ${projectHookTrustHeader}`);
1561
+ assert.doesNotMatch(runtimeConfig, new RegExp(join(runtimeCodexHome, "hooks.json").replace(/[.*+?^${}()|[\]\\]/g, "\\$&")));
1423
1562
  }
1424
1563
  finally {
1425
1564
  await rm(wd, { recursive: true, force: true });
@@ -1797,9 +1936,19 @@ describe("detached tmux new-session sequencing", () => {
1797
1936
  assert.doesNotMatch(argsText, /CUSTOM_LLM_API_KEY/);
1798
1937
  assert.doesNotMatch(argsText, /fake-provider-key/);
1799
1938
  });
1800
- it("runCodex builds inside-tmux HUD command with OMX_SESSION_ID", async () => {
1939
+ it("runCodex coalesces stale same-leader HUD panes across session ids", async () => {
1940
+ const source = await readFile(join(repoRoot, "src", "cli", "index.ts"), "utf8");
1941
+ assert.match(source, /const staleHudPaneIds = currentPaneId\s*\? listHudWatchPaneIdsInCurrentWindow\(currentPaneId, \{ leaderPaneId: currentPaneId \}\)\s*: \[\];/);
1942
+ assert.doesNotMatch(source, /const staleHudPaneIds = listHudWatchPaneIdsInCurrentWindow\(currentPaneId, \{ sessionId, leaderPaneId: currentPaneId \}\);/);
1943
+ });
1944
+ it("runCodex skips launch-time HUD cleanup when TMUX_PANE is unavailable", async () => {
1945
+ const source = await readFile(join(repoRoot, "src", "cli", "index.ts"), "utf8");
1946
+ assert.match(source, /const staleHudPaneIds = currentPaneId\s*\? listHudWatchPaneIdsInCurrentWindow\(currentPaneId, \{ leaderPaneId: currentPaneId \}\)\s*: \[\];/);
1947
+ });
1948
+ it("runCodex builds inside-tmux HUD command with OMX_SESSION_ID and OMX_ROOT when set", async () => {
1801
1949
  const source = await readFile(join(repoRoot, 'src', 'cli', 'index.ts'), 'utf-8');
1802
- assert.match(source, /buildTmuxPaneCommand\("env",\s*\[\s*`OMX_SESSION_ID=\$\{sessionId\}`,\s*`\$\{OMX_TMUX_HUD_OWNER_ENV\}=1`,\s*"node",\s*omxBin,\s*"hud",\s*"--watch",?\s*\]\)/);
1950
+ assert.match(source, /const hudEnvArgs = \[\s*`OMX_SESSION_ID=\$\{sessionId\}`,\s*`\$\{OMX_TMUX_HUD_OWNER_ENV\}=1`,\s*\.\.\.\(currentPaneId \? \[`\$\{OMX_TMUX_HUD_LEADER_PANE_ENV\}=\$\{currentPaneId\}`\] : \[\]\),\s*\.\.\.\(omxRootOverride \? \[`OMX_ROOT=\$\{omxRootOverride\}`\] : \[\]\),\s*\]/);
1951
+ assert.match(source, /buildTmuxPaneCommand\("env",\s*\[\.\.\.hudEnvArgs,\s*"node",\s*omxBin,\s*"hud",\s*"--watch"\]\)/);
1803
1952
  });
1804
1953
  it("runCodex registers a HUD resize hook immediately for inside-tmux launches", async () => {
1805
1954
  const source = await readFile(join(repoRoot, 'src', 'cli', 'index.ts'), 'utf-8');
@@ -2626,8 +2775,8 @@ exit 0
2626
2775
  const registerHook = steps.find((step) => step.name === "register-resize-hook");
2627
2776
  const schedule = steps.find((step) => step.name === "schedule-delayed-resize");
2628
2777
  const reconcile = steps.find((step) => step.name === "reconcile-hud-resize");
2629
- assert.match(registerHook?.args[5] ?? "", />\/dev\/null 2>&1 \|\| true/);
2630
- assert.match(registerHook?.args[5] ?? "", new RegExp(`-y ${HUD_TMUX_HEIGHT_LINES}\\b`));
2778
+ assert.match(registerHook?.args[4] ?? "", />\/dev\/null 2>&1 \|\| true/);
2779
+ assert.match(registerHook?.args[4] ?? "", new RegExp(`-y ${HUD_TMUX_HEIGHT_LINES}\\b`));
2631
2780
  assert.match(schedule?.args[2] ?? "", />\/dev\/null 2>&1 \|\| true/);
2632
2781
  assert.match(schedule?.args[2] ?? "", new RegExp(`-y ${HUD_TMUX_HEIGHT_LINES}\\b`));
2633
2782
  assert.match((reconcile?.args ?? []).join(" "), />\/dev\/null 2>&1 \|\| true/);
@@ -2661,7 +2810,8 @@ exit 0
2661
2810
  assert.equal(steps[0]?.args[2], "-t");
2662
2811
  assert.equal(steps[0]?.args[3], "omx-demo:0");
2663
2812
  assert.match(steps[0]?.args[4] ?? "", /^client-attached\[\d+\]$/);
2664
- assert.match(steps[1]?.args[5] ?? "", /^window-resized\[\d+\]$/);
2813
+ assert.match(steps[1]?.args[4] ?? "", /^client-resized\[\d+\]$/);
2814
+ assert.doesNotMatch(steps[1]?.args.join(" ") ?? "", /window-resized/);
2665
2815
  assert.deepEqual(steps[2]?.args, ["kill-session", "-t", "omx-demo"]);
2666
2816
  });
2667
2817
  it("buildDetachedSessionRollbackSteps only kills session when no hook metadata exists", () => {