oh-my-codex 0.16.1 → 0.16.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 (247) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +2 -2
  4. package/dist/cli/__tests__/doctor-warning-copy.test.js +37 -1
  5. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  6. package/dist/cli/__tests__/explore.test.js +2 -2
  7. package/dist/cli/__tests__/explore.test.js.map +1 -1
  8. package/dist/cli/__tests__/index.test.js +173 -3
  9. package/dist/cli/__tests__/index.test.js.map +1 -1
  10. package/dist/cli/__tests__/launch-fallback.test.js +58 -0
  11. package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
  12. package/dist/cli/__tests__/ralph.test.js +1 -0
  13. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  14. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +8 -0
  15. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
  16. package/dist/cli/__tests__/setup-install-mode.test.js +82 -2
  17. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  18. package/dist/cli/__tests__/setup-scope.test.js +12 -0
  19. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  20. package/dist/cli/__tests__/team.test.js +161 -0
  21. package/dist/cli/__tests__/team.test.js.map +1 -1
  22. package/dist/cli/__tests__/ultragoal.test.js +14 -9
  23. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  24. package/dist/cli/__tests__/uninstall.test.js +44 -2
  25. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  26. package/dist/cli/__tests__/update.test.js +109 -19
  27. package/dist/cli/__tests__/update.test.js.map +1 -1
  28. package/dist/cli/doctor.d.ts.map +1 -1
  29. package/dist/cli/doctor.js +17 -0
  30. package/dist/cli/doctor.js.map +1 -1
  31. package/dist/cli/explore.d.ts.map +1 -1
  32. package/dist/cli/explore.js +3 -4
  33. package/dist/cli/explore.js.map +1 -1
  34. package/dist/cli/index.d.ts.map +1 -1
  35. package/dist/cli/index.js +34 -4
  36. package/dist/cli/index.js.map +1 -1
  37. package/dist/cli/setup.d.ts.map +1 -1
  38. package/dist/cli/setup.js +72 -6
  39. package/dist/cli/setup.js.map +1 -1
  40. package/dist/cli/team.d.ts.map +1 -1
  41. package/dist/cli/team.js +54 -15
  42. package/dist/cli/team.js.map +1 -1
  43. package/dist/cli/ultragoal.d.ts +1 -1
  44. package/dist/cli/ultragoal.d.ts.map +1 -1
  45. package/dist/cli/ultragoal.js +26 -8
  46. package/dist/cli/ultragoal.js.map +1 -1
  47. package/dist/cli/uninstall.d.ts.map +1 -1
  48. package/dist/cli/uninstall.js +68 -5
  49. package/dist/cli/uninstall.js.map +1 -1
  50. package/dist/cli/update.d.ts +10 -2
  51. package/dist/cli/update.d.ts.map +1 -1
  52. package/dist/cli/update.js +99 -5
  53. package/dist/cli/update.js.map +1 -1
  54. package/dist/config/__tests__/codex-hooks.test.js +269 -2
  55. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  56. package/dist/config/__tests__/generator-idempotent.test.js +60 -2
  57. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  58. package/dist/config/__tests__/generator-notify.test.js +59 -1
  59. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  60. package/dist/config/__tests__/wiki-config-contract.test.js +2 -1
  61. package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
  62. package/dist/config/codex-hooks.d.ts +52 -4
  63. package/dist/config/codex-hooks.d.ts.map +1 -1
  64. package/dist/config/codex-hooks.js +268 -7
  65. package/dist/config/codex-hooks.js.map +1 -1
  66. package/dist/config/generator.d.ts +13 -1
  67. package/dist/config/generator.d.ts.map +1 -1
  68. package/dist/config/generator.js +207 -12
  69. package/dist/config/generator.js.map +1 -1
  70. package/dist/hooks/__tests__/keyword-detector.test.js +37 -25
  71. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  72. package/dist/hooks/__tests__/notify-fallback-watcher.test.js +29 -1
  73. package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
  74. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +20 -4
  75. package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
  76. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +1 -0
  77. package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
  78. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts +2 -0
  79. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts.map +1 -0
  80. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +52 -0
  81. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -0
  82. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +148 -0
  83. package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
  84. package/dist/hooks/__tests__/notify-hook-session-scope.test.js +3 -0
  85. package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
  86. package/dist/hooks/__tests__/wiki-docs-contract.test.js +5 -4
  87. package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +1 -1
  88. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  89. package/dist/hooks/keyword-detector.js +2 -4
  90. package/dist/hooks/keyword-detector.js.map +1 -1
  91. package/dist/mcp/__tests__/state-server.test.js +145 -6
  92. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  93. package/dist/mcp/__tests__/wiki-server.test.js +97 -1
  94. package/dist/mcp/__tests__/wiki-server.test.js.map +1 -1
  95. package/dist/mcp/wiki-server.d.ts.map +1 -1
  96. package/dist/mcp/wiki-server.js +11 -2
  97. package/dist/mcp/wiki-server.js.map +1 -1
  98. package/dist/planning/__tests__/artifacts.test.js +64 -0
  99. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  100. package/dist/planning/__tests__/ready-context-pack-role-refs.test.d.ts +2 -0
  101. package/dist/planning/__tests__/ready-context-pack-role-refs.test.d.ts.map +1 -0
  102. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +90 -0
  103. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -0
  104. package/dist/planning/artifacts.d.ts +7 -2
  105. package/dist/planning/artifacts.d.ts.map +1 -1
  106. package/dist/planning/artifacts.js +62 -8
  107. package/dist/planning/artifacts.js.map +1 -1
  108. package/dist/planning/context-pack-status.d.ts +6 -0
  109. package/dist/planning/context-pack-status.d.ts.map +1 -1
  110. package/dist/planning/context-pack-status.js +25 -0
  111. package/dist/planning/context-pack-status.js.map +1 -1
  112. package/dist/ralph/persistence.d.ts +1 -1
  113. package/dist/ralph/persistence.d.ts.map +1 -1
  114. package/dist/ralph/persistence.js +8 -2
  115. package/dist/ralph/persistence.js.map +1 -1
  116. package/dist/scripts/__tests__/codex-native-hook.test.js +190 -1
  117. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  118. package/dist/scripts/codex-execution-surface.d.ts +1 -1
  119. package/dist/scripts/codex-execution-surface.d.ts.map +1 -1
  120. package/dist/scripts/codex-execution-surface.js.map +1 -1
  121. package/dist/scripts/codex-native-hook.d.ts +1 -1
  122. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  123. package/dist/scripts/codex-native-hook.js +18 -3
  124. package/dist/scripts/codex-native-hook.js.map +1 -1
  125. package/dist/scripts/notify-dispatcher.d.ts +7 -0
  126. package/dist/scripts/notify-dispatcher.d.ts.map +1 -0
  127. package/dist/scripts/notify-dispatcher.js +58 -0
  128. package/dist/scripts/notify-dispatcher.js.map +1 -0
  129. package/dist/scripts/notify-fallback-watcher.js +4 -0
  130. package/dist/scripts/notify-fallback-watcher.js.map +1 -1
  131. package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
  132. package/dist/scripts/notify-hook/ralph-session-resume.js +96 -8
  133. package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
  134. package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
  135. package/dist/scripts/notify-hook/state-io.js +6 -2
  136. package/dist/scripts/notify-hook/state-io.js.map +1 -1
  137. package/dist/scripts/notify-hook/visual-verdict.js +3 -3
  138. package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
  139. package/dist/scripts/notify-hook.js +124 -0
  140. package/dist/scripts/notify-hook.js.map +1 -1
  141. package/dist/state/__tests__/operations.test.js +79 -0
  142. package/dist/state/__tests__/operations.test.js.map +1 -1
  143. package/dist/state/__tests__/skill-active.test.js +10 -18
  144. package/dist/state/__tests__/skill-active.test.js.map +1 -1
  145. package/dist/state/operations.d.ts.map +1 -1
  146. package/dist/state/operations.js +1 -20
  147. package/dist/state/operations.js.map +1 -1
  148. package/dist/state/skill-active.d.ts +1 -0
  149. package/dist/state/skill-active.d.ts.map +1 -1
  150. package/dist/state/skill-active.js +28 -18
  151. package/dist/state/skill-active.js.map +1 -1
  152. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  153. package/dist/state/workflow-transition-reconcile.js +1 -0
  154. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  155. package/dist/team/__tests__/approved-execution.test.js +45 -1
  156. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  157. package/dist/team/__tests__/runtime.test.js +173 -19
  158. package/dist/team/__tests__/runtime.test.js.map +1 -1
  159. package/dist/team/__tests__/worker-bootstrap.test.js +37 -0
  160. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  161. package/dist/team/approved-execution.d.ts +1 -0
  162. package/dist/team/approved-execution.d.ts.map +1 -1
  163. package/dist/team/approved-execution.js +50 -0
  164. package/dist/team/approved-execution.js.map +1 -1
  165. package/dist/team/delivery-log.d.ts.map +1 -1
  166. package/dist/team/delivery-log.js +8 -1
  167. package/dist/team/delivery-log.js.map +1 -1
  168. package/dist/team/runtime.d.ts.map +1 -1
  169. package/dist/team/runtime.js +104 -18
  170. package/dist/team/runtime.js.map +1 -1
  171. package/dist/team/state/mailbox.d.ts +1 -0
  172. package/dist/team/state/mailbox.d.ts.map +1 -1
  173. package/dist/team/state/mailbox.js +10 -1
  174. package/dist/team/state/mailbox.js.map +1 -1
  175. package/dist/team/state-root.js +1 -1
  176. package/dist/team/state-root.js.map +1 -1
  177. package/dist/team/state.d.ts.map +1 -1
  178. package/dist/team/state.js +2 -2
  179. package/dist/team/state.js.map +1 -1
  180. package/dist/team/worker-bootstrap.d.ts +7 -2
  181. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  182. package/dist/team/worker-bootstrap.js +17 -4
  183. package/dist/team/worker-bootstrap.js.map +1 -1
  184. package/dist/ultragoal/__tests__/artifacts.test.js +81 -7
  185. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  186. package/dist/ultragoal/__tests__/docs-contract.test.js +8 -0
  187. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  188. package/dist/ultragoal/artifacts.d.ts +4 -0
  189. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  190. package/dist/ultragoal/artifacts.js +72 -4
  191. package/dist/ultragoal/artifacts.js.map +1 -1
  192. package/dist/utils/paths.d.ts +3 -1
  193. package/dist/utils/paths.d.ts.map +1 -1
  194. package/dist/utils/paths.js +6 -2
  195. package/dist/utils/paths.js.map +1 -1
  196. package/dist/wiki/__tests__/ingest.test.js +35 -1
  197. package/dist/wiki/__tests__/ingest.test.js.map +1 -1
  198. package/dist/wiki/__tests__/lint.test.js +14 -1
  199. package/dist/wiki/__tests__/lint.test.js.map +1 -1
  200. package/dist/wiki/__tests__/query.test.js +28 -3
  201. package/dist/wiki/__tests__/query.test.js.map +1 -1
  202. package/dist/wiki/__tests__/session-hooks.test.js +30 -2
  203. package/dist/wiki/__tests__/session-hooks.test.js.map +1 -1
  204. package/dist/wiki/__tests__/storage.test.js +62 -22
  205. package/dist/wiki/__tests__/storage.test.js.map +1 -1
  206. package/dist/wiki/index.d.ts +2 -2
  207. package/dist/wiki/index.d.ts.map +1 -1
  208. package/dist/wiki/index.js +2 -2
  209. package/dist/wiki/index.js.map +1 -1
  210. package/dist/wiki/ingest.js +2 -2
  211. package/dist/wiki/ingest.js.map +1 -1
  212. package/dist/wiki/lifecycle.d.ts +5 -0
  213. package/dist/wiki/lifecycle.d.ts.map +1 -1
  214. package/dist/wiki/lifecycle.js +31 -4
  215. package/dist/wiki/lifecycle.js.map +1 -1
  216. package/dist/wiki/lint.d.ts.map +1 -1
  217. package/dist/wiki/lint.js +12 -8
  218. package/dist/wiki/lint.js.map +1 -1
  219. package/dist/wiki/query.d.ts.map +1 -1
  220. package/dist/wiki/query.js +3 -2
  221. package/dist/wiki/query.js.map +1 -1
  222. package/dist/wiki/storage.d.ts +4 -0
  223. package/dist/wiki/storage.d.ts.map +1 -1
  224. package/dist/wiki/storage.js +54 -18
  225. package/dist/wiki/storage.js.map +1 -1
  226. package/package.json +1 -1
  227. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  228. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +2 -2
  229. package/plugins/oh-my-codex/skills/plan/SKILL.md +4 -4
  230. package/plugins/oh-my-codex/skills/ralplan/SKILL.md +2 -2
  231. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +11 -7
  232. package/plugins/oh-my-codex/skills/wiki/SKILL.md +5 -5
  233. package/prompts/planner.md +1 -1
  234. package/skills/deep-interview/SKILL.md +2 -2
  235. package/skills/plan/SKILL.md +4 -4
  236. package/skills/ralplan/SKILL.md +2 -2
  237. package/skills/ultragoal/SKILL.md +11 -7
  238. package/skills/wiki/SKILL.md +5 -5
  239. package/src/scripts/__tests__/codex-native-hook.test.ts +218 -1
  240. package/src/scripts/codex-execution-surface.ts +2 -0
  241. package/src/scripts/codex-native-hook.ts +22 -3
  242. package/src/scripts/notify-dispatcher.ts +74 -0
  243. package/src/scripts/notify-fallback-watcher.ts +6 -2
  244. package/src/scripts/notify-hook/ralph-session-resume.ts +117 -8
  245. package/src/scripts/notify-hook/state-io.ts +4 -2
  246. package/src/scripts/notify-hook/visual-verdict.ts +3 -3
  247. package/src/scripts/notify-hook.ts +116 -0
@@ -14,6 +14,8 @@ import { writeSessionStart } from "../../hooks/session.js";
14
14
  import { resetTriageConfigCache } from "../../hooks/triage-config.js";
15
15
  import { executeStateOperation } from "../../state/operations.js";
16
16
  import { OMX_TMUX_HUD_OWNER_ENV } from "../../hud/reconcile.js";
17
+ import { writePage } from "../../wiki/storage.js";
18
+ import { WIKI_SCHEMA_VERSION } from "../../wiki/types.js";
17
19
  function nativeHookScriptPath() {
18
20
  return join(process.cwd(), "dist", "scripts", "codex-native-hook.js");
19
21
  }
@@ -176,6 +178,8 @@ describe("codex native hook config", () => {
176
178
  "PreToolUse",
177
179
  "PostToolUse",
178
180
  "UserPromptSubmit",
181
+ "PreCompact",
182
+ "PostCompact",
179
183
  "Stop",
180
184
  ]);
181
185
  const sessionStart = config.hooks.SessionStart[0];
@@ -195,6 +199,10 @@ describe("codex native hook config", () => {
195
199
  assert.equal(userPromptSubmit.hooks?.[0]?.statusMessage, undefined);
196
200
  const stop = config.hooks.Stop[0];
197
201
  assert.equal(stop.hooks?.[0]?.timeout, 30);
202
+ const postCompact = config.hooks.PostCompact[0];
203
+ assert.equal(postCompact.matcher, undefined);
204
+ assert.match(String(postCompact.hooks?.[0]?.command || ""), /codex-native-hook\.js"?$/);
205
+ assert.doesNotMatch(String(postCompact.hooks?.[0]?.command || ""), /PostCompact Nudge|additionalContext|printf/);
198
206
  });
199
207
  });
200
208
  describe("codex native hook dispatch", () => {
@@ -392,8 +400,100 @@ describe("codex native hook dispatch", () => {
392
400
  assert.equal(mapCodexHookEventToOmxEvent("UserPromptSubmit"), "keyword-detector");
393
401
  assert.equal(mapCodexHookEventToOmxEvent("PreToolUse"), "pre-tool-use");
394
402
  assert.equal(mapCodexHookEventToOmxEvent("PostToolUse"), "post-tool-use");
403
+ assert.equal(mapCodexHookEventToOmxEvent("PreCompact"), "pre-compact");
404
+ assert.equal(mapCodexHookEventToOmxEvent("PostCompact"), "post-compact");
395
405
  assert.equal(mapCodexHookEventToOmxEvent("Stop"), "stop");
396
406
  });
407
+ it("does not write PreCompact stdout that Codex rejects as hook JSON", async () => {
408
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-precompact-"));
409
+ try {
410
+ writePage(cwd, {
411
+ filename: "architecture.md",
412
+ frontmatter: {
413
+ title: "Architecture",
414
+ tags: ["architecture"],
415
+ created: "2026-05-08T00:00:00.000Z",
416
+ updated: "2026-05-08T00:00:00.000Z",
417
+ sources: [],
418
+ links: [],
419
+ category: "architecture",
420
+ confidence: "high",
421
+ schemaVersion: WIKI_SCHEMA_VERSION,
422
+ },
423
+ content: "\n# Architecture\n\nCompaction-relevant architecture note.\n",
424
+ });
425
+ const result = await dispatchCodexNativeHook({
426
+ hook_event_name: "PreCompact",
427
+ cwd,
428
+ session_id: "sess-precompact",
429
+ });
430
+ assert.equal(result.hookEventName, "PreCompact");
431
+ assert.equal(result.omxEventName, "pre-compact");
432
+ assert.equal(result.outputJson, null);
433
+ }
434
+ finally {
435
+ await rm(cwd, { recursive: true, force: true });
436
+ }
437
+ });
438
+ it("emits no CLI stdout for PreCompact when no Codex action is needed", async () => {
439
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-precompact-cli-"));
440
+ try {
441
+ writePage(cwd, {
442
+ filename: "architecture.md",
443
+ frontmatter: {
444
+ title: "Architecture",
445
+ tags: ["architecture"],
446
+ created: "2026-05-08T00:00:00.000Z",
447
+ updated: "2026-05-08T00:00:00.000Z",
448
+ sources: [],
449
+ links: [],
450
+ category: "architecture",
451
+ confidence: "high",
452
+ schemaVersion: WIKI_SCHEMA_VERSION,
453
+ },
454
+ content: "\n# Architecture\n\nCompaction-relevant architecture note.\n",
455
+ });
456
+ const stdout = runNativeHookCli({
457
+ hook_event_name: "PreCompact",
458
+ cwd,
459
+ session_id: "sess-precompact-cli",
460
+ });
461
+ assert.equal(stdout, "");
462
+ }
463
+ finally {
464
+ await rm(cwd, { recursive: true, force: true });
465
+ }
466
+ });
467
+ it("does not write PostCompact stdout that Codex rejects as hook JSON", async () => {
468
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-postcompact-"));
469
+ try {
470
+ const result = await dispatchCodexNativeHook({
471
+ hook_event_name: "PostCompact",
472
+ cwd,
473
+ session_id: "sess-postcompact",
474
+ });
475
+ assert.equal(result.hookEventName, "PostCompact");
476
+ assert.equal(result.omxEventName, "post-compact");
477
+ assert.equal(result.outputJson, null);
478
+ }
479
+ finally {
480
+ await rm(cwd, { recursive: true, force: true });
481
+ }
482
+ });
483
+ it("emits no CLI stdout for PostCompact when no Codex action is needed", async () => {
484
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-postcompact-cli-"));
485
+ try {
486
+ const stdout = runNativeHookCli({
487
+ hook_event_name: "PostCompact",
488
+ cwd,
489
+ session_id: "sess-postcompact-cli",
490
+ });
491
+ assert.equal(stdout, "");
492
+ }
493
+ finally {
494
+ await rm(cwd, { recursive: true, force: true });
495
+ }
496
+ });
397
497
  it("writes SessionStart state against the long-lived session owner pid and injects environment context", async () => {
398
498
  const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-session-start-"));
399
499
  try {
@@ -863,7 +963,8 @@ describe("codex native hook dispatch", () => {
863
963
  assert.equal(result.skillState?.skill, "ralplan");
864
964
  assert.ok(result.outputJson, "UserPromptSubmit should emit developer context");
865
965
  assert.match(JSON.stringify(result.outputJson), /skill: ralplan activated and initial state initialized at \.omx\/state\/sessions\/sess-1\/ralplan-state\.json; write subsequent updates via omx_state MCP\./);
866
- const statePath = join(cwd, ".omx", "state", "skill-active-state.json");
966
+ assert.equal(existsSync(join(cwd, ".omx", "state", "skill-active-state.json")), false, "session-scoped keyword activation should not write root skill-active-state.json");
967
+ const statePath = join(cwd, ".omx", "state", "sessions", "sess-1", "skill-active-state.json");
867
968
  assert.equal(existsSync(statePath), true);
868
969
  const state = JSON.parse(await readFile(statePath, "utf-8"));
869
970
  assert.equal(state.skill, "ralplan");
@@ -924,6 +1025,94 @@ describe("codex native hook dispatch", () => {
924
1025
  await rm(cwd, { recursive: true, force: true });
925
1026
  }
926
1027
  });
1028
+ it("does not block Stop for non-passing autoresearch-goal professor-critic verdicts", async () => {
1029
+ for (const verdict of ["blocked", "fail", "failed"]) {
1030
+ const cwd = await mkdtemp(join(tmpdir(), `omx-native-hook-autoresearch-${verdict}-stop-`));
1031
+ const slug = `${verdict}-mission`;
1032
+ try {
1033
+ await writeJson(join(cwd, ".omx", "goals", "autoresearch", slug, "mission.json"), {
1034
+ version: 1,
1035
+ workflow: "autoresearch-goal",
1036
+ slug,
1037
+ topic: "Blocked research",
1038
+ status: verdict === "blocked" ? "blocked" : "failed",
1039
+ });
1040
+ await writeJson(join(cwd, ".omx", "goals", "autoresearch", slug, "completion.json"), {
1041
+ verdict,
1042
+ passed: false,
1043
+ });
1044
+ const result = await dispatchCodexNativeHook({
1045
+ hook_event_name: "Stop",
1046
+ cwd,
1047
+ session_id: `sess-autoresearch-${verdict}-stop`,
1048
+ thread_id: `thread-autoresearch-${verdict}-stop`,
1049
+ last_assistant_message: "Autoresearch goal complete; next call update_goal({status: \"complete\"}).",
1050
+ }, { cwd });
1051
+ assert.notEqual(result.outputJson?.decision, "block");
1052
+ assert.doesNotMatch(JSON.stringify(result.outputJson), new RegExp(`autoresearch-goal complete --slug ${slug}`));
1053
+ assert.doesNotMatch(JSON.stringify(result.outputJson), /get_goal snapshot reconciliation/);
1054
+ }
1055
+ finally {
1056
+ await rm(cwd, { recursive: true, force: true });
1057
+ }
1058
+ }
1059
+ });
1060
+ it("blocks Stop for passing autoresearch-goal professor-critic verdicts that need reconciliation", async () => {
1061
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autoresearch-pass-stop-"));
1062
+ try {
1063
+ await writeJson(join(cwd, ".omx", "goals", "autoresearch", "passing-mission", "mission.json"), {
1064
+ version: 1,
1065
+ workflow: "autoresearch-goal",
1066
+ slug: "passing-mission",
1067
+ topic: "Passing research",
1068
+ status: "validation_passed",
1069
+ });
1070
+ await writeJson(join(cwd, ".omx", "goals", "autoresearch", "passing-mission", "completion.json"), {
1071
+ verdict: "fail",
1072
+ passed: true,
1073
+ });
1074
+ const result = await dispatchCodexNativeHook({
1075
+ hook_event_name: "Stop",
1076
+ cwd,
1077
+ session_id: "sess-autoresearch-pass-stop",
1078
+ thread_id: "thread-autoresearch-pass-stop",
1079
+ last_assistant_message: "Autoresearch goal complete; next call update_goal({status: \"complete\"}).",
1080
+ }, { cwd });
1081
+ assert.equal(result.outputJson?.decision, "block");
1082
+ assert.match(JSON.stringify(result.outputJson), /get_goal snapshot reconciliation/);
1083
+ assert.match(JSON.stringify(result.outputJson), /omx autoresearch-goal complete --slug passing-mission/);
1084
+ }
1085
+ finally {
1086
+ await rm(cwd, { recursive: true, force: true });
1087
+ }
1088
+ });
1089
+ it("blocks Stop for autoresearch-goal verdict=pass even when passed is omitted", async () => {
1090
+ const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autoresearch-verdict-pass-stop-"));
1091
+ try {
1092
+ await writeJson(join(cwd, ".omx", "goals", "autoresearch", "verdict-pass-mission", "mission.json"), {
1093
+ version: 1,
1094
+ workflow: "autoresearch-goal",
1095
+ slug: "verdict-pass-mission",
1096
+ topic: "Passing research",
1097
+ status: "validation_passed",
1098
+ });
1099
+ await writeJson(join(cwd, ".omx", "goals", "autoresearch", "verdict-pass-mission", "completion.json"), {
1100
+ verdict: "pass",
1101
+ });
1102
+ const result = await dispatchCodexNativeHook({
1103
+ hook_event_name: "Stop",
1104
+ cwd,
1105
+ session_id: "sess-autoresearch-verdict-pass-stop",
1106
+ thread_id: "thread-autoresearch-verdict-pass-stop",
1107
+ last_assistant_message: "Autoresearch goal complete; next call update_goal({status: \"complete\"}).",
1108
+ }, { cwd });
1109
+ assert.equal(result.outputJson?.decision, "block");
1110
+ assert.match(JSON.stringify(result.outputJson), /omx autoresearch-goal complete --slug verdict-pass-mission/);
1111
+ }
1112
+ finally {
1113
+ await rm(cwd, { recursive: true, force: true });
1114
+ }
1115
+ });
927
1116
  it("treats workflow keywords in native subagent prompt text as literal delegation text", async () => {
928
1117
  const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-subagent-keyword-literal-"));
929
1118
  try {