oh-my-codex 0.20.2 → 0.20.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 (367) hide show
  1. package/Cargo.lock +7 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +26 -0
  4. package/crates/omx-runtime/Cargo.toml +1 -0
  5. package/crates/omx-runtime/src/main.rs +25 -2
  6. package/crates/omx-runtime/tests/execution.rs +219 -0
  7. package/crates/omx-runtime-core/src/dispatch.rs +96 -10
  8. package/crates/omx-runtime-core/src/engine.rs +839 -29
  9. package/crates/omx-runtime-core/src/lib.rs +8 -0
  10. package/dist/agents/__tests__/definitions.test.js +81 -0
  11. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  12. package/dist/agents/__tests__/native-config.test.js +25 -0
  13. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  14. package/dist/agents/native-config.d.ts +2 -1
  15. package/dist/agents/native-config.d.ts.map +1 -1
  16. package/dist/agents/native-config.js.map +1 -1
  17. package/dist/auth/hotswap.d.ts +6 -0
  18. package/dist/auth/hotswap.d.ts.map +1 -1
  19. package/dist/auth/hotswap.js +85 -15
  20. package/dist/auth/hotswap.js.map +1 -1
  21. package/dist/autopilot/__tests__/ralplan-gate.test.js +1 -1
  22. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  23. package/dist/cli/__tests__/auth.test.js +60 -6
  24. package/dist/cli/__tests__/auth.test.js.map +1 -1
  25. package/dist/cli/__tests__/codex-plugin-layout.test.js +80 -0
  26. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  27. package/dist/cli/__tests__/doctor-warning-copy.test.js +103 -1
  28. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  29. package/dist/cli/__tests__/exec.test.js +136 -0
  30. package/dist/cli/__tests__/exec.test.js.map +1 -1
  31. package/dist/cli/__tests__/index.test.js +258 -4
  32. package/dist/cli/__tests__/index.test.js.map +1 -1
  33. package/dist/cli/__tests__/launch-fallback.test.js +287 -1
  34. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  35. package/dist/cli/__tests__/mcp-parity.test.js +4 -1
  36. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  37. package/dist/cli/__tests__/native-hook-claim-journal.test.js +84 -6
  38. package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -1
  39. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +3 -3
  40. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  41. package/dist/cli/__tests__/ralph.test.js +3 -3
  42. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  43. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +56 -171
  44. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -1
  45. package/dist/cli/__tests__/ralplan.test.js +37 -111
  46. package/dist/cli/__tests__/ralplan.test.js.map +1 -1
  47. package/dist/cli/__tests__/resume.test.js +11 -10
  48. package/dist/cli/__tests__/resume.test.js.map +1 -1
  49. package/dist/cli/__tests__/session-search-help.test.js +25 -1
  50. package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
  51. package/dist/cli/__tests__/setup-install-mode.test.js +42 -4
  52. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  53. package/dist/cli/__tests__/team.test.js +105 -7
  54. package/dist/cli/__tests__/team.test.js.map +1 -1
  55. package/dist/cli/__tests__/uninstall.test.js +46 -0
  56. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  57. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +2 -1
  58. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
  59. package/dist/cli/doctor.d.ts +3 -0
  60. package/dist/cli/doctor.d.ts.map +1 -1
  61. package/dist/cli/doctor.js +15 -2
  62. package/dist/cli/doctor.js.map +1 -1
  63. package/dist/cli/index.d.ts +4 -1
  64. package/dist/cli/index.d.ts.map +1 -1
  65. package/dist/cli/index.js +138 -38
  66. package/dist/cli/index.js.map +1 -1
  67. package/dist/cli/mcp-parity.js +2 -2
  68. package/dist/cli/mcp-parity.js.map +1 -1
  69. package/dist/cli/native-hook-claim-journal.d.ts +16 -5
  70. package/dist/cli/native-hook-claim-journal.d.ts.map +1 -1
  71. package/dist/cli/native-hook-claim-journal.js +42 -29
  72. package/dist/cli/native-hook-claim-journal.js.map +1 -1
  73. package/dist/cli/ralph.js +2 -2
  74. package/dist/cli/ralph.js.map +1 -1
  75. package/dist/cli/ralplan.d.ts +4 -8
  76. package/dist/cli/ralplan.d.ts.map +1 -1
  77. package/dist/cli/ralplan.js +19 -112
  78. package/dist/cli/ralplan.js.map +1 -1
  79. package/dist/cli/session-search.d.ts +5 -0
  80. package/dist/cli/session-search.d.ts.map +1 -1
  81. package/dist/cli/session-search.js +87 -0
  82. package/dist/cli/session-search.js.map +1 -1
  83. package/dist/cli/setup.d.ts +5 -0
  84. package/dist/cli/setup.d.ts.map +1 -1
  85. package/dist/cli/setup.js +80 -31
  86. package/dist/cli/setup.js.map +1 -1
  87. package/dist/cli/uninstall.d.ts +9 -0
  88. package/dist/cli/uninstall.d.ts.map +1 -1
  89. package/dist/cli/uninstall.js +61 -19
  90. package/dist/cli/uninstall.js.map +1 -1
  91. package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
  92. package/dist/config/__tests__/generator-idempotent.test.js +330 -1
  93. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  94. package/dist/config/__tests__/generator-notify.test.js +2 -2
  95. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  96. package/dist/config/__tests__/models.test.js +67 -3
  97. package/dist/config/__tests__/models.test.js.map +1 -1
  98. package/dist/config/generator.d.ts +4 -20
  99. package/dist/config/generator.d.ts.map +1 -1
  100. package/dist/config/generator.js +499 -119
  101. package/dist/config/generator.js.map +1 -1
  102. package/dist/config/models.d.ts +12 -2
  103. package/dist/config/models.d.ts.map +1 -1
  104. package/dist/config/models.js +15 -1
  105. package/dist/config/models.js.map +1 -1
  106. package/dist/hooks/__tests__/agents-overlay.test.js +2 -2
  107. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  108. package/dist/hooks/__tests__/keyword-detector.test.js +4 -4
  109. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  110. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +238 -543
  111. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  112. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +38 -4
  113. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  114. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +96 -9
  115. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  116. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +531 -12
  117. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  118. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +155 -23
  119. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  120. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +482 -32
  121. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  122. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +68 -1
  123. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  124. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +7 -1
  125. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  126. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +43 -4
  127. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  128. package/dist/hooks/__tests__/session.test.js +348 -2
  129. package/dist/hooks/__tests__/session.test.js.map +1 -1
  130. package/dist/hooks/agents-overlay.js +1 -1
  131. package/dist/hooks/session.d.ts +26 -2
  132. package/dist/hooks/session.d.ts.map +1 -1
  133. package/dist/hooks/session.js +169 -13
  134. package/dist/hooks/session.js.map +1 -1
  135. package/dist/leader/__tests__/contract.test.js +57 -7
  136. package/dist/leader/__tests__/contract.test.js.map +1 -1
  137. package/dist/leader/contract.d.ts +16 -0
  138. package/dist/leader/contract.d.ts.map +1 -1
  139. package/dist/leader/contract.js +79 -4
  140. package/dist/leader/contract.js.map +1 -1
  141. package/dist/mcp/__tests__/code-intel-server.test.js +31 -3
  142. package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
  143. package/dist/mcp/__tests__/wiki-server.test.js +18 -0
  144. package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
  145. package/dist/mcp/code-intel-server.d.ts.map +1 -1
  146. package/dist/mcp/code-intel-server.js +13 -3
  147. package/dist/mcp/code-intel-server.js.map +1 -1
  148. package/dist/mcp/wiki-server.d.ts +11 -0
  149. package/dist/mcp/wiki-server.d.ts.map +1 -1
  150. package/dist/mcp/wiki-server.js +9 -2
  151. package/dist/mcp/wiki-server.js.map +1 -1
  152. package/dist/modes/__tests__/base-tmux-pane.test.js +4 -4
  153. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  154. package/dist/notifications/temp-contract.d.ts.map +1 -1
  155. package/dist/notifications/temp-contract.js +4 -0
  156. package/dist/notifications/temp-contract.js.map +1 -1
  157. package/dist/pipeline/__tests__/orchestrator.test.js +4 -4
  158. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  159. package/dist/pipeline/__tests__/stages.test.js +8 -8
  160. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  161. package/dist/ralplan/__tests__/consensus-gate.test.js +134 -10
  162. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  163. package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts +2 -0
  164. package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts.map +1 -0
  165. package/dist/ralplan/__tests__/documented-leader-preflight.test.js +46 -0
  166. package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
  167. package/dist/ralplan/__tests__/runtime.test.js +8 -4
  168. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  169. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  170. package/dist/ralplan/consensus-gate.js +58 -50
  171. package/dist/ralplan/consensus-gate.js.map +1 -1
  172. package/dist/ralplan/documented-leader-preflight.d.ts +34 -0
  173. package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
  174. package/dist/ralplan/documented-leader-preflight.js +58 -0
  175. package/dist/ralplan/documented-leader-preflight.js.map +1 -0
  176. package/dist/ralplan/runtime.d.ts +1 -0
  177. package/dist/ralplan/runtime.d.ts.map +1 -1
  178. package/dist/ralplan/runtime.js +11 -7
  179. package/dist/ralplan/runtime.js.map +1 -1
  180. package/dist/runtime/__tests__/bridge.test.js +42 -1
  181. package/dist/runtime/__tests__/bridge.test.js.map +1 -1
  182. package/dist/runtime/bridge.d.ts +12 -0
  183. package/dist/runtime/bridge.d.ts.map +1 -1
  184. package/dist/runtime/bridge.js +52 -1
  185. package/dist/runtime/bridge.js.map +1 -1
  186. package/dist/scripts/__tests__/codex-native-hook.test.js +2620 -487
  187. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  188. package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts +2 -0
  189. package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts.map +1 -0
  190. package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +108 -0
  191. package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -0
  192. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +46 -173
  193. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -1
  194. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +39 -159
  195. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -1
  196. package/dist/scripts/__tests__/smoke-packed-install.test.js +254 -2
  197. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
  198. package/dist/scripts/codex-native-hook.d.ts +4 -1
  199. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  200. package/dist/scripts/codex-native-hook.js +11013 -1153
  201. package/dist/scripts/codex-native-hook.js.map +1 -1
  202. package/dist/scripts/notify-fallback-watcher.js +82 -108
  203. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  204. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  205. package/dist/scripts/notify-hook/auto-nudge.js +74 -3
  206. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  207. package/dist/scripts/notify-hook/team-dispatch.d.ts +9 -0
  208. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  209. package/dist/scripts/notify-hook/team-dispatch.js +234 -79
  210. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  211. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  212. package/dist/scripts/notify-hook/team-leader-nudge.js +39 -13
  213. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  214. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +12 -4
  215. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  216. package/dist/scripts/notify-hook/team-tmux-guard.js +365 -44
  217. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  218. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
  219. package/dist/scripts/notify-hook/team-worker-stop.js +19 -18
  220. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
  221. package/dist/scripts/notify-hook/team-worker.d.ts +3 -0
  222. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
  223. package/dist/scripts/notify-hook/team-worker.js +37 -28
  224. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  225. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  226. package/dist/scripts/notify-hook/tmux-injection.js +28 -2
  227. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  228. package/dist/scripts/notify-hook.js +1 -0
  229. package/dist/scripts/notify-hook.js.map +1 -1
  230. package/dist/scripts/smoke-packed-install.d.ts +48 -3
  231. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  232. package/dist/scripts/smoke-packed-install.js +2796 -13
  233. package/dist/scripts/smoke-packed-install.js.map +1 -1
  234. package/dist/state/__tests__/mode-state-context.test.js +54 -0
  235. package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
  236. package/dist/state/__tests__/operations.test.js +2 -0
  237. package/dist/state/__tests__/operations.test.js.map +1 -1
  238. package/dist/state/mode-state-context.d.ts +5 -0
  239. package/dist/state/mode-state-context.d.ts.map +1 -1
  240. package/dist/state/mode-state-context.js +59 -0
  241. package/dist/state/mode-state-context.js.map +1 -1
  242. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +24 -245
  243. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -1
  244. package/dist/subagents/tracker.d.ts +1 -82
  245. package/dist/subagents/tracker.d.ts.map +1 -1
  246. package/dist/subagents/tracker.js +3 -275
  247. package/dist/subagents/tracker.js.map +1 -1
  248. package/dist/team/__tests__/api-interop.test.js +91 -1
  249. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  250. package/dist/team/__tests__/delivery-e2e-smoke.test.js +52 -10
  251. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
  252. package/dist/team/__tests__/idle-nudge.test.js +45 -15
  253. package/dist/team/__tests__/idle-nudge.test.js.map +1 -1
  254. package/dist/team/__tests__/mcp-comm.test.js +93 -27
  255. package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
  256. package/dist/team/__tests__/model-contract.test.js +110 -3
  257. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  258. package/dist/team/__tests__/runtime-cli.test.js +9 -0
  259. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  260. package/dist/team/__tests__/runtime.test.js +3204 -335
  261. package/dist/team/__tests__/runtime.test.js.map +1 -1
  262. package/dist/team/__tests__/scaling.test.js +2359 -142
  263. package/dist/team/__tests__/scaling.test.js.map +1 -1
  264. package/dist/team/__tests__/state.test.js +804 -36
  265. package/dist/team/__tests__/state.test.js.map +1 -1
  266. package/dist/team/__tests__/team-ops-contract.test.js +6 -0
  267. package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
  268. package/dist/team/__tests__/tmux-session.test.js +3049 -784
  269. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  270. package/dist/team/__tests__/worker-runtime-identity.test.js +38 -2
  271. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  272. package/dist/team/__tests__/worktree.test.js +6 -0
  273. package/dist/team/__tests__/worktree.test.js.map +1 -1
  274. package/dist/team/api-interop.d.ts.map +1 -1
  275. package/dist/team/api-interop.js +15 -9
  276. package/dist/team/api-interop.js.map +1 -1
  277. package/dist/team/exact-pane.d.ts +23 -0
  278. package/dist/team/exact-pane.d.ts.map +1 -0
  279. package/dist/team/exact-pane.js +133 -0
  280. package/dist/team/exact-pane.js.map +1 -0
  281. package/dist/team/idle-nudge.d.ts +12 -1
  282. package/dist/team/idle-nudge.d.ts.map +1 -1
  283. package/dist/team/idle-nudge.js +41 -14
  284. package/dist/team/idle-nudge.js.map +1 -1
  285. package/dist/team/model-contract.d.ts +2 -5
  286. package/dist/team/model-contract.d.ts.map +1 -1
  287. package/dist/team/model-contract.js +59 -17
  288. package/dist/team/model-contract.js.map +1 -1
  289. package/dist/team/runtime.d.ts +1 -0
  290. package/dist/team/runtime.d.ts.map +1 -1
  291. package/dist/team/runtime.js +1244 -180
  292. package/dist/team/runtime.js.map +1 -1
  293. package/dist/team/scaling.d.ts +13 -1
  294. package/dist/team/scaling.d.ts.map +1 -1
  295. package/dist/team/scaling.js +1430 -384
  296. package/dist/team/scaling.js.map +1 -1
  297. package/dist/team/state/dispatch.d.ts.map +1 -1
  298. package/dist/team/state/dispatch.js +26 -8
  299. package/dist/team/state/dispatch.js.map +1 -1
  300. package/dist/team/state/locks.d.ts.map +1 -1
  301. package/dist/team/state/locks.js +61 -13
  302. package/dist/team/state/locks.js.map +1 -1
  303. package/dist/team/state/tasks.d.ts.map +1 -1
  304. package/dist/team/state/tasks.js +4 -3
  305. package/dist/team/state/tasks.js.map +1 -1
  306. package/dist/team/state.d.ts +67 -1
  307. package/dist/team/state.d.ts.map +1 -1
  308. package/dist/team/state.js +636 -129
  309. package/dist/team/state.js.map +1 -1
  310. package/dist/team/team-ops.d.ts +5 -0
  311. package/dist/team/team-ops.d.ts.map +1 -1
  312. package/dist/team/team-ops.js +4 -0
  313. package/dist/team/team-ops.js.map +1 -1
  314. package/dist/team/tmux-session.d.ts +123 -23
  315. package/dist/team/tmux-session.d.ts.map +1 -1
  316. package/dist/team/tmux-session.js +1250 -291
  317. package/dist/team/tmux-session.js.map +1 -1
  318. package/dist/team/worktree.d.ts.map +1 -1
  319. package/dist/team/worktree.js +4 -0
  320. package/dist/team/worktree.js.map +1 -1
  321. package/dist/utils/__tests__/file-durability.test.d.ts +2 -0
  322. package/dist/utils/__tests__/file-durability.test.d.ts.map +1 -0
  323. package/dist/utils/__tests__/file-durability.test.js +57 -0
  324. package/dist/utils/__tests__/file-durability.test.js.map +1 -0
  325. package/dist/utils/file-durability.d.ts +15 -0
  326. package/dist/utils/file-durability.d.ts.map +1 -0
  327. package/dist/utils/file-durability.js +37 -0
  328. package/dist/utils/file-durability.js.map +1 -0
  329. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +3 -0
  330. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
  331. package/dist/wiki/lint.d.ts +4 -1
  332. package/dist/wiki/lint.d.ts.map +1 -1
  333. package/dist/wiki/lint.js +3 -2
  334. package/dist/wiki/lint.js.map +1 -1
  335. package/package.json +1 -1
  336. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  337. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +24 -0
  338. package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -4
  339. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +3 -2
  340. package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
  341. package/skills/ralph/SKILL.md +6 -4
  342. package/skills/ralplan/SKILL.md +3 -2
  343. package/skills/team/SKILL.md +13 -9
  344. package/src/scripts/__tests__/codex-native-hook.test.ts +2826 -497
  345. package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
  346. package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +48 -185
  347. package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +44 -177
  348. package/src/scripts/__tests__/smoke-packed-install.test.ts +320 -2
  349. package/src/scripts/codex-native-hook.ts +10715 -1069
  350. package/src/scripts/notify-fallback-watcher.ts +84 -115
  351. package/src/scripts/notify-hook/auto-nudge.ts +71 -3
  352. package/src/scripts/notify-hook/team-dispatch.ts +242 -75
  353. package/src/scripts/notify-hook/team-leader-nudge.ts +40 -18
  354. package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
  355. package/src/scripts/notify-hook/team-worker-stop.ts +20 -16
  356. package/src/scripts/notify-hook/team-worker.ts +39 -26
  357. package/src/scripts/notify-hook/tmux-injection.ts +28 -2
  358. package/src/scripts/notify-hook.ts +1 -0
  359. package/src/scripts/smoke-packed-install.ts +3196 -14
  360. package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +0 -2
  361. package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +0 -1
  362. package/dist/subagents/__tests__/adapted-role-binding.test.js +0 -988
  363. package/dist/subagents/__tests__/adapted-role-binding.test.js.map +0 -1
  364. package/dist/subagents/adapted-role-binding.d.ts +0 -17
  365. package/dist/subagents/adapted-role-binding.d.ts.map +0 -1
  366. package/dist/subagents/adapted-role-binding.js +0 -75
  367. package/dist/subagents/adapted-role-binding.js.map +0 -1
@@ -18,7 +18,15 @@ async function withTempWorkingDir(run) {
18
18
  }
19
19
  }
20
20
  async function writeJson(path, value) {
21
- await writeFile(path, JSON.stringify(value, null, 2));
21
+ let persisted = value;
22
+ if (path.endsWith('/config.json') && value && typeof value === 'object' && !Array.isArray(value)) {
23
+ const config = value;
24
+ if (!Object.prototype.hasOwnProperty.call(config, 'tmux_pane_owner_id')
25
+ && typeof config.name === 'string' && config.name.trim()) {
26
+ persisted = { ...config, tmux_pane_owner_id: `team:${config.name.trim()}` };
27
+ }
28
+ }
29
+ await writeFile(path, JSON.stringify(persisted, null, 2));
22
30
  }
23
31
  async function writeCanonicalTeamFixture(cwd, { teamName, sessionId, ownerSessionId, coarseState = 'missing', }) {
24
32
  const stateDir = join(cwd, '.omx', 'state');
@@ -69,6 +77,8 @@ async function writeCanonicalTeamFixture(cwd, { teamName, sessionId, ownerSessio
69
77
  },
70
78
  tmux_session: `${teamName}:0`,
71
79
  leader_pane_id: '%97',
80
+ leader_pane_pid: 12097,
81
+ tmux_pane_owner_id: `team:${teamName}`,
72
82
  hud_pane_id: null,
73
83
  resize_hook_name: null,
74
84
  resize_hook_target: null,
@@ -196,9 +206,21 @@ fi
196
206
  if [[ "$cmd" == "send-keys" ]]; then
197
207
  exit 0
198
208
  fi
209
+ if [[ "$cmd" == "show-option" ]]; then
210
+ target=""
211
+ while [[ "$#" -gt 0 ]]; do
212
+ case "$1" in
213
+ -t) target="$2"; shift 2 ;;
214
+ *) shift ;;
215
+ esac
216
+ done
217
+ node -e 'const fs=require("fs"),path=require("path"),root=process.argv[1],target=process.argv[2],teamRoot=path.join(root,".omx","state","team");for(const team of fs.readdirSync(teamRoot,{withFileTypes:true}).filter(entry=>entry.isDirectory()).map(entry=>entry.name)){const dir=path.join(teamRoot,team),manifest=path.join(dir,"manifest.v2.json"),config=path.join(dir,"config.json"),source=fs.existsSync(manifest)?manifest:config;if(!fs.existsSync(source))continue;try{const raw=JSON.parse(fs.readFileSync(source,"utf8"));if(raw.leader_pane_id===target){process.stdout.write(String(raw.tmux_pane_owner_id||"team:"+team));break;}}catch{}}' "$(dirname "$(dirname "$0")")" "$target"
218
+ exit 0
219
+ fi
199
220
  if [[ "$cmd" == "list-panes" ]]; then
200
- echo "%1 12345"
201
- echo "%2 12346"
221
+ for pane in $(seq 1 200); do
222
+ printf '%%%s\t0\t%s\n' "$pane" "$((12000 + pane))"
223
+ done
202
224
  exit 0
203
225
  fi
204
226
  exit 0
@@ -244,6 +266,17 @@ fi
244
266
  if [[ "$cmd" == "send-keys" ]]; then
245
267
  exit 0
246
268
  fi
269
+ if [[ "$cmd" == "show-option" ]]; then
270
+ target=""
271
+ while [[ "$#" -gt 0 ]]; do
272
+ case "$1" in
273
+ -t) target="$2"; shift 2 ;;
274
+ *) shift ;;
275
+ esac
276
+ done
277
+ node -e 'const fs=require("fs"),path=require("path"),root=process.argv[1],target=process.argv[2],teamRoot=path.join(root,".omx","state","team");for(const team of fs.readdirSync(teamRoot,{withFileTypes:true}).filter(entry=>entry.isDirectory()).map(entry=>entry.name)){const dir=path.join(teamRoot,team),manifest=path.join(dir,"manifest.v2.json"),config=path.join(dir,"config.json"),source=fs.existsSync(manifest)?manifest:config;if(!fs.existsSync(source))continue;try{const raw=JSON.parse(fs.readFileSync(source,"utf8"));if(raw.leader_pane_id===target){process.stdout.write(String(raw.tmux_pane_owner_id||"team:"+team));break;}}catch{}}' "$(dirname "$(dirname "$0")")" "$target"
278
+ exit 0
279
+ fi
247
280
  if [[ "$cmd" == "list-panes" ]]; then
248
281
  printf "%b\\n" "${escapedLines}"
249
282
  exit 0
@@ -251,6 +284,12 @@ fi
251
284
  exit 0
252
285
  `;
253
286
  }
287
+ function fakeTmuxOwnerOptionHandler(ownerId) {
288
+ return `if [[ "$cmd" == "show-option" ]]; then
289
+ echo "${ownerId}"
290
+ exit 0
291
+ fi`;
292
+ }
254
293
  function runNotifyHook(cwd, fakeBinDir, extraEnv = {}) {
255
294
  const sessionPath = join(cwd, '.omx', 'state', 'session.json');
256
295
  if (!existsSync(sessionPath)) {
@@ -308,6 +347,8 @@ describe('notify-hook leader-side authority handoff', () => {
308
347
  name: teamName,
309
348
  tmux_session: 'handoff-sess:0',
310
349
  leader_pane_id: '%91',
350
+ leader_pane_pid: 12091,
351
+ tmux_pane_owner_id: 'team:handoff-alpha',
311
352
  });
312
353
  await writeJson(join(stateDir, 'hud-state.json'), {
313
354
  last_turn_at: new Date(Date.now() - 300_000).toISOString(),
@@ -325,16 +366,51 @@ describe('notify-hook leader-side authority handoff', () => {
325
366
  },
326
367
  ],
327
368
  });
328
- await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath));
369
+ await writeFile(fakeTmuxPath, buildFakeTmux(tmuxLogPath).replace('if [[ "$cmd" == "show-option" ]]; then', 'if [[ "$cmd" == "show-option" ]]; then\n echo "team:foreign"\n exit 0\nfi\nif [[ "$cmd" == "show-option" ]]; then'));
329
370
  await chmod(fakeTmuxPath, 0o755);
330
371
  const result = runNotifyHook(cwd, fakeBinDir, {
331
372
  OMX_SESSION_ID: 'sess-canonical-missing',
332
373
  });
333
374
  assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
334
375
  const tmuxLog = await readFile(tmuxLogPath, 'utf-8').catch(() => '');
335
- assert.match(tmuxLog, /send-keys/, 'current implementation nudges the leader directly in this stale-leader path');
376
+ assert.doesNotMatch(tmuxLog, /send-keys/, 'a same-ID/PID foreign owner must not receive leader input');
336
377
  });
337
378
  });
379
+ it('defers leader nudges without tmux reads when the persisted owner token is missing or malformed', async () => {
380
+ for (const owner of [undefined, 17]) {
381
+ await withTempWorkingDir(async (cwd) => {
382
+ const stateDir = join(cwd, '.omx', 'state');
383
+ const logsDir = join(cwd, '.omx', 'logs');
384
+ const teamName = 'owner-required';
385
+ const teamDir = join(stateDir, 'team', teamName);
386
+ const fakeBinDir = join(cwd, 'fake-bin');
387
+ const tmuxLogPath = join(cwd, 'tmux.log');
388
+ await mkdir(logsDir, { recursive: true });
389
+ await mkdir(fakeBinDir, { recursive: true });
390
+ await mkdir(teamDir, { recursive: true });
391
+ await writeJson(join(stateDir, 'team-state.json'), {
392
+ active: true,
393
+ team_name: teamName,
394
+ current_phase: 'team-exec',
395
+ });
396
+ const config = {
397
+ name: teamName,
398
+ tmux_session: `${teamName}:0`,
399
+ leader_pane_id: '%91',
400
+ leader_pane_pid: 12091,
401
+ };
402
+ config.tmux_pane_owner_id = owner === undefined ? null : owner;
403
+ await writeJson(join(teamDir, 'config.json'), config);
404
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
405
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
406
+ const result = runNotifyHook(cwd, fakeBinDir, { OMX_SESSION_ID: 'sess-canonical-missing' });
407
+ assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
408
+ assert.equal(existsSync(tmuxLogPath), false, 'missing or malformed persisted owner must not capture or send tmux input');
409
+ const delivery = await readTeamDeliveryLog(cwd);
410
+ assert.ok(delivery.some((entry) => entry.reason === 'leader_pane_owner_missing_no_injection'), 'owner absence must be durably deferred');
411
+ });
412
+ }
413
+ });
338
414
  it('does not drain pending dispatch requests from notify-hook leader context', async () => {
339
415
  await withTempWorkingDir(async (cwd) => {
340
416
  const fakeBinDir = join(cwd, 'fake-bin');
@@ -382,6 +458,7 @@ describe('notify-hook leader-side authority handoff', () => {
382
458
  name: teamName,
383
459
  tmux_session: 'omx-team-beta-active-status',
384
460
  leader_pane_id: '%92',
461
+ leader_pane_pid: 12092,
385
462
  workers: [
386
463
  { name: 'worker-1', index: 1, pane_id: '%10' },
387
464
  ],
@@ -448,6 +525,7 @@ describe('notify-hook team leader nudge', () => {
448
525
  name: teamName,
449
526
  tmux_session: 'deep-interview-suppressed:0',
450
527
  leader_pane_id: '%97',
528
+ leader_pane_pid: 12097,
451
529
  });
452
530
  await writeJson(join(stateDir, 'hud-state.json'), {
453
531
  last_turn_at: new Date(Date.now() - 300_000).toISOString(),
@@ -490,6 +568,7 @@ describe('notify-hook team leader nudge', () => {
490
568
  name: teamName,
491
569
  tmux_session: 'idle-sess:0',
492
570
  leader_pane_id: '%99',
571
+ leader_pane_pid: 12099,
493
572
  workers: [
494
573
  { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: [] },
495
574
  { name: 'worker-2', index: 2, role: 'executor', assigned_tasks: [] },
@@ -560,6 +639,7 @@ describe('notify-hook team leader nudge', () => {
560
639
  name: teamName,
561
640
  tmux_session: 'idle-shutdown:0',
562
641
  leader_pane_id: '%96',
642
+ leader_pane_pid: 12096,
563
643
  workers: [
564
644
  { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
565
645
  { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
@@ -584,7 +664,7 @@ describe('notify-hook team leader nudge', () => {
584
664
  updated_at: nowIso,
585
665
  });
586
666
  }
587
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
667
+ await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%96\t0\t12096', '%10\t0\t12010', '%11\t0\t12011']));
588
668
  await chmod(fakeTmuxPath, 0o755);
589
669
  const result = runNotifyHook(cwd, fakeBinDir, {
590
670
  OMX_SESSION_ID: 'sess-canonical-missing',
@@ -623,6 +703,7 @@ describe('notify-hook team leader nudge', () => {
623
703
  name: teamName,
624
704
  tmux_session: 'idle-followup-reuse:0',
625
705
  leader_pane_id: '%97',
706
+ leader_pane_pid: 12097,
626
707
  workers: [
627
708
  { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
628
709
  { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
@@ -646,7 +727,7 @@ describe('notify-hook team leader nudge', () => {
646
727
  updated_at: nowIso,
647
728
  });
648
729
  }
649
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%10 12345', '%11 12346']));
730
+ await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%97\t0\t12097', '%10\t0\t12010', '%11\t0\t12011']));
650
731
  await chmod(fakeTmuxPath, 0o755);
651
732
  const result = runNotifyHook(cwd, fakeBinDir, {
652
733
  OMX_SESSION_ID: 'sess-canonical-inactive',
@@ -685,6 +766,7 @@ describe('notify-hook team leader nudge', () => {
685
766
  name: teamName,
686
767
  tmux_session: 'idle-followup-relaunch:0',
687
768
  leader_pane_id: '%98',
769
+ leader_pane_pid: 12098,
688
770
  workers: [
689
771
  { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
690
772
  { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
@@ -708,7 +790,7 @@ describe('notify-hook team leader nudge', () => {
708
790
  updated_at: nowIso,
709
791
  });
710
792
  }
711
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%98 12349']));
793
+ await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%98\t0\t12098']));
712
794
  await chmod(fakeTmuxPath, 0o755);
713
795
  const result = runNotifyHook(cwd, fakeBinDir);
714
796
  assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
@@ -746,6 +828,7 @@ describe('notify-hook team leader nudge', () => {
746
828
  name: teamName,
747
829
  tmux_session: 'idle-global:0',
748
830
  leader_pane_id: '%97',
831
+ leader_pane_pid: 12097,
749
832
  workers: [
750
833
  { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: [] },
751
834
  { name: 'worker-2', index: 2, role: 'executor', assigned_tasks: [] },
@@ -869,6 +952,7 @@ describe('notify-hook team leader nudge', () => {
869
952
  leader: { session_id: 'sess-canonical-safe', worker_id: 'leader-fixed', role: 'coordinator' },
870
953
  tmux_session: 'bad:0',
871
954
  leader_pane_id: '%666',
955
+ leader_pane_pid: 12666,
872
956
  hud_pane_id: null,
873
957
  resize_hook_name: null,
874
958
  resize_hook_target: null,
@@ -936,6 +1020,7 @@ describe('notify-hook team leader nudge', () => {
936
1020
  name: teamName,
937
1021
  tmux_session: 'devsess:0',
938
1022
  leader_pane_id: '%91',
1023
+ leader_pane_pid: 12091,
939
1024
  });
940
1025
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
941
1026
  worker: 'leader-fixed',
@@ -991,6 +1076,7 @@ describe('notify-hook team leader nudge', () => {
991
1076
  name: teamName,
992
1077
  tmux_session: 'leader-nudge-teardown-race:0',
993
1078
  leader_pane_id: '%91',
1079
+ leader_pane_pid: 12091,
994
1080
  workers: [{ name: 'worker-1', index: 1, pane_id: '%11' }],
995
1081
  });
996
1082
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
@@ -1032,7 +1118,11 @@ if [[ "$cmd" == "display-message" ]]; then
1032
1118
  exit 0
1033
1119
  fi
1034
1120
  if [[ "$cmd" == "list-panes" ]]; then
1035
- echo "%11 12345"
1121
+ printf '%%91\t0\t12091\n'
1122
+ exit 0
1123
+ fi
1124
+ if [[ "$cmd" == "show-option" ]]; then
1125
+ echo "team:leader-nudge-teardown-race"
1036
1126
  exit 0
1037
1127
  fi
1038
1128
  if [[ "$cmd" == "capture-pane" ]]; then
@@ -1117,6 +1207,7 @@ exit 0
1117
1207
  name: teamName,
1118
1208
  tmux_session: 'leader-nudge-late-persist-race:0',
1119
1209
  leader_pane_id: '%91',
1210
+ leader_pane_pid: 12091,
1120
1211
  workers: [{ name: 'worker-1', index: 1, pane_id: '%11' }],
1121
1212
  });
1122
1213
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
@@ -1131,7 +1222,7 @@ exit 0
1131
1222
  },
1132
1223
  ],
1133
1224
  });
1134
- await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%11 12345']));
1225
+ await writeFile(fakeTmuxPath, buildFakeTmuxWithListPanes(tmuxLogPath, ['%91\t0\t12091', '%11\t0\t12345']));
1135
1226
  await chmod(fakeTmuxPath, 0o755);
1136
1227
  try {
1137
1228
  setLeaderNudgeTestHooksForTests({
@@ -1296,6 +1387,8 @@ exit 0
1296
1387
  name: teamName,
1297
1388
  tmux_session: 'busy-live-pane:0',
1298
1389
  leader_pane_id: '%93',
1390
+ leader_pane_pid: 12093,
1391
+ tmux_pane_owner_id: `team:${teamName}`,
1299
1392
  });
1300
1393
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1301
1394
  worker: 'leader-fixed',
@@ -1314,6 +1407,7 @@ set -eu
1314
1407
  echo "$@" >> "${tmuxLogPath}"
1315
1408
  cmd="$1"
1316
1409
  shift || true
1410
+ ${fakeTmuxOwnerOptionHandler(`team:${teamName}`)}
1317
1411
  if [[ "$cmd" == "display-message" ]]; then
1318
1412
  target=""
1319
1413
  format=""
@@ -1371,7 +1465,7 @@ if [[ "$cmd" == "send-keys" ]]; then
1371
1465
  exit 0
1372
1466
  fi
1373
1467
  if [[ "$cmd" == "list-panes" ]]; then
1374
- echo "%1 12345"
1468
+ printf '%%93\t0\t12093\n'
1375
1469
  exit 0
1376
1470
  fi
1377
1471
  exit 0
@@ -1420,6 +1514,7 @@ exit 0
1420
1514
  name: teamName,
1421
1515
  tmux_session: 'ack-sess:0',
1422
1516
  leader_pane_id: '%94',
1517
+ leader_pane_pid: 12094,
1423
1518
  workers: [
1424
1519
  { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: ['1'] },
1425
1520
  ],
@@ -1480,6 +1575,7 @@ exit 0
1480
1575
  name: teamName,
1481
1576
  tmux_session: 'ack-started:0',
1482
1577
  leader_pane_id: '%95',
1578
+ leader_pane_pid: 12095,
1483
1579
  workers: [
1484
1580
  { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: ['1'] },
1485
1581
  ],
@@ -1550,6 +1646,7 @@ exit 0
1550
1646
  name: teamName,
1551
1647
  tmux_session: 'fresh-mailbox-bounded:0',
1552
1648
  leader_pane_id: '%97',
1649
+ leader_pane_pid: 12097,
1553
1650
  workers: [
1554
1651
  { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: ['1'] },
1555
1652
  ],
@@ -1604,6 +1701,7 @@ exit 0
1604
1701
  name: teamName,
1605
1702
  tmux_session: 'shell-guard:0',
1606
1703
  leader_pane_id: '%71',
1704
+ leader_pane_pid: 12071,
1607
1705
  });
1608
1706
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1609
1707
  worker: 'leader-fixed',
@@ -1622,6 +1720,7 @@ set -eu
1622
1720
  echo "$@" >> "${tmuxLogPath}"
1623
1721
  cmd="$1"
1624
1722
  shift || true
1723
+ ${fakeTmuxOwnerOptionHandler(`team:${teamName}`)}
1625
1724
  if [[ "$cmd" == "display-message" ]]; then
1626
1725
  target=""
1627
1726
  format=""
@@ -1666,7 +1765,7 @@ if [[ "$cmd" == "send-keys" ]]; then
1666
1765
  exit 0
1667
1766
  fi
1668
1767
  if [[ "$cmd" == "list-panes" ]]; then
1669
- echo "%1 12345"
1768
+ printf '%%71\t0\t12071\n'
1670
1769
  exit 0
1671
1770
  fi
1672
1771
  exit 0
@@ -1708,6 +1807,7 @@ exit 0
1708
1807
  name: teamName,
1709
1808
  tmux_session: 'busy-leader-queue:0',
1710
1809
  leader_pane_id: '%73',
1810
+ leader_pane_pid: 12073,
1711
1811
  });
1712
1812
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1713
1813
  worker: 'leader-fixed',
@@ -1726,6 +1826,7 @@ set -eu
1726
1826
  echo "$@" >> "${tmuxLogPath}"
1727
1827
  cmd="$1"
1728
1828
  shift || true
1829
+ ${fakeTmuxOwnerOptionHandler(`team:${teamName}`)}
1729
1830
  if [[ "$cmd" == "display-message" ]]; then
1730
1831
  target=""
1731
1832
  format=""
@@ -1779,7 +1880,7 @@ if [[ "$cmd" == "send-keys" ]]; then
1779
1880
  exit 0
1780
1881
  fi
1781
1882
  if [[ "$cmd" == "list-panes" ]]; then
1782
- echo "%1 12345"
1883
+ printf '%%73\t0\t12073\n'
1783
1884
  exit 0
1784
1885
  fi
1785
1886
  exit 0
@@ -1802,7 +1903,7 @@ exit 0
1802
1903
  }
1803
1904
  });
1804
1905
  });
1805
- it('injects leader nudge when capture-pane fails but the leader pane is a live codex pane', async () => {
1906
+ it('defers leader nudge when capture-pane cannot verify readiness despite authoritative live-pane proof', async () => {
1806
1907
  await withTempWorkingDir(async (cwd) => {
1807
1908
  const omxDir = join(cwd, '.omx');
1808
1909
  const stateDir = join(omxDir, 'state');
@@ -1825,6 +1926,7 @@ exit 0
1825
1926
  name: teamName,
1826
1927
  tmux_session: 'capture-failure-live-leader:0',
1827
1928
  leader_pane_id: '%74',
1929
+ leader_pane_pid: 12074,
1828
1930
  });
1829
1931
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1830
1932
  worker: 'leader-fixed',
@@ -1843,6 +1945,7 @@ set -eu
1843
1945
  echo "$@" >> "${tmuxLogPath}"
1844
1946
  cmd="$1"
1845
1947
  shift || true
1948
+ ${fakeTmuxOwnerOptionHandler(`team:${teamName}`)}
1846
1949
  if [[ "$cmd" == "display-message" ]]; then
1847
1950
  target=""
1848
1951
  format=""
@@ -1896,7 +1999,7 @@ if [[ "$cmd" == "send-keys" ]]; then
1896
1999
  exit 0
1897
2000
  fi
1898
2001
  if [[ "$cmd" == "list-panes" ]]; then
1899
- echo "%1 12345"
2002
+ printf '%%74\t0\t12074\n'
1900
2003
  exit 0
1901
2004
  fi
1902
2005
  exit 0
@@ -1906,14 +2009,23 @@ exit 0
1906
2009
  const result = runNotifyHook(cwd, fakeBinDir);
1907
2010
  assert.equal(result.status, 0, `notify-hook failed: ${result.stderr || result.stdout}`);
1908
2011
  const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
2012
+ assert.match(tmuxLog, /list-panes -a -F #\{pane_id\}\t#\{pane_dead\}\t#\{pane_pid\}/, 'should retain authoritative exact-pane live proof');
2013
+ assert.match(tmuxLog, /display-message -p -t %74 #\{pane_current_command\}/, 'should query the exact pane command before capture readiness');
1909
2014
  assert.match(tmuxLog, /capture-pane -t %74 -p -S -80/);
1910
- assert.match(tmuxLog, /send-keys -t %74/, 'capture failures should not suppress leader injection into a live codex pane');
2015
+ assert.doesNotMatch(tmuxLog, /(?:set-buffer|paste-buffer|send-keys)/, 'capture readiness failure must suppress all input-effect tmux commands');
1911
2016
  const eventsPath = join(teamDir, 'events', 'events.ndjson');
1912
- if (existsSync(eventsPath)) {
1913
- const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
1914
- const deferred = events.find((entry) => entry.type === 'leader_notification_deferred');
1915
- assert.equal(deferred, undefined, 'capture failure alone should not defer a live codex leader pane');
1916
- }
2017
+ const events = (await readFile(eventsPath, 'utf-8')).trim().split('\n').filter(Boolean).map((line) => JSON.parse(line));
2018
+ const deferred = events.find((entry) => entry.type === 'leader_notification_deferred' && entry.reason === 'pane_readiness_unverified');
2019
+ assert.ok(deferred, 'capture readiness failure should emit a fail-closed deferred event');
2020
+ assert.equal(deferred.pane_current_command, 'codex');
2021
+ assert.equal(deferred.tmux_injection_attempted, false);
2022
+ const deliveryLog = await readTeamDeliveryLog(cwd);
2023
+ assert.ok(deliveryLog.some((entry) => entry.event === 'nudge_triggered'
2024
+ && entry.team === teamName
2025
+ && entry.to_worker === 'leader-fixed'
2026
+ && entry.transport === 'none'
2027
+ && entry.result === 'deferred'
2028
+ && entry.reason === 'pane_readiness_unverified'), 'capture readiness failure should record a fail-closed delivery receipt');
1917
2029
  });
1918
2030
  });
1919
2031
  it('suppresses duplicate visible leader injection when the pane already shows the same classified state', async () => {
@@ -1939,6 +2051,7 @@ exit 0
1939
2051
  name: teamName,
1940
2052
  tmux_session: 'same-classified-state:0',
1941
2053
  leader_pane_id: '%75',
2054
+ leader_pane_pid: 12075,
1942
2055
  });
1943
2056
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
1944
2057
  worker: 'leader-fixed',
@@ -1957,6 +2070,7 @@ set -eu
1957
2070
  echo "$@" >> "${tmuxLogPath}"
1958
2071
  cmd="$1"
1959
2072
  shift || true
2073
+ ${fakeTmuxOwnerOptionHandler(`team:${teamName}`)}
1960
2074
  if [[ "$cmd" == "display-message" ]]; then
1961
2075
  target=""
1962
2076
  format=""
@@ -2012,7 +2126,7 @@ if [[ "$cmd" == "send-keys" ]]; then
2012
2126
  exit 0
2013
2127
  fi
2014
2128
  if [[ "$cmd" == "list-panes" ]]; then
2015
- echo "%1 12345"
2129
+ printf '%%75\t0\t12075\n'
2016
2130
  exit 0
2017
2131
  fi
2018
2132
  exit 0
@@ -2061,6 +2175,7 @@ exit 0
2061
2175
  name: teamName,
2062
2176
  tmux_session: 'scroll-guard:0',
2063
2177
  leader_pane_id: '%72',
2178
+ leader_pane_pid: 12072,
2064
2179
  });
2065
2180
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
2066
2181
  worker: 'leader-fixed',
@@ -2079,6 +2194,7 @@ set -eu
2079
2194
  echo "$@" >> "${tmuxLogPath}"
2080
2195
  cmd="$1"
2081
2196
  shift || true
2197
+ ${fakeTmuxOwnerOptionHandler(`team:${teamName}`)}
2082
2198
  if [[ "$cmd" == "display-message" ]]; then
2083
2199
  target=""
2084
2200
  format=""
@@ -2128,7 +2244,7 @@ if [[ "$cmd" == "send-keys" ]]; then
2128
2244
  exit 0
2129
2245
  fi
2130
2246
  if [[ "$cmd" == "list-panes" ]]; then
2131
- echo "%1 12345"
2247
+ printf '%%72\t0\t12072\n'
2132
2248
  exit 0
2133
2249
  fi
2134
2250
  exit 0
@@ -2210,6 +2326,7 @@ exit 0
2210
2326
  name: teamName,
2211
2327
  tmux_session: 'completed-reopen:0',
2212
2328
  leader_pane_id: '%91',
2329
+ leader_pane_pid: 12091,
2213
2330
  workers: [
2214
2331
  { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
2215
2332
  { name: 'worker-2', index: 2, pane_id: '%11', role: 'executor' },
@@ -2275,6 +2392,7 @@ exit 0
2275
2392
  },
2276
2393
  tmux_session: 'other-session-team:0',
2277
2394
  leader_pane_id: '%94',
2395
+ leader_pane_pid: 12094,
2278
2396
  worker_count: 2,
2279
2397
  workers: [
2280
2398
  { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },
@@ -2342,6 +2460,7 @@ exit 0
2342
2460
  name: teamName,
2343
2461
  tmux_session: 'omx-team-beta',
2344
2462
  leader_pane_id: '%92',
2463
+ leader_pane_pid: 12092,
2345
2464
  });
2346
2465
  // Leader HUD state is stale (last turn 5 minutes ago)
2347
2466
  await writeJson(join(stateDir, 'hud-state.json'), {
@@ -2388,6 +2507,7 @@ exit 0
2388
2507
  name: teamName,
2389
2508
  tmux_session: 'omx-team-stalled-progress',
2390
2509
  leader_pane_id: '%90',
2510
+ leader_pane_pid: 12090,
2391
2511
  workers: [
2392
2512
  { name: 'worker-1', index: 1, pane_id: '%10' },
2393
2513
  { name: 'worker-2', index: 2, pane_id: '%11' },
@@ -2505,6 +2625,7 @@ exit 0
2505
2625
  name: teamName,
2506
2626
  tmux_session: 'omx-team-stalled-before-stale',
2507
2627
  leader_pane_id: '%89',
2628
+ leader_pane_pid: 12089,
2508
2629
  workers: [
2509
2630
  { name: 'worker-1', index: 1, pane_id: '%10' },
2510
2631
  { name: 'worker-2', index: 2, pane_id: '%11' },
@@ -2623,6 +2744,7 @@ exit 0
2623
2744
  name: teamName,
2624
2745
  tmux_session: 'omx-team-worker-turn-stall-threshold',
2625
2746
  leader_pane_id: '%86',
2747
+ leader_pane_pid: 12086,
2626
2748
  workers: [
2627
2749
  { name: 'worker-1', index: 1, pane_id: '%10' },
2628
2750
  ],
@@ -2717,6 +2839,7 @@ exit 0
2717
2839
  name: teamName,
2718
2840
  tmux_session: 'omx-team-active-turns-no-stall',
2719
2841
  leader_pane_id: '%87',
2842
+ leader_pane_pid: 12087,
2720
2843
  workers: [
2721
2844
  { name: 'worker-1', index: 1, pane_id: '%10' },
2722
2845
  { name: 'worker-2', index: 2, pane_id: '%11' },
@@ -2828,6 +2951,7 @@ exit 0
2828
2951
  name: teamName,
2829
2952
  tmux_session: 'omx-team-stalled-before-stale-bounded',
2830
2953
  leader_pane_id: '%88',
2954
+ leader_pane_pid: 12088,
2831
2955
  workers: [
2832
2956
  { name: 'worker-1', index: 1, pane_id: '%10' },
2833
2957
  { name: 'worker-2', index: 2, pane_id: '%11' },
@@ -2934,6 +3058,7 @@ exit 0
2934
3058
  name: teamName,
2935
3059
  tmux_session: 'omx-team-stale-no-workers',
2936
3060
  leader_pane_id: '%92',
3061
+ leader_pane_pid: 12092,
2937
3062
  hud_pane_id: '%93',
2938
3063
  workers: [
2939
3064
  { name: 'worker-1', index: 1, pane_id: '%10' },
@@ -2974,6 +3099,7 @@ exit 0
2974
3099
  name: teamName,
2975
3100
  tmux_session: 'omx-team-fresh',
2976
3101
  leader_pane_id: '%95',
3102
+ leader_pane_pid: 12095,
2977
3103
  });
2978
3104
  await writeJson(join(stateDir, 'hud-state.json'), {
2979
3105
  last_turn_at: new Date().toISOString(),
@@ -3012,6 +3138,7 @@ exit 0
3012
3138
  name: teamName,
3013
3139
  tmux_session: 'omx-team-stale-cadence',
3014
3140
  leader_pane_id: '%96',
3141
+ leader_pane_pid: 12096,
3015
3142
  });
3016
3143
  const staleHud = {
3017
3144
  last_turn_at: new Date(now - 300_000).toISOString(),
@@ -3077,6 +3204,7 @@ exit 0
3077
3204
  name: teamName,
3078
3205
  tmux_session: 'omx-team-fresh-detached-progress',
3079
3206
  leader_pane_id: '%99',
3207
+ leader_pane_pid: 12099,
3080
3208
  workers: [
3081
3209
  { name: 'worker-1', index: 1, pane_id: '%10', worktree_path: workerWorktree },
3082
3210
  ],
@@ -3170,6 +3298,7 @@ exit 0
3170
3298
  name: teamName,
3171
3299
  tmux_session: 'omx-team-gamma',
3172
3300
  leader_pane_id: '%93',
3301
+ leader_pane_pid: 12093,
3173
3302
  });
3174
3303
  await writeJson(join(mailboxDir, 'leader-fixed.json'), {
3175
3304
  worker: 'leader-fixed',
@@ -3301,6 +3430,7 @@ exit 0
3301
3430
  name: teamName,
3302
3431
  tmux_session: 'idle-bounded:0',
3303
3432
  leader_pane_id: '%98',
3433
+ leader_pane_pid: 12098,
3304
3434
  workers: [
3305
3435
  { name: 'worker-1', index: 1, role: 'executor', assigned_tasks: [] },
3306
3436
  { name: 'worker-2', index: 2, role: 'executor', assigned_tasks: [] },
@@ -3378,6 +3508,7 @@ exit 0
3378
3508
  name: teamName,
3379
3509
  tmux_session: 'omx-team-delta',
3380
3510
  leader_pane_id: '%94',
3511
+ leader_pane_pid: 12094,
3381
3512
  });
3382
3513
  // Leader stale
3383
3514
  await writeJson(join(stateDir, 'hud-state.json'), {
@@ -3454,6 +3585,7 @@ exit 0
3454
3585
  },
3455
3586
  tmux_session: 'valid-team:0',
3456
3587
  leader_pane_id: '%94',
3588
+ leader_pane_pid: 12094,
3457
3589
  worker_count: 1,
3458
3590
  workers: [
3459
3591
  { name: 'worker-1', index: 1, pane_id: '%10', role: 'executor' },