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
@@ -1,11 +1,25 @@
1
1
  // @ts-nocheck
2
2
  import assert from 'node:assert/strict';
3
- import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
3
+ import { access, chmod, mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises';
4
+ import { EventEmitter } from 'node:events';
4
5
  import { tmpdir } from 'node:os';
5
- import { join } from 'node:path';
6
+ import { delimiter, join } from 'node:path';
7
+ import { PassThrough } from 'node:stream';
6
8
  import { test } from 'node:test';
7
- import { ensureRepoDependencies, hasUsableNodeModules, buildNativeHookSmokePayload, PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS, PACKED_INSTALL_SMOKE_CORE_COMMANDS, parseNpmPackJsonOutput, resolveGitCommonDir, resolveReusableNodeModulesSource, validateHookStdout, } from '../smoke-packed-install.js';
8
- test('packed install smoke stays limited to boot + core commands', () => {
9
+ import { assertInstalledPluginSurface, assertInstalledReasoningDeclarationContract, assertInstalledReasoningRuntimeContract, assertInstalledRootReasoningHelp, assertInstalledRootReasoningRejection, assertInstalledTeamSkillContract, assertPackedInstallFileMetadata, buildNativeHookSmokePayload, ensureRepoDependencies, hasUsableNodeModules, buildPackedRegressionEnvironment, CODEX_APP_SERVER_TIMEOUTS, CodexAppServer, CodexExecutableNotFoundError, MANAGED_CODEX_HOOK_EVENTS, PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS, PACKED_INSTALL_NATIVE_HOOK_REGRESSION_PROMPTS, PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, PACKED_INSTALL_SMOKE_CORE_COMMANDS, appendForeignHookGroups, appendDisplayOrderStableForeignHookGroups, createCodexBatchWriteEnvelope, createCodexHooksListEnvelope, createCodexInitializeEnvelope, foreignHookGroupSnapshot, generatedHookTrustState, isForbiddenPackedInstallArtifact, PACKED_INSTALL_FORBIDDEN_ARTIFACT_PATHS, PACKED_INSTALL_REQUIRED_ARTIFACT_PATHS, PACKED_INSTALL_PLUGIN_MCP_TARGETS, parseFakeCodexLaunches, parseNpmPackJsonOutput, parseCodexHooksListResult, probeCodexVersion, resolveGitCommonDir, resolveReusableNodeModulesSource, validateHookStdout, assertCodexBatchWriteResult, assertGeneratedTrustMatchesCodex, managedCodexHooksByEvent, } from '../smoke-packed-install.js';
10
+ import { parseNativeSubagentResultDisposition } from '../../leader/contract.js';
11
+ function createFakeCodexAppServer(onRequest) {
12
+ const child = Object.assign(new EventEmitter(), {
13
+ stdin: new PassThrough(),
14
+ stdout: new PassThrough(),
15
+ stderr: new PassThrough(),
16
+ kill: () => true,
17
+ });
18
+ child.stdin.on('data', (chunk) => onRequest(JSON.parse(chunk.toString('utf-8')), child));
19
+ child.stdin.on('finish', () => child.emit('close', 0, null));
20
+ return new CodexAppServer(child);
21
+ }
22
+ test('packed install smoke retains narrow boot commands and adds the isolated lifecycle separately', () => {
9
23
  assert.deepEqual(PACKED_INSTALL_SMOKE_CORE_COMMANDS, [
10
24
  ['--help'],
11
25
  ['version'],
@@ -15,6 +29,680 @@ test('packed install smoke stays limited to boot + core commands', () => {
15
29
  assert.equal(PACKED_INSTALL_SMOKE_CORE_COMMANDS.some((argv) => argv.includes('api')), true);
16
30
  assert.equal(PACKED_INSTALL_SMOKE_CORE_COMMANDS.some((argv) => argv.includes('sparkshell')), true);
17
31
  });
32
+ test('packed 0.144.5 fixture is sanitized, pointer-free, and kept separate from the 0.142.5 lifecycle pin', () => {
33
+ assert.deepEqual(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, {
34
+ hook_event_name: 'PreToolUse',
35
+ session_id: 'packed-01445-session',
36
+ turn_id: 'packed-01445-turn',
37
+ tool_name: 'Bash',
38
+ tool_use_id: 'packed-01445-tool',
39
+ tool_input: { command: 'omx ralplan role-intent write --role architect --parent-thread "$CODEX_THREAD_ID" --json' },
40
+ });
41
+ assert.equal(Object.hasOwn(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, 'tracker'), false);
42
+ assert.equal(Object.hasOwn(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, 'session_pointer'), false);
43
+ assert.equal(Object.hasOwn(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, 'cwd'), false);
44
+ assert.equal(Object.hasOwn(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, 'thread_id'), false);
45
+ assert.equal(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE.session_id.includes('-'), true);
46
+ });
47
+ test('packed plugin collaboration success stays authoritative over unrelated child prose', () => {
48
+ const packedResponse = JSON.stringify({
49
+ success: true,
50
+ status: 'completed',
51
+ output: 'Packed/plugin child succeeded; an optional adapter was unavailable, unsupported, and not found.',
52
+ });
53
+ for (const toolName of [
54
+ 'collaboration.spawn_agent',
55
+ 'collaboration.list_agents',
56
+ 'collaboration.followup_task',
57
+ 'collaboration.wait_agent',
58
+ ]) {
59
+ assert.equal(parseNativeSubagentResultDisposition(toolName, packedResponse).kind, 'success', toolName);
60
+ }
61
+ });
62
+ test('packed lifecycle keeps the pinned newline-delimited Codex app-server envelopes literal', () => {
63
+ assert.deepEqual(createCodexInitializeEnvelope('omx-hook-trust-regression'), {
64
+ id: 1,
65
+ method: 'initialize',
66
+ params: {
67
+ clientInfo: { name: 'omx-hook-trust-regression', version: '1.0.0' },
68
+ capabilities: null,
69
+ },
70
+ });
71
+ assert.deepEqual(createCodexHooksListEnvelope('/tmp/project'), {
72
+ id: 2,
73
+ method: 'hooks/list',
74
+ params: { cwds: ['/tmp/project'] },
75
+ });
76
+ assert.deepEqual(createCodexBatchWriteEnvelope({ first: 'sha256:first', second: 'sha256:second' }), {
77
+ id: 3,
78
+ method: 'config/batchWrite',
79
+ params: {
80
+ edits: [{
81
+ keyPath: 'hooks.state',
82
+ value: {
83
+ first: { trusted_hash: 'sha256:first' },
84
+ second: { trusted_hash: 'sha256:second' },
85
+ },
86
+ mergeStrategy: 'upsert',
87
+ }],
88
+ filePath: null,
89
+ expectedVersion: null,
90
+ reloadUserConfig: true,
91
+ },
92
+ });
93
+ assert.deepEqual(CODEX_APP_SERVER_TIMEOUTS, {
94
+ versionProbeMs: 2_000,
95
+ initializeMs: 15_000,
96
+ requestMs: 10_000,
97
+ shutdownMs: 5_000,
98
+ });
99
+ });
100
+ test('Codex app-server accepts method-bearing notifications but rejects invalid idless envelopes', async () => {
101
+ const accepted = createFakeCodexAppServer((request, child) => {
102
+ child.stdout.write(`${JSON.stringify({ method: 'thread/started', params: { thread: 'fake' } })}\n`);
103
+ child.stdout.write(`${JSON.stringify({ id: request.id, result: { ok: true } })}\n`);
104
+ });
105
+ assert.deepEqual(await accepted.request({ id: 1, method: 'hooks/list' }, 100), { ok: true });
106
+ await accepted.close();
107
+ for (const envelope of [
108
+ { result: { invalid: true } },
109
+ { error: { code: -1, message: 'invalid' } },
110
+ { unknown: true },
111
+ { method: ' ' },
112
+ { method: 'thread/started', result: { invalid: true } },
113
+ ]) {
114
+ const server = createFakeCodexAppServer((_request, child) => {
115
+ child.stdout.write(`${JSON.stringify(envelope)}\n`);
116
+ });
117
+ await assert.rejects(server.request({ id: 1, method: 'hooks/list' }, 100), /invalid idless JSON-RPC envelope/);
118
+ await assert.rejects(server.close(), /invalid idless JSON-RPC envelope/);
119
+ }
120
+ });
121
+ test('Codex app-server rejects id-bearing envelopes that mix response and request fields', async () => {
122
+ for (const envelope of [
123
+ { id: 1, method: 'thread/started', result: { invalid: true } },
124
+ { id: 1, params: { thread: 'fake' }, result: { invalid: true } },
125
+ { id: 1, method: 'thread/started', params: {}, error: { code: -1, message: 'invalid' } },
126
+ { id: 1, result: { invalid: true }, error: { code: -1, message: 'invalid' } },
127
+ { id: 1 },
128
+ ]) {
129
+ const server = createFakeCodexAppServer((_request, child) => {
130
+ child.stdout.write(`${JSON.stringify(envelope)}\n`);
131
+ });
132
+ await assert.rejects(server.request({ id: 1, method: 'hooks/list' }, 100), /codex app-server response/);
133
+ await assert.rejects(server.close(), /codex app-server response/);
134
+ }
135
+ });
136
+ test('Codex app-server validates JSON-RPC error response shapes', async () => {
137
+ const valid = createFakeCodexAppServer((_request, child) => {
138
+ child.stdout.write(`${JSON.stringify({
139
+ id: 1,
140
+ error: { code: -32600, message: 'invalid request', data: { source: 'fake' } },
141
+ })}\n`);
142
+ });
143
+ await assert.rejects(valid.request({ id: 1, method: 'hooks/list' }, 100), /returned JSON-RPC error/);
144
+ await valid.close();
145
+ for (const error of [
146
+ null,
147
+ {},
148
+ { code: '-32600', message: 'invalid request' },
149
+ { code: -32600, message: null },
150
+ ]) {
151
+ const server = createFakeCodexAppServer((_request, child) => {
152
+ child.stdout.write(`${JSON.stringify({ id: 1, error })}\n`);
153
+ });
154
+ await assert.rejects(server.request({ id: 1, method: 'hooks/list' }, 100), /malformed JSON-RPC error/);
155
+ await assert.rejects(server.close(), /malformed JSON-RPC error/);
156
+ }
157
+ });
158
+ test('Codex app-server incrementally decodes split UTF-8 responses and rejects invalid byte sequences', async () => {
159
+ const split = createFakeCodexAppServer((_request, child) => {
160
+ child.stdout.write(Buffer.from('{"id":1,"result":"', 'utf-8'));
161
+ child.stdout.write(Buffer.from([0xe2, 0x82]));
162
+ child.stdout.write(Buffer.from([0xac]));
163
+ child.stdout.write(Buffer.from('"}\n', 'utf-8'));
164
+ });
165
+ assert.equal(await split.request({ id: 1, method: 'hooks/list' }, 100), '€');
166
+ await split.close();
167
+ for (const writeInvalidResponse of [
168
+ (child) => {
169
+ child.stdout.write(Buffer.from('{"id":1,"result":"', 'utf-8'));
170
+ child.stdout.write(Buffer.from([0xff]));
171
+ child.stdout.write(Buffer.from('"}\n', 'utf-8'));
172
+ },
173
+ (child) => {
174
+ child.stdout.write(Buffer.from('{"id":1,"result":"', 'utf-8'));
175
+ child.stdout.write(Buffer.from([0xc3]));
176
+ },
177
+ ]) {
178
+ const server = createFakeCodexAppServer((_request, child) => writeInvalidResponse(child));
179
+ const request = server.request({ id: 1, method: 'hooks/list' }, 100);
180
+ await assert.rejects(Promise.all([request, server.close()]), /invalid UTF-8 stdout/);
181
+ }
182
+ });
183
+ test('Codex app-server rejects non-empty unterminated stdout when the server closes', async () => {
184
+ const server = createFakeCodexAppServer((_request, child) => {
185
+ child.stdout.write('{"id":1');
186
+ });
187
+ const request = server.request({ id: 1, method: 'hooks/list' }, 100);
188
+ await assert.rejects(Promise.all([request, server.close()]), /unterminated JSON-RPC stdout/);
189
+ });
190
+ test('packed lifecycle parses the pinned hooks/list eventName schema', () => {
191
+ const project = '/tmp/project';
192
+ const hooksPath = '/tmp/project/.codex/hooks.json';
193
+ const parsed = parseCodexHooksListResult({
194
+ data: [{
195
+ cwd: project,
196
+ hooks: [{
197
+ eventName: 'preToolUse',
198
+ command: 'node hook.js',
199
+ sourcePath: hooksPath,
200
+ key: `${hooksPath}:pre_tool_use:0:0`,
201
+ currentHash: 'sha256:current',
202
+ displayOrder: 0,
203
+ trustStatus: 'trusted',
204
+ }],
205
+ warnings: [],
206
+ errors: [],
207
+ }],
208
+ }, project, hooksPath);
209
+ assert.equal(parsed.hooks[0]?.event, 'PreToolUse');
210
+ assert.equal(parsed.hooks[0]?.trustStatus, 'trusted');
211
+ });
212
+ test('packed lifecycle normalizes omitted enabled handlers and rejects disabled or non-integer hook metadata', () => {
213
+ const project = '/tmp/project';
214
+ const hooksPath = '/tmp/project/.codex/hooks.json';
215
+ const response = {
216
+ data: [{
217
+ cwd: project,
218
+ hooks: [{
219
+ eventName: 'preToolUse',
220
+ command: 'node hook.js',
221
+ sourcePath: hooksPath,
222
+ key: `${hooksPath}:pre_tool_use:0:0`,
223
+ currentHash: 'sha256:current',
224
+ displayOrder: 0,
225
+ trustStatus: 'trusted',
226
+ }],
227
+ warnings: [],
228
+ errors: [],
229
+ }],
230
+ };
231
+ assert.doesNotThrow(() => parseCodexHooksListResult(response, project, hooksPath));
232
+ for (const update of [
233
+ { enabled: false },
234
+ { enabled: 'true' },
235
+ { enabled: true, displayOrder: 0.5 },
236
+ { enabled: true, displayOrder: -1 },
237
+ ]) {
238
+ const invalid = structuredClone(response);
239
+ Object.assign(invalid.data[0].hooks[0], update);
240
+ assert.throws(() => parseCodexHooksListResult(invalid, project, hooksPath), /enabled command handler|invalid hooks\[0\]\.displayOrder/);
241
+ }
242
+ });
243
+ test('packed lifecycle requires exactly seven generated OMX trust keys and an isolated approval target', () => {
244
+ const hooks = MANAGED_CODEX_HOOK_EVENTS.map((event, index) => ({
245
+ event,
246
+ command: 'node /tmp/omx/dist/scripts/codex-native-hook.js',
247
+ sourcePath: '/tmp/project/.codex/hooks.json',
248
+ key: `/tmp/project/.codex/hooks.json:${event}:${index}:0`,
249
+ currentHash: `sha256:${event}`,
250
+ displayOrder: index,
251
+ trustStatus: 'untrusted',
252
+ }));
253
+ const trust = Object.fromEntries(hooks.map((hook) => [hook.key, hook.currentHash]));
254
+ assert.doesNotThrow(() => assertGeneratedTrustMatchesCodex(trust, hooks));
255
+ assert.throws(() => assertGeneratedTrustMatchesCodex({
256
+ ...trust,
257
+ '/tmp/project/.codex/hooks.json:foreign:0:0': 'sha256:foreign',
258
+ }, hooks), /exactly the 7 current OMX hooks with no stale keys/);
259
+ assert.throws(() => assertGeneratedTrustMatchesCodex(Object.fromEntries(Object.entries(trust).slice(0, -1)), hooks), /exactly the 7 current OMX hooks with no stale keys/);
260
+ assert.doesNotThrow(() => assertCodexBatchWriteResult({
261
+ filePath: '/tmp/isolated-codex-home/config.toml',
262
+ status: 'ok',
263
+ version: null,
264
+ }, '/tmp/isolated-codex-home/config.toml'));
265
+ assert.throws(() => assertCodexBatchWriteResult({
266
+ filePath: '/home/user/.codex/config.toml',
267
+ status: 'ok',
268
+ version: null,
269
+ }, '/tmp/isolated-codex-home/config.toml'), /expected isolated user config/);
270
+ });
271
+ test('packed lifecycle fails closed on malformed project hooks.state entries and stale raw keys', () => {
272
+ const hooks = MANAGED_CODEX_HOOK_EVENTS.map((event, index) => ({
273
+ event,
274
+ command: 'node /tmp/omx/dist/scripts/codex-native-hook.js',
275
+ sourcePath: '/tmp/project/.codex/hooks.json',
276
+ key: `/tmp/project/.codex/hooks.json:${event}:${index}:0`,
277
+ currentHash: `sha256:${event}`,
278
+ displayOrder: index,
279
+ trustStatus: 'untrusted',
280
+ }));
281
+ const validConfig = [
282
+ '[hooks.state]',
283
+ ...hooks.map((hook) => `${JSON.stringify(hook.key)} = { trusted_hash = ${JSON.stringify(hook.currentHash)} }`),
284
+ ].join('\n');
285
+ const generatedTrust = generatedHookTrustState(validConfig);
286
+ assert.doesNotThrow(() => assertGeneratedTrustMatchesCodex(generatedTrust, hooks));
287
+ for (const malformedEntry of [
288
+ 'first = "sha256:first"',
289
+ 'first = {}',
290
+ 'first = { trusted_hash = "" }',
291
+ 'first = { trusted_hash = 1 }',
292
+ 'first = { trusted_hash = "sha256:first", extra = "unexpected" }',
293
+ ]) {
294
+ assert.throws(() => generatedHookTrustState(`[hooks.state]\n${malformedEntry}`), /invalid hooks\.state entry first/);
295
+ }
296
+ const staleRawTrust = generatedHookTrustState(`${validConfig}\nforeign = { trusted_hash = "sha256:foreign" }`);
297
+ assert.throws(() => assertGeneratedTrustMatchesCodex(staleRawTrust, hooks), /exactly the 7 current OMX hooks with no stale keys/);
298
+ const protoRawTrust = generatedHookTrustState(`${validConfig}\n__proto__ = { trusted_hash = "sha256:proto" }`);
299
+ assert.equal(Object.hasOwn(protoRawTrust, '__proto__'), true);
300
+ assert.throws(() => assertGeneratedTrustMatchesCodex(protoRawTrust, hooks), /exactly the 7 current OMX hooks with no stale keys/);
301
+ });
302
+ test('packed lifecycle treats only the production command grammar as managed ownership', () => {
303
+ const hooks = MANAGED_CODEX_HOOK_EVENTS.map((event, index) => ({
304
+ event,
305
+ command: 'node /tmp/omx/dist/scripts/codex-native-hook.js',
306
+ sourcePath: '/tmp/project/.codex/hooks.json',
307
+ key: `/tmp/project/.codex/hooks.json:${event}:${index}:0`,
308
+ currentHash: `sha256:${event}`,
309
+ displayOrder: index,
310
+ trustStatus: 'untrusted',
311
+ }));
312
+ hooks[0].command = 'node /tmp/foreign-codex-native-hook.js';
313
+ assert.throws(() => managedCodexHooksByEvent(hooks), /Expected exactly one OMX SessionStart hook from Codex, received 0/);
314
+ });
315
+ test('packed lifecycle resolves Windows npm shims through safe command specs for version probes and app-server', async () => {
316
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-windows-shim-'));
317
+ const fakeChild = () => {
318
+ const child = Object.assign(new EventEmitter(), {
319
+ stdin: new PassThrough(),
320
+ stdout: new PassThrough(),
321
+ stderr: new PassThrough(),
322
+ kill: () => {
323
+ queueMicrotask(() => child.emit('close', 0, null));
324
+ return true;
325
+ },
326
+ });
327
+ child.stdin.once('finish', () => queueMicrotask(() => child.emit('close', 0, null)));
328
+ queueMicrotask(() => child.emit('spawn'));
329
+ return child;
330
+ };
331
+ try {
332
+ for (const extension of ['.cmd', '.ps1']) {
333
+ const bin = join(root, extension.slice(1));
334
+ const codexPath = join(bin, `codex${extension}`);
335
+ const powershellPath = join(bin, 'powershell.exe');
336
+ await mkdir(bin, { recursive: true });
337
+ await Promise.all([writeFile(codexPath, ''), writeFile(powershellPath, '')]);
338
+ const versionSpawns = [];
339
+ const appSpawns = [];
340
+ const seam = {
341
+ platform: 'win32',
342
+ spawnSyncImpl: ((command, args, options) => {
343
+ versionSpawns.push({ command, args, options });
344
+ return { status: 0, stdout: 'codex-cli 0.142.5\n', stderr: '', error: undefined };
345
+ }),
346
+ spawnImpl: ((command, args, options) => {
347
+ appSpawns.push({ command, args, options });
348
+ return fakeChild();
349
+ }),
350
+ };
351
+ const env = { PATH: bin, PATHEXT: extension.toUpperCase() };
352
+ assert.equal(probeCodexVersion(root, env, seam), 'codex-cli 0.142.5');
353
+ const server = await CodexAppServer.start({ cwd: root, env, commandSeam: seam });
354
+ await server.close();
355
+ assert.equal(versionSpawns.length, 2);
356
+ assert.deepEqual(versionSpawns.map(({ command, args, options }) => ({ command, args, options })), extension === '.cmd'
357
+ ? [
358
+ {
359
+ command: 'cmd.exe',
360
+ args: ['/d', '/s', '/c', `""${codexPath}" "--version""`],
361
+ options: {
362
+ cwd: root,
363
+ env,
364
+ encoding: 'utf-8',
365
+ timeout: CODEX_APP_SERVER_TIMEOUTS.versionProbeMs,
366
+ killSignal: 'SIGKILL',
367
+ windowsHide: true,
368
+ windowsVerbatimArguments: true,
369
+ },
370
+ },
371
+ {
372
+ command: 'cmd.exe',
373
+ args: ['/d', '/s', '/c', `""${codexPath}" "--version""`],
374
+ options: {
375
+ cwd: root,
376
+ env,
377
+ encoding: 'utf-8',
378
+ timeout: CODEX_APP_SERVER_TIMEOUTS.versionProbeMs,
379
+ killSignal: 'SIGKILL',
380
+ windowsHide: true,
381
+ windowsVerbatimArguments: true,
382
+ },
383
+ },
384
+ ]
385
+ : [
386
+ {
387
+ command: powershellPath,
388
+ args: ['-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', codexPath, '--version'],
389
+ options: {
390
+ cwd: root,
391
+ env,
392
+ encoding: 'utf-8',
393
+ timeout: CODEX_APP_SERVER_TIMEOUTS.versionProbeMs,
394
+ killSignal: 'SIGKILL',
395
+ windowsHide: true,
396
+ },
397
+ },
398
+ {
399
+ command: powershellPath,
400
+ args: ['-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', codexPath, '--version'],
401
+ options: {
402
+ cwd: root,
403
+ env,
404
+ encoding: 'utf-8',
405
+ timeout: CODEX_APP_SERVER_TIMEOUTS.versionProbeMs,
406
+ killSignal: 'SIGKILL',
407
+ windowsHide: true,
408
+ },
409
+ },
410
+ ]);
411
+ assert.deepEqual(appSpawns, extension === '.cmd'
412
+ ? [{
413
+ command: 'cmd.exe',
414
+ args: ['/d', '/s', '/c', `""${codexPath}" "app-server" "--stdio""`],
415
+ options: { cwd: root, env, stdio: 'pipe', windowsHide: true, windowsVerbatimArguments: true },
416
+ }]
417
+ : [{
418
+ command: powershellPath,
419
+ args: ['-NoLogo', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', codexPath, 'app-server', '--stdio'],
420
+ options: { cwd: root, env, stdio: 'pipe', windowsHide: true },
421
+ }]);
422
+ }
423
+ }
424
+ finally {
425
+ await rm(root, { recursive: true, force: true });
426
+ }
427
+ });
428
+ test('packed lifecycle bypasses an unrelated codex binary shadowing the pinned CLI', async () => {
429
+ if (process.platform === 'win32')
430
+ return;
431
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-path-'));
432
+ const shadowDir = join(root, 'shadow');
433
+ const pinnedDir = join(root, 'pinned');
434
+ try {
435
+ await Promise.all([
436
+ mkdir(shadowDir, { recursive: true }),
437
+ mkdir(pinnedDir, { recursive: true }),
438
+ ]);
439
+ const shadow = join(shadowDir, 'codex');
440
+ const pinned = join(pinnedDir, 'codex');
441
+ await Promise.all([
442
+ writeFile(shadow, '#!/bin/sh\necho "codex 0.2.3"\n'),
443
+ writeFile(pinned, '#!/bin/sh\necho "codex-cli 0.142.5"\n'),
444
+ ]);
445
+ await Promise.all([chmod(shadow, 0o755), chmod(pinned, 0o755)]);
446
+ assert.equal(probeCodexVersion(root, { PATH: `${shadowDir}${delimiter}${pinnedDir}` }), 'codex-cli 0.142.5');
447
+ }
448
+ finally {
449
+ await rm(root, { recursive: true, force: true });
450
+ }
451
+ });
452
+ test('packed lifecycle deduplicates repeated PATH entries before enforcing the candidate budget', async () => {
453
+ if (process.platform === 'win32')
454
+ return;
455
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-path-dedup-'));
456
+ const shadowDir = join(root, 'shadow');
457
+ const pinnedDir = join(root, 'pinned');
458
+ try {
459
+ await Promise.all([
460
+ mkdir(shadowDir, { recursive: true }),
461
+ mkdir(pinnedDir, { recursive: true }),
462
+ ]);
463
+ await Promise.all([
464
+ writeFile(join(shadowDir, 'codex'), '#!/bin/sh\necho "codex 0.2.3"\n'),
465
+ writeFile(join(pinnedDir, 'codex'), '#!/bin/sh\necho "codex-cli 0.142.5"\n'),
466
+ ]);
467
+ await Promise.all([
468
+ chmod(join(shadowDir, 'codex'), 0o755),
469
+ chmod(join(pinnedDir, 'codex'), 0o755),
470
+ ]);
471
+ assert.equal(probeCodexVersion(root, {
472
+ PATH: [...Array.from({ length: 40 }, () => shadowDir), pinnedDir].join(delimiter),
473
+ }), 'codex-cli 0.142.5');
474
+ }
475
+ finally {
476
+ await rm(root, { recursive: true, force: true });
477
+ }
478
+ });
479
+ test('packed lifecycle accepts only the exact stable pinned Codex version output', async () => {
480
+ if (process.platform === 'win32')
481
+ return;
482
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-version-'));
483
+ const candidateDir = join(root, 'candidate');
484
+ const executable = join(candidateDir, 'codex');
485
+ const candidates = [
486
+ { output: 'codex-cli 0.142.5', stderr: '', accepted: true },
487
+ { output: 'codex-cli 0.142.5', stderr: 'warning: harmless test diagnostic', accepted: true },
488
+ { output: 'codex-cli 0.142.5\nextra output', stderr: '', accepted: false },
489
+ { output: 'codex-cli 0.142.5-beta', stderr: '', accepted: false },
490
+ { output: 'codex-cli 0.142.5+meta', stderr: '', accepted: false },
491
+ { output: 'codex-cli 0.142.5.1', stderr: '', accepted: false },
492
+ { output: 'codex-cli v0.142.5', stderr: '', accepted: false },
493
+ { output: 'codex-cli 0-142-5', stderr: '', accepted: false },
494
+ { output: 'codex-cli 0.142.5', stderr: 'unexpected version probe error', accepted: false },
495
+ ];
496
+ try {
497
+ await mkdir(candidateDir, { recursive: true });
498
+ for (const candidate of candidates) {
499
+ await writeFile(executable, `#!/bin/sh\nprintf '%s\\n' '${candidate.output}'\n${candidate.stderr ? `printf '%s\\n' '${candidate.stderr}' >&2\n` : ''}`);
500
+ await chmod(executable, 0o755);
501
+ if (candidate.accepted) {
502
+ assert.equal(probeCodexVersion(root, { PATH: candidateDir }), 'codex-cli 0.142.5');
503
+ }
504
+ else {
505
+ assert.throws(() => probeCodexVersion(root, { PATH: candidateDir }), /Unsupported installed Codex version for the 0\.142\.5 boundary/);
506
+ }
507
+ }
508
+ }
509
+ finally {
510
+ await rm(root, { recursive: true, force: true });
511
+ }
512
+ });
513
+ test('packed lifecycle does not classify an installed Codex with a broken shebang as absent', async () => {
514
+ if (process.platform === 'win32')
515
+ return;
516
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-broken-shebang-'));
517
+ const candidateDir = join(root, 'candidate');
518
+ const executable = join(candidateDir, 'codex');
519
+ try {
520
+ await mkdir(candidateDir, { recursive: true });
521
+ await writeFile(executable, '#!/definitely-not-an-installed-interpreter\n');
522
+ await chmod(executable, 0o755);
523
+ assert.throws(() => probeCodexVersion(root, { PATH: candidateDir }), /launch returned ENOENT after an existing candidate was observed/);
524
+ }
525
+ finally {
526
+ await rm(root, { recursive: true, force: true });
527
+ }
528
+ });
529
+ test('packed lifecycle does not classify a dangling Codex candidate as absent', async () => {
530
+ if (process.platform === 'win32')
531
+ return;
532
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-dangling-'));
533
+ const candidateDir = join(root, 'candidate');
534
+ try {
535
+ await mkdir(candidateDir, { recursive: true });
536
+ await symlink(join(root, 'missing-codex'), join(candidateDir, 'codex'));
537
+ assert.throws(() => probeCodexVersion(root, { PATH: candidateDir }), /candidate exists but its target is unavailable/);
538
+ }
539
+ finally {
540
+ await rm(root, { recursive: true, force: true });
541
+ }
542
+ });
543
+ test('packed lifecycle does not classify a dangling PATH entry as absent', async () => {
544
+ if (process.platform === 'win32')
545
+ return;
546
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-dangling-path-'));
547
+ const danglingPathEntry = join(root, 'dangling-path-entry');
548
+ try {
549
+ await symlink(join(root, 'missing-path-entry'), danglingPathEntry);
550
+ assert.throws(() => probeCodexVersion(root, { PATH: danglingPathEntry }), /PATH entry exists but its target is unavailable/);
551
+ }
552
+ finally {
553
+ await rm(root, { recursive: true, force: true });
554
+ }
555
+ });
556
+ test('packed lifecycle bounds all slow Codex candidates with a global deadline', async () => {
557
+ if (process.platform === 'win32')
558
+ return;
559
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-global-deadline-'));
560
+ const slowDirs = ['slow-one', 'slow-two', 'slow-three'].map((name) => join(root, name));
561
+ try {
562
+ await Promise.all(slowDirs.map((dir) => mkdir(dir, { recursive: true })));
563
+ await Promise.all(slowDirs.map(async (dir) => {
564
+ const executable = join(dir, 'codex');
565
+ await writeFile(executable, '#!/bin/sh\nexec /bin/sleep 30\n');
566
+ await chmod(executable, 0o755);
567
+ }));
568
+ const startedAt = Date.now();
569
+ assert.throws(() => probeCodexVersion(root, { PATH: slowDirs.join(delimiter) }), /global deadline/);
570
+ assert.ok(Date.now() - startedAt < 6_500, 'the global version-resolution deadline must force termination');
571
+ }
572
+ finally {
573
+ await rm(root, { recursive: true, force: true });
574
+ }
575
+ });
576
+ test('packed lifecycle fails before probing the 33rd unique PATH candidate', async () => {
577
+ if (process.platform === 'win32')
578
+ return;
579
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-candidate-budget-'));
580
+ const candidateDirs = Array.from({ length: 33 }, (_value, index) => join(root, `candidate-${index}`));
581
+ const thirtyThirdProbe = join(root, '33rd-candidate-was-probed');
582
+ try {
583
+ await Promise.all(candidateDirs.map((dir) => mkdir(dir, { recursive: true })));
584
+ await Promise.all(candidateDirs.map(async (dir, index) => {
585
+ const executable = join(dir, 'codex');
586
+ await writeFile(executable, index === candidateDirs.length - 1
587
+ ? `#!/bin/sh\n: > ${JSON.stringify(thirtyThirdProbe)}\nprintf '%s\\n' 'codex-cli 0.142.5'\n`
588
+ : '#!/bin/sh\nexit 1\n');
589
+ await chmod(executable, 0o755);
590
+ }));
591
+ assert.throws(() => probeCodexVersion(root, { PATH: candidateDirs.join(delimiter) }), /32-candidate PATH budget/);
592
+ await assert.rejects(access(thirtyThirdProbe));
593
+ }
594
+ finally {
595
+ await rm(root, { recursive: true, force: true });
596
+ }
597
+ });
598
+ test('packed lifecycle continues after a timed-out version probe candidate', async () => {
599
+ if (process.platform === 'win32')
600
+ return;
601
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-timeout-'));
602
+ const slowDir = join(root, 'slow');
603
+ const pinnedDir = join(root, 'pinned');
604
+ try {
605
+ await Promise.all([mkdir(slowDir, { recursive: true }), mkdir(pinnedDir, { recursive: true })]);
606
+ await Promise.all([
607
+ writeFile(join(slowDir, 'codex'), '#!/bin/sh\nexec /bin/sleep 30\n'),
608
+ writeFile(join(pinnedDir, 'codex'), '#!/bin/sh\nprintf \'%s\\n\' \'codex-cli 0.142.5\'\n'),
609
+ ]);
610
+ await Promise.all([chmod(join(slowDir, 'codex'), 0o755), chmod(join(pinnedDir, 'codex'), 0o755)]);
611
+ const startedAt = Date.now();
612
+ assert.equal(probeCodexVersion(root, { PATH: `${slowDir}${delimiter}${pinnedDir}` }), 'codex-cli 0.142.5');
613
+ assert.ok(Date.now() - startedAt < 5_000, 'a timed-out candidate must not block later PATH candidates');
614
+ }
615
+ finally {
616
+ await rm(root, { recursive: true, force: true });
617
+ }
618
+ });
619
+ test('packed lifecycle fails instead of skipping when Codex disappears after start version validation', async () => {
620
+ if (process.platform === 'win32')
621
+ return;
622
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-disappears-after-version-'));
623
+ const candidateDir = join(root, 'candidate');
624
+ const executable = join(candidateDir, 'codex');
625
+ try {
626
+ await mkdir(candidateDir, { recursive: true });
627
+ await writeFile(executable, [
628
+ '#!/bin/sh',
629
+ 'state="${0}.version-count"',
630
+ 'if [ "$1" = "--version" ]; then',
631
+ ' if [ -f "$state" ]; then /bin/rm -f "$0"; else : > "$state"; fi',
632
+ ' printf \'%s\\n\' \'codex-cli 0.142.5\'',
633
+ ' exit 0',
634
+ 'fi',
635
+ 'exit 1',
636
+ '',
637
+ ].join('\n'));
638
+ await chmod(executable, 0o755);
639
+ assert.equal(probeCodexVersion(root, { PATH: candidateDir }), 'codex-cli 0.142.5');
640
+ await assert.rejects(CodexAppServer.start({ cwd: root, env: { PATH: candidateDir } }), (error) => {
641
+ assert.equal(error instanceof CodexExecutableNotFoundError, false);
642
+ assert.equal(error.code, 'ENOENT');
643
+ return true;
644
+ });
645
+ }
646
+ finally {
647
+ await rm(root, { recursive: true, force: true });
648
+ }
649
+ });
650
+ test('packed lifecycle preserves the true-absence Codex skip signal', async () => {
651
+ if (process.platform === 'win32')
652
+ return;
653
+ const root = await mkdtemp(join(tmpdir(), 'omx-codex-absent-'));
654
+ try {
655
+ assert.throws(() => probeCodexVersion(root, { PATH: root }), CodexExecutableNotFoundError);
656
+ }
657
+ finally {
658
+ await rm(root, { recursive: true, force: true });
659
+ }
660
+ });
661
+ test('packed lifecycle pre-seeds and preserves nested foreign group and handler coordinates', () => {
662
+ const marker = 'packed-foreign-fixture';
663
+ const seeded = appendForeignHookGroups('{"hooks":{}}', marker, { appendGroups: true });
664
+ const inserted = appendForeignHookGroups(seeded, marker, { appendGroups: false });
665
+ const snapshot = foreignHookGroupSnapshot(inserted, marker);
666
+ assert.equal(snapshot.length, 4);
667
+ assert.deepEqual(snapshot.map((entry) => ({
668
+ event: entry.event,
669
+ groupIndex: entry.groupIndex,
670
+ handlerIndex: entry.handlerIndex,
671
+ })), [
672
+ { event: 'PreToolUse', groupIndex: 0, handlerIndex: 0 },
673
+ { event: 'PreToolUse', groupIndex: 0, handlerIndex: 1 },
674
+ { event: 'PostToolUse', groupIndex: 0, handlerIndex: 0 },
675
+ { event: 'PostToolUse', groupIndex: 0, handlerIndex: 1 },
676
+ ]);
677
+ assert.match(inserted, /foreign_group_metadata/);
678
+ assert.match(inserted, /foreign_handler_metadata/);
679
+ });
680
+ test('display-order-stable foreign fixture preserves pre-approved group and handler coordinates', () => {
681
+ const marker = 'packed-display-order-fixture';
682
+ const seeded = appendDisplayOrderStableForeignHookGroups('{"hooks":{}}', marker, { appendGroups: true });
683
+ const inserted = appendDisplayOrderStableForeignHookGroups(seeded, marker, { appendGroups: false });
684
+ const snapshot = foreignHookGroupSnapshot(inserted, marker);
685
+ assert.deepEqual(snapshot.map((entry) => ({
686
+ event: entry.event,
687
+ groupIndex: entry.groupIndex,
688
+ handlerIndex: entry.handlerIndex,
689
+ })), [
690
+ { event: 'PreToolUse', groupIndex: 0, handlerIndex: 0 },
691
+ { event: 'PreToolUse', groupIndex: 1, handlerIndex: 0 },
692
+ { event: 'PreToolUse', groupIndex: 1, handlerIndex: 1 },
693
+ { event: 'PreToolUse', groupIndex: 1, handlerIndex: 2 },
694
+ ]);
695
+ });
696
+ test('packed install smoke probes every advertised plugin MCP target', () => {
697
+ assert.deepEqual(PACKED_INSTALL_PLUGIN_MCP_TARGETS, [
698
+ ['omx_state', 'state', 'omx-state'],
699
+ ['omx_memory', 'memory', 'omx-memory'],
700
+ ['omx_code_intel', 'code-intel', 'omx-code-intel'],
701
+ ['omx_trace', 'trace', 'omx-trace'],
702
+ ['omx_wiki', 'wiki', 'omx-wiki'],
703
+ ['omx_hermes', 'hermes', 'omx-hermes'],
704
+ ]);
705
+ });
18
706
  test('packed install smoke covers every installed native hook event with minimal payloads', () => {
19
707
  assert.deepEqual(PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS, [
20
708
  'SessionStart',
@@ -32,11 +720,229 @@ test('packed install smoke covers every installed native hook event with minimal
32
720
  assert.equal(payload.cwd, '/tmp/omx-packed-hook-smoke');
33
721
  }
34
722
  });
723
+ test('packed install smoke covers directive activation and terminal false-activation regressions', () => {
724
+ assert.deepEqual(PACKED_INSTALL_NATIVE_HOOK_REGRESSION_PROMPTS, [
725
+ { name: 'directive-use-ralplan', prompt: 'use $ralplan plan this', expectedSkill: 'ralplan', expectedStopBlock: true },
726
+ { name: 'directive-please-use-ralplan', prompt: 'please use $ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
727
+ { name: 'directive-run-ralplan', prompt: 'run $ralplan plan this', expectedSkill: 'ralplan', expectedStopBlock: true },
728
+ { name: 'directive-list-use-ralplan', prompt: '- use $ralplan plan this', expectedSkill: 'ralplan', expectedStopBlock: true },
729
+ { name: 'directive-documentation-then-command', prompt: 'use $ralplan is the consensus-planning command\n$autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
730
+ { name: 'directive-documentation-then-implicit-command', prompt: 'use $ralplan is the consensus-planning command\nUse autopilot mode.', expectedSkill: 'autopilot', expectedStopBlock: true },
731
+ { name: 'directive-documentation-trailing-prose-then-command', prompt: 'use $ralplan is the workflow command for planning\n$autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
732
+ { name: 'directive-documentation-implicit-prose', prompt: 'use $ralplan is the workflow command for autopilot mode', expectedSkill: null, expectedStopBlock: false },
733
+ { name: 'directive-documentation-alias-prose', prompt: 'use $ralplan is the consensus-planning command\nAutopilot mode is its alias.', expectedSkill: null, expectedStopBlock: false },
734
+ { name: 'directive-coordinated-documentation-then-command', prompt: '- use $ralplan and $autopilot are workflow commands\n$ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
735
+ { name: 'directive-documentation-semicolon-directive', prompt: 'use $ralplan is the consensus-planning command; use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
736
+ { name: 'directive-two-documentation-blocks', prompt: 'use $ralplan is the consensus-planning command\nuse $autopilot is the autonomous workflow command\n$ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
737
+ { name: 'directive-documentation-embedded-token-then-command', prompt: 'use $ralplan is the workflow command for $team\n$autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
738
+ { name: 'doc-task-noun', prompt: 'use $ralplan is the workflow command; use $autopilot update the documentation', expectedSkill: 'autopilot', expectedStopBlock: true },
739
+ { name: 'doc-implicit-followup', prompt: 'use $ralplan is the consensus-planning command; use autopilot mode.', expectedSkill: 'autopilot', expectedStopBlock: true },
740
+ { name: 'doc-transition-followup', prompt: 'use $ralplan is the consensus-planning command; then use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
741
+ { name: 'doc-explicit-alias', prompt: 'use $ralplan is the consensus-planning command; $team is its alias', expectedSkill: null, expectedStopBlock: false },
742
+ { name: 'doc-implicit-chain', prompt: 'use $ralplan is the consensus-planning command\nAutopilot mode is its alias.\n$ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
743
+ { name: 'doc-fullwidth-separator', prompt: 'use $ralplan,$autopilot are workflow commands', expectedSkill: null, expectedStopBlock: false },
744
+ { name: 'doc-compact-slash', prompt: 'use $ralplan/$autopilot are workflow commands\n$ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
745
+ { name: 'reference-prompts-followup', prompt: '[docs]: /target "title\nUse /prompts:architect"\n$ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
746
+ { name: 'doc-period-implicit', prompt: 'use $ralplan is the consensus-planning command. Use autopilot mode.', expectedSkill: 'autopilot', expectedStopBlock: true },
747
+ { name: 'doc-bare-implicit', prompt: 'use $ralplan is the consensus-planning command; autopilot mode.', expectedSkill: 'autopilot', expectedStopBlock: true },
748
+ { name: 'doc-fullwidth-semicolon', prompt: 'use $ralplan is the consensus-planning command; use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
749
+ { name: 'doc-but-followup', prompt: 'use $ralplan is the workflow command; but use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
750
+ { name: 'doc-fullwidth-oxford', prompt: 'use $ralplan, $autopilot, and $team are workflow commands', expectedSkill: null, expectedStopBlock: false },
751
+ { name: 'reference-zero-title', prompt: '[docs]: ./target\n(autopilot mode)', expectedSkill: null, expectedStopBlock: false },
752
+ { name: 'doc-also-alias-explicit', prompt: 'use $ralplan is the consensus-planning command; $team is also its alias', expectedSkill: null, expectedStopBlock: false },
753
+ { name: 'doc-also-alias-implicit', prompt: 'use $ralplan is the consensus-planning command\nAutopilot mode is also its alias.', expectedSkill: null, expectedStopBlock: false },
754
+ { name: 'doc-embedded-mention', prompt: 'use $ralplan is the workflow command; $team appears in the documentation.', expectedSkill: null, expectedStopBlock: false },
755
+ { name: 'chained-negation', prompt: '$ralplan; $autopilot is prohibited', expectedSkill: 'ralplan', expectedStopBlock: true, expectedDeferredSkills: [] },
756
+ { name: 'long-negation', prompt: `$ralplan; $autopilot${' '.repeat(193)}is prohibited`, expectedSkill: 'ralplan', expectedStopBlock: true, expectedDeferredSkills: [] },
757
+ { name: 'doc-arabic-comma', prompt: 'use $ralplan، $autopilot are workflow commands', expectedSkill: null, expectedStopBlock: false },
758
+ { name: 'arabic-negation', prompt: '$ralplan، $autopilot are prohibited', expectedSkill: null, expectedStopBlock: false },
759
+ { name: 'implicit-arabic-negation', prompt: 'Autopilot mode، deep interview are prohibited.', expectedSkill: null, expectedStopBlock: false },
760
+ { name: 'fullwidth-frame-reset', prompt: 'For instance: manual mode is slower。 Use autopilot mode.', expectedSkill: 'autopilot', expectedStopBlock: true },
761
+ { name: 'doc-abbreviation', prompt: 'use $ralplan is the workflow command, e.g. use $autopilot in examples.', expectedSkill: null, expectedStopBlock: false },
762
+ { name: 'implicit-doc-mention', prompt: 'use $ralplan is the workflow command; autopilot mode appears in the documentation.', expectedSkill: null, expectedStopBlock: false },
763
+ { name: 'implicit-doc-chain', prompt: 'use $ralplan is the workflow command; autopilot mode is its alias; $ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
764
+ { name: 'long-command-gap', prompt: `use $ralplan is the workflow command; use${' '.repeat(161)}$autopilot build it`, expectedSkill: 'autopilot', expectedStopBlock: true },
765
+ { name: 'ideographic-negation', prompt: '$ralplan、 $autopilot are prohibited', expectedSkill: null, expectedStopBlock: false },
766
+ { name: 'implicit-ideo-negation', prompt: 'Autopilot mode、 deep interview are prohibited.', expectedSkill: null, expectedStopBlock: false },
767
+ { name: 'doc-exclamation', prompt: 'use $ralplan is the consensus-planning command! run $autopilot', expectedSkill: 'autopilot', expectedStopBlock: true },
768
+ { name: 'doc-fullwidth-question', prompt: 'use $ralplan is the consensus-planning command? run $autopilot', expectedSkill: 'autopilot', expectedStopBlock: true },
769
+ { name: 'implicit-doc-predecessor', prompt: 'Autopilot mode is workflow documentation.\n$ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
770
+ { name: 'confusable-use-verb', prompt: 'uſe $ralplan plan it', expectedSkill: null, expectedStopBlock: false },
771
+ { name: 'confusable-please', prompt: 'pleaſe use $ralplan plan it', expectedSkill: null, expectedStopBlock: false },
772
+ { name: 'confusable-prompts-token-then-command', prompt: '/promptſ:architect; use autopilot mode.', expectedSkill: 'autopilot', expectedStopBlock: true },
773
+ { name: 'reserved-em-dash-boundary', prompt: '/prompts:architect— use autopilot mode', expectedSkill: null, expectedStopBlock: false },
774
+ { name: 'reserved-fullwidth-comma-boundary', prompt: '/prompts:architect, use autopilot mode', expectedSkill: null, expectedStopBlock: false },
775
+ { name: 'confusable-implicit-verb', prompt: 'Do not use deep interview but uſe autopilot mode.', expectedSkill: null, expectedStopBlock: false },
776
+ { name: 'frame-fullwidth-colon', prompt: 'For instance: use autopilot mode.', expectedSkill: null, expectedStopBlock: false },
777
+ { name: 'frame-fullwidth-comma', prompt: 'For instance, use autopilot mode.', expectedSkill: null, expectedStopBlock: false },
778
+ { name: 'frame-arabic-comma', prompt: 'For instance، use autopilot mode.', expectedSkill: null, expectedStopBlock: false },
779
+ { name: 'frame-ideo-comma', prompt: 'For instance、 use autopilot mode.', expectedSkill: null, expectedStopBlock: false },
780
+ { name: 'doc-explicit-documented', prompt: 'use $ralplan is the workflow command; $autopilot is documented in the guide.', expectedSkill: null, expectedStopBlock: false },
781
+ { name: 'doc-explicit-described', prompt: '$autopilot is described in the manual.', expectedSkill: null, expectedStopBlock: false },
782
+ { name: 'doc-comma-followup', prompt: 'use $ralplan is the workflow command, but use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
783
+ { name: 'doc-fw-comma-followup', prompt: 'use $ralplan is the workflow command, but use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
784
+ { name: 'doc-arabic-followup', prompt: 'use $ralplan is the workflow command، but use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
785
+ { name: 'doc-ideo-followup', prompt: 'use $ralplan is the workflow command、 but use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
786
+ { name: 'neg-arabic-followup', prompt: 'Do not run $ralplan، use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
787
+ { name: 'neg-ideo-followup', prompt: 'Do not run $ralplan、 use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
788
+ { name: 'implicit-doc-prefix-next', prompt: 'The docs mention autopilot mode.\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
789
+ { name: 'implicit-doc-prefix-line', prompt: 'The docs mention autopilot mode; use $ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
790
+ { name: 'implicit-doc-subject-line', prompt: 'Autopilot mode is workflow documentation; use $ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
791
+ { name: 'compact-explicit-negation', prompt: '$ralplan,$autopilot are prohibited', expectedSkill: null, expectedStopBlock: false },
792
+ { name: 'compact-implicit-negation', prompt: 'Autopilot mode،deep interview are prohibited.', expectedSkill: null, expectedStopBlock: false },
793
+ { name: 'doc-clause-local-prefix', prompt: '$ralplan; $autopilot is documented in the guide.', expectedSkill: 'ralplan', expectedStopBlock: true },
794
+ { name: 'doc-chain-described', prompt: 'use $ralplan is the workflow command; autopilot mode is documented in the guide; $team execute it', expectedSkill: 'team', expectedStopBlock: false, insideTmux: true },
795
+ { name: 'doc-chain-workflow', prompt: 'use $ralplan is the workflow command; autopilot mode is workflow documentation; use $ralph execute it', expectedSkill: 'ralph', expectedStopBlock: true },
796
+ { name: 'ref-inline-explicit', prompt: '[docs]: $ralplan\n$autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
797
+ { name: 'ref-inline-prompts', prompt: '[docs]: /prompts:architect\n$autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
798
+ { name: 'list-fullwidth-explicit-doc', prompt: '- $ralplan: consensus-planning workflow', expectedSkill: null, expectedStopBlock: false },
799
+ { name: 'list-fullwidth-implicit-doc', prompt: '- autopilot mode: autonomous workflow command', expectedSkill: null, expectedStopBlock: false },
800
+ { name: 'possessive-straight', prompt: "$ralplan's workflow is documented", expectedSkill: null, expectedStopBlock: false },
801
+ { name: 'possessive-curly', prompt: '$ralplan’s workflow is documented', expectedSkill: null, expectedStopBlock: false },
802
+ { name: 'possessive-fullwidth', prompt: '$ralplan's workflow is documented', expectedSkill: null, expectedStopBlock: false },
803
+ { name: 'possessive-prompts', prompt: "/prompts:architect's syntax is documented", expectedSkill: null, expectedStopBlock: false },
804
+ { name: 'malformed-prefix-kata', prompt: '$・autopilot mode', expectedSkill: null, expectedStopBlock: false },
805
+ { name: 'malformed-prefix-half', prompt: '$・autopilot mode', expectedSkill: null, expectedStopBlock: false },
806
+ { name: 'malformed-prefix-arabic', prompt: '$٪autopilot mode', expectedSkill: null, expectedStopBlock: false },
807
+ { name: 'malformed-prefix-division', prompt: '$∕autopilot mode', expectedSkill: null, expectedStopBlock: false },
808
+ { name: 'doc-but-directive', prompt: 'use $autopilot is documented but use $ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
809
+ { name: 'list-directive-fw-colon', prompt: '- use $ralplan: consensus-planning workflow', expectedSkill: null, expectedStopBlock: false },
810
+ { name: 'doc-arabic-question', prompt: 'use $ralplan is the workflow command؟ run $autopilot', expectedSkill: 'autopilot', expectedStopBlock: true },
811
+ { name: 'arabic-semicolon-negation', prompt: '$ralplan؛ $autopilot is prohibited', expectedSkill: 'ralplan', expectedStopBlock: true, expectedDeferredSkills: [] },
812
+ { name: 'confusable-postposed-transition', prompt: '$ralplan is prohibited but uſe autopilot mode.', expectedSkill: null, expectedStopBlock: false },
813
+ { name: 'mixed-negation', prompt: 'Autopilot mode and $ralplan are prohibited.', expectedSkill: null, expectedStopBlock: false },
814
+ { name: 'both-mixed-negation', prompt: 'Both autopilot mode and $ralplan are prohibited.', expectedSkill: null, expectedStopBlock: false },
815
+ { name: 'mixed-documentation', prompt: 'use $ralplan and autopilot mode are workflow commands', expectedSkill: null, expectedStopBlock: false },
816
+ { name: 'prose-doc-no-reopen', prompt: '$ralplan is prohibited because docs use $autopilot.', expectedSkill: null, expectedStopBlock: false },
817
+ { name: 'neg-fw-dot-reopen', prompt: 'Do not run $ralplan. use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
818
+ { name: 'neg-greek-q-reopen', prompt: 'Do not run $ralplan; use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
819
+ { name: 'unicode-attached-contrast', prompt: 'Do not use deep interview яbut use autopilot mode.', expectedSkill: null, expectedStopBlock: false },
820
+ { name: 'prefix-list-followup', prompt: 'Do not run $ralplan, $autopilot; use $team execute it', expectedSkill: 'team', expectedStopBlock: false, insideTmux: true },
821
+ { name: 'mixed-postposed-chain', prompt: '$ralplan, autopilot mode, $team are prohibited.', expectedSkill: null, expectedStopBlock: false },
822
+ { name: 'implicit-first-doc-chain', prompt: 'Autopilot mode and $ralplan are workflow commands; use $team execute it', expectedSkill: 'team', expectedStopBlock: false, insideTmux: true },
823
+ { name: 'both-mixed-doc-followup', prompt: 'Both autopilot mode and $ralplan are workflow commands; use $team execute it', expectedSkill: 'team', expectedStopBlock: false, insideTmux: true },
824
+ { name: 'doc-semicolon-preserves-earlier', prompt: 'Use autopilot mode; use $ralplan is the workflow command.', expectedSkill: 'autopilot', expectedStopBlock: true },
825
+ { name: 'doc-independent-comma', prompt: 'Use autopilot mode, and $ralplan is documented in the guide.', expectedSkill: 'autopilot', expectedStopBlock: true },
826
+ { name: 'reference-unclosed-quote-destination', prompt: '[docs]: "target\n$autopilot build it', expectedSkill: null, expectedStopBlock: false },
827
+ { name: 'reference-unclosed-inline-destination', prompt: '[docs]: `target\n$autopilot build it', expectedSkill: null, expectedStopBlock: false },
828
+ { name: 'mixed-prefix-negation-implicit', prompt: 'Do not run $ralplan and use autopilot mode.', expectedSkill: null, expectedStopBlock: false },
829
+ { name: 'repeated-postposed-followup', prompt: '$team is prohibited and is forbidden; use $ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
830
+ { name: 'doc-preserves-earlier', prompt: 'Use autopilot mode; "note"; use $ralplan is the workflow command.', expectedSkill: 'autopilot', expectedStopBlock: true },
831
+ { name: 'doc-colon-followup', prompt: 'use $ralplan is the workflow command: use $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
832
+ { name: 'table-followup', prompt: 'Mode | Meaning\n--- | ---\nmanual | documentation\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
833
+ { name: 'neg-advance-reopen', prompt: 'Do not run $ralplan but advance to $ultragoal', expectedSkill: 'ultragoal', expectedStopBlock: false },
834
+ { name: 'neg-jump-reopen', prompt: 'Do not run $ralplan but jump straight to $ultragoal', expectedSkill: 'ultragoal', expectedStopBlock: false },
835
+ { name: 'reference-plain-title', prompt: '[docs]: /target "title\nplain text"\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
836
+ { name: 'reference-plain-destination', prompt: '[docs]: ./target\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
837
+ { name: 'directive-use-the', prompt: 'Do not run $ralplan; use the $autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true },
838
+ { name: 'directive-continue-after-quote', prompt: '"quoted"\ncontinue with $ralplan', expectedSkill: 'ralplan', expectedStopBlock: true },
839
+ { name: 'doc-advance-followup', prompt: 'use $ralplan is the workflow command; advance to $ultragoal', expectedSkill: 'ultragoal', expectedStopBlock: false },
840
+ { name: 'directive-run-code-review', prompt: 'run $code-review', expectedSkill: 'code-review', expectedStopBlock: false },
841
+ { name: 'directive-documentation', prompt: 'use $ralplan is the consensus-planning command', expectedSkill: null, expectedStopBlock: false },
842
+ { name: 'nested-bounded-child-unbounded-parent', prompt: '"`x`\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
843
+ { name: 'first-contiguous-block-terminal', prompt: '$ralplan plan it\n"x"\n$autopilot build it', expectedSkill: 'ralplan', expectedStopBlock: true, expectedDeferredSkills: [] },
844
+ { name: 'leading-reserved-dominance', prompt: '/prompts:architect\n"x"\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
845
+ { name: 'list-fence-root-opener', prompt: '- ```\n sample\n```\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
846
+ { name: 'list-fence-relative-closer', prompt: '- ```\n sample\n ```\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
847
+ { name: 'reference-multiline-title-explicit', prompt: '[docs]: /target "title\nuse /prompts:architect\n$ralplan plan it"', expectedSkill: null, expectedStopBlock: false },
848
+ { name: 'reference-multiline-title-implicit', prompt: '[docs]: /target "title\nuse autopilot mode"', expectedSkill: null, expectedStopBlock: false },
849
+ { name: 'reference-next-line-title', prompt: '[docs]: ./target\n (autopilot mode)', expectedSkill: null, expectedStopBlock: false },
850
+ { name: 'reference-next-line-destination-title', prompt: '[docs]:\n ./target\n (autopilot mode)', expectedSkill: null, expectedStopBlock: false },
851
+ { name: 'kelvin-case-fold-suffix', prompt: '$ultraworK execute', expectedSkill: null, expectedStopBlock: false },
852
+ { name: 'katakana-middle-dot-suffix', prompt: '$ralplan・suffix plan it', expectedSkill: null, expectedStopBlock: false },
853
+ { name: 'halfwidth-middle-dot-suffix', prompt: '$ralplan・suffix plan it', expectedSkill: null, expectedStopBlock: false },
854
+ { name: 'arabic-percent-suffix', prompt: '$ralplan٪docs', expectedSkill: null, expectedStopBlock: false },
855
+ { name: 'division-slash-suffix', prompt: '$ralplan∕config', expectedSkill: null, expectedStopBlock: false },
856
+ { name: 'unclosed-prompts-quote', prompt: '"Use /prompts:architect\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
857
+ { name: 'malformed-prompts-suffix', prompt: '/prompts:architect한글\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
858
+ { name: 'stale-predecessor-prose-directive', prompt: '> quoted context\nProse\n$ralplan implement this', expectedSkill: null, expectedStopBlock: false },
859
+ { name: 'stale-predecessor-reserved-directive', prompt: '> quoted context\n/prompts:architect\n$ralplan plan this', expectedSkill: null, expectedStopBlock: false },
860
+ { name: 'stale-predecessor-first-block-terminal', prompt: '> quoted context\n$ralplan plan it\nLater discussion.\n$autopilot build it', expectedSkill: 'ralplan', expectedStopBlock: true, expectedDeferredSkills: [] },
861
+ { name: 'stale-predecessor-unclosed-after-negation', prompt: 'Do not run $ralplan.\n"unclosed context\n$autopilot build it', expectedSkill: null, expectedStopBlock: false },
862
+ { name: 'stale-predecessor-reference-unclosed', prompt: '[$ralplan]: ./docs\n"unclosed context\n$autopilot build it', expectedSkill: null, expectedStopBlock: false },
863
+ { name: 'stale-directive-clause-prefix', prompt: '> quoted context\nProse\nUse $ralplan plan this', expectedSkill: null, expectedStopBlock: false },
864
+ { name: 'nested-reserved-predecessor-successor', prompt: '- Use /prompts:architect.\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
865
+ { name: 'nested-fence-predecessor-successor', prompt: '- - ```\n quoted context\n ```\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
866
+ { name: 'reference-multiline-destination-implicit', prompt: '[docs]:\nautopilot', expectedSkill: null, expectedStopBlock: false },
867
+ { name: 'middle-dot-suffix', prompt: '$ralplan·suffix plan it', expectedSkill: null, expectedStopBlock: false },
868
+ { name: 'percent-suffix', prompt: '$ralplan%docs', expectedSkill: null, expectedStopBlock: false },
869
+ { name: 'fullwidth-percent-suffix', prompt: '$ralplan%docs', expectedSkill: null, expectedStopBlock: false },
870
+ { name: 'g1a-ordered-multi-skill', prompt: '$ralplan, $autopilot; $team', expectedSkill: 'ralplan', expectedStopBlock: true, expectedDeferredSkills: ['autopilot', 'team'], expectedActiveSkills: ['ralplan'], insideTmux: true },
871
+ { name: 'g1c-duplicate-alias', prompt: '$autopilot $oh-my-codex:autopilot build it', expectedSkill: 'autopilot', expectedStopBlock: true, expectedDeferredSkills: [], expectedActiveSkills: ['autopilot'] },
872
+ { name: 'b3-longer-valid-fence', prompt: '```text\n$autopilot build it\n````\n$ralplan plan it', expectedSkill: 'ralplan', expectedStopBlock: true },
873
+ { name: 'b4-shorter-invalid-fence', prompt: '````text\n$autopilot build it\n```\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
874
+ { name: 'b5-different-marker-invalid-fence', prompt: '```text\n$autopilot build it\n~~~\n$ralplan plan it', expectedSkill: null, expectedStopBlock: false },
875
+ ]);
876
+ });
877
+ test('packed regression environment clears inherited Team routing state', () => {
878
+ const environment = buildPackedRegressionEnvironment({ name: 'poisoned-team-case', insideTmux: true }, {
879
+ OMX_ROOT: '/tmp/poison-root',
880
+ OMX_STATE_ROOT: '/tmp/poison-state',
881
+ OMX_TEAM_STATE_ROOT: '/tmp/poison-team-state',
882
+ OMX_SESSION_ID: 'poison-session',
883
+ CODEX_SESSION_ID: 'poison-codex-session',
884
+ SESSION_ID: 'poison-generic-session',
885
+ OMX_TEAM_WORKER: 'poison/worker-1',
886
+ OMX_TEAM_INTERNAL_WORKER: 'poison/worker-2',
887
+ OMX_TEAM_LEADER_CWD: '/tmp/poison-leader',
888
+ OMX_TEAM_MODE: 'disabled',
889
+ OMX_QUESTION_RETURN_PANE: '%1',
890
+ OMX_LEADER_PANE_ID: '%2',
891
+ OMX_TMUX_HUD_OWNER: '1',
892
+ TMUX: '/tmp/poison-tmux',
893
+ TMUX_PANE: '%9',
894
+ });
895
+ assert.equal(environment.OMX_ROOT, '');
896
+ assert.equal(environment.OMX_STATE_ROOT, '');
897
+ assert.equal(environment.OMX_TEAM_STATE_ROOT, '');
898
+ assert.equal(environment.OMX_TEAM_WORKER, '');
899
+ assert.equal(environment.OMX_TEAM_INTERNAL_WORKER, '');
900
+ assert.equal(environment.OMX_TEAM_LEADER_CWD, '');
901
+ assert.equal(environment.OMX_TEAM_MODE, 'enabled');
902
+ assert.equal(environment.TMUX, '/tmp/tmux-pr3140-regression');
903
+ assert.equal(environment.TMUX_PANE, '%3140');
904
+ });
35
905
  test('packed install native hook stdout validation allows empty or JSON output only', () => {
36
906
  assert.doesNotThrow(() => validateHookStdout('PostCompact', ''));
37
907
  assert.doesNotThrow(() => validateHookStdout('Stop', '{}\n'));
38
908
  assert.throws(() => validateHookStdout('UserPromptSubmit', '{not json'), /native hook UserPromptSubmit emitted invalid JSON stdout/);
39
909
  });
910
+ test('packed lifecycle and native hook smoke share the seven managed event names', () => {
911
+ assert.deepEqual(MANAGED_CODEX_HOOK_EVENTS, PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS);
912
+ });
913
+ test('packed install native hook stdout validation enforces event output contracts', () => {
914
+ assert.doesNotThrow(() => validateHookStdout('PostCompact', ''));
915
+ assert.doesNotThrow(() => validateHookStdout('Stop', '{}\n'));
916
+ assert.throws(() => validateHookStdout('PostCompact', '{}\n'), /PostCompact must emit empty stdout/);
917
+ for (const value of ['\n', ' ', ' \r\n']) {
918
+ assert.throws(() => validateHookStdout('PostCompact', value), /PostCompact must emit empty stdout/);
919
+ }
920
+ for (const value of ['null', '[]', '"text"', '1']) {
921
+ assert.throws(() => validateHookStdout('Stop', value), /non-object JSON stdout payload/);
922
+ }
923
+ assert.throws(() => validateHookStdout('UserPromptSubmit', '{not json'), /native hook UserPromptSubmit emitted invalid JSON stdout/);
924
+ });
925
+ test('fake Codex launch capture preserves argv and runtime side-effect evidence', () => {
926
+ const capture = `${JSON.stringify({
927
+ argv: ['--', '--spark'],
928
+ cwd: '/tmp/omx-packed-launch',
929
+ hasResumeSqlite: true,
930
+ OMX_NOTIFY_TEMP_CONTRACT: null,
931
+ OMX_TEAM_WORKER_LAUNCH_ARGS: null,
932
+ })}\n`;
933
+ assert.deepEqual(parseFakeCodexLaunches(capture), [{
934
+ argv: ['--', '--spark'],
935
+ cwd: '/tmp/omx-packed-launch',
936
+ hasResumeSqlite: true,
937
+ OMX_NOTIFY_TEMP_CONTRACT: null,
938
+ OMX_TEAM_WORKER_LAUNCH_ARGS: null,
939
+ }]);
940
+ assert.throws(() => parseFakeCodexLaunches(`${JSON.stringify({
941
+ argv: ['--spark'],
942
+ cwd: '/tmp/omx-packed-launch',
943
+ OMX_NOTIFY_TEMP_CONTRACT: null,
944
+ })}\n`), /fake Codex capture did not contain a valid launch record/);
945
+ });
40
946
  test('parseNpmPackJsonOutput ignores prepack logs before npm pack JSON', () => {
41
947
  const parsed = parseNpmPackJsonOutput([
42
948
  '[sync-plugin-mirror] synced 29 canonical skill directories and plugin metadata',
@@ -49,6 +955,196 @@ test('parseNpmPackJsonOutput ignores prepack logs before npm pack JSON', () => {
49
955
  ].join('\n'));
50
956
  assert.deepEqual(parsed, [{ filename: 'oh-my-codex-0.15.0.tgz' }]);
51
957
  });
958
+ test('packed install metadata requires runtime, declarations, Team skills, and plugin assets only', () => {
959
+ const files = PACKED_INSTALL_REQUIRED_ARTIFACT_PATHS.map((path) => ({ path }));
960
+ assert.doesNotThrow(() => assertPackedInstallFileMetadata(files));
961
+ assert.equal(PACKED_INSTALL_REQUIRED_ARTIFACT_PATHS.some((path) => path.startsWith('docs/')), false, 'repository documentation must not become an npm package requirement');
962
+ assert.throws(() => assertPackedInstallFileMetadata(files.slice(1)), /npm pack is missing required artifact: dist\/config\/models\.js/);
963
+ assert.throws(() => assertPackedInstallFileMetadata([...files, { path: 'docs/reference/omx-config-schema-routing.md' }]), /npm pack includes forbidden workspace artifact: docs\/reference\/omx-config-schema-routing\.md/);
964
+ for (const path of [
965
+ '.gjc/session/plan.md',
966
+ 'docs/reference/page.md',
967
+ '.omx/state/team.json',
968
+ 'artifact.tgz',
969
+ 'tmp/smoke-output.txt',
970
+ 'temp/smoke-output.json',
971
+ 'scratch.tmp',
972
+ ]) {
973
+ assert.equal(isForbiddenPackedInstallArtifact(path), true, `expected ${path} to be rejected`);
974
+ }
975
+ for (const prefix of PACKED_INSTALL_FORBIDDEN_ARTIFACT_PATHS) {
976
+ assert.equal(isForbiddenPackedInstallArtifact(`${prefix}probe`), true);
977
+ }
978
+ assert.equal(isForbiddenPackedInstallArtifact('templates/AGENTS.md'), false);
979
+ assert.equal(isForbiddenPackedInstallArtifact('dist/notifications/__tests__/temp-mode.test.d.ts'), false);
980
+ });
981
+ test('packed install helpers enforce root rejection and no config mutation', () => {
982
+ const help = 'Usage: omx reasoning <low|medium|high|xhigh>\n --xhigh\n';
983
+ assert.doesNotThrow(() => assertInstalledRootReasoningHelp(help));
984
+ assert.throws(() => assertInstalledRootReasoningHelp(`${help} --max\n`), /must not advertise --max/);
985
+ const maxStderr = [
986
+ 'Reasoning mode "max" is not supported by "omx reasoning".',
987
+ 'Per-agent "max" is configured with agentReasoning; direct -c model_reasoning_effort=... is passed to Codex and remains capability-dependent.',
988
+ 'Invalid reasoning mode "max". Expected one of: low, medium, high, xhigh.',
989
+ 'Usage: omx reasoning <low|medium|high|xhigh>',
990
+ ].join('\n');
991
+ assert.doesNotThrow(() => assertInstalledRootReasoningRejection('max', { status: 1, stdout: '', stderr: maxStderr }, undefined, undefined));
992
+ assert.throws(() => assertInstalledRootReasoningRejection('max', { status: 1, stdout: '', stderr: maxStderr }, undefined, 'created'), /must not create or mutate config\.toml/);
993
+ const ultraStderr = [
994
+ 'Reasoning mode "ultra" is not supported by OMX root or per-agent reasoning and is not an alias for "max".',
995
+ 'Direct -c model_reasoning_effort=... remains opaque Codex passthrough.',
996
+ 'Invalid reasoning mode "ultra". Expected one of: low, medium, high, xhigh.',
997
+ 'Usage: omx reasoning <low|medium|high|xhigh>',
998
+ ].join('\n');
999
+ assert.doesNotThrow(() => assertInstalledRootReasoningRejection('ultra', { status: 1, stdout: '', stderr: ultraStderr }, 'model = "preserve"\n', 'model = "preserve"\n'));
1000
+ });
1001
+ test('packed install helpers freeze installed runtime and declaration reasoning contracts', () => {
1002
+ const models = {
1003
+ CANONICAL_REASONING_EFFORTS: ['low', 'medium', 'high', 'xhigh'],
1004
+ AMBIGUOUS_UNSUPPORTED_REASONING_EFFORTS: ['max', 'ultra'],
1005
+ PER_AGENT_REASONING_EFFORTS: ['low', 'medium', 'high', 'xhigh', 'max'],
1006
+ ROOT_REASONING_EFFORTS: ['low', 'medium', 'high', 'xhigh'],
1007
+ ROOT_UNSUPPORTED_REASONING_EFFORTS: ['max', 'ultra'],
1008
+ isAmbiguousUnsupportedReasoningEffort: (value) => value.toLowerCase() === 'max' || value.toLowerCase() === 'ultra',
1009
+ isUnsupportedRootReasoningEffort: (value) => value.toLowerCase() === 'max' || value.toLowerCase() === 'ultra',
1010
+ normalizeUnsupportedRootReasoningEffort: (value) => {
1011
+ const normalized = value.trim().toLowerCase();
1012
+ return normalized === 'max' || normalized === 'ultra' ? normalized : undefined;
1013
+ },
1014
+ };
1015
+ assert.doesNotThrow(() => assertInstalledReasoningRuntimeContract(models));
1016
+ const modelsDeclaration = [
1017
+ 'export declare const CANONICAL_REASONING_EFFORTS: readonly ["low", "medium", "high", "xhigh"];',
1018
+ 'export type ConfiguredAgentReasoningEffort = (typeof CANONICAL_REASONING_EFFORTS)[number];',
1019
+ 'export declare const AMBIGUOUS_UNSUPPORTED_REASONING_EFFORTS: readonly ["max", "ultra"];',
1020
+ 'export declare const PER_AGENT_REASONING_EFFORTS: readonly ["low", "medium", "high", "xhigh", "max"];',
1021
+ 'export type PerAgentReasoningEffort = (typeof PER_AGENT_REASONING_EFFORTS)[number];',
1022
+ 'export declare const ROOT_REASONING_EFFORTS: readonly ["low", "medium", "high", "xhigh"];',
1023
+ 'export type RootReasoningEffort = (typeof ROOT_REASONING_EFFORTS)[number];',
1024
+ 'export declare const ROOT_UNSUPPORTED_REASONING_EFFORTS: readonly ["max", "ultra"];',
1025
+ 'export declare function isUnsupportedRootReasoningEffort(value: string): boolean;',
1026
+ 'export declare function normalizeUnsupportedRootReasoningEffort(value: string): RootUnsupportedReasoningEffort | undefined;',
1027
+ ].join('\n');
1028
+ const definitionsDeclaration = [
1029
+ 'export interface AgentDefinition {',
1030
+ " reasoningEffort: 'low' | 'medium' | 'high' | 'xhigh';",
1031
+ '}',
1032
+ ].join('\n');
1033
+ assert.doesNotThrow(() => assertInstalledReasoningDeclarationContract({
1034
+ models: modelsDeclaration,
1035
+ definitions: definitionsDeclaration,
1036
+ nativeConfig: 'export interface GeneratedNativeAgentConfig {\n reasoningEffort?: PerAgentReasoningEffort;\n}',
1037
+ team: 'export type TeamReasoningEffort = PerAgentReasoningEffort;',
1038
+ }));
1039
+ assert.throws(() => assertInstalledReasoningDeclarationContract({
1040
+ models: modelsDeclaration.replace(': boolean;', ': value is RootUnsupportedReasoningEffort;'),
1041
+ definitions: definitionsDeclaration,
1042
+ nativeConfig: 'reasoningEffort?: PerAgentReasoningEffort;',
1043
+ team: 'export type TeamReasoningEffort = PerAgentReasoningEffort;',
1044
+ }), /plain boolean, not a type predicate/);
1045
+ });
1046
+ test('packed install contract requires canonical/plugin Team skill parity and text', async () => {
1047
+ const canonical = await readFile(join(process.cwd(), 'skills/team/SKILL.md'));
1048
+ const pluginMirror = await readFile(join(process.cwd(), 'plugins/oh-my-codex/skills/team/SKILL.md'));
1049
+ assert.doesNotThrow(() => assertInstalledTeamSkillContract(canonical, pluginMirror));
1050
+ });
1051
+ test('packed install plugin assertions enforce the packaged plugin contract', async () => {
1052
+ const root = await mkdtemp(join(tmpdir(), 'omx-packed-plugin-surface-'));
1053
+ try {
1054
+ const pluginRoot = join(root, 'plugins/oh-my-codex');
1055
+ const pluginManifestPath = join(pluginRoot, '.codex-plugin/plugin.json');
1056
+ const mcpManifestPath = join(pluginRoot, '.mcp.json');
1057
+ const appManifestPath = join(pluginRoot, '.app.json');
1058
+ const hooksManifestPath = join(pluginRoot, 'hooks/hooks.json');
1059
+ const hookLauncherPath = join(pluginRoot, 'hooks/codex-native-hook.mjs');
1060
+ const hookCommand = 'node "${PLUGIN_ROOT}/hooks/codex-native-hook.mjs"';
1061
+ await mkdir(join(pluginRoot, '.codex-plugin'), { recursive: true });
1062
+ await mkdir(join(pluginRoot, 'hooks'), { recursive: true });
1063
+ const writeValidPluginSurface = async () => {
1064
+ await writeFile(pluginManifestPath, JSON.stringify({
1065
+ name: 'oh-my-codex',
1066
+ version: '0.0.0-test',
1067
+ skills: './skills/',
1068
+ mcpServers: './.mcp.json',
1069
+ apps: './.app.json',
1070
+ hooks: './hooks/hooks.json',
1071
+ interface: {
1072
+ displayName: 'OMX',
1073
+ shortDescription: 'Test plugin',
1074
+ longDescription: 'Structurally valid plugin test fixture.',
1075
+ developerName: 'Test',
1076
+ category: 'Developer Tools',
1077
+ },
1078
+ }));
1079
+ await writeFile(mcpManifestPath, JSON.stringify({
1080
+ mcpServers: Object.fromEntries([
1081
+ ['omx_state', 'state'],
1082
+ ['omx_memory', 'memory'],
1083
+ ['omx_code_intel', 'code-intel'],
1084
+ ['omx_trace', 'trace'],
1085
+ ['omx_wiki', 'wiki'],
1086
+ ['omx_hermes', 'hermes'],
1087
+ ].map(([name, service]) => [name, {
1088
+ command: 'omx',
1089
+ args: ['mcp-serve', service],
1090
+ enabled: false,
1091
+ }])),
1092
+ }));
1093
+ await writeFile(appManifestPath, JSON.stringify({ apps: {} }));
1094
+ await writeFile(hooksManifestPath, JSON.stringify({
1095
+ hooks: Object.fromEntries(PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS.map((eventName) => [eventName, [{
1096
+ hooks: [{ type: 'command', command: hookCommand }],
1097
+ }]])),
1098
+ }));
1099
+ await writeFile(hookLauncherPath, [
1100
+ '#!/usr/bin/env node',
1101
+ "import { spawn } from 'node:child_process';",
1102
+ "import { join } from 'node:path';",
1103
+ "const OMX_PLUGIN_HOOK_LAUNCHER_CONTRACT_MARKER = 'omx-plugin-hook-launcher:v1';",
1104
+ "const hookDir = new URL('.', import.meta.url).pathname;",
1105
+ 'function readPinnedLauncher() {',
1106
+ " const launcherPath = join(hookDir, 'omx-command.json');",
1107
+ ' return { command: process.execPath, argsPrefix: [], launcherPath };',
1108
+ '}',
1109
+ 'const input = Buffer.from(\'\');',
1110
+ 'const { command, argsPrefix } = readPinnedLauncher();',
1111
+ "const child = spawn(command, [...argsPrefix, 'codex-native-hook']);",
1112
+ 'child.stdin.end(input);',
1113
+ '',
1114
+ ].join('\n'));
1115
+ };
1116
+ await writeValidPluginSurface();
1117
+ assert.doesNotThrow(() => assertInstalledPluginSurface(root));
1118
+ await writeValidPluginSurface();
1119
+ await writeFile(hookLauncherPath, [
1120
+ '#!/usr/bin/env node',
1121
+ "const OMX_PLUGIN_HOOK_LAUNCHER_CONTRACT_MARKER = 'omx-plugin-hook-launcher:v1';",
1122
+ 'process.stdout.write(OMX_PLUGIN_HOOK_LAUNCHER_CONTRACT_MARKER);',
1123
+ '',
1124
+ ].join('\n'));
1125
+ assert.throws(() => assertInstalledPluginSurface(root), /must read its pinned omx-command\.json delegate configuration/);
1126
+ await writeFile(pluginManifestPath, '{}');
1127
+ assert.throws(() => assertInstalledPluginSurface(root), /plugin\.json\.name/);
1128
+ await writeValidPluginSurface();
1129
+ await writeFile(mcpManifestPath, JSON.stringify({ mcpServers: {} }));
1130
+ assert.throws(() => assertInstalledPluginSurface(root), /omx_state/);
1131
+ await writeValidPluginSurface();
1132
+ await writeFile(appManifestPath, JSON.stringify({ apps: [] }));
1133
+ assert.throws(() => assertInstalledPluginSurface(root), /\.app\.json\.apps/);
1134
+ await writeValidPluginSurface();
1135
+ await writeFile(hooksManifestPath, JSON.stringify({ hooks: {} }));
1136
+ assert.throws(() => assertInstalledPluginSurface(root), /hook event is missing: SessionStart/);
1137
+ await writeValidPluginSurface();
1138
+ await writeFile(hookLauncherPath, 'export {};\n');
1139
+ assert.throws(() => assertInstalledPluginSurface(root), /must start with a Node shebang/);
1140
+ await writeValidPluginSurface();
1141
+ await writeFile(mcpManifestPath, '{not-json');
1142
+ assert.throws(() => assertInstalledPluginSurface(root), /plugin manifest is not parseable JSON/);
1143
+ }
1144
+ finally {
1145
+ await rm(root, { recursive: true, force: true });
1146
+ }
1147
+ });
52
1148
  test('resolveGitCommonDir resolves relative git common dir output against the repo root', () => {
53
1149
  const commonDir = resolveGitCommonDir('/tmp/worktree', () => ({
54
1150
  status: 0,