oh-my-codex 0.20.1 → 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 (791) hide show
  1. package/Cargo.lock +7 -6
  2. package/Cargo.toml +1 -1
  3. package/README.md +36 -1
  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/adapt/__tests__/hermes.test.js.map +1 -1
  11. package/dist/adapt/contracts.d.ts.map +1 -1
  12. package/dist/agents/__tests__/definitions.test.js +81 -0
  13. package/dist/agents/__tests__/definitions.test.js.map +1 -1
  14. package/dist/agents/__tests__/native-config.test.js +25 -0
  15. package/dist/agents/__tests__/native-config.test.js.map +1 -1
  16. package/dist/agents/native-config.d.ts +2 -1
  17. package/dist/agents/native-config.d.ts.map +1 -1
  18. package/dist/agents/native-config.js.map +1 -1
  19. package/dist/auth/__tests__/hotswap.test.d.ts +2 -0
  20. package/dist/auth/__tests__/hotswap.test.d.ts.map +1 -0
  21. package/dist/auth/__tests__/hotswap.test.js +183 -0
  22. package/dist/auth/__tests__/hotswap.test.js.map +1 -0
  23. package/dist/auth/hotswap.d.ts +6 -0
  24. package/dist/auth/hotswap.d.ts.map +1 -1
  25. package/dist/auth/hotswap.js +102 -19
  26. package/dist/auth/hotswap.js.map +1 -1
  27. package/dist/auth/paths.js.map +1 -1
  28. package/dist/auth/storage.js.map +1 -1
  29. package/dist/autopilot/__tests__/ralplan-gate.test.js +5 -5
  30. package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
  31. package/dist/autopilot/completion-gate.js.map +1 -1
  32. package/dist/autopilot/fsm.d.ts +1 -1
  33. package/dist/autopilot/fsm.d.ts.map +1 -1
  34. package/dist/autoresearch/goal.js.map +1 -1
  35. package/dist/autoresearch/runtime.js.map +1 -1
  36. package/dist/capabilities/lockfile.js.map +1 -1
  37. package/dist/catalog/reader.js.map +1 -1
  38. package/dist/catalog/skill-mirror.js.map +1 -1
  39. package/dist/cli/__tests__/adapt-help.test.js.map +1 -1
  40. package/dist/cli/__tests__/agents-init.test.js.map +1 -1
  41. package/dist/cli/__tests__/agents.test.js.map +1 -1
  42. package/dist/cli/__tests__/api.test.js.map +1 -1
  43. package/dist/cli/__tests__/ask.test.js.map +1 -1
  44. package/dist/cli/__tests__/auth.test.js +60 -6
  45. package/dist/cli/__tests__/auth.test.js.map +1 -1
  46. package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
  47. package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
  48. package/dist/cli/__tests__/capabilities.test.js.map +1 -1
  49. package/dist/cli/__tests__/codex-plugin-layout.test.js +80 -0
  50. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  51. package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
  52. package/dist/cli/__tests__/doctor-invalid-config.test.js +47 -4
  53. package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
  54. package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
  55. package/dist/cli/__tests__/doctor-warning-copy.test.js +752 -15
  56. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  57. package/dist/cli/__tests__/exec.test.js +136 -0
  58. package/dist/cli/__tests__/exec.test.js.map +1 -1
  59. package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -1
  60. package/dist/cli/__tests__/index.test.js +473 -14
  61. package/dist/cli/__tests__/index.test.js.map +1 -1
  62. package/dist/cli/__tests__/launch-fallback.test.js +336 -4
  63. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  64. package/dist/cli/__tests__/mcp-parity.test.js +87 -12
  65. package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
  66. package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts +2 -0
  67. package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts.map +1 -0
  68. package/dist/cli/__tests__/native-hook-claim-journal.test.js +206 -0
  69. package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -0
  70. package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
  71. package/dist/cli/__tests__/question.test.js.map +1 -1
  72. package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
  73. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +6 -0
  74. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  75. package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
  76. package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
  77. package/dist/cli/__tests__/ralph.test.js +8 -3
  78. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  79. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts +2 -0
  80. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts.map +1 -0
  81. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +72 -0
  82. package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -0
  83. package/dist/cli/__tests__/ralplan.test.d.ts +2 -0
  84. package/dist/cli/__tests__/ralplan.test.d.ts.map +1 -0
  85. package/dist/cli/__tests__/ralplan.test.js +55 -0
  86. package/dist/cli/__tests__/ralplan.test.js.map +1 -0
  87. package/dist/cli/__tests__/resume.test.js +17 -11
  88. package/dist/cli/__tests__/resume.test.js.map +1 -1
  89. package/dist/cli/__tests__/session-scoped-runtime.test.js +25 -0
  90. package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
  91. package/dist/cli/__tests__/session-search-help.test.js +25 -1
  92. package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
  93. package/dist/cli/__tests__/session-search.test.js.map +1 -1
  94. package/dist/cli/__tests__/setup-agents-overwrite.test.js +79 -0
  95. package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
  96. package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -1
  97. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +77 -3
  98. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
  99. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts +2 -0
  100. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts.map +1 -0
  101. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +285 -0
  102. package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -0
  103. package/dist/cli/__tests__/setup-install-mode.test.js +2579 -294
  104. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  105. package/dist/cli/__tests__/setup-preferences.test.d.ts +2 -0
  106. package/dist/cli/__tests__/setup-preferences.test.d.ts.map +1 -0
  107. package/dist/cli/__tests__/setup-preferences.test.js +79 -0
  108. package/dist/cli/__tests__/setup-preferences.test.js.map +1 -0
  109. package/dist/cli/__tests__/setup-refresh.test.js +33 -2
  110. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  111. package/dist/cli/__tests__/setup-scope.test.js +46 -3
  112. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  113. package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
  114. package/dist/cli/__tests__/state.test.js +37 -0
  115. package/dist/cli/__tests__/state.test.js.map +1 -1
  116. package/dist/cli/__tests__/team.test.js +105 -7
  117. package/dist/cli/__tests__/team.test.js.map +1 -1
  118. package/dist/cli/__tests__/ultragoal.test.js +61 -1
  119. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  120. package/dist/cli/__tests__/uninstall.test.js +1817 -24
  121. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  122. package/dist/cli/__tests__/update.test.js +58 -0
  123. package/dist/cli/__tests__/update.test.js.map +1 -1
  124. package/dist/cli/__tests__/url.test.js.map +1 -1
  125. package/dist/cli/__tests__/windows-popup-loop-contract.test.js +2 -1
  126. package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
  127. package/dist/cli/adapt.js.map +1 -1
  128. package/dist/cli/agents-init.js.map +1 -1
  129. package/dist/cli/agents.js.map +1 -1
  130. package/dist/cli/api.js.map +1 -1
  131. package/dist/cli/ask.d.ts +1 -1
  132. package/dist/cli/ask.d.ts.map +1 -1
  133. package/dist/cli/ask.js.map +1 -1
  134. package/dist/cli/auth.js.map +1 -1
  135. package/dist/cli/autoresearch-guided.js.map +1 -1
  136. package/dist/cli/autoresearch-intake.js.map +1 -1
  137. package/dist/cli/capabilities.js.map +1 -1
  138. package/dist/cli/cleanup.js.map +1 -1
  139. package/dist/cli/codex-feature-probe.js.map +1 -1
  140. package/dist/cli/codex-home.js.map +1 -1
  141. package/dist/cli/doctor.d.ts +21 -0
  142. package/dist/cli/doctor.d.ts.map +1 -1
  143. package/dist/cli/doctor.js +607 -130
  144. package/dist/cli/doctor.js.map +1 -1
  145. package/dist/cli/explore.js.map +1 -1
  146. package/dist/cli/index.d.ts +14 -3
  147. package/dist/cli/index.d.ts.map +1 -1
  148. package/dist/cli/index.js +245 -57
  149. package/dist/cli/index.js.map +1 -1
  150. package/dist/cli/mcp-parity.js +2 -2
  151. package/dist/cli/mcp-parity.js.map +1 -1
  152. package/dist/cli/mcp-serve.js.map +1 -1
  153. package/dist/cli/mission.js.map +1 -1
  154. package/dist/cli/native-assets.js.map +1 -1
  155. package/dist/cli/native-hook-claim-journal.d.ts +29 -0
  156. package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
  157. package/dist/cli/native-hook-claim-journal.js +252 -0
  158. package/dist/cli/native-hook-claim-journal.js.map +1 -0
  159. package/dist/cli/omx.js.map +1 -1
  160. package/dist/cli/plugin-marketplace.js.map +1 -1
  161. package/dist/cli/project-runtime-codex-homes.js.map +1 -1
  162. package/dist/cli/question.js.map +1 -1
  163. package/dist/cli/ralph.d.ts.map +1 -1
  164. package/dist/cli/ralph.js +3 -2
  165. package/dist/cli/ralph.js.map +1 -1
  166. package/dist/cli/ralplan.d.ts +10 -0
  167. package/dist/cli/ralplan.d.ts.map +1 -0
  168. package/dist/cli/ralplan.js +110 -0
  169. package/dist/cli/ralplan.js.map +1 -0
  170. package/dist/cli/session-search.d.ts +5 -0
  171. package/dist/cli/session-search.d.ts.map +1 -1
  172. package/dist/cli/session-search.js +87 -0
  173. package/dist/cli/session-search.js.map +1 -1
  174. package/dist/cli/setup-preferences.d.ts +11 -0
  175. package/dist/cli/setup-preferences.d.ts.map +1 -1
  176. package/dist/cli/setup-preferences.js +32 -0
  177. package/dist/cli/setup-preferences.js.map +1 -1
  178. package/dist/cli/setup.d.ts +58 -0
  179. package/dist/cli/setup.d.ts.map +1 -1
  180. package/dist/cli/setup.js +1450 -398
  181. package/dist/cli/setup.js.map +1 -1
  182. package/dist/cli/sparkshell.js.map +1 -1
  183. package/dist/cli/star-prompt.js.map +1 -1
  184. package/dist/cli/state.d.ts.map +1 -1
  185. package/dist/cli/state.js +2 -1
  186. package/dist/cli/state.js.map +1 -1
  187. package/dist/cli/team.js.map +1 -1
  188. package/dist/cli/ultragoal.d.ts +5 -1
  189. package/dist/cli/ultragoal.d.ts.map +1 -1
  190. package/dist/cli/ultragoal.js +34 -2
  191. package/dist/cli/ultragoal.js.map +1 -1
  192. package/dist/cli/uninstall.d.ts +17 -0
  193. package/dist/cli/uninstall.d.ts.map +1 -1
  194. package/dist/cli/uninstall.js +986 -95
  195. package/dist/cli/uninstall.js.map +1 -1
  196. package/dist/cli/update.d.ts.map +1 -1
  197. package/dist/cli/update.js +8 -1
  198. package/dist/cli/update.js.map +1 -1
  199. package/dist/cli/url.js.map +1 -1
  200. package/dist/compat/__tests__/doctor-contract.test.js +5 -1
  201. package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
  202. package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
  203. package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
  204. package/dist/config/__tests__/codex-hooks.test.js +1287 -11
  205. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  206. package/dist/config/__tests__/generator-idempotent.test.js +1179 -32
  207. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  208. package/dist/config/__tests__/generator-notify.test.js +6 -1
  209. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  210. package/dist/config/__tests__/models.test.js +67 -3
  211. package/dist/config/__tests__/models.test.js.map +1 -1
  212. package/dist/config/codex-feature-flags.d.ts.map +1 -1
  213. package/dist/config/codex-feature-flags.js.map +1 -1
  214. package/dist/config/codex-hooks.d.ts +124 -1
  215. package/dist/config/codex-hooks.d.ts.map +1 -1
  216. package/dist/config/codex-hooks.js +2142 -265
  217. package/dist/config/codex-hooks.js.map +1 -1
  218. package/dist/config/commit-lore-guard.js.map +1 -1
  219. package/dist/config/generator.d.ts +23 -34
  220. package/dist/config/generator.d.ts.map +1 -1
  221. package/dist/config/generator.js +1480 -246
  222. package/dist/config/generator.js.map +1 -1
  223. package/dist/config/mcp-registry.js.map +1 -1
  224. package/dist/config/models.d.ts +14 -4
  225. package/dist/config/models.d.ts.map +1 -1
  226. package/dist/config/models.js +15 -1
  227. package/dist/config/models.js.map +1 -1
  228. package/dist/config/omx-first-party-mcp.js.map +1 -1
  229. package/dist/config/team-mode.d.ts.map +1 -1
  230. package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -1
  231. package/dist/document-refresh/enforcer.js.map +1 -1
  232. package/dist/exec/followup.js.map +1 -1
  233. package/dist/goal-workflows/artifacts.js.map +1 -1
  234. package/dist/hooks/__tests__/agents-overlay.test.js +7 -4
  235. package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
  236. package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
  237. package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
  238. package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
  239. package/dist/hooks/__tests__/autopilot-skill-contract.test.js +9 -3
  240. package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
  241. package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
  242. package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
  243. package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
  244. package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
  245. package/dist/hooks/__tests__/keyword-detector.test.js +1376 -6
  246. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  247. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +252 -543
  248. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  249. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +38 -4
  250. package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
  251. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +765 -10
  252. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  253. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +2 -0
  254. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
  255. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +142 -1
  256. package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
  257. package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
  258. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +48 -2
  259. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
  260. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +61 -44
  261. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
  262. package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
  263. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +3 -2
  264. package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -1
  265. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +243 -4
  266. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  267. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +531 -12
  268. package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
  269. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +163 -24
  270. package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
  271. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +482 -32
  272. package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
  273. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +68 -1
  274. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  275. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +7 -1
  276. package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
  277. package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -1
  278. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +43 -4
  279. package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
  280. package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -1
  281. package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
  282. package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
  283. package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
  284. package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
  285. package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts +2 -0
  286. package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts.map +1 -0
  287. package/dist/hooks/__tests__/prompt-session-provenance.test.js +82 -0
  288. package/dist/hooks/__tests__/prompt-session-provenance.test.js.map +1 -0
  289. package/dist/hooks/__tests__/session.test.js +878 -11
  290. package/dist/hooks/__tests__/session.test.js.map +1 -1
  291. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
  292. package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
  293. package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
  294. package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
  295. package/dist/hooks/agents-overlay.js +5 -5
  296. package/dist/hooks/agents-overlay.js.map +1 -1
  297. package/dist/hooks/code-simplifier/index.js.map +1 -1
  298. package/dist/hooks/explore-routing.js.map +1 -1
  299. package/dist/hooks/extensibility/dispatcher.js.map +1 -1
  300. package/dist/hooks/extensibility/events.js.map +1 -1
  301. package/dist/hooks/extensibility/loader.js.map +1 -1
  302. package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -1
  303. package/dist/hooks/extensibility/sdk/logging.js.map +1 -1
  304. package/dist/hooks/keyword-detector.d.ts +33 -7
  305. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  306. package/dist/hooks/keyword-detector.js +2228 -119
  307. package/dist/hooks/keyword-detector.js.map +1 -1
  308. package/dist/hooks/keyword-registry.d.ts +12 -0
  309. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  310. package/dist/hooks/keyword-registry.js +41 -0
  311. package/dist/hooks/keyword-registry.js.map +1 -1
  312. package/dist/hooks/prompt-session-provenance.d.ts +87 -0
  313. package/dist/hooks/prompt-session-provenance.d.ts.map +1 -0
  314. package/dist/hooks/prompt-session-provenance.js +180 -0
  315. package/dist/hooks/prompt-session-provenance.js.map +1 -0
  316. package/dist/hooks/session.d.ts +163 -34
  317. package/dist/hooks/session.d.ts.map +1 -1
  318. package/dist/hooks/session.js +1395 -317
  319. package/dist/hooks/session.js.map +1 -1
  320. package/dist/hooks/task-size-detector.js.map +1 -1
  321. package/dist/hud/__tests__/state.test.js.map +1 -1
  322. package/dist/hud/authority.js.map +1 -1
  323. package/dist/hud/constants.js.map +1 -1
  324. package/dist/hud/index.js.map +1 -1
  325. package/dist/hud/reconcile.js.map +1 -1
  326. package/dist/hud/render.js.map +1 -1
  327. package/dist/hud/state.js.map +1 -1
  328. package/dist/hud/tmux.js.map +1 -1
  329. package/dist/leader/__tests__/contract.test.js +153 -1
  330. package/dist/leader/__tests__/contract.test.js.map +1 -1
  331. package/dist/leader/contract.d.ts +42 -5
  332. package/dist/leader/contract.d.ts.map +1 -1
  333. package/dist/leader/contract.js +184 -3
  334. package/dist/leader/contract.js.map +1 -1
  335. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  336. package/dist/mcp/__tests__/code-intel-server.test.js +31 -3
  337. package/dist/mcp/__tests__/code-intel-server.test.js.map +1 -1
  338. package/dist/mcp/__tests__/server-lifecycle.test.js +15 -2
  339. package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
  340. package/dist/mcp/__tests__/state-paths.test.js +98 -1
  341. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  342. package/dist/mcp/__tests__/wiki-server.test.js +18 -0
  343. package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
  344. package/dist/mcp/bootstrap.js.map +1 -1
  345. package/dist/mcp/code-intel-server.d.ts +58 -58
  346. package/dist/mcp/code-intel-server.d.ts.map +1 -1
  347. package/dist/mcp/code-intel-server.js +13 -3
  348. package/dist/mcp/code-intel-server.js.map +1 -1
  349. package/dist/mcp/hermes-bridge.js.map +1 -1
  350. package/dist/mcp/hermes-server.d.ts +70 -70
  351. package/dist/mcp/hermes-server.d.ts.map +1 -1
  352. package/dist/mcp/lifecycle-telemetry.js.map +1 -1
  353. package/dist/mcp/memory-server.d.ts +34 -34
  354. package/dist/mcp/memory-server.d.ts.map +1 -1
  355. package/dist/mcp/memory-server.js.map +1 -1
  356. package/dist/mcp/state-paths.d.ts +14 -0
  357. package/dist/mcp/state-paths.d.ts.map +1 -1
  358. package/dist/mcp/state-paths.js +96 -20
  359. package/dist/mcp/state-paths.js.map +1 -1
  360. package/dist/mcp/state-server.d.ts +47 -47
  361. package/dist/mcp/state-server.d.ts.map +1 -1
  362. package/dist/mcp/trace-server.d.ts +4 -4
  363. package/dist/mcp/trace-server.d.ts.map +1 -1
  364. package/dist/mcp/trace-server.js.map +1 -1
  365. package/dist/mcp/wiki-server.d.ts +34 -23
  366. package/dist/mcp/wiki-server.d.ts.map +1 -1
  367. package/dist/mcp/wiki-server.js +9 -2
  368. package/dist/mcp/wiki-server.js.map +1 -1
  369. package/dist/modes/__tests__/base-session-scope.test.js +53 -1
  370. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  371. package/dist/modes/__tests__/base-tmux-pane.test.js +4 -4
  372. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  373. package/dist/modes/base.d.ts.map +1 -1
  374. package/dist/modes/base.js +5 -5
  375. package/dist/modes/base.js.map +1 -1
  376. package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
  377. package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
  378. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +177 -85
  379. package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -1
  380. package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
  381. package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
  382. package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
  383. package/dist/notifications/http-client.js.map +1 -1
  384. package/dist/notifications/index.d.ts +4 -1
  385. package/dist/notifications/index.d.ts.map +1 -1
  386. package/dist/notifications/index.js +3 -9
  387. package/dist/notifications/index.js.map +1 -1
  388. package/dist/notifications/lifecycle-dedupe.js.map +1 -1
  389. package/dist/notifications/reply-listener.d.ts.map +1 -1
  390. package/dist/notifications/reply-listener.js.map +1 -1
  391. package/dist/notifications/session-registry.js.map +1 -1
  392. package/dist/notifications/session-status.js.map +1 -1
  393. package/dist/notifications/temp-contract.d.ts.map +1 -1
  394. package/dist/notifications/temp-contract.js +4 -0
  395. package/dist/notifications/temp-contract.js.map +1 -1
  396. package/dist/notifications/tmux-detector.js.map +1 -1
  397. package/dist/notifications/tmux.js.map +1 -1
  398. package/dist/openclaw/config.js.map +1 -1
  399. package/dist/openclaw/dispatcher.js.map +1 -1
  400. package/dist/pipeline/__tests__/orchestrator.test.js +4 -4
  401. package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
  402. package/dist/pipeline/__tests__/stages.test.js +16 -13
  403. package/dist/pipeline/__tests__/stages.test.js.map +1 -1
  404. package/dist/pipeline/stages/code-review.js.map +1 -1
  405. package/dist/pipeline/stages/ralph-verify.js.map +1 -1
  406. package/dist/pipeline/stages/ralplan.js.map +1 -1
  407. package/dist/pipeline/stages/team-exec.js.map +1 -1
  408. package/dist/pipeline/stages/ultragoal.js.map +1 -1
  409. package/dist/pipeline/stages/ultraqa.js.map +1 -1
  410. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
  411. package/dist/planning/artifact-names.js.map +1 -1
  412. package/dist/planning/artifacts.js.map +1 -1
  413. package/dist/question/__tests__/state.test.js.map +1 -1
  414. package/dist/question/__tests__/ui.test.js.map +1 -1
  415. package/dist/question/autopilot-wait.js.map +1 -1
  416. package/dist/question/client.d.ts.map +1 -1
  417. package/dist/question/client.js.map +1 -1
  418. package/dist/question/deep-interview.js.map +1 -1
  419. package/dist/question/events.js.map +1 -1
  420. package/dist/question/renderer.js.map +1 -1
  421. package/dist/question/state.d.ts.map +1 -1
  422. package/dist/question/state.js.map +1 -1
  423. package/dist/question/ui.js.map +1 -1
  424. package/dist/ralph/contract.d.ts +1 -1
  425. package/dist/ralph/contract.d.ts.map +1 -1
  426. package/dist/ralplan/__tests__/consensus-gate.test.js +527 -8
  427. package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
  428. package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts +2 -0
  429. package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts.map +1 -0
  430. package/dist/ralplan/__tests__/documented-leader-preflight.test.js +46 -0
  431. package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
  432. package/dist/ralplan/__tests__/runtime.test.js +116 -14
  433. package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
  434. package/dist/ralplan/consensus-gate.d.ts +3 -3
  435. package/dist/ralplan/consensus-gate.d.ts.map +1 -1
  436. package/dist/ralplan/consensus-gate.js +173 -70
  437. package/dist/ralplan/consensus-gate.js.map +1 -1
  438. package/dist/ralplan/documented-leader-preflight.d.ts +34 -0
  439. package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
  440. package/dist/ralplan/documented-leader-preflight.js +58 -0
  441. package/dist/ralplan/documented-leader-preflight.js.map +1 -0
  442. package/dist/ralplan/runtime.d.ts +3 -2
  443. package/dist/ralplan/runtime.d.ts.map +1 -1
  444. package/dist/ralplan/runtime.js +12 -9
  445. package/dist/ralplan/runtime.js.map +1 -1
  446. package/dist/runtime/__tests__/bridge.test.js +42 -1
  447. package/dist/runtime/__tests__/bridge.test.js.map +1 -1
  448. package/dist/runtime/bridge.d.ts +12 -0
  449. package/dist/runtime/bridge.d.ts.map +1 -1
  450. package/dist/runtime/bridge.js +52 -1
  451. package/dist/runtime/bridge.js.map +1 -1
  452. package/dist/runtime/process-tree.js.map +1 -1
  453. package/dist/runtime/run-loop.js.map +1 -1
  454. package/dist/runtime/run-outcome.d.ts +3 -3
  455. package/dist/runtime/run-outcome.d.ts.map +1 -1
  456. package/dist/runtime/run-outcome.js.map +1 -1
  457. package/dist/runtime/run-state.js.map +1 -1
  458. package/dist/scripts/__tests__/codex-native-hook.test.js +6657 -995
  459. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  460. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts +2 -0
  461. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts.map +1 -0
  462. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js +634 -0
  463. package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js.map +1 -0
  464. package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
  465. package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
  466. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
  467. package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts +2 -0
  468. package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts.map +1 -0
  469. package/dist/scripts/__tests__/notify-fallback-delivery.test.js +174 -0
  470. package/dist/scripts/__tests__/notify-fallback-delivery.test.js.map +1 -0
  471. package/dist/scripts/__tests__/notify-state-io.test.js +57 -1
  472. package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
  473. package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts +2 -0
  474. package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts.map +1 -0
  475. package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +108 -0
  476. package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -0
  477. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts +2 -0
  478. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts.map +1 -0
  479. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +78 -0
  480. package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -0
  481. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts +2 -0
  482. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts.map +1 -0
  483. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +55 -0
  484. package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -0
  485. package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
  486. package/dist/scripts/__tests__/smoke-packed-install.test.js +1100 -4
  487. package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
  488. package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -1
  489. package/dist/scripts/build-api.js.map +1 -1
  490. package/dist/scripts/build-explore-harness.js.map +1 -1
  491. package/dist/scripts/build-sparkshell.js.map +1 -1
  492. package/dist/scripts/cleanup-explore-harness.js.map +1 -1
  493. package/dist/scripts/codex-execution-surface.js.map +1 -1
  494. package/dist/scripts/codex-native-hook.d.ts +4 -1
  495. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  496. package/dist/scripts/codex-native-hook.js +11577 -1184
  497. package/dist/scripts/codex-native-hook.js.map +1 -1
  498. package/dist/scripts/generate-native-release-manifest.js.map +1 -1
  499. package/dist/scripts/generate-release-body.js.map +1 -1
  500. package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
  501. package/dist/scripts/hook-payload-guard.js.map +1 -1
  502. package/dist/scripts/notify-fallback-delivery.d.ts +48 -0
  503. package/dist/scripts/notify-fallback-delivery.d.ts.map +1 -0
  504. package/dist/scripts/notify-fallback-delivery.js +419 -0
  505. package/dist/scripts/notify-fallback-delivery.js.map +1 -0
  506. package/dist/scripts/notify-fallback-watcher.js +218 -138
  507. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  508. package/dist/scripts/notify-hook/auto-nudge.d.ts +18 -9
  509. package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
  510. package/dist/scripts/notify-hook/auto-nudge.js +112 -15
  511. package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
  512. package/dist/scripts/notify-hook/managed-tmux.d.ts +23 -0
  513. package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
  514. package/dist/scripts/notify-hook/managed-tmux.js +122 -12
  515. package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
  516. package/dist/scripts/notify-hook/orchestration-intent.d.ts +7 -7
  517. package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
  518. package/dist/scripts/notify-hook/ralph-session-resume.d.ts +5 -2
  519. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  520. package/dist/scripts/notify-hook/ralph-session-resume.js +33 -37
  521. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  522. package/dist/scripts/notify-hook/state-io.d.ts +17 -0
  523. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  524. package/dist/scripts/notify-hook/state-io.js +73 -11
  525. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  526. package/dist/scripts/notify-hook/team-dispatch.d.ts +10 -1
  527. package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
  528. package/dist/scripts/notify-hook/team-dispatch.js +234 -79
  529. package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
  530. package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -2
  531. package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
  532. package/dist/scripts/notify-hook/team-leader-nudge.js +39 -13
  533. package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
  534. package/dist/scripts/notify-hook/team-tmux-guard.d.ts +16 -8
  535. package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
  536. package/dist/scripts/notify-hook/team-tmux-guard.js +365 -44
  537. package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
  538. package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
  539. package/dist/scripts/notify-hook/team-worker-stop.d.ts +1 -1
  540. package/dist/scripts/notify-hook/team-worker-stop.d.ts.map +1 -1
  541. package/dist/scripts/notify-hook/team-worker-stop.js +19 -18
  542. package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
  543. package/dist/scripts/notify-hook/team-worker.d.ts +5 -2
  544. package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
  545. package/dist/scripts/notify-hook/team-worker.js +37 -28
  546. package/dist/scripts/notify-hook/team-worker.js.map +1 -1
  547. package/dist/scripts/notify-hook/tmux-injection.d.ts +8 -1
  548. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  549. package/dist/scripts/notify-hook/tmux-injection.js +53 -18
  550. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  551. package/dist/scripts/notify-hook/visual-verdict.d.ts +1 -1
  552. package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -1
  553. package/dist/scripts/notify-hook/visual-verdict.js +15 -13
  554. package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
  555. package/dist/scripts/notify-hook.d.ts +24 -1
  556. package/dist/scripts/notify-hook.d.ts.map +1 -1
  557. package/dist/scripts/notify-hook.js +267 -90
  558. package/dist/scripts/notify-hook.js.map +1 -1
  559. package/dist/scripts/postinstall.js.map +1 -1
  560. package/dist/scripts/prompt-inventory.js.map +1 -1
  561. package/dist/scripts/smoke-packed-install.d.ts +927 -5
  562. package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
  563. package/dist/scripts/smoke-packed-install.js +4317 -13
  564. package/dist/scripts/smoke-packed-install.js.map +1 -1
  565. package/dist/scripts/sync-plugin-mirror.js.map +1 -1
  566. package/dist/scripts/test-reply-listener-live.js.map +1 -1
  567. package/dist/scripts/test-sparkshell.js.map +1 -1
  568. package/dist/scripts/verify-native-agents.js.map +1 -1
  569. package/dist/session-history/friction.js.map +1 -1
  570. package/dist/session-history/search.js.map +1 -1
  571. package/dist/sidecar/__tests__/boundary.test.js.map +1 -1
  572. package/dist/sidecar/collector.js.map +1 -1
  573. package/dist/sidecar/index.js.map +1 -1
  574. package/dist/sidecar/render.js.map +1 -1
  575. package/dist/sidecar/tmux.js.map +1 -1
  576. package/dist/state/__tests__/mode-state-context.test.js +54 -0
  577. package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
  578. package/dist/state/__tests__/operations.test.js +66 -15
  579. package/dist/state/__tests__/operations.test.js.map +1 -1
  580. package/dist/state/__tests__/skill-active.test.js +19 -1
  581. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  582. package/dist/state/__tests__/workflow-transition.test.js +61 -0
  583. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  584. package/dist/state/mode-state-context.d.ts +5 -0
  585. package/dist/state/mode-state-context.d.ts.map +1 -1
  586. package/dist/state/mode-state-context.js +59 -0
  587. package/dist/state/mode-state-context.js.map +1 -1
  588. package/dist/state/operations.d.ts +1 -1
  589. package/dist/state/operations.d.ts.map +1 -1
  590. package/dist/state/operations.js +49 -55
  591. package/dist/state/operations.js.map +1 -1
  592. package/dist/state/paths.d.ts +1 -1
  593. package/dist/state/paths.d.ts.map +1 -1
  594. package/dist/state/paths.js +1 -1
  595. package/dist/state/paths.js.map +1 -1
  596. package/dist/state/skill-active.d.ts +13 -1
  597. package/dist/state/skill-active.d.ts.map +1 -1
  598. package/dist/state/skill-active.js +43 -4
  599. package/dist/state/skill-active.js.map +1 -1
  600. package/dist/state/terminal-normalization.js.map +1 -1
  601. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  602. package/dist/state/workflow-transition-reconcile.js +20 -4
  603. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  604. package/dist/state/workflow-transition.d.ts +1 -1
  605. package/dist/state/workflow-transition.d.ts.map +1 -1
  606. package/dist/state/workflow-transition.js.map +1 -1
  607. package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts +2 -0
  608. package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts.map +1 -0
  609. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +52 -0
  610. package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -0
  611. package/dist/subagents/__tests__/tracker.test.js +1550 -10
  612. package/dist/subagents/__tests__/tracker.test.js.map +1 -1
  613. package/dist/subagents/role-routing-marker.d.ts +10 -0
  614. package/dist/subagents/role-routing-marker.d.ts.map +1 -0
  615. package/dist/subagents/role-routing-marker.js +136 -0
  616. package/dist/subagents/role-routing-marker.js.map +1 -0
  617. package/dist/subagents/tracker.d.ts +91 -0
  618. package/dist/subagents/tracker.d.ts.map +1 -1
  619. package/dist/subagents/tracker.js +806 -62
  620. package/dist/subagents/tracker.js.map +1 -1
  621. package/dist/team/__tests__/api-interop.test.js +91 -1
  622. package/dist/team/__tests__/api-interop.test.js.map +1 -1
  623. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  624. package/dist/team/__tests__/delivery-e2e-smoke.test.js +52 -10
  625. package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
  626. package/dist/team/__tests__/idle-nudge.test.js +45 -15
  627. package/dist/team/__tests__/idle-nudge.test.js.map +1 -1
  628. package/dist/team/__tests__/mcp-comm.test.js +93 -27
  629. package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
  630. package/dist/team/__tests__/model-contract.test.js +341 -4
  631. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  632. package/dist/team/__tests__/role-router.test.js.map +1 -1
  633. package/dist/team/__tests__/runtime-cli.test.js +9 -0
  634. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  635. package/dist/team/__tests__/runtime.test.js +3624 -355
  636. package/dist/team/__tests__/runtime.test.js.map +1 -1
  637. package/dist/team/__tests__/scaling.test.js +2516 -118
  638. package/dist/team/__tests__/scaling.test.js.map +1 -1
  639. package/dist/team/__tests__/state-root.test.js.map +1 -1
  640. package/dist/team/__tests__/state.test.js +804 -36
  641. package/dist/team/__tests__/state.test.js.map +1 -1
  642. package/dist/team/__tests__/team-ops-contract.test.js +6 -0
  643. package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
  644. package/dist/team/__tests__/tmux-session.test.js +3664 -969
  645. package/dist/team/__tests__/tmux-session.test.js.map +1 -1
  646. package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
  647. package/dist/team/__tests__/worker-runtime-identity.test.js +38 -2
  648. package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
  649. package/dist/team/__tests__/worktree.test.js +6 -0
  650. package/dist/team/__tests__/worktree.test.js.map +1 -1
  651. package/dist/team/api-interop.d.ts +2 -2
  652. package/dist/team/api-interop.d.ts.map +1 -1
  653. package/dist/team/api-interop.js +15 -9
  654. package/dist/team/api-interop.js.map +1 -1
  655. package/dist/team/commit-hygiene.js.map +1 -1
  656. package/dist/team/contracts.d.ts +5 -5
  657. package/dist/team/contracts.d.ts.map +1 -1
  658. package/dist/team/delivery-log.js.map +1 -1
  659. package/dist/team/exact-pane.d.ts +23 -0
  660. package/dist/team/exact-pane.d.ts.map +1 -0
  661. package/dist/team/exact-pane.js +133 -0
  662. package/dist/team/exact-pane.js.map +1 -0
  663. package/dist/team/followup-planner.js.map +1 -1
  664. package/dist/team/goal-workflow.js.map +1 -1
  665. package/dist/team/idle-nudge.d.ts +12 -1
  666. package/dist/team/idle-nudge.d.ts.map +1 -1
  667. package/dist/team/idle-nudge.js +41 -14
  668. package/dist/team/idle-nudge.js.map +1 -1
  669. package/dist/team/model-contract.d.ts +18 -2
  670. package/dist/team/model-contract.d.ts.map +1 -1
  671. package/dist/team/model-contract.js +314 -35
  672. package/dist/team/model-contract.js.map +1 -1
  673. package/dist/team/orchestrator.js.map +1 -1
  674. package/dist/team/pane-status.js.map +1 -1
  675. package/dist/team/phase-controller.js.map +1 -1
  676. package/dist/team/reminder-intents.d.ts +1 -1
  677. package/dist/team/reminder-intents.d.ts.map +1 -1
  678. package/dist/team/reminder-intents.js.map +1 -1
  679. package/dist/team/runtime-cli.js.map +1 -1
  680. package/dist/team/runtime.d.ts +1 -0
  681. package/dist/team/runtime.d.ts.map +1 -1
  682. package/dist/team/runtime.js +1326 -231
  683. package/dist/team/runtime.js.map +1 -1
  684. package/dist/team/scaling.d.ts +22 -8
  685. package/dist/team/scaling.d.ts.map +1 -1
  686. package/dist/team/scaling.js +1463 -376
  687. package/dist/team/scaling.js.map +1 -1
  688. package/dist/team/state/dispatch-lock.js.map +1 -1
  689. package/dist/team/state/dispatch.d.ts.map +1 -1
  690. package/dist/team/state/dispatch.js +26 -8
  691. package/dist/team/state/dispatch.js.map +1 -1
  692. package/dist/team/state/events.js.map +1 -1
  693. package/dist/team/state/locks.d.ts.map +1 -1
  694. package/dist/team/state/locks.js +61 -13
  695. package/dist/team/state/locks.js.map +1 -1
  696. package/dist/team/state/tasks.d.ts.map +1 -1
  697. package/dist/team/state/tasks.js +4 -3
  698. package/dist/team/state/tasks.js.map +1 -1
  699. package/dist/team/state-root.js.map +1 -1
  700. package/dist/team/state.d.ts +67 -1
  701. package/dist/team/state.d.ts.map +1 -1
  702. package/dist/team/state.js +636 -129
  703. package/dist/team/state.js.map +1 -1
  704. package/dist/team/team-identity.d.ts.map +1 -1
  705. package/dist/team/team-identity.js.map +1 -1
  706. package/dist/team/team-ops.d.ts +5 -0
  707. package/dist/team/team-ops.d.ts.map +1 -1
  708. package/dist/team/team-ops.js +4 -0
  709. package/dist/team/team-ops.js.map +1 -1
  710. package/dist/team/tmux-session.d.ts +125 -23
  711. package/dist/team/tmux-session.d.ts.map +1 -1
  712. package/dist/team/tmux-session.js +1340 -333
  713. package/dist/team/tmux-session.js.map +1 -1
  714. package/dist/team/worker-bootstrap.js.map +1 -1
  715. package/dist/team/worktree.d.ts.map +1 -1
  716. package/dist/team/worktree.js +4 -0
  717. package/dist/team/worktree.js.map +1 -1
  718. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  719. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  720. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  721. package/dist/ultragoal/artifacts.js +4 -1
  722. package/dist/ultragoal/artifacts.js.map +1 -1
  723. package/dist/url-reader/index.js.map +1 -1
  724. package/dist/utils/__tests__/file-durability.test.d.ts +2 -0
  725. package/dist/utils/__tests__/file-durability.test.d.ts.map +1 -0
  726. package/dist/utils/__tests__/file-durability.test.js +57 -0
  727. package/dist/utils/__tests__/file-durability.test.js.map +1 -0
  728. package/dist/utils/agents-model-table.js.map +1 -1
  729. package/dist/utils/file-durability.d.ts +15 -0
  730. package/dist/utils/file-durability.d.ts.map +1 -0
  731. package/dist/utils/file-durability.js +37 -0
  732. package/dist/utils/file-durability.js.map +1 -0
  733. package/dist/utils/package.js.map +1 -1
  734. package/dist/utils/paths.js.map +1 -1
  735. package/dist/utils/platform-command.js.map +1 -1
  736. package/dist/utils/repo-deps.js.map +1 -1
  737. package/dist/utils/version.js.map +1 -1
  738. package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
  739. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +3 -0
  740. package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
  741. package/dist/verification/verifier.js.map +1 -1
  742. package/dist/visual/constants.d.ts +1 -1
  743. package/dist/visual/constants.d.ts.map +1 -1
  744. package/dist/vscode/__tests__/index.test.js.map +1 -1
  745. package/dist/vscode/index.js.map +1 -1
  746. package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -1
  747. package/dist/wiki/__tests__/lint.test.js.map +1 -1
  748. package/dist/wiki/__tests__/query.test.js.map +1 -1
  749. package/dist/wiki/__tests__/storage.test.js.map +1 -1
  750. package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -1
  751. package/dist/wiki/lint.d.ts +4 -1
  752. package/dist/wiki/lint.d.ts.map +1 -1
  753. package/dist/wiki/lint.js +3 -2
  754. package/dist/wiki/lint.js.map +1 -1
  755. package/dist/wiki/query.js.map +1 -1
  756. package/dist/wiki/storage.js.map +1 -1
  757. package/package.json +2 -2
  758. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  759. package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +24 -0
  760. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
  761. package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -2
  762. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +6 -2
  763. package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
  764. package/skills/omx-setup/SKILL.md +10 -5
  765. package/skills/ralph/SKILL.md +6 -2
  766. package/skills/ralplan/SKILL.md +6 -2
  767. package/skills/team/SKILL.md +13 -9
  768. package/src/scripts/__tests__/codex-native-hook.test.ts +20048 -10827
  769. package/src/scripts/__tests__/fixtures/issue-3138-installed-smoke.ts +734 -0
  770. package/src/scripts/__tests__/notify-fallback-delivery.test.ts +177 -0
  771. package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
  772. package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
  773. package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +78 -0
  774. package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +60 -0
  775. package/src/scripts/__tests__/smoke-packed-install.test.ts +1309 -4
  776. package/src/scripts/codex-native-hook.ts +11429 -1163
  777. package/src/scripts/notify-fallback-delivery.ts +416 -0
  778. package/src/scripts/notify-fallback-watcher.ts +216 -155
  779. package/src/scripts/notify-hook/auto-nudge.ts +113 -14
  780. package/src/scripts/notify-hook/managed-tmux.ts +149 -12
  781. package/src/scripts/notify-hook/ralph-session-resume.ts +37 -36
  782. package/src/scripts/notify-hook/state-io.ts +100 -13
  783. package/src/scripts/notify-hook/team-dispatch.ts +242 -75
  784. package/src/scripts/notify-hook/team-leader-nudge.ts +40 -18
  785. package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
  786. package/src/scripts/notify-hook/team-worker-stop.ts +20 -16
  787. package/src/scripts/notify-hook/team-worker.ts +39 -26
  788. package/src/scripts/notify-hook/tmux-injection.ts +66 -23
  789. package/src/scripts/notify-hook/visual-verdict.ts +22 -12
  790. package/src/scripts/notify-hook.ts +336 -90
  791. package/src/scripts/smoke-packed-install.ts +5154 -149
@@ -6,6 +6,9 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
6
6
  import { tmpdir } from 'node:os';
7
7
  import { join } from 'node:path';
8
8
  import { buildTmuxSessionName } from '../../cli/index.js';
9
+ import { classifyKeywordInput, recordSkillActivation } from '../keyword-detector.js';
10
+ import { recordNotifySkillActivation, recordNotifySkillActivationNonFatal } from '../../scripts/notify-hook.js';
11
+ import { normalizeSkillActiveState } from '../../scripts/notify-hook/auto-nudge.js';
9
12
  const NOTIFY_HOOK_SCRIPT = new URL('../../../dist/scripts/notify-hook.js', import.meta.url);
10
13
  const DEEP_INTERVIEW_BLOCKED_APPROVAL_INPUTS = ['yes', 'y', 'proceed', 'continue', 'ok', 'sure', 'go ahead', 'next i should'];
11
14
  const NEXT_I_SHOULD_RESPONSE = 'Next I should update the focused tests.';
@@ -18,6 +21,17 @@ const INHERITED_OMX_ENV_KEYS = [
18
21
  'OMX_STARTUP_CWD',
19
22
  'OMX_ENTRY_PATH',
20
23
  ];
24
+ describe('notify lifecycle owner normalization', () => {
25
+ it('preserves the stored Codex owner for lifecycle authorization checks', () => {
26
+ const state = normalizeSkillActiveState({
27
+ skill: 'ralph',
28
+ active: true,
29
+ phase: 'executing',
30
+ owner_codex_session_id: 'codex-owner-a',
31
+ });
32
+ assert.equal(state?.owner_codex_session_id, 'codex-owner-a');
33
+ });
34
+ });
21
35
  async function withTempWorkingDir(run) {
22
36
  const cwd = await mkdtemp(join(tmpdir(), 'omx-auto-nudge-'));
23
37
  try {
@@ -79,6 +93,12 @@ async function writeWorkerIdentityFixture(stateRoot, cwd, teamName, workerName)
79
93
  worktree_path: cwd,
80
94
  team_state_root: stateRoot,
81
95
  });
96
+ await writeJson(join(stateRoot, 'team', teamName, 'config.json'), {
97
+ name: teamName,
98
+ tmux_pane_owner_id: `team:${teamName}`,
99
+ hud_pane_id: null,
100
+ workers: [{ name: workerName, pane_id: '%99', pid: 9999 }],
101
+ });
82
102
  }
83
103
  function escapeRegex(value) {
84
104
  return value.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
@@ -130,6 +150,15 @@ fi
130
150
  if [[ "\$cmd" == "send-keys" ]]; then
131
151
  exit 0
132
152
  fi
153
+ if [[ "$cmd" == "show-option" ]]; then
154
+ option="\${@: -1}"
155
+ case "$option" in
156
+ @omx_team_pane_owner_id) echo "\${OMX_TEST_TMUX_OWNER:-team:auto-nudge}" ;;
157
+ @omx_pane_instance_id) echo "\${OMX_TEST_TMUX_PANE_INSTANCE_ID:-}" ;;
158
+ @omx_instance_id) echo "\${OMX_TEST_TMUX_INSTANCE_ID:-}" ;;
159
+ esac
160
+ exit 0
161
+ fi
133
162
  if [[ "\$cmd" == "display-message" ]]; then
134
163
  target=""
135
164
  format=""
@@ -170,7 +199,7 @@ if [[ "\$cmd" == "list-panes" ]]; then
170
199
  printf '%%99\t1\tnode\tcodex --model gpt-5\n'
171
200
  exit 0
172
201
  fi
173
- echo "%1 12345"
202
+ printf '%%99\t0\t%s\n%%100\t0\t10000\n' "\${OMX_TEST_TMUX_PANE_PID:-9999}"
174
203
  exit 0
175
204
  fi
176
205
  exit 0
@@ -623,7 +652,7 @@ if [[ "$cmd" == "list-panes" ]]; then
623
652
  printf "%%99\t0\tsh\tbash\n%%100\t1\tnode\tcodex --model gpt-5\n"
624
653
  exit 0
625
654
  fi
626
- echo "%1 12345"
655
+ printf '%%99\t0\t9999\n%%100\t0\t10000\n'
627
656
  exit 0
628
657
  fi
629
658
  if [[ "$cmd" == "capture-pane" ]]; then
@@ -740,7 +769,7 @@ if [[ "$cmd" == "list-panes" ]]; then
740
769
  printf "%%99\t0\tcodex\tcodex\\n%%100\t1\tcodex\tcodex\\n"
741
770
  exit 0
742
771
  fi
743
- echo "%1 12345"
772
+ printf '%%99\t0\t9999\n%%100\t0\t10000\n'
744
773
  exit 0
745
774
  fi
746
775
  if [[ "$cmd" == "capture-pane" ]]; then
@@ -858,7 +887,7 @@ if [[ "$cmd" == "list-panes" ]]; then
858
887
  printf "%%99\t0\tnode\tbash\\n%%100\t1\tnode\tcodex --model gpt-5\\n"
859
888
  exit 0
860
889
  fi
861
- echo "%1 12345"
890
+ printf '%%99\t0\t9999\n%%100\t0\t10000\n'
862
891
  exit 0
863
892
  fi
864
893
  if [[ "$cmd" == "capture-pane" ]]; then
@@ -976,7 +1005,7 @@ if [[ "$cmd" == "list-panes" ]]; then
976
1005
  printf "%%99\t1\tbash\tcodex --model gpt-5\\n%%100\t0\tnode\tcodex --model gpt-5\\n"
977
1006
  exit 0
978
1007
  fi
979
- echo "%1 12345"
1008
+ printf '%%99\t0\t9999\n%%100\t0\t10000\n'
980
1009
  exit 0
981
1010
  fi
982
1011
  if [[ "$cmd" == "capture-pane" ]]; then
@@ -1090,7 +1119,7 @@ if [[ "$cmd" == "list-panes" ]]; then
1090
1119
  printf "%%99\t1\tbash\tcodex --model gpt-5\\n%%100\t0\tbash\tbash\\n"
1091
1120
  exit 0
1092
1121
  fi
1093
- echo "%1 12345"
1122
+ printf '%%99\t0\t9999\n%%100\t0\t10000\n'
1094
1123
  exit 0
1095
1124
  fi
1096
1125
  if [[ "$cmd" == "capture-pane" ]]; then
@@ -1171,6 +1200,74 @@ exit 0
1171
1200
  assert.ok(existsSync(nudgeStatePath), 'worker state root should receive auto-nudge state');
1172
1201
  });
1173
1202
  });
1203
+ it('does not capture or send in team-worker context without a persisted string owner token', async () => {
1204
+ for (const owner of [undefined, 17]) {
1205
+ await withTempWorkingDir(async (cwd) => {
1206
+ const workerStateRoot = join(cwd, 'leader-state-root');
1207
+ const codexHome = join(cwd, 'codex-home');
1208
+ const fakeBinDir = join(cwd, 'fake-bin');
1209
+ const tmuxLogPath = join(cwd, 'tmux.log');
1210
+ await mkdir(workerStateRoot, { recursive: true });
1211
+ await mkdir(codexHome, { recursive: true });
1212
+ await mkdir(fakeBinDir, { recursive: true });
1213
+ await writeWorkerIdentityFixture(workerStateRoot, cwd, 'auto-nudge', 'worker-1');
1214
+ const configPath = join(workerStateRoot, 'team', 'auto-nudge', 'config.json');
1215
+ const config = JSON.parse(await readFile(configPath, 'utf-8'));
1216
+ if (owner === undefined)
1217
+ delete config.tmux_pane_owner_id;
1218
+ else
1219
+ config.tmux_pane_owner_id = owner;
1220
+ await writeJson(configPath, config);
1221
+ await writeJson(join(codexHome, '.omx-config.json'), { autoNudge: { enabled: true, delaySec: 0, stallMs: 0 } });
1222
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1223
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1224
+ const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
1225
+ 'last-assistant-message': 'I can continue with the worker follow-up from here.',
1226
+ }, {
1227
+ OMX_TEAM_WORKER: 'auto-nudge/worker-1',
1228
+ OMX_TEAM_STATE_ROOT: workerStateRoot,
1229
+ });
1230
+ assert.equal(result.status, 0, `hook failed: ${result.stderr || result.stdout}`);
1231
+ const tmuxLog = await readFile(tmuxLogPath, 'utf-8').catch(() => '');
1232
+ assert.doesNotMatch(tmuxLog, /capture-pane|send-keys/, 'missing or malformed persisted owner must not capture or send tmux input');
1233
+ });
1234
+ }
1235
+ });
1236
+ it('fails closed for Team-worker owner takeover, recycled panes, and HUD targets', async () => {
1237
+ for (const scenario of [
1238
+ { name: 'owner takeover', env: { OMX_TEST_TMUX_OWNER: 'team:foreign' }, hudPaneId: null },
1239
+ { name: 'recycled pane', env: { OMX_TEST_TMUX_PANE_PID: '10001' }, hudPaneId: null },
1240
+ { name: 'HUD target', env: {}, hudPaneId: '%99' },
1241
+ ]) {
1242
+ await withTempWorkingDir(async (cwd) => {
1243
+ const workerStateRoot = join(cwd, 'leader-state-root');
1244
+ const codexHome = join(cwd, 'codex-home');
1245
+ const fakeBinDir = join(cwd, 'fake-bin');
1246
+ const tmuxLogPath = join(cwd, 'tmux.log');
1247
+ await mkdir(workerStateRoot, { recursive: true });
1248
+ await mkdir(codexHome, { recursive: true });
1249
+ await mkdir(fakeBinDir, { recursive: true });
1250
+ await writeWorkerIdentityFixture(workerStateRoot, cwd, 'auto-nudge', 'worker-1');
1251
+ const configPath = join(workerStateRoot, 'team', 'auto-nudge', 'config.json');
1252
+ const config = JSON.parse(await readFile(configPath, 'utf-8'));
1253
+ config.hud_pane_id = scenario.hudPaneId;
1254
+ await writeJson(configPath, config);
1255
+ await writeJson(join(codexHome, '.omx-config.json'), { autoNudge: { enabled: true, delaySec: 0, stallMs: 0 } });
1256
+ await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(tmuxLogPath));
1257
+ await chmod(join(fakeBinDir, 'tmux'), 0o755);
1258
+ const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
1259
+ 'last-assistant-message': 'I can continue with the worker follow-up from here.',
1260
+ }, {
1261
+ OMX_TEAM_WORKER: 'auto-nudge/worker-1',
1262
+ OMX_TEAM_STATE_ROOT: workerStateRoot,
1263
+ ...scenario.env,
1264
+ });
1265
+ assert.equal(result.status, 0, `${scenario.name}: hook failed: ${result.stderr || result.stdout}`);
1266
+ const tmuxLog = await readFile(tmuxLogPath, 'utf-8');
1267
+ assert.doesNotMatch(tmuxLog, defaultAutoNudgePattern('%99'), `${scenario.name} must not inject Team input`);
1268
+ });
1269
+ }
1270
+ });
1174
1271
  it('fails closed in team-worker context when the worker state root lacks a valid identity', async () => {
1175
1272
  await withTempWorkingDir(async (cwd) => {
1176
1273
  const localStateRoot = join(cwd, '.omx', 'state');
@@ -1280,8 +1377,12 @@ fi
1280
1377
  if [[ "$cmd" == "send-keys" ]]; then
1281
1378
  exit 0
1282
1379
  fi
1380
+ if [[ "$cmd" == "show-option" ]]; then
1381
+ echo "team:auto-nudge"
1382
+ exit 0
1383
+ fi
1283
1384
  if [[ "$cmd" == "list-panes" ]]; then
1284
- echo "%1 12345"
1385
+ printf '%%99\t0\t9999\n%%100\t0\t10000\n'
1285
1386
  exit 0
1286
1387
  fi
1287
1388
  exit 0
@@ -1400,7 +1501,7 @@ if [[ "$cmd" == "send-keys" ]]; then
1400
1501
  exit 0
1401
1502
  fi
1402
1503
  if [[ "$cmd" == "list-panes" ]]; then
1403
- echo "%1 12345"
1504
+ printf '%%99\t0\t9999\n%%100\t0\t10000\n'
1404
1505
  exit 0
1405
1506
  fi
1406
1507
  exit 0
@@ -1517,7 +1618,7 @@ if [[ "$cmd" == "list-panes" ]]; then
1517
1618
  printf "%%99\t1\tsh\tbash\\n%%100\t0\tnode\tcodex --model gpt-5\\n"
1518
1619
  exit 0
1519
1620
  fi
1520
- echo "%1 12345"
1621
+ printf '%%99\t0\t9999\n%%100\t0\t10000\n'
1521
1622
  exit 0
1522
1623
  fi
1523
1624
  exit 0
@@ -2048,6 +2149,656 @@ exit 0
2048
2149
  assert.equal(autopilotState.turn_id, 'turn-later-autopilot-start');
2049
2150
  });
2050
2151
  });
2152
+ it('shares immutable classification across the terminal replay activation matrix', async () => {
2153
+ await withTempWorkingDir(async (cwd) => {
2154
+ const stateDir = join(cwd, '.omx', 'state');
2155
+ const sessionId = 'sess-notify-replay-matrix';
2156
+ const sessionStateDir = join(stateDir, 'sessions', sessionId);
2157
+ const terminalThreadId = 'thread-autopilot-complete';
2158
+ const terminalTurnId = 'turn-autopilot-complete';
2159
+ const terminalPayload = {
2160
+ type: 'agent-turn-complete',
2161
+ 'thread-id': terminalThreadId,
2162
+ 'turn-id': terminalTurnId,
2163
+ 'last-assistant-message': 'Autopilot complete.',
2164
+ };
2165
+ await mkdir(sessionStateDir, { recursive: true });
2166
+ await writeJson(join(sessionStateDir, 'autopilot-state.json'), {
2167
+ mode: 'autopilot',
2168
+ active: false,
2169
+ current_phase: 'complete',
2170
+ completed_at: '2026-05-31T20:24:39.005Z',
2171
+ session_id: sessionId,
2172
+ thread_id: terminalThreadId,
2173
+ turn_id: terminalTurnId,
2174
+ });
2175
+ const terminalAutopilotStatePath = join(sessionStateDir, 'autopilot-state.json');
2176
+ const terminalSessionSkillStatePath = join(sessionStateDir, 'skill-active-state.json');
2177
+ const terminalRootSkillStatePath = join(stateDir, 'skill-active-state.json');
2178
+ for (const text of ['$autopilot replay task café\r\n', 'autopilot mode — replay café']) {
2179
+ const bytesBefore = Buffer.from(text, 'utf8');
2180
+ const terminalStateBefore = await readFile(terminalAutopilotStatePath);
2181
+ let classifierCalls = 0;
2182
+ let classifierText = '';
2183
+ let writerCalls = 0;
2184
+ const result = await recordNotifySkillActivation({
2185
+ stateDir,
2186
+ sourceCwd: cwd,
2187
+ text,
2188
+ sessionId,
2189
+ threadId: terminalThreadId,
2190
+ turnId: terminalTurnId,
2191
+ payload: terminalPayload,
2192
+ }, {
2193
+ classifyKeywordInput: (input) => {
2194
+ classifierCalls += 1;
2195
+ classifierText = input;
2196
+ return classifyKeywordInput(input);
2197
+ },
2198
+ recordSkillActivation: async () => {
2199
+ writerCalls += 1;
2200
+ return null;
2201
+ },
2202
+ });
2203
+ assert.equal(classifierCalls, 1, 'notify should classify each latest input once');
2204
+ assert.equal(writerCalls, 0, 'same-turn terminal replay must not reach the writer');
2205
+ assert.equal(result, null);
2206
+ assert.deepEqual(Buffer.from(classifierText, 'utf8'), bytesBefore, 'classifier must receive the original input bytes');
2207
+ assert.deepEqual(await readFile(terminalAutopilotStatePath), terminalStateBefore, 'same-turn replay must preserve terminal detail bytes');
2208
+ assert.equal(existsSync(terminalSessionSkillStatePath), false, 'same-turn replay must not create session canonical state');
2209
+ assert.equal(existsSync(terminalRootSkillStatePath), false, 'same-turn replay must not create root canonical state');
2210
+ }
2211
+ const markedSessionId = 'sess-notify-terminal-marked-answer';
2212
+ const markedThreadId = 'thread-notify-terminal-marked-answer';
2213
+ const markedTurnId = 'turn-notify-terminal-marked-answer';
2214
+ const markedSessionDir = join(stateDir, 'sessions', markedSessionId);
2215
+ const markedSkillPath = join(markedSessionDir, 'skill-active-state.json');
2216
+ const markedDetailPath = join(markedSessionDir, 'autopilot-state.json');
2217
+ await mkdir(markedSessionDir, { recursive: true });
2218
+ await writeJson(markedSkillPath, {
2219
+ version: 1,
2220
+ active: true,
2221
+ skill: 'autopilot',
2222
+ keyword: '$autopilot',
2223
+ phase: 'completing',
2224
+ activated_at: '2026-05-31T20:24:39.005Z',
2225
+ updated_at: '2026-05-31T20:24:39.005Z',
2226
+ session_id: markedSessionId,
2227
+ active_skills: [{ skill: 'autopilot', phase: 'completing', active: true, session_id: markedSessionId }],
2228
+ });
2229
+ await writeJson(markedDetailPath, {
2230
+ mode: 'autopilot',
2231
+ active: false,
2232
+ current_phase: 'complete',
2233
+ completed_at: '2026-05-31T20:24:39.005Z',
2234
+ session_id: markedSessionId,
2235
+ });
2236
+ const markedSkillBefore = await readFile(markedSkillPath);
2237
+ const markedDetailBefore = await readFile(markedDetailPath);
2238
+ let markedWriterCalls = 0;
2239
+ const markedResult = await recordNotifySkillActivation({
2240
+ stateDir,
2241
+ sourceCwd: cwd,
2242
+ text: '[omx question answered] yes',
2243
+ sessionId: markedSessionId,
2244
+ threadId: markedThreadId,
2245
+ turnId: markedTurnId,
2246
+ payload: {
2247
+ type: 'agent-turn-complete',
2248
+ 'thread-id': markedThreadId,
2249
+ 'turn-id': markedTurnId,
2250
+ 'last-assistant-message': 'Autopilot complete.',
2251
+ },
2252
+ }, {
2253
+ recordSkillActivation: async (input) => {
2254
+ markedWriterCalls += 1;
2255
+ return recordSkillActivation(input);
2256
+ },
2257
+ });
2258
+ assert.equal(markedWriterCalls, 1);
2259
+ assert.equal(markedResult, null);
2260
+ assert.deepEqual(await readFile(markedSkillPath), markedSkillBefore);
2261
+ assert.deepEqual(await readFile(markedDetailPath), markedDetailBefore);
2262
+ for (const orderedCase of [
2263
+ { text: '$ralplan $autopilot plan this change', skill: 'ralplan' },
2264
+ { text: '$ralph $autopilot ship this change', skill: 'ralph' },
2265
+ ]) {
2266
+ const orderedSessionId = `sess-notify-primary-${orderedCase.skill}`;
2267
+ const orderedThreadId = `thread-notify-primary-${orderedCase.skill}`;
2268
+ const orderedTurnId = `turn-notify-primary-${orderedCase.skill}`;
2269
+ const orderedSessionDir = join(stateDir, 'sessions', orderedSessionId);
2270
+ await mkdir(orderedSessionDir, { recursive: true });
2271
+ await writeJson(join(orderedSessionDir, 'autopilot-state.json'), {
2272
+ mode: 'autopilot',
2273
+ active: false,
2274
+ current_phase: 'complete',
2275
+ completed_at: '2026-05-31T20:24:39.005Z',
2276
+ session_id: orderedSessionId,
2277
+ thread_id: orderedThreadId,
2278
+ turn_id: orderedTurnId,
2279
+ });
2280
+ const orderedAutopilotPath = join(orderedSessionDir, 'autopilot-state.json');
2281
+ const orderedAutopilotBefore = await readFile(orderedAutopilotPath);
2282
+ await writeJson(join(orderedSessionDir, 'skill-active-state.json'), {
2283
+ version: 1,
2284
+ active: true,
2285
+ skill: 'autopilot',
2286
+ keyword: '$autopilot',
2287
+ phase: 'completing',
2288
+ activated_at: '2026-05-31T20:24:39.005Z',
2289
+ updated_at: '2026-05-31T20:24:39.005Z',
2290
+ session_id: orderedSessionId,
2291
+ thread_id: orderedThreadId,
2292
+ turn_id: orderedTurnId,
2293
+ active_skills: [{
2294
+ skill: 'autopilot',
2295
+ phase: 'completing',
2296
+ active: true,
2297
+ session_id: orderedSessionId,
2298
+ thread_id: orderedThreadId,
2299
+ turn_id: orderedTurnId,
2300
+ }],
2301
+ });
2302
+ let orderedWriterCalls = 0;
2303
+ const orderedResult = await recordNotifySkillActivation({
2304
+ stateDir,
2305
+ sourceCwd: cwd,
2306
+ text: orderedCase.text,
2307
+ sessionId: orderedSessionId,
2308
+ threadId: orderedThreadId,
2309
+ turnId: orderedTurnId,
2310
+ payload: {
2311
+ type: 'agent-turn-complete',
2312
+ 'thread-id': orderedThreadId,
2313
+ 'turn-id': orderedTurnId,
2314
+ 'last-assistant-message': 'Autopilot complete.',
2315
+ },
2316
+ }, {
2317
+ recordSkillActivation: async (input) => {
2318
+ orderedWriterCalls += 1;
2319
+ return recordSkillActivation(input);
2320
+ },
2321
+ });
2322
+ assert.equal(orderedWriterCalls, 1, `leading ${orderedCase.skill} must reach the writer`);
2323
+ assert.equal(orderedResult?.skill, orderedCase.skill, orderedCase.text);
2324
+ assert.equal(orderedResult?.active, true, orderedCase.text);
2325
+ assert.equal(existsSync(join(orderedSessionDir, 'skill-active-state.json')), true, orderedCase.text);
2326
+ assert.equal(orderedResult?.active_skills?.some((entry) => entry.skill === 'autopilot'), false, orderedCase.text);
2327
+ assert.deepEqual(await readFile(orderedAutopilotPath), orderedAutopilotBefore, orderedCase.text);
2328
+ }
2329
+ const filteredSessionId = 'sess-notify-disabled-team-terminal-autopilot';
2330
+ const filteredThreadId = 'thread-notify-disabled-team-terminal-autopilot';
2331
+ const filteredTurnId = 'turn-notify-disabled-team-terminal-autopilot';
2332
+ const filteredSessionDir = join(stateDir, 'sessions', filteredSessionId);
2333
+ const filteredAutopilotPath = join(filteredSessionDir, 'autopilot-state.json');
2334
+ await mkdir(filteredSessionDir, { recursive: true });
2335
+ await writeJson(filteredAutopilotPath, {
2336
+ mode: 'autopilot',
2337
+ active: false,
2338
+ current_phase: 'complete',
2339
+ completed_at: '2026-05-31T20:24:39.005Z',
2340
+ session_id: filteredSessionId,
2341
+ thread_id: filteredThreadId,
2342
+ turn_id: filteredTurnId,
2343
+ });
2344
+ const filteredAutopilotBefore = await readFile(filteredAutopilotPath);
2345
+ const previousTeamMode = process.env.OMX_TEAM_MODE;
2346
+ process.env.OMX_TEAM_MODE = 'disabled';
2347
+ try {
2348
+ const filteredResult = await recordNotifySkillActivation({
2349
+ stateDir,
2350
+ sourceCwd: cwd,
2351
+ text: '$team $autopilot retry',
2352
+ sessionId: filteredSessionId,
2353
+ threadId: filteredThreadId,
2354
+ turnId: filteredTurnId,
2355
+ payload: {
2356
+ type: 'agent-turn-complete',
2357
+ 'thread-id': filteredThreadId,
2358
+ 'turn-id': filteredTurnId,
2359
+ 'last-assistant-message': 'Autopilot complete.',
2360
+ },
2361
+ });
2362
+ assert.equal(filteredResult, null);
2363
+ assert.deepEqual(await readFile(filteredAutopilotPath), filteredAutopilotBefore);
2364
+ assert.equal(existsSync(join(filteredSessionDir, 'skill-active-state.json')), false);
2365
+ assert.equal(existsSync(join(stateDir, 'skill-active-state.json')), false);
2366
+ }
2367
+ finally {
2368
+ if (previousTeamMode === undefined)
2369
+ delete process.env.OMX_TEAM_MODE;
2370
+ else
2371
+ process.env.OMX_TEAM_MODE = previousTeamMode;
2372
+ }
2373
+ const restartText = '$autopilot new task — café';
2374
+ const restartBytes = Buffer.from(restartText, 'utf8');
2375
+ let restartClassification;
2376
+ let writerClassification;
2377
+ let writerResult;
2378
+ let writerCalls = 0;
2379
+ let writerText = '';
2380
+ const restartResult = await recordNotifySkillActivation({
2381
+ stateDir,
2382
+ sourceCwd: cwd,
2383
+ text: restartText,
2384
+ sessionId,
2385
+ threadId: terminalThreadId,
2386
+ turnId: 'turn-autopilot-restart',
2387
+ payload: {
2388
+ ...terminalPayload,
2389
+ 'turn-id': 'turn-autopilot-restart',
2390
+ 'last-assistant-message': 'Autopilot complete text from a prior turn.',
2391
+ },
2392
+ }, {
2393
+ classifyKeywordInput: (input) => {
2394
+ restartClassification = classifyKeywordInput(input);
2395
+ return restartClassification;
2396
+ },
2397
+ recordSkillActivation: async (input) => {
2398
+ writerCalls += 1;
2399
+ writerText = input.text;
2400
+ writerClassification = input.classification;
2401
+ writerResult = await recordSkillActivation(input);
2402
+ return writerResult;
2403
+ },
2404
+ });
2405
+ assert.equal(writerCalls, 1, 'a different turn must reach the writer');
2406
+ assert.strictEqual(writerClassification, restartClassification, 'writer must receive the classifier object by identity');
2407
+ assert.strictEqual(restartResult, writerResult, 'notify must return the writer result unchanged');
2408
+ assert.deepEqual(Buffer.from(writerText, 'utf8'), restartBytes, 'writer must receive the original input bytes');
2409
+ const reactivatedAutopilot = JSON.parse(await readFile(join(sessionStateDir, 'autopilot-state.json'), 'utf-8'));
2410
+ assert.equal(reactivatedAutopilot.active, true);
2411
+ assert.equal(reactivatedAutopilot.current_phase, 'deep-interview');
2412
+ assert.equal(reactivatedAutopilot.turn_id, 'turn-autopilot-restart');
2413
+ const sessionSkillStatePath = join(sessionStateDir, 'skill-active-state.json');
2414
+ const autopilotStatePath = join(sessionStateDir, 'autopilot-state.json');
2415
+ const rootSkillStatePath = join(stateDir, 'skill-active-state.json');
2416
+ for (const [index, text] of ['do not start $autopilot — café', '"$autopilot" — quoted only'].entries()) {
2417
+ const bytesBefore = Buffer.from(text, 'utf8');
2418
+ const skillStateBefore = await readFile(sessionSkillStatePath);
2419
+ const autopilotStateBefore = await readFile(autopilotStatePath);
2420
+ let rejectedClassification;
2421
+ let rejectedWriterClassification;
2422
+ let rejectedWriterResult;
2423
+ let rejectedWriterCalls = 0;
2424
+ let rejectedWriterText = '';
2425
+ const rejectedResult = await recordNotifySkillActivation({
2426
+ stateDir,
2427
+ sourceCwd: cwd,
2428
+ text,
2429
+ sessionId,
2430
+ threadId: terminalThreadId,
2431
+ turnId: `turn-rejected-${index}`,
2432
+ payload: {
2433
+ type: 'agent-turn-complete',
2434
+ 'thread-id': terminalThreadId,
2435
+ 'turn-id': `turn-rejected-${index}`,
2436
+ 'last-assistant-message': 'Normal nonterminal reply.',
2437
+ },
2438
+ }, {
2439
+ classifyKeywordInput: (input) => {
2440
+ rejectedClassification = classifyKeywordInput(input);
2441
+ return rejectedClassification;
2442
+ },
2443
+ recordSkillActivation: async (input) => {
2444
+ rejectedWriterCalls += 1;
2445
+ rejectedWriterText = input.text;
2446
+ rejectedWriterClassification = input.classification;
2447
+ rejectedWriterResult = await recordSkillActivation(input);
2448
+ return rejectedWriterResult;
2449
+ },
2450
+ });
2451
+ assert.equal(rejectedWriterCalls, 1, 'rejected nonterminal text must still reach the real writer once');
2452
+ assert.strictEqual(rejectedResult, rejectedWriterResult, 'notify must return the real writer result unchanged');
2453
+ assert.equal(rejectedResult, null);
2454
+ assert.strictEqual(rejectedWriterClassification, rejectedClassification, 'rejected input must retain classification identity');
2455
+ assert.deepEqual(rejectedClassification?.matches, [], 'negated and quoted text must not activate a workflow');
2456
+ assert.deepEqual(Buffer.from(rejectedWriterText, 'utf8'), bytesBefore, 'writer must receive rejected input bytes unchanged');
2457
+ assert.deepEqual(await readFile(sessionSkillStatePath), skillStateBefore, 'rejected input must preserve canonical state bytes');
2458
+ assert.deepEqual(await readFile(autopilotStatePath), autopilotStateBefore, 'rejected input must preserve detail state bytes');
2459
+ assert.equal(existsSync(rootSkillStatePath), false, 'rejected session input must not create root canonical state');
2460
+ }
2461
+ });
2462
+ });
2463
+ it('G1a-N preserves ordered multi-skill classification and seeds only the ralplan primary when Team is enabled', async () => {
2464
+ await withTempWorkingDir(async (cwd) => {
2465
+ const stateDir = join(cwd, '.omx', 'state');
2466
+ const sessionId = 'sess-g1a-notify-ordered';
2467
+ const threadId = 'thread-g1a-notify-ordered';
2468
+ const turnId = 'turn-g1a-notify-ordered';
2469
+ const sessionDir = join(stateDir, 'sessions', sessionId);
2470
+ const text = '$ralplan, $autopilot; $team';
2471
+ let classification;
2472
+ let writerClassification;
2473
+ let writerCalls = 0;
2474
+ const previousTeamMode = process.env.OMX_TEAM_MODE;
2475
+ process.env.OMX_TEAM_MODE = 'enabled';
2476
+ try {
2477
+ const result = await recordNotifySkillActivation({
2478
+ stateDir,
2479
+ sourceCwd: cwd,
2480
+ text,
2481
+ sessionId,
2482
+ threadId,
2483
+ turnId,
2484
+ payload: { type: 'agent-turn-complete', 'thread-id': threadId, 'turn-id': turnId },
2485
+ }, {
2486
+ classifyKeywordInput: (input) => {
2487
+ classification = classifyKeywordInput(input);
2488
+ return classification;
2489
+ },
2490
+ recordSkillActivation: async (input) => {
2491
+ writerCalls += 1;
2492
+ writerClassification = input.classification;
2493
+ return recordSkillActivation(input);
2494
+ },
2495
+ });
2496
+ assert.equal(writerCalls, 1);
2497
+ assert.strictEqual(writerClassification, classification, 'notify must pass the ordered classifier output to the writer');
2498
+ assert.deepEqual(classification?.matches.map((match) => match.skill), ['ralplan', 'autopilot', 'team']);
2499
+ assert.equal(result?.skill, 'ralplan');
2500
+ assert.deepEqual(result?.deferred_skills, ['autopilot', 'team']);
2501
+ assert.deepEqual(result?.active_skills?.map((entry) => entry.skill), ['ralplan']);
2502
+ assert.equal(existsSync(join(sessionDir, 'ralplan-state.json')), true);
2503
+ assert.equal(existsSync(join(sessionDir, 'autopilot-state.json')), false);
2504
+ assert.equal(existsSync(join(stateDir, 'team-state.json')), false);
2505
+ }
2506
+ finally {
2507
+ if (previousTeamMode === undefined)
2508
+ delete process.env.OMX_TEAM_MODE;
2509
+ else
2510
+ process.env.OMX_TEAM_MODE = previousTeamMode;
2511
+ }
2512
+ });
2513
+ });
2514
+ it('G1c-N deduplicates exact canonical and alias Autopilot invocations across classifier, writer, canonical state, and detail state', async () => {
2515
+ await withTempWorkingDir(async (cwd) => {
2516
+ const stateDir = join(cwd, '.omx', 'state');
2517
+ const sessionId = 'sess-g1c-notify-duplicate';
2518
+ const threadId = 'thread-g1c-notify-duplicate';
2519
+ const turnId = 'turn-g1c-notify-duplicate';
2520
+ const sessionDir = join(stateDir, 'sessions', sessionId);
2521
+ const text = '$autopilot $oh-my-codex:autopilot build it';
2522
+ let classification;
2523
+ let writerClassification;
2524
+ let writerCalls = 0;
2525
+ const result = await recordNotifySkillActivation({
2526
+ stateDir,
2527
+ sourceCwd: cwd,
2528
+ text,
2529
+ sessionId,
2530
+ threadId,
2531
+ turnId,
2532
+ payload: { type: 'agent-turn-complete', 'thread-id': threadId, 'turn-id': turnId },
2533
+ }, {
2534
+ classifyKeywordInput: (input) => {
2535
+ classification = classifyKeywordInput(input);
2536
+ return classification;
2537
+ },
2538
+ recordSkillActivation: async (input) => {
2539
+ writerCalls += 1;
2540
+ writerClassification = input.classification;
2541
+ return recordSkillActivation(input);
2542
+ },
2543
+ });
2544
+ assert.equal(writerCalls, 1);
2545
+ assert.strictEqual(writerClassification, classification, 'writer must receive the deduplicated classifier output');
2546
+ assert.deepEqual(classification?.matches.map((match) => match.skill), ['autopilot']);
2547
+ assert.equal(result?.skill, 'autopilot');
2548
+ assert.deepEqual(result?.deferred_skills ?? [], []);
2549
+ assert.deepEqual(result?.active_skills?.map((entry) => entry.skill), ['autopilot']);
2550
+ const canonical = JSON.parse(await readFile(join(sessionDir, 'skill-active-state.json'), 'utf8'));
2551
+ assert.deepEqual(canonical.active_skills?.map((entry) => entry.skill), ['autopilot']);
2552
+ assert.equal(existsSync(join(sessionDir, 'autopilot-state.json')), true);
2553
+ });
2554
+ });
2555
+ // Notify Stop is N/A: it has no user-prompt activation transport to replay.
2556
+ it('G1b-N filters disabled Team before suppressing an exact same-turn terminal Autopilot replay without changing state bytes', async () => {
2557
+ await withTempWorkingDir(async (cwd) => {
2558
+ const stateDir = join(cwd, '.omx', 'state');
2559
+ const sessionId = 'sess-g1b-notify-terminal';
2560
+ const threadId = 'thread-g1b-notify-terminal';
2561
+ const turnId = 'turn-g1b-notify-terminal';
2562
+ const sessionDir = join(stateDir, 'sessions', sessionId);
2563
+ const sessionSkillPath = join(sessionDir, 'skill-active-state.json');
2564
+ const sessionAutopilotPath = join(sessionDir, 'autopilot-state.json');
2565
+ const rootSkillPath = join(stateDir, 'skill-active-state.json');
2566
+ const rootAutopilotPath = join(stateDir, 'autopilot-state.json');
2567
+ const seededPaths = [sessionSkillPath, sessionAutopilotPath, rootSkillPath, rootAutopilotPath];
2568
+ await mkdir(sessionDir, { recursive: true });
2569
+ await writeJson(sessionSkillPath, {
2570
+ version: 1,
2571
+ active: true,
2572
+ skill: 'autopilot',
2573
+ keyword: '$autopilot',
2574
+ phase: 'completing',
2575
+ session_id: sessionId,
2576
+ thread_id: threadId,
2577
+ turn_id: turnId,
2578
+ active_skills: [{ skill: 'autopilot', phase: 'completing', active: true, session_id: sessionId, thread_id: threadId, turn_id: turnId }],
2579
+ });
2580
+ await writeJson(sessionAutopilotPath, {
2581
+ mode: 'autopilot',
2582
+ active: false,
2583
+ current_phase: 'complete',
2584
+ completed_at: '2026-05-31T20:24:39.005Z',
2585
+ session_id: sessionId,
2586
+ thread_id: threadId,
2587
+ turn_id: turnId,
2588
+ });
2589
+ await writeJson(rootSkillPath, {
2590
+ version: 1,
2591
+ active: true,
2592
+ skill: 'autopilot',
2593
+ keyword: '$autopilot',
2594
+ phase: 'completing',
2595
+ scope: 'root-copy',
2596
+ session_id: sessionId,
2597
+ thread_id: threadId,
2598
+ turn_id: turnId,
2599
+ });
2600
+ await writeJson(rootAutopilotPath, {
2601
+ mode: 'autopilot',
2602
+ active: false,
2603
+ current_phase: 'complete',
2604
+ completed_at: '2026-05-31T20:24:39.005Z',
2605
+ scope: 'root-copy',
2606
+ session_id: sessionId,
2607
+ thread_id: threadId,
2608
+ turn_id: turnId,
2609
+ });
2610
+ const bytesBefore = new Map(await Promise.all(seededPaths.map(async (path) => [path, await readFile(path)])));
2611
+ const previousTeamMode = process.env.OMX_TEAM_MODE;
2612
+ process.env.OMX_TEAM_MODE = 'disabled';
2613
+ try {
2614
+ let classification;
2615
+ let writerCalls = 0;
2616
+ const result = await recordNotifySkillActivation({
2617
+ stateDir,
2618
+ sourceCwd: cwd,
2619
+ text: '$team $autopilot retry',
2620
+ sessionId,
2621
+ threadId,
2622
+ turnId,
2623
+ payload: {
2624
+ type: 'agent-turn-complete',
2625
+ 'thread-id': threadId,
2626
+ 'turn-id': turnId,
2627
+ 'last-assistant-message': 'Autopilot complete.',
2628
+ },
2629
+ }, {
2630
+ classifyKeywordInput: (text) => {
2631
+ classification = classifyKeywordInput(text);
2632
+ return classification;
2633
+ },
2634
+ recordSkillActivation: async () => {
2635
+ writerCalls += 1;
2636
+ return null;
2637
+ },
2638
+ });
2639
+ assert.deepEqual(classification?.matches.map((match) => match.skill), ['team', 'autopilot'], 'the source classification must retain Team before runtime filtering');
2640
+ assert.equal(writerCalls, 0, 'disabled Team filtering must expose the same-turn terminal Autopilot replay for suppression');
2641
+ assert.equal(result, null);
2642
+ for (const path of seededPaths) {
2643
+ assert.deepEqual(await readFile(path), bytesBefore.get(path), `same-turn notify replay must preserve ${path} byte-for-byte`);
2644
+ }
2645
+ }
2646
+ finally {
2647
+ if (previousTeamMode === undefined)
2648
+ delete process.env.OMX_TEAM_MODE;
2649
+ else
2650
+ process.env.OMX_TEAM_MODE = previousTeamMode;
2651
+ }
2652
+ });
2653
+ });
2654
+ it('G2a sends the exact stale predecessor prompt through the shared classification and writer boundary without state', async () => {
2655
+ await withTempWorkingDir(async (cwd) => {
2656
+ const stateDir = join(cwd, 'isolated-g2a-state-root');
2657
+ const sessionId = 'sess-g2a-stale-predecessor';
2658
+ const sessionDir = join(stateDir, 'sessions', sessionId);
2659
+ const rootSkillPath = join(stateDir, 'skill-active-state.json');
2660
+ const sessionSkillPath = join(sessionDir, 'skill-active-state.json');
2661
+ const rootRalplanPath = join(stateDir, 'ralplan-state.json');
2662
+ const sessionRalplanPath = join(sessionDir, 'ralplan-state.json');
2663
+ const text = 'use $ralplan is the consensus-planning command';
2664
+ const textBytes = Buffer.from(text, 'utf8');
2665
+ let classification;
2666
+ let writerClassification;
2667
+ let writerText = '';
2668
+ let writerCalls = 0;
2669
+ const result = await recordNotifySkillActivation({
2670
+ stateDir,
2671
+ sourceCwd: cwd,
2672
+ text,
2673
+ sessionId,
2674
+ threadId: 'thread-g2a-stale-predecessor',
2675
+ turnId: 'turn-g2a-stale-predecessor',
2676
+ payload: { type: 'agent-turn-complete' },
2677
+ }, {
2678
+ classifyKeywordInput: (input) => {
2679
+ classification = classifyKeywordInput(input);
2680
+ return classification;
2681
+ },
2682
+ recordSkillActivation: async (input) => {
2683
+ writerCalls += 1;
2684
+ writerText = input.text;
2685
+ writerClassification = input.classification;
2686
+ return recordSkillActivation(input);
2687
+ },
2688
+ });
2689
+ assert.equal(writerCalls, 1, 'notify must invoke the shared writer boundary once');
2690
+ assert.strictEqual(writerClassification, classification, 'notify must pass the original classification object to the writer');
2691
+ assert.deepEqual(Buffer.from(writerText, 'utf8'), textBytes, 'notify must pass the stale predecessor bytes unchanged');
2692
+ assert.deepEqual(classification?.matches, [], 'the stale predecessor wording must not activate ralplan');
2693
+ assert.equal(result, null);
2694
+ assert.equal(existsSync(stateDir), false, 'the stale predecessor wording must not create isolated state');
2695
+ assert.equal(existsSync(rootSkillPath), false, 'the stale predecessor wording must not create root canonical state');
2696
+ assert.equal(existsSync(sessionSkillPath), false, 'the stale predecessor wording must not create session canonical state');
2697
+ assert.equal(existsSync(rootRalplanPath), false, 'the stale predecessor wording must not create root ralplan detail state');
2698
+ assert.equal(existsSync(sessionRalplanPath), false, 'the stale predecessor wording must not create session ralplan detail state');
2699
+ });
2700
+ });
2701
+ it('G2b-N preserves five distinct terminal state files for the exact negated notify prompt without a fabricated Stop signal', async () => {
2702
+ await withTempWorkingDir(async (cwd) => {
2703
+ const stateDir = join(cwd, '.omx', 'state');
2704
+ const sessionId = 'sess-g2b-negated-terminal';
2705
+ const threadId = 'thread-g2b-negated-terminal';
2706
+ const turnId = 'turn-g2b-negated-terminal';
2707
+ const sessionDir = join(stateDir, 'sessions', sessionId);
2708
+ const sessionJsonPath = join(stateDir, 'session.json');
2709
+ const rootSkillPath = join(stateDir, 'skill-active-state.json');
2710
+ const rootAutopilotPath = join(stateDir, 'autopilot-state.json');
2711
+ const sessionSkillPath = join(sessionDir, 'skill-active-state.json');
2712
+ const sessionAutopilotPath = join(sessionDir, 'autopilot-state.json');
2713
+ const seededPaths = [sessionJsonPath, rootSkillPath, rootAutopilotPath, sessionSkillPath, sessionAutopilotPath];
2714
+ const terminalBytes = [
2715
+ Buffer.from(`{\n "session_id": "${sessionId}",\n "started_at": "2026-06-01T00:00:01.001Z",\n "turn_id": "turn-g2b-session-pointer"\n}\n`),
2716
+ Buffer.from(`{\n "version": 1,\n "active": true,\n "skill": "autopilot",\n "phase": "completing",\n "updated_at": "2026-06-01T00:00:02.002Z",\n "turn_id": "turn-g2b-root-skill"\n}\n`),
2717
+ Buffer.from(`{\n "mode": "autopilot",\n "active": false,\n "current_phase": "complete",\n "completed_at": "2026-06-01T00:00:03.003Z",\n "turn_id": "turn-g2b-root-detail"\n}\n`),
2718
+ Buffer.from(`{\n "version": 1,\n "active": true,\n "skill": "autopilot",\n "phase": "completing",\n "updated_at": "2026-06-01T00:00:04.004Z",\n "turn_id": "turn-g2b-session-skill"\n}\n`),
2719
+ Buffer.from(`{\n "mode": "autopilot",\n "active": false,\n "current_phase": "complete",\n "completed_at": "2026-06-01T00:00:05.005Z",\n "turn_id": "turn-g2b-session-detail"\n}\n`),
2720
+ ];
2721
+ await mkdir(sessionDir, { recursive: true });
2722
+ await Promise.all(seededPaths.map((path, index) => writeFile(path, terminalBytes[index])));
2723
+ const text = 'do not start $autopilot — café';
2724
+ const textBytes = Buffer.from(text, 'utf8');
2725
+ let classification;
2726
+ let writerClassification;
2727
+ let writerText = '';
2728
+ let writerCalls = 0;
2729
+ const result = await recordNotifySkillActivation({
2730
+ stateDir,
2731
+ sourceCwd: cwd,
2732
+ text,
2733
+ sessionId,
2734
+ threadId,
2735
+ turnId,
2736
+ payload: {
2737
+ type: 'agent-turn-complete',
2738
+ 'thread-id': threadId,
2739
+ 'turn-id': turnId,
2740
+ },
2741
+ }, {
2742
+ classifyKeywordInput: (input) => {
2743
+ classification = classifyKeywordInput(input);
2744
+ return classification;
2745
+ },
2746
+ recordSkillActivation: async (input) => {
2747
+ writerCalls += 1;
2748
+ writerText = input.text;
2749
+ writerClassification = input.classification;
2750
+ return recordSkillActivation(input);
2751
+ },
2752
+ });
2753
+ assert.equal(writerCalls, 1, 'the negated notify input must reach the shared writer boundary once');
2754
+ assert.strictEqual(writerClassification, classification, 'notify must retain classification identity for negated input');
2755
+ assert.deepEqual(Buffer.from(writerText, 'utf8'), textBytes, 'notify must retain the exact negated input bytes');
2756
+ assert.deepEqual(classification?.matches, [], 'the exact negated input must not restart Autopilot');
2757
+ assert.equal(result, null);
2758
+ for (const [index, path] of seededPaths.entries()) {
2759
+ assert.deepEqual(await readFile(path), terminalBytes[index], `negated notify input must preserve ${path} byte-for-byte`);
2760
+ }
2761
+ });
2762
+ });
2763
+ it('logs injected skill activation writer failures without failing the notify hook boundary', async () => {
2764
+ await withTempWorkingDir(async (cwd) => {
2765
+ const stateDir = join(cwd, '.omx', 'state');
2766
+ const logsDir = join(cwd, '.omx', 'logs');
2767
+ const sessionId = 'sess-notify-writer-failure';
2768
+ const threadId = 'thread-notify-writer-failure';
2769
+ const turnId = 'turn-notify-writer-failure';
2770
+ let writerCalls = 0;
2771
+ await mkdir(logsDir, { recursive: true });
2772
+ const result = await recordNotifySkillActivationNonFatal({
2773
+ stateDir,
2774
+ sourceCwd: cwd,
2775
+ text: '$ralplan plan this change',
2776
+ sessionId,
2777
+ threadId,
2778
+ turnId,
2779
+ payload: { type: 'agent-turn-complete' },
2780
+ }, logsDir, {
2781
+ recordSkillActivation: async () => {
2782
+ writerCalls += 1;
2783
+ throw new Error(`injected writer failure ${'x'.repeat(1_000)}`);
2784
+ },
2785
+ });
2786
+ assert.equal(result, null);
2787
+ assert.equal(writerCalls, 1);
2788
+ const logPath = join(logsDir, `notify-hook-${new Date().toISOString().split('T')[0]}.jsonl`);
2789
+ const events = (await readFile(logPath, 'utf8')).trim().split('\n')
2790
+ .map((line) => JSON.parse(line));
2791
+ const failure = events.find((event) => event.type === 'notify_skill_activation_failure');
2792
+ assert.ok(failure);
2793
+ assert.equal(failure.level, 'warn');
2794
+ assert.equal(failure.session_id, sessionId);
2795
+ assert.equal(failure.thread_id, threadId);
2796
+ assert.equal(failure.turn_id, turnId);
2797
+ assert.match(String(failure.error), /^injected writer failure /);
2798
+ assert.ok(String(failure.error).length <= 512);
2799
+ assert.equal(Number.isNaN(Date.parse(String(failure.timestamp))), false);
2800
+ });
2801
+ });
2051
2802
  it('writes skill-active-state.json when keyword activation is detected', async () => {
2052
2803
  await withTempWorkingDir(async (cwd) => {
2053
2804
  const omxDir = join(cwd, '.omx');
@@ -2067,7 +2818,7 @@ exit 0
2067
2818
  await writeFile(join(fakeBinDir, 'tmux'), buildFakeTmux(join(cwd, 'tmux.log')));
2068
2819
  await chmod(join(fakeBinDir, 'tmux'), 0o755);
2069
2820
  const result = runNotifyHook(cwd, fakeBinDir, codexHome, {
2070
- 'input-messages': ['please use $autopilot for this task'],
2821
+ 'input-messages': ['$autopilot handle this task'],
2071
2822
  'last-assistant-message': 'Here is the plan I will follow.',
2072
2823
  });
2073
2824
  assert.equal(result.status, 0, `hook failed: ${result.stderr || result.stdout}`);
@@ -2439,12 +3190,14 @@ exit 0
2439
3190
  phase: 'executing',
2440
3191
  source: 'keyword-detector',
2441
3192
  session_id: 'sess-managed',
3193
+ owner_codex_session_id: 'sess-managed',
2442
3194
  });
2443
3195
  await writeJson(join(sessionStateDir, 'autoresearch-state.json'), {
2444
3196
  active: true,
2445
3197
  mode: 'autoresearch',
2446
3198
  current_phase: 'executing',
2447
3199
  session_id: 'sess-managed',
3200
+ owner_codex_session_id: 'sess-managed',
2448
3201
  validation_mode: 'mission-validator-script',
2449
3202
  mission_validator_command: 'node scripts/validate.js',
2450
3203
  completion_artifact_path: '.omx/specs/autoresearch-demo/completion.json',
@@ -2488,12 +3241,14 @@ exit 0
2488
3241
  phase: 'reviewing',
2489
3242
  source: 'keyword-detector',
2490
3243
  session_id: 'sess-managed',
3244
+ owner_codex_session_id: 'sess-managed',
2491
3245
  });
2492
3246
  await writeJson(join(sessionStateDir, 'autoresearch-state.json'), {
2493
3247
  active: true,
2494
3248
  mode: 'autoresearch',
2495
3249
  current_phase: 'reviewing',
2496
3250
  session_id: 'sess-managed',
3251
+ owner_codex_session_id: 'sess-managed',
2497
3252
  validation_mode: 'mission-validator-script',
2498
3253
  mission_validator_command: 'node scripts/validate.js',
2499
3254
  completion_artifact_path: '.omx/specs/autoresearch-demo/completion.json',