oh-my-codex 0.18.6 → 0.18.8

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 (444) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +59 -10
  4. package/crates/omx-sparkshell/tests/execution.rs +1 -1
  5. package/dist/agents/__tests__/definitions.test.js +11 -0
  6. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  7. package/dist/agents/__tests__/native-config.test.js +56 -6
  8. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  9. package/dist/agents/definitions.d.ts +10 -0
  10. package/dist/agents/definitions.d.ts.map +1 -1
  11. package/dist/agents/definitions.js +5 -1
  12. package/dist/agents/definitions.js.map +1 -1
  13. package/dist/agents/native-config.d.ts +5 -1
  14. package/dist/agents/native-config.d.ts.map +1 -1
  15. package/dist/agents/native-config.js +19 -4
  16. package/dist/agents/native-config.js.map +1 -1
  17. package/dist/autopilot/__tests__/fsm.test.d.ts +2 -0
  18. package/dist/autopilot/__tests__/fsm.test.d.ts.map +1 -0
  19. package/dist/autopilot/__tests__/fsm.test.js +75 -0
  20. package/dist/autopilot/__tests__/fsm.test.js.map +1 -0
  21. package/dist/autopilot/__tests__/ralplan-gate.test.d.ts +2 -0
  22. package/dist/autopilot/__tests__/ralplan-gate.test.d.ts.map +1 -0
  23. package/dist/autopilot/__tests__/ralplan-gate.test.js +79 -0
  24. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -0
  25. package/dist/autopilot/deep-interview-gate.d.ts +18 -0
  26. package/dist/autopilot/deep-interview-gate.d.ts.map +1 -0
  27. package/dist/autopilot/deep-interview-gate.js +256 -0
  28. package/dist/autopilot/deep-interview-gate.js.map +1 -0
  29. package/dist/autopilot/fsm.d.ts +13 -0
  30. package/dist/autopilot/fsm.d.ts.map +1 -0
  31. package/dist/autopilot/fsm.js +70 -0
  32. package/dist/autopilot/fsm.js.map +1 -0
  33. package/dist/autopilot/ralplan-gate.d.ts +17 -0
  34. package/dist/autopilot/ralplan-gate.d.ts.map +1 -0
  35. package/dist/autopilot/ralplan-gate.js +61 -0
  36. package/dist/autopilot/ralplan-gate.js.map +1 -0
  37. package/dist/cli/__tests__/codex-plugin-layout.test.js +512 -1
  38. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  39. package/dist/cli/__tests__/doctor-warning-copy.test.js +39 -0
  40. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  41. package/dist/cli/__tests__/index.test.js +83 -7
  42. package/dist/cli/__tests__/index.test.js.map +1 -1
  43. package/dist/cli/__tests__/launch-fallback.test.js +175 -6
  44. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  45. package/dist/cli/__tests__/package-bin-contract.test.js +8 -4
  46. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  47. package/dist/cli/__tests__/question.test.js +100 -0
  48. package/dist/cli/__tests__/question.test.js.map +1 -1
  49. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +13 -0
  50. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  51. package/dist/cli/__tests__/ralph.test.js +14 -0
  52. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  53. package/dist/cli/__tests__/setup-install-mode.test.js +89 -0
  54. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  55. package/dist/cli/__tests__/setup-refresh.test.js +83 -0
  56. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  57. package/dist/cli/__tests__/state.test.js +21 -0
  58. package/dist/cli/__tests__/state.test.js.map +1 -1
  59. package/dist/cli/__tests__/team.test.js +2 -2
  60. package/dist/cli/__tests__/team.test.js.map +1 -1
  61. package/dist/cli/__tests__/update.test.js +110 -2
  62. package/dist/cli/__tests__/update.test.js.map +1 -1
  63. package/dist/cli/doctor.d.ts.map +1 -1
  64. package/dist/cli/doctor.js +8 -1
  65. package/dist/cli/doctor.js.map +1 -1
  66. package/dist/cli/index.d.ts +14 -3
  67. package/dist/cli/index.d.ts.map +1 -1
  68. package/dist/cli/index.js +298 -50
  69. package/dist/cli/index.js.map +1 -1
  70. package/dist/cli/plugin-marketplace.d.ts +14 -2
  71. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  72. package/dist/cli/plugin-marketplace.js +62 -15
  73. package/dist/cli/plugin-marketplace.js.map +1 -1
  74. package/dist/cli/question.d.ts.map +1 -1
  75. package/dist/cli/question.js +36 -5
  76. package/dist/cli/question.js.map +1 -1
  77. package/dist/cli/ralph.d.ts.map +1 -1
  78. package/dist/cli/ralph.js +3 -1
  79. package/dist/cli/ralph.js.map +1 -1
  80. package/dist/cli/setup-preferences.d.ts +2 -0
  81. package/dist/cli/setup-preferences.d.ts.map +1 -1
  82. package/dist/cli/setup-preferences.js +4 -0
  83. package/dist/cli/setup-preferences.js.map +1 -1
  84. package/dist/cli/setup.d.ts +3 -0
  85. package/dist/cli/setup.d.ts.map +1 -1
  86. package/dist/cli/setup.js +166 -27
  87. package/dist/cli/setup.js.map +1 -1
  88. package/dist/cli/state.d.ts.map +1 -1
  89. package/dist/cli/state.js +8 -1
  90. package/dist/cli/state.js.map +1 -1
  91. package/dist/cli/tmux-hook.d.ts.map +1 -1
  92. package/dist/cli/tmux-hook.js +16 -0
  93. package/dist/cli/tmux-hook.js.map +1 -1
  94. package/dist/cli/update.d.ts +2 -0
  95. package/dist/cli/update.d.ts.map +1 -1
  96. package/dist/cli/update.js +47 -3
  97. package/dist/cli/update.js.map +1 -1
  98. package/dist/config/__tests__/deep-interview.test.js +7 -6
  99. package/dist/config/__tests__/deep-interview.test.js.map +1 -1
  100. package/dist/config/__tests__/generator-notify.test.js +1 -0
  101. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  102. package/dist/config/deep-interview.d.ts.map +1 -1
  103. package/dist/config/deep-interview.js +14 -4
  104. package/dist/config/deep-interview.js.map +1 -1
  105. package/dist/config/generator.d.ts +2 -2
  106. package/dist/config/generator.d.ts.map +1 -1
  107. package/dist/config/generator.js +2 -2
  108. package/dist/config/generator.js.map +1 -1
  109. package/dist/config/team-mode.d.ts +12 -0
  110. package/dist/config/team-mode.d.ts.map +1 -0
  111. package/dist/config/team-mode.js +91 -0
  112. package/dist/config/team-mode.js.map +1 -0
  113. package/dist/hooks/__tests__/agents-overlay.test.js +88 -0
  114. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  115. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +8 -0
  116. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  117. package/dist/hooks/__tests__/code-review-skill-contract.test.js +8 -0
  118. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
  119. package/dist/hooks/__tests__/deep-interview-contract.test.js +10 -0
  120. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  121. package/dist/hooks/__tests__/keyword-detector.test.js +1072 -14
  122. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  123. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +64 -1
  124. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  125. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +189 -0
  126. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  127. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +35 -2
  128. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  129. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +3 -3
  130. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  131. package/dist/hooks/__tests__/session.test.js +25 -0
  132. package/dist/hooks/__tests__/session.test.js.map +1 -1
  133. package/dist/hooks/__tests__/skill-guidance-contract.test.js +21 -0
  134. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
  135. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  136. package/dist/hooks/agents-overlay.js +36 -50
  137. package/dist/hooks/agents-overlay.js.map +1 -1
  138. package/dist/hooks/deep-interview-config-instruction.js +1 -1
  139. package/dist/hooks/deep-interview-config-instruction.js.map +1 -1
  140. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +31 -0
  141. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -1
  142. package/dist/hooks/extensibility/plugin-runner.js +17 -21
  143. package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
  144. package/dist/hooks/keyword-detector.d.ts +1 -0
  145. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  146. package/dist/hooks/keyword-detector.js +428 -32
  147. package/dist/hooks/keyword-detector.js.map +1 -1
  148. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  149. package/dist/hooks/keyword-registry.js +1 -0
  150. package/dist/hooks/keyword-registry.js.map +1 -1
  151. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  152. package/dist/hooks/prompt-guidance-contract.js +6 -0
  153. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  154. package/dist/hooks/session.d.ts +3 -0
  155. package/dist/hooks/session.d.ts.map +1 -1
  156. package/dist/hooks/session.js +13 -5
  157. package/dist/hooks/session.js.map +1 -1
  158. package/dist/hud/__tests__/authority.test.js +469 -31
  159. package/dist/hud/__tests__/authority.test.js.map +1 -1
  160. package/dist/hud/__tests__/hud-tmux-injection.test.js +2 -1
  161. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
  162. package/dist/hud/__tests__/index.test.js +210 -2
  163. package/dist/hud/__tests__/index.test.js.map +1 -1
  164. package/dist/hud/__tests__/reconcile.test.js +588 -28
  165. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  166. package/dist/hud/__tests__/render.test.js +61 -0
  167. package/dist/hud/__tests__/render.test.js.map +1 -1
  168. package/dist/hud/__tests__/state.test.js +208 -0
  169. package/dist/hud/__tests__/state.test.js.map +1 -1
  170. package/dist/hud/__tests__/tmux.test.js +314 -22
  171. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  172. package/dist/hud/authority.d.ts +5 -0
  173. package/dist/hud/authority.d.ts.map +1 -1
  174. package/dist/hud/authority.js +337 -30
  175. package/dist/hud/authority.js.map +1 -1
  176. package/dist/hud/index.d.ts +20 -2
  177. package/dist/hud/index.d.ts.map +1 -1
  178. package/dist/hud/index.js +103 -26
  179. package/dist/hud/index.js.map +1 -1
  180. package/dist/hud/reconcile.d.ts +3 -3
  181. package/dist/hud/reconcile.d.ts.map +1 -1
  182. package/dist/hud/reconcile.js +129 -20
  183. package/dist/hud/reconcile.js.map +1 -1
  184. package/dist/hud/render.d.ts.map +1 -1
  185. package/dist/hud/render.js +35 -0
  186. package/dist/hud/render.js.map +1 -1
  187. package/dist/hud/state.d.ts.map +1 -1
  188. package/dist/hud/state.js +64 -50
  189. package/dist/hud/state.js.map +1 -1
  190. package/dist/hud/tmux.d.ts +26 -6
  191. package/dist/hud/tmux.d.ts.map +1 -1
  192. package/dist/hud/tmux.js +173 -38
  193. package/dist/hud/tmux.js.map +1 -1
  194. package/dist/hud/types.d.ts +11 -0
  195. package/dist/hud/types.d.ts.map +1 -1
  196. package/dist/hud/types.js.map +1 -1
  197. package/dist/mcp/__tests__/hermes-bridge.test.js +203 -7
  198. package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -1
  199. package/dist/mcp/__tests__/state-paths.test.js +71 -1
  200. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  201. package/dist/mcp/__tests__/state-server.test.js +13 -1
  202. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  203. package/dist/mcp/hermes-bridge.d.ts +12 -2
  204. package/dist/mcp/hermes-bridge.d.ts.map +1 -1
  205. package/dist/mcp/hermes-bridge.js +83 -9
  206. package/dist/mcp/hermes-bridge.js.map +1 -1
  207. package/dist/mcp/state-paths.d.ts +32 -0
  208. package/dist/mcp/state-paths.d.ts.map +1 -1
  209. package/dist/mcp/state-paths.js +113 -17
  210. package/dist/mcp/state-paths.js.map +1 -1
  211. package/dist/mcp/state-server.d.ts +4 -4
  212. package/dist/modes/__tests__/base-autoresearch-contract.test.js +7 -1
  213. package/dist/modes/__tests__/base-autoresearch-contract.test.js.map +1 -1
  214. package/dist/pipeline/__tests__/stages.test.js +130 -0
  215. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  216. package/dist/pipeline/orchestrator.js +1 -1
  217. package/dist/pipeline/orchestrator.js.map +1 -1
  218. package/dist/pipeline/stages/ralplan.d.ts +1 -0
  219. package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
  220. package/dist/pipeline/stages/ralplan.js +14 -5
  221. package/dist/pipeline/stages/ralplan.js.map +1 -1
  222. package/dist/question/__tests__/deep-interview.test.js +160 -2
  223. package/dist/question/__tests__/deep-interview.test.js.map +1 -1
  224. package/dist/question/__tests__/policy.test.js +63 -3
  225. package/dist/question/__tests__/policy.test.js.map +1 -1
  226. package/dist/question/__tests__/renderer.test.js +191 -2
  227. package/dist/question/__tests__/renderer.test.js.map +1 -1
  228. package/dist/question/__tests__/state.test.js +94 -3
  229. package/dist/question/__tests__/state.test.js.map +1 -1
  230. package/dist/question/__tests__/ui.test.js +4 -0
  231. package/dist/question/__tests__/ui.test.js.map +1 -1
  232. package/dist/question/autopilot-wait.d.ts +12 -2
  233. package/dist/question/autopilot-wait.d.ts.map +1 -1
  234. package/dist/question/autopilot-wait.js +158 -47
  235. package/dist/question/autopilot-wait.js.map +1 -1
  236. package/dist/question/deep-interview.d.ts.map +1 -1
  237. package/dist/question/deep-interview.js +22 -6
  238. package/dist/question/deep-interview.js.map +1 -1
  239. package/dist/question/policy.d.ts.map +1 -1
  240. package/dist/question/policy.js +2 -5
  241. package/dist/question/policy.js.map +1 -1
  242. package/dist/question/renderer.d.ts +12 -0
  243. package/dist/question/renderer.d.ts.map +1 -1
  244. package/dist/question/renderer.js +87 -3
  245. package/dist/question/renderer.js.map +1 -1
  246. package/dist/question/state.d.ts +8 -1
  247. package/dist/question/state.d.ts.map +1 -1
  248. package/dist/question/state.js +54 -14
  249. package/dist/question/state.js.map +1 -1
  250. package/dist/question/types.d.ts +1 -1
  251. package/dist/question/types.d.ts.map +1 -1
  252. package/dist/question/ui.d.ts +1 -0
  253. package/dist/question/ui.d.ts.map +1 -1
  254. package/dist/question/ui.js +1 -0
  255. package/dist/question/ui.js.map +1 -1
  256. package/dist/ralplan/__tests__/runtime.test.js +191 -0
  257. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  258. package/dist/ralplan/consensus-gate.d.ts +9 -1
  259. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  260. package/dist/ralplan/consensus-gate.js +84 -2
  261. package/dist/ralplan/consensus-gate.js.map +1 -1
  262. package/dist/ralplan/runtime.d.ts +9 -0
  263. package/dist/ralplan/runtime.d.ts.map +1 -1
  264. package/dist/ralplan/runtime.js +32 -11
  265. package/dist/ralplan/runtime.js.map +1 -1
  266. package/dist/scripts/__tests__/codex-native-hook.test.js +2315 -280
  267. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  268. package/dist/scripts/__tests__/notify-state-io.test.js +72 -1
  269. package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
  270. package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts +2 -0
  271. package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts.map +1 -0
  272. package/dist/scripts/__tests__/notify-tmux-injection.test.js +57 -0
  273. package/dist/scripts/__tests__/notify-tmux-injection.test.js.map +1 -0
  274. package/dist/scripts/__tests__/run-test-files.test.js +74 -0
  275. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  276. package/dist/scripts/__tests__/verify-native-agents.test.js +65 -0
  277. package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
  278. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  279. package/dist/scripts/codex-native-hook.js +431 -56
  280. package/dist/scripts/codex-native-hook.js.map +1 -1
  281. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  282. package/dist/scripts/codex-native-pre-post.js +79 -1
  283. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  284. package/dist/scripts/eval/eval-parity-smoke.js +1 -1
  285. package/dist/scripts/eval/eval-parity-smoke.js.map +1 -1
  286. package/dist/scripts/hook-payload-guard.d.ts +9 -0
  287. package/dist/scripts/hook-payload-guard.d.ts.map +1 -0
  288. package/dist/scripts/hook-payload-guard.js +111 -0
  289. package/dist/scripts/hook-payload-guard.js.map +1 -0
  290. package/dist/scripts/notify-fallback-watcher.js +8 -1
  291. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  292. package/dist/scripts/notify-hook/__tests__/payload-guard.test.d.ts +2 -0
  293. package/dist/scripts/notify-hook/__tests__/payload-guard.test.d.ts.map +1 -0
  294. package/dist/scripts/notify-hook/__tests__/payload-guard.test.js +39 -0
  295. package/dist/scripts/notify-hook/__tests__/payload-guard.test.js.map +1 -0
  296. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  297. package/dist/scripts/notify-hook/auto-nudge.js +3 -1
  298. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  299. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  300. package/dist/scripts/notify-hook/ralph-session-resume.js +3 -10
  301. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  302. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  303. package/dist/scripts/notify-hook/state-io.js +62 -38
  304. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  305. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  306. package/dist/scripts/notify-hook/team-leader-nudge.js +7 -0
  307. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  308. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
  309. package/dist/scripts/notify-hook/team-worker-stop.js +234 -86
  310. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
  311. package/dist/scripts/notify-hook/tmux-injection.d.ts +7 -0
  312. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  313. package/dist/scripts/notify-hook/tmux-injection.js +24 -18
  314. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  315. package/dist/scripts/notify-hook.js +86 -13
  316. package/dist/scripts/notify-hook.js.map +1 -1
  317. package/dist/scripts/run-test-files.js +193 -22
  318. package/dist/scripts/run-test-files.js.map +1 -1
  319. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  320. package/dist/scripts/sync-plugin-mirror.js +61 -3
  321. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  322. package/dist/scripts/verify-native-agents.d.ts.map +1 -1
  323. package/dist/scripts/verify-native-agents.js +58 -1
  324. package/dist/scripts/verify-native-agents.js.map +1 -1
  325. package/dist/state/__tests__/operations.test.js +1125 -1
  326. package/dist/state/__tests__/operations.test.js.map +1 -1
  327. package/dist/state/__tests__/skill-active.test.js +46 -1
  328. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  329. package/dist/state/__tests__/workflow-transition.test.js +98 -7
  330. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  331. package/dist/state/operations.d.ts.map +1 -1
  332. package/dist/state/operations.js +159 -2
  333. package/dist/state/operations.js.map +1 -1
  334. package/dist/state/skill-active.js +6 -8
  335. package/dist/state/skill-active.js.map +1 -1
  336. package/dist/state/workflow-transition-reconcile.d.ts +6 -0
  337. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  338. package/dist/state/workflow-transition-reconcile.js +38 -15
  339. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  340. package/dist/state/workflow-transition.d.ts.map +1 -1
  341. package/dist/state/workflow-transition.js +10 -3
  342. package/dist/state/workflow-transition.js.map +1 -1
  343. package/dist/subagents/__tests__/tracker.test.js +139 -0
  344. package/dist/subagents/__tests__/tracker.test.js.map +1 -1
  345. package/dist/subagents/tracker.d.ts +3 -0
  346. package/dist/subagents/tracker.d.ts.map +1 -1
  347. package/dist/subagents/tracker.js +41 -4
  348. package/dist/subagents/tracker.js.map +1 -1
  349. package/dist/team/__tests__/coordination-protocol.test.d.ts +2 -0
  350. package/dist/team/__tests__/coordination-protocol.test.d.ts.map +1 -0
  351. package/dist/team/__tests__/coordination-protocol.test.js +173 -0
  352. package/dist/team/__tests__/coordination-protocol.test.js.map +1 -0
  353. package/dist/team/__tests__/runtime.test.js +52 -3
  354. package/dist/team/__tests__/runtime.test.js.map +1 -1
  355. package/dist/team/__tests__/scaling.test.js +9 -4
  356. package/dist/team/__tests__/scaling.test.js.map +1 -1
  357. package/dist/team/__tests__/state.test.js +83 -0
  358. package/dist/team/__tests__/state.test.js.map +1 -1
  359. package/dist/team/__tests__/tmux-session.test.js +240 -2
  360. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  361. package/dist/team/__tests__/worker-bootstrap.test.js +84 -0
  362. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  363. package/dist/team/__tests__/worker-runtime-identity.test.js +4 -2
  364. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  365. package/dist/team/coordination-protocol.d.ts +14 -0
  366. package/dist/team/coordination-protocol.d.ts.map +1 -0
  367. package/dist/team/coordination-protocol.js +244 -0
  368. package/dist/team/coordination-protocol.js.map +1 -0
  369. package/dist/team/runtime.d.ts +1 -0
  370. package/dist/team/runtime.d.ts.map +1 -1
  371. package/dist/team/runtime.js +19 -3
  372. package/dist/team/runtime.js.map +1 -1
  373. package/dist/team/scaling.d.ts.map +1 -1
  374. package/dist/team/scaling.js +3 -2
  375. package/dist/team/scaling.js.map +1 -1
  376. package/dist/team/state/tasks.d.ts.map +1 -1
  377. package/dist/team/state/tasks.js +24 -0
  378. package/dist/team/state/tasks.js.map +1 -1
  379. package/dist/team/state/types.d.ts +21 -1
  380. package/dist/team/state/types.d.ts.map +1 -1
  381. package/dist/team/state/types.js.map +1 -1
  382. package/dist/team/state.d.ts +17 -1
  383. package/dist/team/state.d.ts.map +1 -1
  384. package/dist/team/state.js +12 -5
  385. package/dist/team/state.js.map +1 -1
  386. package/dist/team/team-ops.d.ts +1 -1
  387. package/dist/team/team-ops.d.ts.map +1 -1
  388. package/dist/team/team-ops.js.map +1 -1
  389. package/dist/team/tmux-session.d.ts +2 -0
  390. package/dist/team/tmux-session.d.ts.map +1 -1
  391. package/dist/team/tmux-session.js +161 -13
  392. package/dist/team/tmux-session.js.map +1 -1
  393. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  394. package/dist/team/worker-bootstrap.js +63 -0
  395. package/dist/team/worker-bootstrap.js.map +1 -1
  396. package/dist/utils/__tests__/agents-model-table.test.js +4 -2
  397. package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
  398. package/dist/utils/agents-model-table.d.ts.map +1 -1
  399. package/dist/utils/agents-model-table.js +3 -0
  400. package/dist/utils/agents-model-table.js.map +1 -1
  401. package/dist/verification/__tests__/ci-rust-gates.test.js +81 -1
  402. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  403. package/package.json +8 -8
  404. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  405. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +334 -21
  406. package/plugins/oh-my-codex/hooks/hooks.json +1 -2
  407. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +13 -6
  408. package/plugins/oh-my-codex/skills/code-review/SKILL.md +7 -7
  409. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +9 -4
  410. package/plugins/oh-my-codex/skills/ralph/SKILL.md +22 -22
  411. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +12 -0
  412. package/plugins/oh-my-codex/skills/team/SKILL.md +16 -0
  413. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +9 -0
  414. package/plugins/oh-my-codex/skills/worker/SKILL.md +14 -0
  415. package/skills/autopilot/SKILL.md +13 -6
  416. package/skills/code-review/SKILL.md +7 -7
  417. package/skills/deep-interview/SKILL.md +9 -4
  418. package/skills/ralph/SKILL.md +22 -22
  419. package/skills/ralplan/SKILL.md +12 -0
  420. package/skills/team/SKILL.md +16 -0
  421. package/skills/ultraqa/SKILL.md +9 -0
  422. package/skills/worker/SKILL.md +14 -0
  423. package/src/scripts/__tests__/codex-native-hook.test.ts +4435 -2083
  424. package/src/scripts/__tests__/notify-state-io.test.ts +95 -0
  425. package/src/scripts/__tests__/notify-tmux-injection.test.ts +82 -0
  426. package/src/scripts/__tests__/run-test-files.test.ts +102 -0
  427. package/src/scripts/__tests__/verify-native-agents.test.ts +75 -0
  428. package/src/scripts/codex-native-hook.ts +536 -51
  429. package/src/scripts/codex-native-pre-post.ts +80 -0
  430. package/src/scripts/demo-team-e2e.sh +10 -7
  431. package/src/scripts/eval/eval-parity-smoke.ts +1 -1
  432. package/src/scripts/hook-payload-guard.ts +113 -0
  433. package/src/scripts/notify-fallback-watcher.ts +8 -1
  434. package/src/scripts/notify-hook/__tests__/payload-guard.test.ts +41 -0
  435. package/src/scripts/notify-hook/auto-nudge.ts +3 -1
  436. package/src/scripts/notify-hook/ralph-session-resume.ts +2 -8
  437. package/src/scripts/notify-hook/state-io.ts +75 -37
  438. package/src/scripts/notify-hook/team-leader-nudge.ts +7 -0
  439. package/src/scripts/notify-hook/team-worker-stop.ts +193 -52
  440. package/src/scripts/notify-hook/tmux-injection.ts +35 -19
  441. package/src/scripts/notify-hook.ts +105 -6
  442. package/src/scripts/run-test-files.ts +192 -22
  443. package/src/scripts/sync-plugin-mirror.ts +98 -9
  444. package/src/scripts/verify-native-agents.ts +65 -1
@@ -1223,6 +1223,85 @@ function hasActionableBashHardFailure(normalized: NormalizedPostToolUsePayload):
1223
1223
  return containsHardFailure(`${normalized.stderrText}\n${normalized.stdoutText}`);
1224
1224
  }
1225
1225
 
1226
+ function isShellEnvAssignment(token: string): boolean {
1227
+ return /^[A-Za-z_][A-Za-z0-9_]*=.*/.test(token);
1228
+ }
1229
+
1230
+ function shellCommandBasename(token: string): string {
1231
+ const normalized = token.replace(/\\/g, "/");
1232
+ return (normalized.split("/").pop() || normalized).toLowerCase();
1233
+ }
1234
+
1235
+ function skipEnvWrapper(tokens: string[]): number {
1236
+ let index = 0;
1237
+ while (isShellEnvAssignment(tokens[index] || "")) index += 1;
1238
+ if (!isEnvExecutableToken(tokens[index] || "")) return index;
1239
+
1240
+ index += 1;
1241
+ while (index < tokens.length) {
1242
+ const token = tokens[index] || "";
1243
+ if (token === "--") {
1244
+ index += 1;
1245
+ break;
1246
+ }
1247
+ if (isShellEnvAssignment(token)) {
1248
+ index += 1;
1249
+ continue;
1250
+ }
1251
+ if (envOptionConsumesNextValue(token)) {
1252
+ index += 2;
1253
+ continue;
1254
+ }
1255
+ if (token === "-i" || token === "--ignore-environment" || token.startsWith("-u") && token.length > 2) {
1256
+ index += 1;
1257
+ continue;
1258
+ }
1259
+ break;
1260
+ }
1261
+ return index;
1262
+ }
1263
+
1264
+ function skipGhGlobalOptions(tokens: string[], startIndex: number): number {
1265
+ let index = startIndex;
1266
+ const optionsWithValue = new Set(["--repo", "-R", "--hostname", "--config-dir"]);
1267
+ while (index < tokens.length) {
1268
+ const token = tokens[index] || "";
1269
+ if (optionsWithValue.has(token)) {
1270
+ index += 2;
1271
+ continue;
1272
+ }
1273
+ if (/^(?:--repo|--hostname|--config-dir)=/.test(token)) {
1274
+ index += 1;
1275
+ continue;
1276
+ }
1277
+ if (token.startsWith("-") && token !== "-") {
1278
+ index += 1;
1279
+ continue;
1280
+ }
1281
+ break;
1282
+ }
1283
+ return index;
1284
+ }
1285
+
1286
+ function isReviewableGhPrChecksTokens(tokens: string[]): boolean {
1287
+ const commandIndex = skipEnvWrapper(tokens);
1288
+ const basename = shellCommandBasename(tokens[commandIndex] || "");
1289
+ if (basename !== "gh" && basename !== "gh.exe") return false;
1290
+ const subcommandIndex = skipGhGlobalOptions(tokens, commandIndex + 1);
1291
+ return tokens[subcommandIndex] === "pr" && tokens[subcommandIndex + 1] === "checks";
1292
+ }
1293
+
1294
+ function isReviewableNonZeroBashCommand(command: string): boolean {
1295
+ const boundaryTokens = tokenizeShellCommandWithBoundaries(removeHereDocBodies(command));
1296
+ if (!boundaryTokens) return false;
1297
+ for (let commandStart = 0; commandStart < boundaryTokens.length; commandStart = nextCommandStart(boundaryTokens, commandStart)) {
1298
+ const commandEnd = nextCommandStart(boundaryTokens, commandStart);
1299
+ const commandTokens = boundaryTokens.slice(commandStart, commandEnd).map((candidate) => candidate.value);
1300
+ if (isReviewableGhPrChecksTokens(commandTokens)) return true;
1301
+ }
1302
+ return false;
1303
+ }
1304
+
1226
1305
  export function buildNativePostToolUseOutput(
1227
1306
  payload: CodexHookPayload,
1228
1307
  ): Record<string, unknown> | null {
@@ -1264,6 +1343,7 @@ export function buildNativePostToolUseOutput(
1264
1343
  && normalized.exitCode !== 0
1265
1344
  && combined.length > 0
1266
1345
  && !containsHardFailure(combined)
1346
+ && isReviewableNonZeroBashCommand(normalized.normalizedCommand)
1267
1347
  ) {
1268
1348
  return {
1269
1349
  decision: "block",
@@ -89,10 +89,8 @@ OMX_TEAM_WORKER_LAUNCH_ARGS="${OMX_TEAM_WORKER_LAUNCH_ARGS:--c model_reasoning_e
89
89
  TEAM_STARTED=0
90
90
  cleanup() {
91
91
  if ((TEAM_STARTED == 1)); then
92
- echo "[cleanup] shutting down team: $TEAM_NAME"
93
- omx team shutdown "$TEAM_NAME" >/dev/null 2>&1 || true
94
- echo "[cleanup] cleaning state for team: $TEAM_NAME"
95
- omx team api cleanup --input "{\"team_name\":\"$TEAM_NAME\"}" --json >/dev/null 2>&1 || true
92
+ echo "[cleanup] force-cleaning demo team: $TEAM_NAME"
93
+ omx team api cleanup --input "{\"team_name\":\"$TEAM_NAME\",\"force\":true,\"confirm_issues\":true}" --json >/dev/null 2>&1 || true
96
94
  fi
97
95
  }
98
96
  trap cleanup EXIT
@@ -106,7 +104,13 @@ echo "OMX_TEAM_WORKER_CLI_MAP=$OMX_TEAM_WORKER_CLI_MAP"
106
104
  echo "OMX_TEAM_WORKER_LAUNCH_ARGS=$OMX_TEAM_WORKER_LAUNCH_ARGS"
107
105
 
108
106
  echo "[1/8] start team (${WORKER_COUNT} mixed workers)"
109
- omx team "${WORKER_COUNT}:executor" "$TEAM_TASK"
107
+ START_OUTPUT="$(omx team "${WORKER_COUNT}:executor" "$TEAM_TASK")"
108
+ echo "$START_OUTPUT"
109
+ ACTUAL_TEAM_NAME="$(echo "$START_OUTPUT" | sed -nE 's/^Team started: ([^[:space:]]+)$/\1/p' | head -n 1)"
110
+ if [[ -n "$ACTUAL_TEAM_NAME" && "$ACTUAL_TEAM_NAME" != "$TEAM_NAME" ]]; then
111
+ echo "TEAM_NAME_RESOLVED=$ACTUAL_TEAM_NAME"
112
+ TEAM_NAME="$ACTUAL_TEAM_NAME"
113
+ fi
110
114
  TEAM_STARTED=1
111
115
 
112
116
  echo "[2/8] status"
@@ -174,8 +178,7 @@ SUMMARY_JSON="$(omx team api get-summary --input "$SUMMARY_INPUT" --json)"
174
178
  echo "$SUMMARY_JSON" | jq -e '.schema_version == "1.0" and .operation == "get-summary" and .ok == true' >/dev/null
175
179
 
176
180
  echo "[8/8] shutdown + cleanup"
177
- omx team shutdown "$TEAM_NAME"
178
- omx team api cleanup --input "{\"team_name\":\"$TEAM_NAME\"}" --json >/dev/null
181
+ omx team api cleanup --input "{\"team_name\":\"$TEAM_NAME\",\"force\":true,\"confirm_issues\":true}" --json >/dev/null
179
182
  TEAM_STARTED=0
180
183
 
181
184
  echo "E2E demo complete."
@@ -9,7 +9,7 @@ if (build.status !== 0) {
9
9
  }
10
10
 
11
11
  const test = spawnSync('node', [
12
- '--test',
12
+ 'dist/scripts/run-test-files.js',
13
13
  'dist/autoresearch/__tests__/contracts.test.js',
14
14
  'dist/autoresearch/__tests__/runtime.test.js',
15
15
  'dist/cli/__tests__/autoresearch.test.js',
@@ -0,0 +1,113 @@
1
+ export const MAX_NOTIFY_ARGV_JSON_BYTES = 64 * 1024;
2
+ export const MAX_NATIVE_STDIN_JSON_BYTES = 1024 * 1024;
3
+ export const RAW_JSON_FIELD_SCAN_BYTES = 64 * 1024;
4
+
5
+ export const CODEX_HOOK_EVENT_NAMES = [
6
+ "SessionStart",
7
+ "PreToolUse",
8
+ "PostToolUse",
9
+ "UserPromptSubmit",
10
+ "PreCompact",
11
+ "PostCompact",
12
+ "Stop",
13
+ ] as const;
14
+
15
+ export type RawCodexHookEventName = typeof CODEX_HOOK_EVENT_NAMES[number];
16
+
17
+ export function utf8ByteLength(value: string): number {
18
+ return Buffer.byteLength(value, "utf-8");
19
+ }
20
+
21
+ function skipJsonWhitespace(raw: string, index: number): number {
22
+ while (index < raw.length && /\s/.test(raw[index] ?? "")) index += 1;
23
+ return index;
24
+ }
25
+
26
+ function readJsonStringLiteral(raw: string, quoteIndex: number): { value: string; endIndex: number } | null {
27
+ if (raw[quoteIndex] !== '"') return null;
28
+ let value = "";
29
+ for (let index = quoteIndex + 1; index < raw.length; index += 1) {
30
+ const char = raw[index];
31
+ if (char === '"') return { value, endIndex: index + 1 };
32
+ if (char !== "\\") {
33
+ value += char;
34
+ continue;
35
+ }
36
+
37
+ index += 1;
38
+ if (index >= raw.length) return null;
39
+ const escaped = raw[index];
40
+ switch (escaped) {
41
+ case '"':
42
+ case "\\":
43
+ case "/":
44
+ value += escaped;
45
+ break;
46
+ case "b":
47
+ value += "\b";
48
+ break;
49
+ case "f":
50
+ value += "\f";
51
+ break;
52
+ case "n":
53
+ value += "\n";
54
+ break;
55
+ case "r":
56
+ value += "\r";
57
+ break;
58
+ case "t":
59
+ value += "\t";
60
+ break;
61
+ case "u": {
62
+ const hex = raw.slice(index + 1, index + 5);
63
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
64
+ value += String.fromCharCode(Number.parseInt(hex, 16));
65
+ index += 4;
66
+ break;
67
+ }
68
+ default:
69
+ return null;
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+
75
+ export function extractRawJsonStringField(rawInput: string, fieldNames: readonly string[]): string | null {
76
+ const raw = rawInput.slice(0, RAW_JSON_FIELD_SCAN_BYTES);
77
+ const wanted = new Set(fieldNames);
78
+ let depth = 0;
79
+ let index = 0;
80
+
81
+ while (index < raw.length) {
82
+ const char = raw[index];
83
+ if (char === '"') {
84
+ const key = readJsonStringLiteral(raw, index);
85
+ if (!key) return null;
86
+ index = key.endIndex;
87
+ const afterKey = skipJsonWhitespace(raw, index);
88
+ if (depth === 1 && raw[afterKey] === ":" && wanted.has(key.value)) {
89
+ const valueStart = skipJsonWhitespace(raw, afterKey + 1);
90
+ const value = readJsonStringLiteral(raw, valueStart);
91
+ return value?.value ?? null;
92
+ }
93
+ continue;
94
+ }
95
+ if (char === "{") depth += 1;
96
+ else if (char === "}") depth = Math.max(0, depth - 1);
97
+ index += 1;
98
+ }
99
+
100
+ return null;
101
+ }
102
+
103
+ export function extractRawCodexHookEventName(rawInput: string): RawCodexHookEventName | null {
104
+ const raw = extractRawJsonStringField(rawInput, [
105
+ "hook_event_name",
106
+ "hookEventName",
107
+ "event",
108
+ "name",
109
+ ]);
110
+ return CODEX_HOOK_EVENT_NAMES.includes(raw as RawCodexHookEventName)
111
+ ? raw as RawCodexHookEventName
112
+ : null;
113
+ }
@@ -1963,10 +1963,15 @@ function shutdown(signal: string): void {
1963
1963
  }
1964
1964
 
1965
1965
  async function main(): Promise<void> {
1966
+ if (process.env.NODE_ENV === 'test' && process.env.OMX_NOTIFY_FALLBACK_TEST_FATAL === '1') {
1967
+ throw new Error('test fatal notify fallback failure');
1968
+ }
1966
1969
  await mkdir(logsDir, { recursive: true }).catch(() => {});
1967
1970
  await mkdir(stateDir, { recursive: true }).catch(() => {});
1968
1971
  if (!existsSync(notifyScript)) {
1972
+ const reason = `notify script missing: ${notifyScript}`;
1969
1973
  await eventLog({ type: 'watcher_error', reason: 'notify_script_missing', notify_script: notifyScript });
1974
+ process.stderr.write(`notify-fallback-watcher: ${reason}\n`);
1970
1975
  process.exit(1);
1971
1976
  }
1972
1977
 
@@ -2006,10 +2011,12 @@ async function main(): Promise<void> {
2006
2011
 
2007
2012
  main().catch(async (err) => {
2008
2013
  await mkdir(dirname(logPath), { recursive: true }).catch(() => {});
2014
+ const message = err instanceof Error ? err.message : safeString(err);
2009
2015
  await eventLog({
2010
2016
  type: 'watcher_error',
2011
2017
  reason: 'fatal',
2012
- error: err instanceof Error ? err.message : safeString(err),
2018
+ error: message,
2013
2019
  });
2020
+ process.stderr.write(`notify-fallback-watcher: fatal: ${message || 'unknown error'}\n`);
2014
2021
  process.exit(1);
2015
2022
  });
@@ -0,0 +1,41 @@
1
+ import assert from 'node:assert/strict';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { existsSync } from 'node:fs';
4
+ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ import { describe, it } from 'node:test';
8
+ import { MAX_NOTIFY_ARGV_JSON_BYTES } from '../../hook-payload-guard.js';
9
+
10
+ function notifyHookScriptPath(): string {
11
+ return join(process.cwd(), 'dist', 'scripts', 'notify-hook.js');
12
+ }
13
+
14
+ describe('notify-hook raw payload guard', () => {
15
+ it('ignores oversized argv JSON before parsing or writing hook state', async () => {
16
+ const cwd = await mkdtemp(join(tmpdir(), 'omx-notify-hook-oversized-'));
17
+ try {
18
+ await mkdir(join(cwd, '.omx'), { recursive: true });
19
+ await writeFile(join(cwd, '.omx', 'setup-scope.json'), '{}', 'utf-8');
20
+ const payload = JSON.stringify({
21
+ cwd,
22
+ type: 'agent-turn-complete',
23
+ session_id: 'sess-notify-oversized',
24
+ turn_id: 'turn-notify-oversized',
25
+ input_messages: ['hello'],
26
+ last_assistant_message: 'x'.repeat(MAX_NOTIFY_ARGV_JSON_BYTES + 1),
27
+ });
28
+
29
+ execFileSync(process.execPath, [notifyHookScriptPath(), payload], {
30
+ cwd,
31
+ stdio: ['ignore', 'pipe', 'pipe'],
32
+ env: process.env,
33
+ });
34
+
35
+ assert.equal(existsSync(join(cwd, '.omx', 'logs')), false);
36
+ assert.equal(existsSync(join(cwd, '.omx', 'state')), false);
37
+ } finally {
38
+ await rm(cwd, { recursive: true, force: true });
39
+ }
40
+ });
41
+ });
@@ -269,7 +269,9 @@ export async function syncSkillStateFromTurn(stateDir, payload) {
269
269
 
270
270
 
271
271
  export async function isDeepInterviewStateActive(stateDir, sessionId) {
272
- const modeState = await readScopedJsonIfExists(stateDir, 'deep-interview-state.json', sessionId, null);
272
+ const modeState = typeof sessionId === 'string' && sessionId.trim()
273
+ ? await readScopedJsonIfExists(stateDir, 'deep-interview-state.json', sessionId, null)
274
+ : await readJsonIfExists(join(stateDir, 'deep-interview-state.json'), null);
273
275
  return Boolean(modeState && modeState.active === true);
274
276
  }
275
277
 
@@ -1,8 +1,7 @@
1
1
  import { existsSync } from 'fs';
2
2
  import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'fs/promises';
3
- import { dirname, join, resolve } from 'path';
3
+ import { dirname, join } from 'path';
4
4
  import { captureTmuxPaneFromEnv } from '../../state/mode-state-context.js';
5
- import { isSessionStateUsable } from '../../hooks/session.js';
6
5
  import { resolveCodexPane } from '../tmux-hook-engine.js';
7
6
  import { safeString } from './utils.js';
8
7
 
@@ -222,15 +221,10 @@ function readSessionIdFromEnvironment(env: NodeJS.ProcessEnv = process.env): str
222
221
 
223
222
  async function readCurrentOmxSessionId(stateDir: string, env: NodeJS.ProcessEnv = process.env): Promise<string> {
224
223
  const envSessionId = readSessionIdFromEnvironment(env);
225
- if (envSessionId) {
226
- const envScopedDir = join(stateDir, 'sessions', envSessionId);
227
- if (existsSync(envScopedDir)) return envSessionId;
228
- }
224
+ if (envSessionId) return envSessionId;
229
225
 
230
- const cwd = resolve(stateDir, '..', '..');
231
226
  const session = await readJson(join(stateDir, 'session.json'));
232
227
  if (!session || typeof session !== 'object') return '';
233
- if (!isSessionStateUsable(session as any, cwd)) return '';
234
228
  const sessionId = safeString(session?.session_id).trim();
235
229
  return SESSION_ID_PATTERN.test(sessionId) ? sessionId : '';
236
230
  }
@@ -3,12 +3,10 @@
3
3
  */
4
4
 
5
5
  import { mkdir, readFile, readdir, writeFile } from 'fs/promises';
6
- import { dirname, join, resolve } from 'path';
7
- import { existsSync } from 'fs';
8
- import { isSessionStateUsable } from '../../hooks/session.js';
6
+ import { dirname, join } from 'path';
7
+ import { validateSessionId } from '../../mcp/state-paths.js';
9
8
  import { asNumber, safeString } from './utils.js';
10
9
 
11
- const SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
12
10
 
13
11
  export { readdir };
14
12
 
@@ -25,46 +23,90 @@ function isSafeStateFileName(fileName: string): boolean {
25
23
  && !fileName.includes('\\');
26
24
  }
27
25
 
28
- function readSessionIdFromEnvironment(env: NodeJS.ProcessEnv = process.env): string | undefined {
29
- const candidates = [env.OMX_SESSION_ID, env.CODEX_SESSION_ID, env.SESSION_ID];
30
- for (const candidate of candidates) {
31
- const sessionId = safeString(candidate).trim();
32
- if (!SESSION_ID_PATTERN.test(sessionId)) continue;
33
- return sessionId;
26
+ interface SessionMetadata {
27
+ sessionId?: string;
28
+ nativeAliases: string[];
29
+ }
30
+
31
+ async function readSessionMetadataFromBaseStateDir(baseStateDir: string): Promise<SessionMetadata> {
32
+ const session = await readJsonIfExists(join(baseStateDir, 'session.json'), null);
33
+ let sessionId: string | undefined;
34
+ try {
35
+ sessionId = validateSessionId(session?.session_id);
36
+ } catch {
37
+ sessionId = undefined;
34
38
  }
35
- return undefined;
39
+ const nativeAliases = [
40
+ session?.native_session_id,
41
+ session?.codex_session_id,
42
+ session?.previous_native_session_id,
43
+ ]
44
+ .map((value) => safeString(value).trim())
45
+ .filter(Boolean);
46
+ return { sessionId, nativeAliases: [...new Set(nativeAliases)] };
36
47
  }
37
48
 
38
- export async function readCurrentSessionId(baseStateDir: string): Promise<string | undefined> {
39
- const envSessionId = readSessionIdFromEnvironment();
40
- if (envSessionId) {
41
- const envScopedDir = join(baseStateDir, 'sessions', envSessionId);
42
- if (existsSync(envScopedDir)) return envSessionId;
49
+ function readSessionIdFromEnvironment(): string | undefined {
50
+ for (const candidate of [process.env.OMX_SESSION_ID, process.env.CODEX_SESSION_ID, process.env.SESSION_ID]) {
51
+ if (typeof candidate !== 'string') continue;
52
+ const trimmed = candidate.trim();
53
+ if (!trimmed) continue;
54
+ try {
55
+ const sessionId = validateSessionId(trimmed);
56
+ if (sessionId) return sessionId;
57
+ } catch {
58
+ continue;
59
+ }
43
60
  }
61
+ return undefined;
62
+ }
44
63
 
45
- const cwd = resolve(baseStateDir, '..', '..');
46
- const session = await readJsonIfExists(join(baseStateDir, 'session.json'), null);
47
- if (!session || typeof session !== 'object') return undefined;
48
- if (!isSessionStateUsable(session, cwd)) return undefined;
49
- const sessionId = safeString(session?.session_id);
50
- return SESSION_ID_PATTERN.test(sessionId) ? sessionId : undefined;
64
+ function resolveCanonicalSessionId(candidate: string | undefined, metadata: SessionMetadata): string | undefined {
65
+ if (!candidate) return undefined;
66
+ return metadata.sessionId && metadata.nativeAliases.includes(candidate)
67
+ ? metadata.sessionId
68
+ : candidate;
51
69
  }
52
70
 
53
- export async function resolveScopedStateDir(
71
+ async function resolveBaseScopedStateDir(
54
72
  baseStateDir: string,
55
73
  explicitSessionId?: string,
56
74
  ): Promise<string> {
57
- const normalizedExplicit = safeString(explicitSessionId).trim();
58
- if (SESSION_ID_PATTERN.test(normalizedExplicit)) {
59
- return join(baseStateDir, 'sessions', normalizedExplicit);
60
- }
75
+ const normalizedExplicit = typeof explicitSessionId === 'string' && explicitSessionId.trim()
76
+ ? explicitSessionId.trim()
77
+ : undefined;
78
+ const validatedExplicit = validateSessionId(normalizedExplicit);
79
+ const metadata = await readSessionMetadataFromBaseStateDir(baseStateDir);
80
+ const sessionId = resolveCanonicalSessionId(validatedExplicit, metadata)
81
+ ?? resolveCanonicalSessionId(readSessionIdFromEnvironment(), metadata)
82
+ ?? metadata.sessionId;
83
+ return sessionId ? join(baseStateDir, 'sessions', sessionId) : baseStateDir;
84
+ }
61
85
 
62
- const currentSessionId = await readCurrentSessionId(baseStateDir);
63
- if (currentSessionId) {
64
- return join(baseStateDir, 'sessions', currentSessionId);
65
- }
86
+ async function resolveBaseScopedStateDirs(
87
+ baseStateDir: string,
88
+ explicitSessionId?: string,
89
+ options: { includeRootFallback?: boolean } = {},
90
+ ): Promise<string[]> {
91
+ const scopedDir = await resolveBaseScopedStateDir(baseStateDir, explicitSessionId);
92
+ return options.includeRootFallback === true && scopedDir !== baseStateDir
93
+ ? [scopedDir, baseStateDir]
94
+ : [scopedDir];
95
+ }
96
+
97
+
98
+
99
+
100
+ export async function readCurrentSessionId(baseStateDir: string): Promise<string | undefined> {
101
+ const metadata = await readSessionMetadataFromBaseStateDir(baseStateDir);
102
+ return resolveCanonicalSessionId(readSessionIdFromEnvironment(), metadata) ?? metadata.sessionId;
103
+ }
66
104
 
67
- return baseStateDir;
105
+ export async function resolveScopedStateDir(
106
+ baseStateDir: string,
107
+ explicitSessionId?: string,
108
+ ): Promise<string> {
109
+ return resolveBaseScopedStateDir(baseStateDir, explicitSessionId);
68
110
  }
69
111
 
70
112
  export async function getScopedStateDirsForCurrentSession(
@@ -72,11 +114,7 @@ export async function getScopedStateDirsForCurrentSession(
72
114
  explicitSessionId?: string,
73
115
  options: { includeRootFallback?: boolean } = {},
74
116
  ): Promise<string[]> {
75
- const scopedDir = await resolveScopedStateDir(baseStateDir, explicitSessionId);
76
- if (scopedDir === baseStateDir || options.includeRootFallback !== true) {
77
- return [scopedDir];
78
- }
79
- return [scopedDir, baseStateDir];
117
+ return resolveBaseScopedStateDirs(baseStateDir, explicitSessionId, options);
80
118
  }
81
119
 
82
120
  export async function getScopedStatePath(
@@ -25,6 +25,7 @@ import { writeTeamLeaderAttention } from '../../team/state.js';
25
25
  import { readLatestTeamProgressEvidenceMs } from '../../team/progress-evidence.js';
26
26
  import { validateSessionId } from '../../mcp/state-paths.js';
27
27
  import { TEAM_NAME_SAFE_PATTERN } from '../../team/contracts.js';
28
+ import { isDeepInterviewStateActive } from './auto-nudge.js';
28
29
  const LEADER_PANE_MISSING_NO_INJECTION_REASON = 'leader_pane_missing_no_injection';
29
30
  const LEADER_PANE_SHELL_NO_INJECTION_REASON = 'leader_pane_shell_no_injection';
30
31
  const LEADER_PANE_SAME_CLASSIFIED_STATE_SUPPRESSED_REASON = 'pane_already_shows_same_classified_state';
@@ -571,6 +572,12 @@ export async function maybeNudgeTeamLeader({
571
572
 
572
573
  const candidateTeamNames = new Set();
573
574
  const currentSessionId = await resolveCurrentSessionId(stateDir);
575
+ const deepInterviewActive = currentSessionId
576
+ ? await isDeepInterviewStateActive(stateDir, currentSessionId).catch(() => false)
577
+ : await isDeepInterviewStateActive(stateDir, undefined).catch(() => false);
578
+ if (deepInterviewActive) {
579
+ return;
580
+ }
574
581
  try {
575
582
  const scopedDirs = await getScopedStateDirsForCurrentSession(stateDir);
576
583
  const candidateStateDirs = [...new Set([...scopedDirs, stateDir])];