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
@@ -1,10 +1,12 @@
1
1
  import { describe, it } from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { mkdir, mkdtemp, readFile, readdir, rename, rm, symlink, writeFile } from 'node:fs/promises';
3
+ import { spawn } from 'node:child_process';
4
+ import { once } from 'node:events';
4
5
  import { existsSync } from 'node:fs';
6
+ import { mkdir, mkdtemp, readFile, readdir, rename, rm, rmdir, symlink, writeFile } from 'node:fs/promises';
5
7
  import { tmpdir } from 'node:os';
6
8
  import { join } from 'node:path';
7
- import { __createDefaultPidProbeForTests, appendPromptSessionProvenanceRejection, __resetSessionPointerTransactionDependenciesForTests, __setSessionPointerTransactionDependenciesForTests, isSessionPointerLaunchAbort, isSessionStale, readSessionPointer, readSessionState, readUsableSessionState, reconcileNativeSessionStart, resetSessionMetrics, resolveSessionPointerContext, writeSessionEnd, writeSessionStart, } from '../session.js';
9
+ import { __createDefaultPidProbeForTests, appendPromptSessionProvenanceRejection, __resetSessionPointerTransactionDependenciesForTests, __setSessionPointerTransactionDependenciesForTests, inspectSessionPointerLock, isSessionPointerLaunchAbort, isSessionStale, readSessionPointer, readSessionState, readUsableSessionState, reconcileNativeSessionStart, recoverSessionPointerLock, resetSessionMetrics, resolveSessionPointerContext, writeSessionEnd, writeSessionStart, } from '../session.js';
8
10
  function todayIsoDate() {
9
11
  return new Date().toISOString().slice(0, 10);
10
12
  }
@@ -68,6 +70,15 @@ function validLockOwner(overrides = {}) {
68
70
  ...overrides,
69
71
  };
70
72
  }
73
+ async function linuxProcessStartTicks(pid) {
74
+ const stat = await readFile(`/proc/${pid}/stat`, 'utf-8');
75
+ const closingParen = stat.lastIndexOf(')');
76
+ assert.notEqual(closingParen, -1);
77
+ const fieldsAfterCommand = stat.slice(closingParen + 2).trim().split(/\s+/);
78
+ const startTicks = Number.parseInt(fieldsAfterCommand[19] ?? '', 10);
79
+ assert.equal(Number.isInteger(startTicks), true);
80
+ return startTicks;
81
+ }
71
82
  describe('session lifecycle manager', () => {
72
83
  it('resets session metrics files with zeroed counters', async () => {
73
84
  const cwd = await mkdtemp(join(tmpdir(), 'omx-session-metrics-'));
@@ -155,6 +166,55 @@ describe('session lifecycle manager', () => {
155
166
  await rm(cwd, { recursive: true, force: true });
156
167
  }
157
168
  });
169
+ it('emits the session-end warning only after successful end finalization', async () => {
170
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-end-durability-'));
171
+ const originalWrite = process.stderr.write;
172
+ const warnings = [];
173
+ process.stderr.write = ((value) => {
174
+ warnings.push(value);
175
+ return true;
176
+ });
177
+ try {
178
+ await writeSessionEnd(cwd, 'sess-end-durability', {
179
+ platform: 'win32',
180
+ regularFileSync: async () => { throw codedError('EPERM'); },
181
+ });
182
+ assert.deepEqual(warnings, [
183
+ '[omx] warning: Windows EPERM regular-file fsync unsupported in session pointer end; operation succeeded with degraded durability.\n',
184
+ ]);
185
+ }
186
+ finally {
187
+ process.stderr.write = originalWrite;
188
+ await rm(cwd, { recursive: true, force: true });
189
+ }
190
+ });
191
+ it('keeps session-end durability warnings silent when finalization or release fails', async () => {
192
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-end-durability-failure-'));
193
+ const originalWrite = process.stderr.write;
194
+ const warnings = [];
195
+ process.stderr.write = ((value) => {
196
+ warnings.push(value);
197
+ return true;
198
+ });
199
+ const regularFileSync = async () => { throw codedError('EPERM'); };
200
+ try {
201
+ await withPointerDependencies({
202
+ fs: {
203
+ rmdir: async () => { throw new Error('release failure'); },
204
+ },
205
+ }, async () => {
206
+ await assert.rejects(writeSessionEnd(cwd, 'sess-end-release-failure', {
207
+ platform: 'win32',
208
+ regularFileSync,
209
+ }));
210
+ });
211
+ assert.deepEqual(warnings, []);
212
+ }
213
+ finally {
214
+ process.stderr.write = originalWrite;
215
+ await rm(cwd, { recursive: true, force: true });
216
+ }
217
+ });
158
218
  it('does not delete the current session pointer when ending a different session', async () => {
159
219
  const cwd = await mkdtemp(join(tmpdir(), 'omx-session-end-owner-'));
160
220
  try {
@@ -659,6 +719,231 @@ describe('session pointer transaction', () => {
659
719
  }
660
720
  }
661
721
  });
722
+ it('atomically quarantines dead pre-rename temporary owner evidence and stays idempotent', async () => {
723
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-lock-recovery-dead-temp-'));
724
+ try {
725
+ const context = resolveSessionPointerContext(cwd);
726
+ await mkdir(context.lockPath, { recursive: true });
727
+ await writeFile(join(context.lockPath, `owner.${TEST_TOKEN}.tmp`), JSON.stringify(validLockOwner()), 'utf-8');
728
+ await withPointerDependencies({ token: () => SUCCESSOR_TOKEN, probePid: () => 'dead' }, async () => {
729
+ const inspected = await inspectSessionPointerLock(cwd);
730
+ assert.equal(inspected.status, 'dead');
731
+ assert.equal(inspected.evidenceSource, 'owner-temp');
732
+ assert.equal(inspected.safeToRecover, true);
733
+ const recovered = await recoverSessionPointerLock(cwd);
734
+ assert.equal(recovered.recovered, true);
735
+ assert.equal(recovered.action, 'quarantined');
736
+ assert.equal(existsSync(context.lockPath), false);
737
+ assert.equal(existsSync(recovered.quarantinePath), true);
738
+ const repeated = await recoverSessionPointerLock(cwd);
739
+ assert.equal(repeated.recovered, false);
740
+ assert.equal(repeated.action, 'none');
741
+ assert.equal(repeated.status, 'absent');
742
+ });
743
+ }
744
+ finally {
745
+ await rm(cwd, { recursive: true, force: true });
746
+ }
747
+ });
748
+ it('does not recover a dead canonical owner because owner.json is not an exact acquisition claim', async () => {
749
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-lock-recovery-dead-canonical-'));
750
+ try {
751
+ const context = resolveSessionPointerContext(cwd);
752
+ await writeLockOwner(cwd, validLockOwner());
753
+ await withPointerDependencies({ token: () => SUCCESSOR_TOKEN, probePid: () => 'dead' }, async () => {
754
+ const recovered = await recoverSessionPointerLock(cwd);
755
+ assert.equal(recovered.status, 'dead');
756
+ assert.equal(recovered.evidenceSource, 'owner.json');
757
+ assert.equal(recovered.safeToRecover, false);
758
+ assert.equal(recovered.recovered, false);
759
+ assert.equal(recovered.action, 'none');
760
+ assert.equal(existsSync(context.lockPath), true);
761
+ });
762
+ }
763
+ finally {
764
+ await rm(cwd, { recursive: true, force: true });
765
+ }
766
+ });
767
+ it('distinguishes a paused live pre-rename owner from the same owner after SIGKILL', async (t) => {
768
+ if (process.platform !== 'linux') {
769
+ t.skip('Linux process start identity is required for deterministic PID reuse protection.');
770
+ return;
771
+ }
772
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-lock-recovery-sigkill-'));
773
+ const child = spawn(process.execPath, ['-e', 'setInterval(() => {}, 1_000)'], { stdio: 'ignore' });
774
+ try {
775
+ assert.ok(child.pid);
776
+ await once(child, 'spawn');
777
+ const context = resolveSessionPointerContext(cwd);
778
+ await mkdir(context.lockPath, { recursive: true });
779
+ await writeFile(join(context.lockPath, `owner.${TEST_TOKEN}.tmp`), JSON.stringify(validLockOwner({
780
+ pid: child.pid,
781
+ pid_start_ticks: await linuxProcessStartTicks(child.pid),
782
+ })), 'utf-8');
783
+ const paused = await recoverSessionPointerLock(cwd);
784
+ assert.equal(paused.status, 'live');
785
+ assert.equal(paused.recovered, false);
786
+ assert.equal(paused.action, 'none');
787
+ assert.equal(existsSync(context.lockPath), true);
788
+ child.kill('SIGKILL');
789
+ const [exitCode, signal] = await once(child, 'exit');
790
+ assert.equal(exitCode, null);
791
+ assert.equal(signal, 'SIGKILL');
792
+ const orphaned = await recoverSessionPointerLock(cwd);
793
+ assert.equal(orphaned.status, 'dead');
794
+ assert.equal(orphaned.recovered, true);
795
+ assert.equal(orphaned.action, 'quarantined');
796
+ assert.equal(existsSync(context.lockPath), false);
797
+ }
798
+ finally {
799
+ if (child.exitCode === null && child.signalCode === null)
800
+ child.kill('SIGKILL');
801
+ await rm(cwd, { recursive: true, force: true });
802
+ }
803
+ });
804
+ it('fails closed for live pre-rename, PID reuse, malformed, and ambiguous lock evidence', async () => {
805
+ const cases = [
806
+ { name: 'live-temp', files: [[`owner.${TEST_TOKEN}.tmp`, JSON.stringify(validLockOwner())]], probePid: 'alive', identity: matchingProcessIdentity() },
807
+ { name: 'reused', files: [['owner.json', JSON.stringify(validLockOwner())]], probePid: 'alive', identity: { status: 'matching', startTicks: 2 } },
808
+ { name: 'malformed', files: [['owner.json', '{']], probePid: 'dead' },
809
+ { name: 'ambiguous', files: [['owner.json', JSON.stringify(validLockOwner())], [`owner.${SUCCESSOR_TOKEN}.tmp`, JSON.stringify(validLockOwner({ token: SUCCESSOR_TOKEN }))]], probePid: 'dead' },
810
+ ];
811
+ for (const testCase of cases) {
812
+ const cwd = await mkdtemp(join(tmpdir(), `omx-session-lock-recovery-${testCase.name}-`));
813
+ try {
814
+ const context = resolveSessionPointerContext(cwd);
815
+ await mkdir(context.lockPath, { recursive: true });
816
+ await Promise.all(testCase.files.map(async ([name, contents]) => await writeFile(join(context.lockPath, name), contents, 'utf-8')));
817
+ await withPointerDependencies({
818
+ token: () => SUCCESSOR_TOKEN,
819
+ probePid: () => testCase.probePid,
820
+ readProcessIdentity: () => testCase.identity ?? matchingProcessIdentity(),
821
+ }, async () => {
822
+ const before = await readdir(context.lockPath);
823
+ const recovered = await recoverSessionPointerLock(cwd);
824
+ assert.equal(recovered.recovered, false);
825
+ assert.equal(recovered.action, 'none');
826
+ assert.equal(recovered.safeToRecover, false);
827
+ assert.deepEqual(await readdir(context.lockPath), before);
828
+ });
829
+ }
830
+ finally {
831
+ await rm(cwd, { recursive: true, force: true });
832
+ }
833
+ }
834
+ });
835
+ it('claims stale evidence before quarantine so a successor cannot be mistaken for it', async () => {
836
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-lock-recovery-race-'));
837
+ try {
838
+ const context = resolveSessionPointerContext(cwd);
839
+ await mkdir(context.lockPath, { recursive: true });
840
+ await writeFile(join(context.lockPath, `owner.${TEST_TOKEN}.tmp`), JSON.stringify(validLockOwner()), 'utf-8');
841
+ const renames = [];
842
+ let successorBlocked = false;
843
+ await withPointerDependencies({
844
+ token: () => SUCCESSOR_TOKEN,
845
+ probePid: () => 'dead',
846
+ fs: {
847
+ rename: async (from, to) => {
848
+ renames.push([from, to]);
849
+ await rename(from, to);
850
+ if (from.endsWith(`owner.${TEST_TOKEN}.tmp`)) {
851
+ await assert.rejects(mkdir(context.lockPath), { code: 'EEXIST' });
852
+ successorBlocked = true;
853
+ }
854
+ },
855
+ },
856
+ }, async () => {
857
+ const recovered = await recoverSessionPointerLock(cwd);
858
+ assert.equal(recovered.recovered, true);
859
+ });
860
+ assert.equal(successorBlocked, true);
861
+ assert.match(renames[0][0], /owner\.transaction_token_123456\.tmp$/);
862
+ assert.match(renames[0][1], new RegExp(`owner\\.${TEST_TOKEN}\\.${SUCCESSOR_TOKEN}\\.recovery$`));
863
+ assert.match(renames[1][0], new RegExp(`owner\\.${TEST_TOKEN}\\.${SUCCESSOR_TOKEN}\\.recovery$`));
864
+ assert.equal(renames[1][1].includes('.quarantine.'), true);
865
+ }
866
+ finally {
867
+ await rm(cwd, { recursive: true, force: true });
868
+ }
869
+ });
870
+ it('does not claim a successor lock when the inspected orphan is displaced before the exact temp rename', async () => {
871
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-lock-recovery-successor-race-'));
872
+ try {
873
+ const context = resolveSessionPointerContext(cwd);
874
+ const staleTemp = join(context.lockPath, `owner.${TEST_TOKEN}.tmp`);
875
+ const successorTemp = join(context.lockPath, `owner.${SUCCESSOR_TOKEN}.tmp`);
876
+ const displacedPath = `${context.lockPath}.displaced`;
877
+ await mkdir(context.lockPath, { recursive: true });
878
+ await writeFile(staleTemp, JSON.stringify(validLockOwner()), 'utf-8');
879
+ let displaced = false;
880
+ await withPointerDependencies({
881
+ token: () => SUCCESSOR_TOKEN,
882
+ probePid: () => 'dead',
883
+ fs: {
884
+ rename: async (from, to) => {
885
+ if (!displaced && from === staleTemp) {
886
+ displaced = true;
887
+ await rename(context.lockPath, displacedPath);
888
+ await mkdir(context.lockPath);
889
+ await writeFile(successorTemp, JSON.stringify(validLockOwner({ token: SUCCESSOR_TOKEN })), 'utf-8');
890
+ }
891
+ await rename(from, to);
892
+ },
893
+ },
894
+ }, async () => {
895
+ const recovered = await recoverSessionPointerLock(cwd);
896
+ assert.equal(recovered.recovered, false);
897
+ assert.equal(recovered.action, 'none');
898
+ assert.match(recovered.reason, /changed before recovery claim/i);
899
+ });
900
+ assert.equal(displaced, true);
901
+ assert.deepEqual(await readdir(context.lockPath), [`owner.${SUCCESSOR_TOKEN}.tmp`]);
902
+ assert.equal(await readFile(successorTemp, 'utf-8'), JSON.stringify(validLockOwner({ token: SUCCESSOR_TOKEN })));
903
+ }
904
+ finally {
905
+ await rm(cwd, { recursive: true, force: true });
906
+ }
907
+ });
908
+ it('does not quarantine a successor live lock displaced into the canonical path after claim revalidation', async () => {
909
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-lock-recovery-post-claim-race-'));
910
+ try {
911
+ const context = resolveSessionPointerContext(cwd);
912
+ const staleTemp = join(context.lockPath, `owner.${TEST_TOKEN}.tmp`);
913
+ const successorTemp = join(context.lockPath, `owner.${SUCCESSOR_TOKEN}.tmp`);
914
+ const displacedPath = `${context.lockPath}.claimed-displaced`;
915
+ await mkdir(context.lockPath, { recursive: true });
916
+ await writeFile(staleTemp, JSON.stringify(validLockOwner()), 'utf-8');
917
+ let displaced = false;
918
+ await withPointerDependencies({
919
+ token: () => SUCCESSOR_TOKEN,
920
+ probePid: () => 'dead',
921
+ fs: {
922
+ rmdir: async (path) => {
923
+ if (!displaced && path === context.lockPath) {
924
+ displaced = true;
925
+ await rename(context.lockPath, displacedPath);
926
+ await mkdir(context.lockPath);
927
+ await writeFile(successorTemp, JSON.stringify(validLockOwner({ token: SUCCESSOR_TOKEN })), 'utf-8');
928
+ }
929
+ await rmdir(path);
930
+ },
931
+ },
932
+ }, async () => {
933
+ const recovered = await recoverSessionPointerLock(cwd);
934
+ assert.equal(recovered.recovered, false);
935
+ assert.equal(recovered.action, 'none');
936
+ assert.match(recovered.reason, /canonical lock directory was not empty/i);
937
+ assert.ok(recovered.quarantinePath);
938
+ });
939
+ assert.equal(displaced, true);
940
+ assert.deepEqual(await readdir(context.lockPath), [`owner.${SUCCESSOR_TOKEN}.tmp`]);
941
+ assert.equal(await readFile(successorTemp, 'utf-8'), JSON.stringify(validLockOwner({ token: SUCCESSOR_TOKEN })));
942
+ }
943
+ finally {
944
+ await rm(cwd, { recursive: true, force: true });
945
+ }
946
+ });
662
947
  it('retries a positively matching live owner with the bounded 25/50/100 schedule before timing out', async () => {
663
948
  const cwd = await mkdtemp(join(tmpdir(), 'omx-session-lock-timeout-'));
664
949
  try {
@@ -729,6 +1014,65 @@ describe('session pointer transaction', () => {
729
1014
  await rm(cwd, { recursive: true, force: true });
730
1015
  }
731
1016
  });
1017
+ it('publishes the owner and pointer on Windows when regular-file fsync reports EPERM', async () => {
1018
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-windows-eperm-'));
1019
+ let syncCalls = 0;
1020
+ const regularFileSync = async (platform) => {
1021
+ assert.equal(platform, 'win32');
1022
+ syncCalls += 1;
1023
+ throw codedError('EPERM');
1024
+ };
1025
+ try {
1026
+ const state = await writeSessionStart(cwd, 'sess-windows-eperm', {
1027
+ platform: 'win32',
1028
+ regularFileSync,
1029
+ });
1030
+ const context = resolveSessionPointerContext(cwd);
1031
+ assert.equal(state.session_id, 'sess-windows-eperm');
1032
+ assert.equal(syncCalls, 2, 'owner publication and pointer publication must both attempt fsync');
1033
+ assert.equal(existsSync(join(context.lockPath, 'owner.json')), false, 'lock owner is removed after commit');
1034
+ assert.equal(JSON.parse(await readFile(context.sessionPath, 'utf8')).session_id, 'sess-windows-eperm');
1035
+ }
1036
+ finally {
1037
+ await rm(cwd, { recursive: true, force: true });
1038
+ }
1039
+ });
1040
+ it('emits one post-release warning for a degraded session start and stays silent for synced or failed transactions', async () => {
1041
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-session-durability-warning-'));
1042
+ const originalWrite = process.stderr.write;
1043
+ const warnings = [];
1044
+ process.stderr.write = ((value) => {
1045
+ warnings.push({ value, lockExists: existsSync(resolveSessionPointerContext(cwd).lockPath) });
1046
+ return true;
1047
+ });
1048
+ const regularFileSync = async () => { throw codedError('EPERM'); };
1049
+ try {
1050
+ await writeSessionStart(cwd, 'sess-degraded-start', { platform: 'win32', regularFileSync });
1051
+ assert.deepEqual(warnings, [{
1052
+ value: '[omx] warning: Windows EPERM regular-file fsync unsupported in session pointer start/reconcile; operation succeeded with degraded durability.\n',
1053
+ lockExists: false,
1054
+ }]);
1055
+ warnings.length = 0;
1056
+ await writeSessionStart(cwd, 'sess-degraded-start', { platform: 'win32' });
1057
+ assert.deepEqual(warnings, []);
1058
+ await withPointerDependencies({
1059
+ fs: {
1060
+ rename: async (from, to) => {
1061
+ if (to === resolveSessionPointerContext(cwd).sessionPath)
1062
+ throw new Error('rename failure');
1063
+ await rename(from, to);
1064
+ },
1065
+ },
1066
+ }, async () => {
1067
+ await assert.rejects(writeSessionStart(cwd, 'sess-degraded-start', { platform: 'win32', regularFileSync }));
1068
+ });
1069
+ assert.deepEqual(warnings, []);
1070
+ }
1071
+ finally {
1072
+ process.stderr.write = originalWrite;
1073
+ await rm(cwd, { recursive: true, force: true });
1074
+ }
1075
+ });
732
1076
  it('types state-directory, pointer-read, owner-sync, owner-rename, and invalid-token failures before commit', async () => {
733
1077
  const failures = [
734
1078
  {
@@ -767,6 +1111,7 @@ describe('session pointer transaction', () => {
767
1111
  openAndSync: async (path) => {
768
1112
  if (path === join(context.lockPath, `owner.${TEST_TOKEN}.tmp`))
769
1113
  throw new Error('owner sync failure');
1114
+ return 'synced';
770
1115
  },
771
1116
  },
772
1117
  }),
@@ -838,6 +1183,7 @@ describe('session pointer transaction', () => {
838
1183
  openAndSync: async (path) => {
839
1184
  if (phase.fail === 'sync' && path === tempPath)
840
1185
  throw new Error('pointer sync failure');
1186
+ return 'synced';
841
1187
  },
842
1188
  rename: async (from, to) => {
843
1189
  if (phase.fail === 'rename' && from === tempPath && to === context.sessionPath) {