oh-my-codex 0.18.7 → 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 (259) hide show
  1. package/Cargo.lock +6 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +5 -5
  4. package/crates/omx-sparkshell/tests/execution.rs +1 -1
  5. package/dist/agents/__tests__/native-config.test.js +42 -1
  6. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  7. package/dist/agents/definitions.d.ts +8 -0
  8. package/dist/agents/definitions.d.ts.map +1 -1
  9. package/dist/agents/definitions.js +1 -0
  10. package/dist/agents/definitions.js.map +1 -1
  11. package/dist/agents/native-config.d.ts +5 -1
  12. package/dist/agents/native-config.d.ts.map +1 -1
  13. package/dist/agents/native-config.js +17 -2
  14. package/dist/agents/native-config.js.map +1 -1
  15. package/dist/cli/__tests__/codex-plugin-layout.test.js +512 -1
  16. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  17. package/dist/cli/__tests__/doctor-warning-copy.test.js +39 -0
  18. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  19. package/dist/cli/__tests__/index.test.js +61 -5
  20. package/dist/cli/__tests__/index.test.js.map +1 -1
  21. package/dist/cli/__tests__/package-bin-contract.test.js +8 -4
  22. package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
  23. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +13 -0
  24. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  25. package/dist/cli/__tests__/ralph.test.js +14 -0
  26. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  27. package/dist/cli/__tests__/setup-install-mode.test.js +89 -0
  28. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  29. package/dist/cli/__tests__/setup-refresh.test.js +65 -0
  30. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  31. package/dist/cli/__tests__/state.test.js +21 -0
  32. package/dist/cli/__tests__/state.test.js.map +1 -1
  33. package/dist/cli/__tests__/team.test.js +2 -2
  34. package/dist/cli/__tests__/update.test.js +110 -2
  35. package/dist/cli/__tests__/update.test.js.map +1 -1
  36. package/dist/cli/doctor.d.ts.map +1 -1
  37. package/dist/cli/doctor.js +8 -1
  38. package/dist/cli/doctor.js.map +1 -1
  39. package/dist/cli/index.d.ts +11 -2
  40. package/dist/cli/index.d.ts.map +1 -1
  41. package/dist/cli/index.js +108 -15
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/cli/plugin-marketplace.d.ts +14 -2
  44. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  45. package/dist/cli/plugin-marketplace.js +62 -15
  46. package/dist/cli/plugin-marketplace.js.map +1 -1
  47. package/dist/cli/ralph.d.ts.map +1 -1
  48. package/dist/cli/ralph.js +3 -1
  49. package/dist/cli/ralph.js.map +1 -1
  50. package/dist/cli/setup-preferences.d.ts +2 -0
  51. package/dist/cli/setup-preferences.d.ts.map +1 -1
  52. package/dist/cli/setup-preferences.js +4 -0
  53. package/dist/cli/setup-preferences.js.map +1 -1
  54. package/dist/cli/setup.d.ts +3 -0
  55. package/dist/cli/setup.d.ts.map +1 -1
  56. package/dist/cli/setup.js +166 -27
  57. package/dist/cli/setup.js.map +1 -1
  58. package/dist/cli/state.d.ts.map +1 -1
  59. package/dist/cli/state.js +8 -1
  60. package/dist/cli/state.js.map +1 -1
  61. package/dist/cli/tmux-hook.d.ts.map +1 -1
  62. package/dist/cli/tmux-hook.js +16 -0
  63. package/dist/cli/tmux-hook.js.map +1 -1
  64. package/dist/cli/update.d.ts +2 -0
  65. package/dist/cli/update.d.ts.map +1 -1
  66. package/dist/cli/update.js +47 -3
  67. package/dist/cli/update.js.map +1 -1
  68. package/dist/config/__tests__/generator-notify.test.js +1 -0
  69. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  70. package/dist/config/generator.d.ts +2 -2
  71. package/dist/config/generator.d.ts.map +1 -1
  72. package/dist/config/generator.js +2 -2
  73. package/dist/config/generator.js.map +1 -1
  74. package/dist/config/team-mode.d.ts +12 -0
  75. package/dist/config/team-mode.d.ts.map +1 -0
  76. package/dist/config/team-mode.js +91 -0
  77. package/dist/config/team-mode.js.map +1 -0
  78. package/dist/hooks/__tests__/agents-overlay.test.js +88 -0
  79. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  80. package/dist/hooks/__tests__/code-review-skill-contract.test.js +8 -0
  81. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
  82. package/dist/hooks/__tests__/keyword-detector.test.js +423 -3
  83. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  84. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +1 -1
  85. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  86. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +189 -0
  87. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  88. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +35 -2
  89. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  90. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +3 -3
  91. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  92. package/dist/hooks/__tests__/skill-guidance-contract.test.js +21 -0
  93. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
  94. package/dist/hooks/agents-overlay.d.ts.map +1 -1
  95. package/dist/hooks/agents-overlay.js +36 -50
  96. package/dist/hooks/agents-overlay.js.map +1 -1
  97. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +31 -0
  98. package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -1
  99. package/dist/hooks/extensibility/plugin-runner.js +17 -21
  100. package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
  101. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  102. package/dist/hooks/keyword-detector.js +258 -12
  103. package/dist/hooks/keyword-detector.js.map +1 -1
  104. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  105. package/dist/hooks/prompt-guidance-contract.js +6 -0
  106. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  107. package/dist/hooks/session.d.ts +1 -0
  108. package/dist/hooks/session.d.ts.map +1 -1
  109. package/dist/hooks/session.js.map +1 -1
  110. package/dist/hud/__tests__/authority.test.js +435 -32
  111. package/dist/hud/__tests__/authority.test.js.map +1 -1
  112. package/dist/hud/__tests__/hud-tmux-injection.test.js +2 -1
  113. package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
  114. package/dist/hud/__tests__/index.test.js +42 -0
  115. package/dist/hud/__tests__/index.test.js.map +1 -1
  116. package/dist/hud/__tests__/reconcile.test.js +521 -15
  117. package/dist/hud/__tests__/reconcile.test.js.map +1 -1
  118. package/dist/hud/__tests__/render.test.js +61 -0
  119. package/dist/hud/__tests__/render.test.js.map +1 -1
  120. package/dist/hud/__tests__/state.test.js +132 -4
  121. package/dist/hud/__tests__/state.test.js.map +1 -1
  122. package/dist/hud/__tests__/tmux.test.js +180 -21
  123. package/dist/hud/__tests__/tmux.test.js.map +1 -1
  124. package/dist/hud/authority.d.ts +5 -0
  125. package/dist/hud/authority.d.ts.map +1 -1
  126. package/dist/hud/authority.js +324 -28
  127. package/dist/hud/authority.js.map +1 -1
  128. package/dist/hud/index.d.ts +3 -2
  129. package/dist/hud/index.d.ts.map +1 -1
  130. package/dist/hud/index.js +42 -19
  131. package/dist/hud/index.js.map +1 -1
  132. package/dist/hud/reconcile.d.ts +3 -3
  133. package/dist/hud/reconcile.d.ts.map +1 -1
  134. package/dist/hud/reconcile.js +128 -19
  135. package/dist/hud/reconcile.js.map +1 -1
  136. package/dist/hud/render.d.ts.map +1 -1
  137. package/dist/hud/render.js +35 -0
  138. package/dist/hud/render.js.map +1 -1
  139. package/dist/hud/state.d.ts.map +1 -1
  140. package/dist/hud/state.js +61 -62
  141. package/dist/hud/state.js.map +1 -1
  142. package/dist/hud/tmux.d.ts +24 -6
  143. package/dist/hud/tmux.d.ts.map +1 -1
  144. package/dist/hud/tmux.js +136 -38
  145. package/dist/hud/tmux.js.map +1 -1
  146. package/dist/hud/types.d.ts +11 -0
  147. package/dist/hud/types.d.ts.map +1 -1
  148. package/dist/hud/types.js.map +1 -1
  149. package/dist/mcp/__tests__/state-paths.test.js +71 -1
  150. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  151. package/dist/mcp/state-paths.d.ts +32 -0
  152. package/dist/mcp/state-paths.d.ts.map +1 -1
  153. package/dist/mcp/state-paths.js +113 -17
  154. package/dist/mcp/state-paths.js.map +1 -1
  155. package/dist/mcp/state-server.d.ts +4 -4
  156. package/dist/scripts/__tests__/codex-native-hook.test.js +593 -11
  157. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  158. package/dist/scripts/__tests__/notify-state-io.test.js +72 -1
  159. package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
  160. package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts +2 -0
  161. package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts.map +1 -0
  162. package/dist/scripts/__tests__/notify-tmux-injection.test.js +57 -0
  163. package/dist/scripts/__tests__/notify-tmux-injection.test.js.map +1 -0
  164. package/dist/scripts/__tests__/run-test-files.test.js +74 -0
  165. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  166. package/dist/scripts/__tests__/verify-native-agents.test.js +65 -0
  167. package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
  168. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  169. package/dist/scripts/codex-native-hook.js +88 -31
  170. package/dist/scripts/codex-native-hook.js.map +1 -1
  171. package/dist/scripts/eval/eval-parity-smoke.js +1 -1
  172. package/dist/scripts/eval/eval-parity-smoke.js.map +1 -1
  173. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  174. package/dist/scripts/notify-hook/auto-nudge.js +3 -1
  175. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  176. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  177. package/dist/scripts/notify-hook/ralph-session-resume.js +3 -10
  178. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  179. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  180. package/dist/scripts/notify-hook/state-io.js +62 -38
  181. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  182. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  183. package/dist/scripts/notify-hook/team-leader-nudge.js +7 -0
  184. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  185. package/dist/scripts/notify-hook/tmux-injection.d.ts +7 -0
  186. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  187. package/dist/scripts/notify-hook/tmux-injection.js +24 -18
  188. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  189. package/dist/scripts/notify-hook.js +75 -11
  190. package/dist/scripts/notify-hook.js.map +1 -1
  191. package/dist/scripts/run-test-files.js +193 -22
  192. package/dist/scripts/run-test-files.js.map +1 -1
  193. package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
  194. package/dist/scripts/sync-plugin-mirror.js +61 -3
  195. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  196. package/dist/scripts/verify-native-agents.d.ts.map +1 -1
  197. package/dist/scripts/verify-native-agents.js +58 -1
  198. package/dist/scripts/verify-native-agents.js.map +1 -1
  199. package/dist/state/__tests__/operations.test.js +113 -0
  200. package/dist/state/__tests__/operations.test.js.map +1 -1
  201. package/dist/state/__tests__/skill-active.test.js +3 -16
  202. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  203. package/dist/state/__tests__/workflow-transition.test.js +25 -0
  204. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  205. package/dist/state/operations.d.ts.map +1 -1
  206. package/dist/state/operations.js +57 -2
  207. package/dist/state/operations.js.map +1 -1
  208. package/dist/state/skill-active.d.ts.map +1 -1
  209. package/dist/state/skill-active.js +7 -39
  210. package/dist/state/skill-active.js.map +1 -1
  211. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  212. package/dist/state/workflow-transition-reconcile.js +10 -14
  213. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  214. package/dist/team/__tests__/runtime.test.js +1 -1
  215. package/dist/team/__tests__/runtime.test.js.map +1 -1
  216. package/dist/team/__tests__/scaling.test.js +9 -4
  217. package/dist/team/__tests__/scaling.test.js.map +1 -1
  218. package/dist/team/__tests__/tmux-session.test.js +195 -2
  219. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  220. package/dist/team/__tests__/worker-runtime-identity.test.js +4 -2
  221. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  222. package/dist/team/scaling.d.ts.map +1 -1
  223. package/dist/team/scaling.js +3 -2
  224. package/dist/team/scaling.js.map +1 -1
  225. package/dist/team/tmux-session.d.ts +2 -0
  226. package/dist/team/tmux-session.d.ts.map +1 -1
  227. package/dist/team/tmux-session.js +142 -12
  228. package/dist/team/tmux-session.js.map +1 -1
  229. package/dist/verification/__tests__/ci-rust-gates.test.js +81 -1
  230. package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
  231. package/package.json +8 -8
  232. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  233. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +334 -21
  234. package/plugins/oh-my-codex/hooks/hooks.json +1 -2
  235. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +3 -1
  236. package/plugins/oh-my-codex/skills/code-review/SKILL.md +7 -7
  237. package/plugins/oh-my-codex/skills/ralph/SKILL.md +22 -22
  238. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +9 -0
  239. package/skills/autopilot/SKILL.md +3 -1
  240. package/skills/code-review/SKILL.md +7 -7
  241. package/skills/ralph/SKILL.md +22 -22
  242. package/skills/ultraqa/SKILL.md +9 -0
  243. package/src/scripts/__tests__/codex-native-hook.test.ts +686 -13
  244. package/src/scripts/__tests__/notify-state-io.test.ts +95 -0
  245. package/src/scripts/__tests__/notify-tmux-injection.test.ts +82 -0
  246. package/src/scripts/__tests__/run-test-files.test.ts +102 -0
  247. package/src/scripts/__tests__/verify-native-agents.test.ts +75 -0
  248. package/src/scripts/codex-native-hook.ts +105 -28
  249. package/src/scripts/demo-team-e2e.sh +10 -7
  250. package/src/scripts/eval/eval-parity-smoke.ts +1 -1
  251. package/src/scripts/notify-hook/auto-nudge.ts +3 -1
  252. package/src/scripts/notify-hook/ralph-session-resume.ts +2 -8
  253. package/src/scripts/notify-hook/state-io.ts +75 -37
  254. package/src/scripts/notify-hook/team-leader-nudge.ts +7 -0
  255. package/src/scripts/notify-hook/tmux-injection.ts +35 -19
  256. package/src/scripts/notify-hook.ts +91 -4
  257. package/src/scripts/run-test-files.ts +192 -22
  258. package/src/scripts/sync-plugin-mirror.ts +98 -9
  259. package/src/scripts/verify-native-agents.ts +65 -1
@@ -1634,6 +1634,195 @@ exit 0
1634
1634
  assert.ok(nudgeState.lastNudgeAt, 'should have lastNudgeAt timestamp');
1635
1635
  });
1636
1636
  });
1637
+ it('does not reactivate completed autopilot from terminal turn replay', async () => {
1638
+ await withTempWorkingDir(async (cwd) => {
1639
+ const omxDir = join(cwd, '.omx');
1640
+ const stateDir = join(omxDir, 'state');
1641
+ const logsDir = join(omxDir, 'logs');
1642
+ const codexHome = join(cwd, 'codex-home');
1643
+ const fakeBinDir = join(cwd, 'fake-bin');
1644
+ const sessionStateDir = join(stateDir, 'sessions', 'sess-managed');
1645
+ const terminalCompletedAt = '2026-05-31T20:24:39.005Z';
1646
+ await mkdir(logsDir, { recursive: true });
1647
+ await mkdir(sessionStateDir, { recursive: true });
1648
+ await mkdir(codexHome, { recursive: true });
1649
+ await mkdir(fakeBinDir, { recursive: true });
1650
+ await writeJson(join(codexHome, '.omx-config.json'), {
1651
+ autoNudge: { enabled: true, delaySec: 0, stallMs: 0 },
1652
+ });
1653
+ await writeManagedSessionState(stateDir, cwd);
1654
+ await writeJson(join(sessionStateDir, 'autopilot-state.json'), {
1655
+ mode: 'autopilot',
1656
+ active: false,
1657
+ current_phase: 'complete',
1658
+ completed_at: terminalCompletedAt,
1659
+ stop_reason: 'completed',
1660
+ session_id: 'sess-managed',
1661
+ thread_id: 'thread-autopilot-complete',
1662
+ turn_id: 'turn-autopilot-complete',
1663
+ iteration: 7,
1664
+ max_iterations: 10,
1665
+ review_cycle: 1,
1666
+ });
1667
+ await writeJson(join(sessionStateDir, 'skill-active-state.json'), {
1668
+ version: 1,
1669
+ active: false,
1670
+ skill: 'autopilot',
1671
+ keyword: '$autopilot',
1672
+ phase: 'completing',
1673
+ activated_at: '2026-05-31T19:28:04.651Z',
1674
+ updated_at: terminalCompletedAt,
1675
+ source: 'keyword-detector',
1676
+ session_id: 'sess-managed',
1677
+ thread_id: 'thread-autopilot-complete',
1678
+ turn_id: 'turn-autopilot-complete',
1679
+ active_skills: [],
1680
+ });
1681
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(join(cwd, 'tmux.log')));
1682
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1683
+ const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
1684
+ type: 'agent-turn-complete',
1685
+ 'thread-id': 'thread-autopilot-complete',
1686
+ 'turn-id': 'turn-autopilot-complete',
1687
+ 'input-messages': ['$autopilot .omx/specs/hermes-intake-librarian-subagent-mcp.md'],
1688
+ 'last-assistant-message': 'Autopilot complete. Committed:\n- 93302d4b2 enable profile-scoped MCP delegation without leaking tools',
1689
+ });
1690
+ assert.equal(result.status, 0, `hook failed: ${result.stderr || result.stdout}`);
1691
+ const autopilotState = JSON.parse(await readFile(join(sessionStateDir, 'autopilot-state.json'), 'utf-8'));
1692
+ assert.equal(autopilotState.active, false);
1693
+ assert.equal(autopilotState.current_phase, 'complete');
1694
+ assert.equal(autopilotState.completed_at, terminalCompletedAt);
1695
+ assert.equal(autopilotState.started_at, undefined);
1696
+ assert.equal(autopilotState.iteration, 7);
1697
+ const skillState = JSON.parse(await readFile(join(sessionStateDir, 'skill-active-state.json'), 'utf-8'));
1698
+ assert.equal(skillState.active, false);
1699
+ assert.equal(skillState.phase, 'completing');
1700
+ assert.equal(skillState.active_skills?.length ?? 0, 0);
1701
+ });
1702
+ });
1703
+ it('does not reactivate completed autopilot from canonical terminal replay wording', async () => {
1704
+ await withTempWorkingDir(async (cwd) => {
1705
+ const omxDir = join(cwd, '.omx');
1706
+ const stateDir = join(omxDir, 'state');
1707
+ const logsDir = join(omxDir, 'logs');
1708
+ const codexHome = join(cwd, 'codex-home');
1709
+ const fakeBinDir = join(cwd, 'fake-bin');
1710
+ const sessionStateDir = join(stateDir, 'sessions', 'sess-managed');
1711
+ const terminalCompletedAt = '2026-05-31T20:24:39.005Z';
1712
+ await mkdir(logsDir, { recursive: true });
1713
+ await mkdir(sessionStateDir, { recursive: true });
1714
+ await mkdir(codexHome, { recursive: true });
1715
+ await mkdir(fakeBinDir, { recursive: true });
1716
+ await writeJson(join(codexHome, '.omx-config.json'), {
1717
+ autoNudge: { enabled: true, delaySec: 0, stallMs: 0 },
1718
+ });
1719
+ await writeManagedSessionState(stateDir, cwd);
1720
+ await writeJson(join(sessionStateDir, 'autopilot-state.json'), {
1721
+ mode: 'autopilot',
1722
+ active: false,
1723
+ current_phase: 'complete',
1724
+ completed_at: terminalCompletedAt,
1725
+ thread_id: 'thread-autopilot-complete',
1726
+ turn_id: 'turn-autopilot-complete',
1727
+ });
1728
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(join(cwd, 'tmux.log')));
1729
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1730
+ const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
1731
+ type: 'agent-turn-complete',
1732
+ 'thread-id': 'thread-autopilot-complete',
1733
+ 'turn-id': 'turn-autopilot-complete',
1734
+ 'input-messages': ['autopilot mode'],
1735
+ 'last-assistant-message': 'Autopilot completed successfully.',
1736
+ });
1737
+ assert.equal(result.status, 0, `hook failed: ${result.stderr || result.stdout}`);
1738
+ const autopilotState = JSON.parse(await readFile(join(sessionStateDir, 'autopilot-state.json'), 'utf-8'));
1739
+ assert.equal(autopilotState.active, false);
1740
+ assert.equal(autopilotState.current_phase, 'complete');
1741
+ assert.equal(autopilotState.completed_at, terminalCompletedAt);
1742
+ });
1743
+ });
1744
+ it('does not reactivate completed autopilot from registry-alias terminal replay', async () => {
1745
+ await withTempWorkingDir(async (cwd) => {
1746
+ const omxDir = join(cwd, '.omx');
1747
+ const stateDir = join(omxDir, 'state');
1748
+ const logsDir = join(omxDir, 'logs');
1749
+ const codexHome = join(cwd, 'codex-home');
1750
+ const fakeBinDir = join(cwd, 'fake-bin');
1751
+ const sessionStateDir = join(stateDir, 'sessions', 'sess-managed');
1752
+ const terminalCompletedAt = '2026-05-31T20:24:39.005Z';
1753
+ await mkdir(logsDir, { recursive: true });
1754
+ await mkdir(sessionStateDir, { recursive: true });
1755
+ await mkdir(codexHome, { recursive: true });
1756
+ await mkdir(fakeBinDir, { recursive: true });
1757
+ await writeJson(join(codexHome, '.omx-config.json'), {
1758
+ autoNudge: { enabled: true, delaySec: 0, stallMs: 0 },
1759
+ });
1760
+ await writeManagedSessionState(stateDir, cwd);
1761
+ await writeJson(join(sessionStateDir, 'autopilot-state.json'), {
1762
+ mode: 'autopilot',
1763
+ active: false,
1764
+ current_phase: 'complete',
1765
+ completed_at: terminalCompletedAt,
1766
+ thread_id: 'thread-autopilot-complete',
1767
+ turn_id: 'turn-autopilot-complete',
1768
+ });
1769
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(join(cwd, 'tmux.log')));
1770
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1771
+ const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
1772
+ type: 'agent-turn-complete',
1773
+ 'thread-id': 'thread-autopilot-complete',
1774
+ 'turn-id': 'turn-autopilot-complete',
1775
+ 'input-messages': ['build me a terminal replay regression guard'],
1776
+ 'last-assistant-message': 'Autopilot complete. Regression guard shipped.',
1777
+ });
1778
+ assert.equal(result.status, 0, `hook failed: ${result.stderr || result.stdout}`);
1779
+ const autopilotState = JSON.parse(await readFile(join(sessionStateDir, 'autopilot-state.json'), 'utf-8'));
1780
+ assert.equal(autopilotState.active, false);
1781
+ assert.equal(autopilotState.current_phase, 'complete');
1782
+ assert.equal(autopilotState.completed_at, terminalCompletedAt);
1783
+ });
1784
+ });
1785
+ it('allows a later autopilot prompt after completed autopilot state', async () => {
1786
+ await withTempWorkingDir(async (cwd) => {
1787
+ const omxDir = join(cwd, '.omx');
1788
+ const stateDir = join(omxDir, 'state');
1789
+ const logsDir = join(omxDir, 'logs');
1790
+ const codexHome = join(cwd, 'codex-home');
1791
+ const fakeBinDir = join(cwd, 'fake-bin');
1792
+ const sessionStateDir = join(stateDir, 'sessions', 'sess-managed');
1793
+ await mkdir(logsDir, { recursive: true });
1794
+ await mkdir(sessionStateDir, { recursive: true });
1795
+ await mkdir(codexHome, { recursive: true });
1796
+ await mkdir(fakeBinDir, { recursive: true });
1797
+ await writeJson(join(codexHome, '.omx-config.json'), {
1798
+ autoNudge: { enabled: true, delaySec: 0, stallMs: 0 },
1799
+ });
1800
+ await writeManagedSessionState(stateDir, cwd);
1801
+ await writeJson(join(sessionStateDir, 'autopilot-state.json'), {
1802
+ mode: 'autopilot',
1803
+ active: false,
1804
+ current_phase: 'complete',
1805
+ completed_at: '2026-05-31T20:24:39.005Z',
1806
+ thread_id: 'thread-autopilot-complete',
1807
+ turn_id: 'turn-autopilot-complete',
1808
+ });
1809
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(join(cwd, 'tmux.log')));
1810
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1811
+ const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
1812
+ type: 'agent-turn-complete',
1813
+ 'thread-id': 'thread-autopilot-complete',
1814
+ 'turn-id': 'turn-later-autopilot-start',
1815
+ 'input-messages': ['$autopilot .omx/specs/next-task.md'],
1816
+ 'last-assistant-message': 'Autopilot complete replay text from a different turn should not suppress this activation.',
1817
+ });
1818
+ assert.equal(result.status, 0, `hook failed: ${result.stderr || result.stdout}`);
1819
+ const autopilotState = JSON.parse(await readFile(join(sessionStateDir, 'autopilot-state.json'), 'utf-8'));
1820
+ assert.equal(autopilotState.active, true);
1821
+ assert.equal(autopilotState.current_phase, 'deep-interview');
1822
+ assert.equal(autopilotState.completed_at, undefined);
1823
+ assert.equal(autopilotState.turn_id, 'turn-later-autopilot-start');
1824
+ });
1825
+ });
1637
1826
  it('writes skill-active-state.json when keyword activation is detected', async () => {
1638
1827
  await withTempWorkingDir(async (cwd) => {
1639
1828
  const omxDir = join(cwd, '.omx');