oh-my-codex 0.16.2 → 0.16.4
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.
- package/Cargo.lock +5 -5
- package/Cargo.toml +1 -1
- package/README.md +3 -3
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -0
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
- package/dist/cli/__tests__/cleanup.test.js +27 -0
- package/dist/cli/__tests__/cleanup.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -5
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +137 -6
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +303 -4
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +58 -0
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +2 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +48 -0
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +8 -0
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +350 -27
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +85 -3
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +1 -1
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +269 -0
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +69 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +90 -6
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +109 -19
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/cleanup.d.ts.map +1 -1
- package/dist/cli/cleanup.js +8 -4
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.d.ts +9 -0
- package/dist/cli/codex-feature-probe.d.ts.map +1 -0
- package/dist/cli/codex-feature-probe.js +28 -0
- package/dist/cli/codex-feature-probe.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +168 -16
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +9 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +168 -20
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.js +8 -8
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +3 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +88 -0
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +21 -0
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +4 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +7 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +5 -3
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +177 -43
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +54 -15
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +64 -5
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +2 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +76 -5
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update.d.ts +10 -2
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +99 -5
- package/dist/cli/update.js.map +1 -1
- package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
- package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
- package/dist/config/__tests__/codex-feature-flags.test.js +35 -0
- package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
- package/dist/config/__tests__/codex-hooks.test.js +188 -4
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +129 -10
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +148 -7
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/wiki-config-contract.test.js +6 -3
- package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
- package/dist/config/codex-feature-flags.d.ts +21 -0
- package/dist/config/codex-feature-flags.d.ts.map +1 -0
- package/dist/config/codex-feature-flags.js +56 -0
- package/dist/config/codex-feature-flags.js.map +1 -0
- package/dist/config/codex-hooks.d.ts +40 -4
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +204 -18
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +19 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +319 -83
- package/dist/config/generator.js.map +1 -1
- package/dist/config/omx-first-party-mcp.d.ts +3 -1
- package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
- package/dist/config/omx-first-party-mcp.js +2 -2
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +92 -2
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +29 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +10 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +1 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +176 -0
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +148 -0
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +3 -0
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
- package/dist/hooks/__tests__/wiki-docs-contract.test.js +1 -2
- package/dist/hooks/__tests__/wiki-docs-contract.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +2 -2
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +1 -0
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +7 -5
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +164 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +4 -5
- package/dist/hud/state.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +61 -0
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +166 -0
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +23 -2
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +22 -0
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js +57 -26
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -0
- package/dist/modes/base.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +316 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +481 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
- package/dist/planning/__tests__/artifacts.test.js +597 -4
- package/dist/planning/__tests__/artifacts.test.js.map +1 -1
- package/dist/planning/__tests__/context-pack-status.test.js +524 -0
- package/dist/planning/__tests__/context-pack-status.test.js.map +1 -1
- package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
- package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
- package/dist/planning/__tests__/markdown-structure.test.js +459 -0
- package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.d.ts +2 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.d.ts.map +1 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +612 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -0
- package/dist/planning/artifacts.d.ts +7 -2
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +279 -26
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/planning/context-pack-status.d.ts +31 -0
- package/dist/planning/context-pack-status.d.ts.map +1 -1
- package/dist/planning/context-pack-status.js +291 -25
- package/dist/planning/context-pack-status.js.map +1 -1
- package/dist/planning/markdown-structure.d.ts +20 -0
- package/dist/planning/markdown-structure.d.ts.map +1 -0
- package/dist/planning/markdown-structure.js +137 -0
- package/dist/planning/markdown-structure.js.map +1 -0
- package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
- package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
- package/dist/ralph/__tests__/completion-audit.test.js +121 -0
- package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
- package/dist/ralph/completion-audit.d.ts +8 -0
- package/dist/ralph/completion-audit.d.ts.map +1 -0
- package/dist/ralph/completion-audit.js +99 -0
- package/dist/ralph/completion-audit.js.map +1 -0
- package/dist/ralph/persistence.d.ts +1 -1
- package/dist/ralph/persistence.d.ts.map +1 -1
- package/dist/ralph/persistence.js +8 -2
- package/dist/ralph/persistence.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +359 -24
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js +126 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +142 -76
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +4 -2
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/notify-dispatcher.d.ts +7 -0
- package/dist/scripts/notify-dispatcher.d.ts.map +1 -0
- package/dist/scripts/notify-dispatcher.js +87 -0
- package/dist/scripts/notify-dispatcher.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +4 -0
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +96 -8
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +6 -2
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.js +3 -3
- package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
- package/dist/scripts/notify-hook.js +127 -1
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +102 -27
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +9 -3
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +7 -0
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +25 -8
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts +1 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +22 -15
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.js +3 -3
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js +84 -1
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +178 -19
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +497 -2
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +1 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +45 -0
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/approved-execution.d.ts +1 -0
- package/dist/team/approved-execution.d.ts.map +1 -1
- package/dist/team/approved-execution.js +53 -0
- package/dist/team/approved-execution.js.map +1 -1
- package/dist/team/delivery-log.d.ts.map +1 -1
- package/dist/team/delivery-log.js +8 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +104 -18
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +43 -0
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/mailbox.d.ts +1 -0
- package/dist/team/state/mailbox.d.ts.map +1 -1
- package/dist/team/state/mailbox.js +10 -1
- package/dist/team/state/mailbox.js.map +1 -1
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +5 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +3 -7
- package/dist/team/state.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +7 -2
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +17 -4
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +124 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +21 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +44 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +197 -13
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/wiki/lifecycle.js +1 -1
- package/dist/wiki/lifecycle.js.map +1 -1
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/.mcp.json +5 -5
- package/plugins/oh-my-codex/skills/analyze/SKILL.md +0 -2
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -3
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +5 -7
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/plan/SKILL.md +3 -6
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +9 -10
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +21 -24
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
- package/plugins/oh-my-codex/skills/wiki/SKILL.md +13 -13
- package/skills/analyze/SKILL.md +0 -2
- package/skills/ask-claude/SKILL.md +5 -3
- package/skills/ask-gemini/SKILL.md +5 -3
- package/skills/autopilot/SKILL.md +2 -2
- package/skills/code-review/SKILL.md +1 -3
- package/skills/deep-interview/SKILL.md +5 -7
- package/skills/doctor/SKILL.md +2 -2
- package/skills/ecomode/SKILL.md +105 -1
- package/skills/frontend-ui-ux/SKILL.md +4 -26
- package/skills/git-master/SKILL.md +2 -4
- package/skills/omx-setup/SKILL.md +3 -3
- package/skills/pipeline/SKILL.md +3 -3
- package/skills/plan/SKILL.md +3 -6
- package/skills/ralph/SKILL.md +9 -10
- package/skills/swarm/SKILL.md +5 -3
- package/skills/tdd/SKILL.md +95 -1
- package/skills/ultragoal/SKILL.md +36 -3
- package/skills/ultraqa/SKILL.md +21 -24
- package/skills/ultrawork/SKILL.md +8 -8
- package/skills/web-clone/SKILL.md +348 -1
- package/skills/wiki/SKILL.md +13 -13
- package/src/scripts/__tests__/codex-native-hook.test.ts +389 -24
- package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
- package/src/scripts/codex-native-hook.ts +168 -64
- package/src/scripts/codex-native-pre-post.ts +4 -1
- package/src/scripts/notify-dispatcher.ts +113 -0
- package/src/scripts/notify-fallback-watcher.ts +6 -2
- package/src/scripts/notify-hook/ralph-session-resume.ts +117 -8
- package/src/scripts/notify-hook/state-io.ts +4 -2
- package/src/scripts/notify-hook/visual-verdict.ts +3 -3
- package/src/scripts/notify-hook.ts +119 -1
|
@@ -14,6 +14,7 @@ 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 { readAllState } from "../../hud/state.js";
|
|
17
18
|
import { writePage } from "../../wiki/storage.js";
|
|
18
19
|
import { WIKI_SCHEMA_VERSION } from "../../wiki/types.js";
|
|
19
20
|
function nativeHookScriptPath() {
|
|
@@ -183,7 +184,7 @@ describe("codex native hook config", () => {
|
|
|
183
184
|
"Stop",
|
|
184
185
|
]);
|
|
185
186
|
const sessionStart = config.hooks.SessionStart[0];
|
|
186
|
-
assert.equal(sessionStart.matcher, "startup|resume");
|
|
187
|
+
assert.equal(sessionStart.matcher, "startup|resume|clear");
|
|
187
188
|
assert.equal(sessionStart.hooks?.[0]?.statusMessage, undefined);
|
|
188
189
|
const preToolUse = config.hooks.PreToolUse[0];
|
|
189
190
|
assert.equal(preToolUse.matcher, "Bash");
|
|
@@ -199,6 +200,10 @@ describe("codex native hook config", () => {
|
|
|
199
200
|
assert.equal(userPromptSubmit.hooks?.[0]?.statusMessage, undefined);
|
|
200
201
|
const stop = config.hooks.Stop[0];
|
|
201
202
|
assert.equal(stop.hooks?.[0]?.timeout, 30);
|
|
203
|
+
const postCompact = config.hooks.PostCompact[0];
|
|
204
|
+
assert.equal(postCompact.matcher, undefined);
|
|
205
|
+
assert.match(String(postCompact.hooks?.[0]?.command || ""), /codex-native-hook\.js"?$/);
|
|
206
|
+
assert.doesNotMatch(String(postCompact.hooks?.[0]?.command || ""), /PostCompact Nudge|additionalContext|printf/);
|
|
202
207
|
});
|
|
203
208
|
});
|
|
204
209
|
describe("codex native hook dispatch", () => {
|
|
@@ -400,7 +405,7 @@ describe("codex native hook dispatch", () => {
|
|
|
400
405
|
assert.equal(mapCodexHookEventToOmxEvent("PostCompact"), "post-compact");
|
|
401
406
|
assert.equal(mapCodexHookEventToOmxEvent("Stop"), "stop");
|
|
402
407
|
});
|
|
403
|
-
it("
|
|
408
|
+
it("does not write PreCompact stdout that Codex rejects as hook JSON", async () => {
|
|
404
409
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-precompact-"));
|
|
405
410
|
try {
|
|
406
411
|
writePage(cwd, {
|
|
@@ -425,16 +430,42 @@ describe("codex native hook dispatch", () => {
|
|
|
425
430
|
});
|
|
426
431
|
assert.equal(result.hookEventName, "PreCompact");
|
|
427
432
|
assert.equal(result.omxEventName, "pre-compact");
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
433
|
+
assert.equal(result.outputJson, null);
|
|
434
|
+
}
|
|
435
|
+
finally {
|
|
436
|
+
await rm(cwd, { recursive: true, force: true });
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
it("emits no CLI stdout for PreCompact when no Codex action is needed", async () => {
|
|
440
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-precompact-cli-"));
|
|
441
|
+
try {
|
|
442
|
+
writePage(cwd, {
|
|
443
|
+
filename: "architecture.md",
|
|
444
|
+
frontmatter: {
|
|
445
|
+
title: "Architecture",
|
|
446
|
+
tags: ["architecture"],
|
|
447
|
+
created: "2026-05-08T00:00:00.000Z",
|
|
448
|
+
updated: "2026-05-08T00:00:00.000Z",
|
|
449
|
+
sources: [],
|
|
450
|
+
links: [],
|
|
451
|
+
category: "architecture",
|
|
452
|
+
confidence: "high",
|
|
453
|
+
schemaVersion: WIKI_SCHEMA_VERSION,
|
|
454
|
+
},
|
|
455
|
+
content: "\n# Architecture\n\nCompaction-relevant architecture note.\n",
|
|
456
|
+
});
|
|
457
|
+
const stdout = runNativeHookCli({
|
|
458
|
+
hook_event_name: "PreCompact",
|
|
459
|
+
cwd,
|
|
460
|
+
session_id: "sess-precompact-cli",
|
|
461
|
+
});
|
|
462
|
+
assert.equal(stdout, "");
|
|
432
463
|
}
|
|
433
464
|
finally {
|
|
434
465
|
await rm(cwd, { recursive: true, force: true });
|
|
435
466
|
}
|
|
436
467
|
});
|
|
437
|
-
it("
|
|
468
|
+
it("does not write PostCompact stdout that Codex rejects as hook JSON", async () => {
|
|
438
469
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-postcompact-"));
|
|
439
470
|
try {
|
|
440
471
|
const result = await dispatchCodexNativeHook({
|
|
@@ -444,11 +475,21 @@ describe("codex native hook dispatch", () => {
|
|
|
444
475
|
});
|
|
445
476
|
assert.equal(result.hookEventName, "PostCompact");
|
|
446
477
|
assert.equal(result.omxEventName, "post-compact");
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
478
|
+
assert.equal(result.outputJson, null);
|
|
479
|
+
}
|
|
480
|
+
finally {
|
|
481
|
+
await rm(cwd, { recursive: true, force: true });
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
it("emits no CLI stdout for PostCompact when no Codex action is needed", async () => {
|
|
485
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-postcompact-cli-"));
|
|
486
|
+
try {
|
|
487
|
+
const stdout = runNativeHookCli({
|
|
488
|
+
hook_event_name: "PostCompact",
|
|
489
|
+
cwd,
|
|
490
|
+
session_id: "sess-postcompact-cli",
|
|
491
|
+
});
|
|
492
|
+
assert.equal(stdout, "");
|
|
452
493
|
}
|
|
453
494
|
finally {
|
|
454
495
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -922,7 +963,7 @@ describe("codex native hook dispatch", () => {
|
|
|
922
963
|
assert.equal(result.omxEventName, "keyword-detector");
|
|
923
964
|
assert.equal(result.skillState?.skill, "ralplan");
|
|
924
965
|
assert.ok(result.outputJson, "UserPromptSubmit should emit developer context");
|
|
925
|
-
assert.match(JSON.stringify(result.outputJson), /
|
|
966
|
+
assert.match(JSON.stringify(result.outputJson), /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
926
967
|
assert.equal(existsSync(join(cwd, ".omx", "state", "skill-active-state.json")), false, "session-scoped keyword activation should not write root skill-active-state.json");
|
|
927
968
|
const statePath = join(cwd, ".omx", "state", "sessions", "sess-1", "skill-active-state.json");
|
|
928
969
|
assert.equal(existsSync(statePath), true);
|
|
@@ -936,6 +977,114 @@ describe("codex native hook dispatch", () => {
|
|
|
936
977
|
await rm(cwd, { recursive: true, force: true });
|
|
937
978
|
}
|
|
938
979
|
});
|
|
980
|
+
it("records boxed keyword activation mode detail and skill state under OMX_ROOT", async () => {
|
|
981
|
+
const root = await mkdtemp(join(tmpdir(), "omx-native-hook-boxed-"));
|
|
982
|
+
const cwd = join(root, "source");
|
|
983
|
+
const omxRoot = join(root, "box");
|
|
984
|
+
const sessionId = "sess-boxed-ralplan";
|
|
985
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
986
|
+
const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
|
|
987
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
988
|
+
const previousOmxSessionId = process.env.OMX_SESSION_ID;
|
|
989
|
+
try {
|
|
990
|
+
await mkdir(cwd, { recursive: true });
|
|
991
|
+
process.env.OMX_ROOT = omxRoot;
|
|
992
|
+
delete process.env.OMX_STATE_ROOT;
|
|
993
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
994
|
+
process.env.OMX_SESSION_ID = sessionId;
|
|
995
|
+
const result = await dispatchCodexNativeHook({
|
|
996
|
+
hook_event_name: "UserPromptSubmit",
|
|
997
|
+
cwd,
|
|
998
|
+
session_id: sessionId,
|
|
999
|
+
thread_id: "thread-boxed",
|
|
1000
|
+
turn_id: "turn-boxed",
|
|
1001
|
+
prompt: "$ralplan implement issue #1307",
|
|
1002
|
+
}, { cwd });
|
|
1003
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
1004
|
+
assert.equal(result.skillState?.skill, "ralplan");
|
|
1005
|
+
const boxedSessionDir = join(omxRoot, ".omx", "state", "sessions", sessionId);
|
|
1006
|
+
assert.equal(existsSync(join(boxedSessionDir, "skill-active-state.json")), true);
|
|
1007
|
+
assert.equal(existsSync(join(boxedSessionDir, "ralplan-state.json")), true);
|
|
1008
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "skill-active-state.json")), false);
|
|
1009
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "ralplan-state.json")), false);
|
|
1010
|
+
const hudState = await readAllState(cwd);
|
|
1011
|
+
assert.equal(hudState.ralplan?.active, true);
|
|
1012
|
+
assert.equal(hudState.ralplan?.current_phase, "planning");
|
|
1013
|
+
}
|
|
1014
|
+
finally {
|
|
1015
|
+
if (typeof previousOmxRoot === "string")
|
|
1016
|
+
process.env.OMX_ROOT = previousOmxRoot;
|
|
1017
|
+
else
|
|
1018
|
+
delete process.env.OMX_ROOT;
|
|
1019
|
+
if (typeof previousOmxStateRoot === "string")
|
|
1020
|
+
process.env.OMX_STATE_ROOT = previousOmxStateRoot;
|
|
1021
|
+
else
|
|
1022
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1023
|
+
if (typeof previousTeamStateRoot === "string")
|
|
1024
|
+
process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
1025
|
+
else
|
|
1026
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1027
|
+
if (typeof previousOmxSessionId === "string")
|
|
1028
|
+
process.env.OMX_SESSION_ID = previousOmxSessionId;
|
|
1029
|
+
else
|
|
1030
|
+
delete process.env.OMX_SESSION_ID;
|
|
1031
|
+
await rm(root, { recursive: true, force: true });
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
it("records native keyword activation mode detail and skill state under OMX_TEAM_STATE_ROOT", async () => {
|
|
1035
|
+
const root = await mkdtemp(join(tmpdir(), "omx-native-hook-team-root-"));
|
|
1036
|
+
const cwd = join(root, "source");
|
|
1037
|
+
const teamStateRoot = join(root, "team-state");
|
|
1038
|
+
const sessionId = "sess-team-root-ralplan";
|
|
1039
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
1040
|
+
const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
|
|
1041
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
1042
|
+
const previousOmxSessionId = process.env.OMX_SESSION_ID;
|
|
1043
|
+
try {
|
|
1044
|
+
await mkdir(cwd, { recursive: true });
|
|
1045
|
+
delete process.env.OMX_ROOT;
|
|
1046
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1047
|
+
process.env.OMX_TEAM_STATE_ROOT = teamStateRoot;
|
|
1048
|
+
process.env.OMX_SESSION_ID = sessionId;
|
|
1049
|
+
const result = await dispatchCodexNativeHook({
|
|
1050
|
+
hook_event_name: "UserPromptSubmit",
|
|
1051
|
+
cwd,
|
|
1052
|
+
session_id: sessionId,
|
|
1053
|
+
thread_id: "thread-team-root",
|
|
1054
|
+
turn_id: "turn-team-root",
|
|
1055
|
+
prompt: "$ralplan implement issue #1307",
|
|
1056
|
+
}, { cwd });
|
|
1057
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
1058
|
+
assert.equal(result.skillState?.skill, "ralplan");
|
|
1059
|
+
const teamSessionDir = join(teamStateRoot, "sessions", sessionId);
|
|
1060
|
+
assert.equal(existsSync(join(teamSessionDir, "skill-active-state.json")), true);
|
|
1061
|
+
assert.equal(existsSync(join(teamSessionDir, "ralplan-state.json")), true);
|
|
1062
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "skill-active-state.json")), false);
|
|
1063
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "ralplan-state.json")), false);
|
|
1064
|
+
const hudState = await readAllState(cwd);
|
|
1065
|
+
assert.equal(hudState.ralplan?.active, true);
|
|
1066
|
+
assert.equal(hudState.ralplan?.current_phase, "planning");
|
|
1067
|
+
}
|
|
1068
|
+
finally {
|
|
1069
|
+
if (typeof previousOmxRoot === "string")
|
|
1070
|
+
process.env.OMX_ROOT = previousOmxRoot;
|
|
1071
|
+
else
|
|
1072
|
+
delete process.env.OMX_ROOT;
|
|
1073
|
+
if (typeof previousOmxStateRoot === "string")
|
|
1074
|
+
process.env.OMX_STATE_ROOT = previousOmxStateRoot;
|
|
1075
|
+
else
|
|
1076
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1077
|
+
if (typeof previousTeamStateRoot === "string")
|
|
1078
|
+
process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
1079
|
+
else
|
|
1080
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1081
|
+
if (typeof previousOmxSessionId === "string")
|
|
1082
|
+
process.env.OMX_SESSION_ID = previousOmxSessionId;
|
|
1083
|
+
else
|
|
1084
|
+
delete process.env.OMX_SESSION_ID;
|
|
1085
|
+
await rm(root, { recursive: true, force: true });
|
|
1086
|
+
}
|
|
1087
|
+
});
|
|
939
1088
|
it("warns completion-like prompts when active goal workflows need Codex snapshot reconciliation", async () => {
|
|
940
1089
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-goal-warning-"));
|
|
941
1090
|
try {
|
|
@@ -985,6 +1134,94 @@ describe("codex native hook dispatch", () => {
|
|
|
985
1134
|
await rm(cwd, { recursive: true, force: true });
|
|
986
1135
|
}
|
|
987
1136
|
});
|
|
1137
|
+
it("does not block Stop for non-passing autoresearch-goal professor-critic verdicts", async () => {
|
|
1138
|
+
for (const verdict of ["blocked", "fail", "failed"]) {
|
|
1139
|
+
const cwd = await mkdtemp(join(tmpdir(), `omx-native-hook-autoresearch-${verdict}-stop-`));
|
|
1140
|
+
const slug = `${verdict}-mission`;
|
|
1141
|
+
try {
|
|
1142
|
+
await writeJson(join(cwd, ".omx", "goals", "autoresearch", slug, "mission.json"), {
|
|
1143
|
+
version: 1,
|
|
1144
|
+
workflow: "autoresearch-goal",
|
|
1145
|
+
slug,
|
|
1146
|
+
topic: "Blocked research",
|
|
1147
|
+
status: verdict === "blocked" ? "blocked" : "failed",
|
|
1148
|
+
});
|
|
1149
|
+
await writeJson(join(cwd, ".omx", "goals", "autoresearch", slug, "completion.json"), {
|
|
1150
|
+
verdict,
|
|
1151
|
+
passed: false,
|
|
1152
|
+
});
|
|
1153
|
+
const result = await dispatchCodexNativeHook({
|
|
1154
|
+
hook_event_name: "Stop",
|
|
1155
|
+
cwd,
|
|
1156
|
+
session_id: `sess-autoresearch-${verdict}-stop`,
|
|
1157
|
+
thread_id: `thread-autoresearch-${verdict}-stop`,
|
|
1158
|
+
last_assistant_message: "Autoresearch goal complete; next call update_goal({status: \"complete\"}).",
|
|
1159
|
+
}, { cwd });
|
|
1160
|
+
assert.notEqual(result.outputJson?.decision, "block");
|
|
1161
|
+
assert.doesNotMatch(JSON.stringify(result.outputJson), new RegExp(`autoresearch-goal complete --slug ${slug}`));
|
|
1162
|
+
assert.doesNotMatch(JSON.stringify(result.outputJson), /get_goal snapshot reconciliation/);
|
|
1163
|
+
}
|
|
1164
|
+
finally {
|
|
1165
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
it("blocks Stop for passing autoresearch-goal professor-critic verdicts that need reconciliation", async () => {
|
|
1170
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autoresearch-pass-stop-"));
|
|
1171
|
+
try {
|
|
1172
|
+
await writeJson(join(cwd, ".omx", "goals", "autoresearch", "passing-mission", "mission.json"), {
|
|
1173
|
+
version: 1,
|
|
1174
|
+
workflow: "autoresearch-goal",
|
|
1175
|
+
slug: "passing-mission",
|
|
1176
|
+
topic: "Passing research",
|
|
1177
|
+
status: "validation_passed",
|
|
1178
|
+
});
|
|
1179
|
+
await writeJson(join(cwd, ".omx", "goals", "autoresearch", "passing-mission", "completion.json"), {
|
|
1180
|
+
verdict: "fail",
|
|
1181
|
+
passed: true,
|
|
1182
|
+
});
|
|
1183
|
+
const result = await dispatchCodexNativeHook({
|
|
1184
|
+
hook_event_name: "Stop",
|
|
1185
|
+
cwd,
|
|
1186
|
+
session_id: "sess-autoresearch-pass-stop",
|
|
1187
|
+
thread_id: "thread-autoresearch-pass-stop",
|
|
1188
|
+
last_assistant_message: "Autoresearch goal complete; next call update_goal({status: \"complete\"}).",
|
|
1189
|
+
}, { cwd });
|
|
1190
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
1191
|
+
assert.match(JSON.stringify(result.outputJson), /get_goal snapshot reconciliation/);
|
|
1192
|
+
assert.match(JSON.stringify(result.outputJson), /omx autoresearch-goal complete --slug passing-mission/);
|
|
1193
|
+
}
|
|
1194
|
+
finally {
|
|
1195
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1198
|
+
it("blocks Stop for autoresearch-goal verdict=pass even when passed is omitted", async () => {
|
|
1199
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autoresearch-verdict-pass-stop-"));
|
|
1200
|
+
try {
|
|
1201
|
+
await writeJson(join(cwd, ".omx", "goals", "autoresearch", "verdict-pass-mission", "mission.json"), {
|
|
1202
|
+
version: 1,
|
|
1203
|
+
workflow: "autoresearch-goal",
|
|
1204
|
+
slug: "verdict-pass-mission",
|
|
1205
|
+
topic: "Passing research",
|
|
1206
|
+
status: "validation_passed",
|
|
1207
|
+
});
|
|
1208
|
+
await writeJson(join(cwd, ".omx", "goals", "autoresearch", "verdict-pass-mission", "completion.json"), {
|
|
1209
|
+
verdict: "pass",
|
|
1210
|
+
});
|
|
1211
|
+
const result = await dispatchCodexNativeHook({
|
|
1212
|
+
hook_event_name: "Stop",
|
|
1213
|
+
cwd,
|
|
1214
|
+
session_id: "sess-autoresearch-verdict-pass-stop",
|
|
1215
|
+
thread_id: "thread-autoresearch-verdict-pass-stop",
|
|
1216
|
+
last_assistant_message: "Autoresearch goal complete; next call update_goal({status: \"complete\"}).",
|
|
1217
|
+
}, { cwd });
|
|
1218
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
1219
|
+
assert.match(JSON.stringify(result.outputJson), /omx autoresearch-goal complete --slug verdict-pass-mission/);
|
|
1220
|
+
}
|
|
1221
|
+
finally {
|
|
1222
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1223
|
+
}
|
|
1224
|
+
});
|
|
988
1225
|
it("treats workflow keywords in native subagent prompt text as literal delegation text", async () => {
|
|
989
1226
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-subagent-keyword-literal-"));
|
|
990
1227
|
try {
|
|
@@ -1060,7 +1297,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1060
1297
|
assert.equal(result.skillState?.skill, "ralplan");
|
|
1061
1298
|
const message = String(result.outputJson?.hookSpecificOutput?.additionalContext || "");
|
|
1062
1299
|
assert.match(message, /\$oh-my-codex:ralplan" -> ralplan/);
|
|
1063
|
-
assert.match(message, /
|
|
1300
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1064
1301
|
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", "sess-plugin-1", "ralplan-state.json")), true);
|
|
1065
1302
|
}
|
|
1066
1303
|
finally {
|
|
@@ -1234,7 +1471,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1234
1471
|
assert.equal(result.skillState?.skill, "ralph");
|
|
1235
1472
|
const message = String(result.outputJson?.hookSpecificOutput?.additionalContext || "");
|
|
1236
1473
|
assert.match(message, /\$ralph" -> ralph/);
|
|
1237
|
-
assert.match(message, /
|
|
1474
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1238
1475
|
assert.match(message, /Prompt-side `\$ralph` activation seeds Ralph workflow state only; it does not invoke `omx ralph`\./);
|
|
1239
1476
|
assert.match(message, /Use `omx ralph --prd \.\.\.` only when you explicitly want the PRD-gated CLI startup path\./);
|
|
1240
1477
|
}
|
|
@@ -1258,7 +1495,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1258
1495
|
assert.equal(result.skillState?.skill, "ralph");
|
|
1259
1496
|
const message = String(result.outputJson?.hookSpecificOutput?.additionalContext || "");
|
|
1260
1497
|
assert.match(message, /\$oh-my-codex:ralph" -> ralph/);
|
|
1261
|
-
assert.match(message, /
|
|
1498
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1262
1499
|
assert.match(message, /Prompt-side `\$ralph` activation seeds Ralph workflow state only; it does not invoke `omx ralph`\./);
|
|
1263
1500
|
}
|
|
1264
1501
|
finally {
|
|
@@ -1327,7 +1564,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1327
1564
|
assert.equal(result.skillState?.skill, "deep-interview");
|
|
1328
1565
|
const message = String(result.outputJson?.hookSpecificOutput?.additionalContext || "");
|
|
1329
1566
|
assert.match(message, /\$deep-interview" -> deep-interview/);
|
|
1330
|
-
assert.match(message, /
|
|
1567
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1331
1568
|
assert.match(message, /Deep-interview is active, but this session is not attached to tmux/);
|
|
1332
1569
|
assert.match(message, /Do not invoke `omx question`, `omx hud`, or `omx team`/);
|
|
1333
1570
|
assert.match(message, /native structured question tool when available/);
|
|
@@ -1717,8 +1954,11 @@ export async function onHookEvent(event) {
|
|
|
1717
1954
|
}, { cwd });
|
|
1718
1955
|
assert.match(JSON.stringify(denied.outputJson), /denied workflow keyword/i);
|
|
1719
1956
|
assert.match(JSON.stringify(denied.outputJson), /Unsupported workflow overlap: team \+ autopilot\./);
|
|
1720
|
-
assert.match(JSON.stringify(denied.outputJson),
|
|
1721
|
-
assert.match(JSON.stringify(denied.outputJson),
|
|
1957
|
+
assert.match(JSON.stringify(denied.outputJson), /omx state clear --input/);
|
|
1958
|
+
assert.match(JSON.stringify(denied.outputJson), /mode\\":\\"<mode>/);
|
|
1959
|
+
assert.match(JSON.stringify(denied.outputJson), /--json/);
|
|
1960
|
+
assert.match(JSON.stringify(denied.outputJson), /explicit MCP compatibility is enabled/);
|
|
1961
|
+
assert.match(JSON.stringify(denied.outputJson), /`omx_state\.\*` tools/);
|
|
1722
1962
|
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", "sess-deny-1", "autopilot-state.json")), false);
|
|
1723
1963
|
}
|
|
1724
1964
|
finally {
|
|
@@ -1777,7 +2017,7 @@ export async function onHookEvent(event) {
|
|
|
1777
2017
|
assert.match(message, /\$ralph" -> ralph/);
|
|
1778
2018
|
assert.doesNotMatch(message, /mode transiting:/);
|
|
1779
2019
|
assert.match(message, /planning preserved over simultaneous execution follow-up; deferred skills: team, ralph\./);
|
|
1780
|
-
assert.match(message, /
|
|
2020
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1781
2021
|
assert.doesNotMatch(message, /Use the durable OMX team runtime via `omx team \.\.\.`/);
|
|
1782
2022
|
}
|
|
1783
2023
|
finally {
|
|
@@ -1802,7 +2042,7 @@ export async function onHookEvent(event) {
|
|
|
1802
2042
|
assert.match(message, /\$oh-my-codex:ralph" -> ralph/);
|
|
1803
2043
|
assert.doesNotMatch(message, /mode transiting:/);
|
|
1804
2044
|
assert.match(message, /planning preserved over simultaneous execution follow-up; deferred skills: team, ralph\./);
|
|
1805
|
-
assert.match(message, /
|
|
2045
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1806
2046
|
}
|
|
1807
2047
|
finally {
|
|
1808
2048
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -3572,7 +3812,7 @@ exit 0
|
|
|
3572
3812
|
assert.equal(output?.decision, "block");
|
|
3573
3813
|
assert.equal(output?.reason, "The MCP tool appears to have lost its transport/server connection. Preserve state, debug the transport failure, and use OMX CLI/file-backed fallbacks instead of retrying blindly.");
|
|
3574
3814
|
const additionalContext = String(output?.hookSpecificOutput?.additionalContext ?? "");
|
|
3575
|
-
assert.match(additionalContext, /omx state
|
|
3815
|
+
assert.match(additionalContext, /omx state write --input/);
|
|
3576
3816
|
assert.match(additionalContext, /plain Node stdio processes/i);
|
|
3577
3817
|
assert.match(additionalContext, /read-stall-state/);
|
|
3578
3818
|
assert.match(additionalContext, /OMX_MCP_TRANSPORT_DEBUG=1/);
|
|
@@ -3742,7 +3982,7 @@ exit 0
|
|
|
3742
3982
|
assert.match(String(result.outputJson?.reason || ""), /lost its transport\/server connection/);
|
|
3743
3983
|
const hookSpecificOutput = result.outputJson?.hookSpecificOutput;
|
|
3744
3984
|
assert.equal(hookSpecificOutput?.hookEventName, "PostToolUse");
|
|
3745
|
-
assert.match(String(hookSpecificOutput?.additionalContext || ""), /Retry via CLI parity with `omx state
|
|
3985
|
+
assert.match(String(hookSpecificOutput?.additionalContext || ""), /Retry via CLI parity with `omx state write --input '\{\}' --json`\./);
|
|
3746
3986
|
assert.match(String(hookSpecificOutput?.additionalContext || ""), /omx team api read-stall-state/);
|
|
3747
3987
|
const phase = JSON.parse(await readFile(join(cwd, ".omx", "state", "team", "mcp-transport-dead-team", "phase.json"), "utf-8"));
|
|
3748
3988
|
assert.equal(phase.current_phase, "failed");
|
|
@@ -3800,7 +4040,7 @@ exit 0
|
|
|
3800
4040
|
reason: "The MCP tool appears to have lost its transport/server connection. Preserve state, debug the transport failure, and use OMX CLI/file-backed fallbacks instead of retrying blindly.",
|
|
3801
4041
|
hookSpecificOutput: {
|
|
3802
4042
|
hookEventName: "PostToolUse",
|
|
3803
|
-
additionalContext: "Clear MCP transport-death signal detected. Preserve current team/runtime state. Retry via CLI parity with `omx state
|
|
4043
|
+
additionalContext: "Clear MCP transport-death signal detected. Preserve current team/runtime state. Retry via CLI parity with `omx state write --input '{\"mode\":\"team\",\"active\":true}' --json`. OMX MCP servers are plain Node stdio processes, so they still shut down when stdin/transport closes. If this happened during team runtime, inspect first with `omx team status <team>` or `omx team api read-stall-state --input '{\"team_name\":\"<team>\"}' --json`, and only force cleanup after capturing needed state. For root-cause debugging, rerun with `OMX_MCP_TRANSPORT_DEBUG=1` to log why the stdio transport closed.",
|
|
3804
4044
|
},
|
|
3805
4045
|
});
|
|
3806
4046
|
const phase = await readTeamPhase("transport-team", cwd);
|
|
@@ -4965,6 +5205,38 @@ exit 0
|
|
|
4965
5205
|
await rm(cwd, { recursive: true, force: true });
|
|
4966
5206
|
}
|
|
4967
5207
|
});
|
|
5208
|
+
it("ignores stale source-root team Stop fallback when OMX_TEAM_STATE_ROOT is authoritative", async () => {
|
|
5209
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-team-stale-source-root-"));
|
|
5210
|
+
const teamStateRoot = join(cwd, "shared-team-state");
|
|
5211
|
+
const priorTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
5212
|
+
try {
|
|
5213
|
+
process.env.OMX_TEAM_STATE_ROOT = teamStateRoot;
|
|
5214
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
5215
|
+
await mkdir(join(teamStateRoot, "team", "stale-source-team"), { recursive: true });
|
|
5216
|
+
await writeJson(join(cwd, ".omx", "state", "team-state.json"), {
|
|
5217
|
+
active: true,
|
|
5218
|
+
team_name: "stale-source-team",
|
|
5219
|
+
current_phase: "team-exec",
|
|
5220
|
+
});
|
|
5221
|
+
await writeJson(join(teamStateRoot, "team", "stale-source-team", "phase.json"), {
|
|
5222
|
+
current_phase: "team-exec",
|
|
5223
|
+
});
|
|
5224
|
+
const result = await dispatchCodexNativeHook({
|
|
5225
|
+
hook_event_name: "Stop",
|
|
5226
|
+
cwd,
|
|
5227
|
+
session_id: "sess-stale-source-team",
|
|
5228
|
+
}, { cwd });
|
|
5229
|
+
assert.equal(result.omxEventName, "stop");
|
|
5230
|
+
assert.equal(result.outputJson, null);
|
|
5231
|
+
}
|
|
5232
|
+
finally {
|
|
5233
|
+
if (typeof priorTeamStateRoot === "string")
|
|
5234
|
+
process.env.OMX_TEAM_STATE_ROOT = priorTeamStateRoot;
|
|
5235
|
+
else
|
|
5236
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
5237
|
+
await rm(cwd, { recursive: true, force: true });
|
|
5238
|
+
}
|
|
5239
|
+
});
|
|
4968
5240
|
it("returns Stop continuation output from canonical team state rooted via OMX_TEAM_STATE_ROOT", async () => {
|
|
4969
5241
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-team-env-root-"));
|
|
4970
5242
|
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
@@ -5856,6 +6128,69 @@ exit 0
|
|
|
5856
6128
|
await rm(cwd, { recursive: true, force: true });
|
|
5857
6129
|
}
|
|
5858
6130
|
});
|
|
6131
|
+
it("blocks Codex App Stop when Ralph is marked complete without completion-audit evidence", async () => {
|
|
6132
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralph-complete-audit-missing-"));
|
|
6133
|
+
try {
|
|
6134
|
+
const sessionId = "sess-ralph-complete-missing";
|
|
6135
|
+
const statePath = join(cwd, ".omx", "state", "sessions", sessionId, "ralph-state.json");
|
|
6136
|
+
await writeJson(join(cwd, ".omx", "state", "session.json"), { session_id: sessionId, native_session_id: sessionId, cwd });
|
|
6137
|
+
await writeJson(statePath, {
|
|
6138
|
+
active: false,
|
|
6139
|
+
mode: "ralph",
|
|
6140
|
+
current_phase: "complete",
|
|
6141
|
+
session_id: sessionId,
|
|
6142
|
+
completed_at: "2026-05-10T12:00:00.000Z",
|
|
6143
|
+
});
|
|
6144
|
+
const result = await dispatchCodexNativeHook({
|
|
6145
|
+
hook_event_name: "Stop",
|
|
6146
|
+
cwd,
|
|
6147
|
+
session_id: sessionId,
|
|
6148
|
+
last_assistant_message: "Done. Ralph complete.",
|
|
6149
|
+
}, { cwd });
|
|
6150
|
+
assert.equal(result.omxEventName, "stop");
|
|
6151
|
+
assert.match(String(result.outputJson?.reason), /Ralph completion audit is missing required evidence/);
|
|
6152
|
+
assert.equal(result.outputJson?.stopReason, "ralph_completion_audit_missing_completion_audit");
|
|
6153
|
+
const reopened = JSON.parse(await readFile(statePath, "utf-8"));
|
|
6154
|
+
assert.equal(reopened.active, true);
|
|
6155
|
+
assert.equal(reopened.current_phase, "verifying");
|
|
6156
|
+
assert.equal(reopened.completion_audit_gate, "blocked");
|
|
6157
|
+
assert.equal(reopened.completion_audit_missing_reason, "missing_completion_audit");
|
|
6158
|
+
assert.equal(typeof reopened.completed_at, "undefined");
|
|
6159
|
+
}
|
|
6160
|
+
finally {
|
|
6161
|
+
await rm(cwd, { recursive: true, force: true });
|
|
6162
|
+
}
|
|
6163
|
+
});
|
|
6164
|
+
it("allows Codex App Stop when complete Ralph state carries checklist and verification evidence", async () => {
|
|
6165
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralph-complete-audit-present-"));
|
|
6166
|
+
try {
|
|
6167
|
+
const sessionId = "sess-ralph-complete-present";
|
|
6168
|
+
await writeJson(join(cwd, ".omx", "state", "session.json"), { session_id: sessionId, native_session_id: sessionId, cwd });
|
|
6169
|
+
await writeJson(join(cwd, ".omx", "state", "sessions", sessionId, "ralph-state.json"), {
|
|
6170
|
+
active: false,
|
|
6171
|
+
mode: "ralph",
|
|
6172
|
+
current_phase: "complete",
|
|
6173
|
+
session_id: sessionId,
|
|
6174
|
+
completed_at: "2026-05-10T12:00:00.000Z",
|
|
6175
|
+
completion_audit: {
|
|
6176
|
+
passed: true,
|
|
6177
|
+
prompt_to_artifact_checklist: ["issue #2260 fixed", "tests added"],
|
|
6178
|
+
verification_evidence: ["node --test dist/scripts/__tests__/codex-native-hook.test.js"],
|
|
6179
|
+
},
|
|
6180
|
+
});
|
|
6181
|
+
const result = await dispatchCodexNativeHook({
|
|
6182
|
+
hook_event_name: "Stop",
|
|
6183
|
+
cwd,
|
|
6184
|
+
session_id: sessionId,
|
|
6185
|
+
last_assistant_message: "Done with completion audit evidence recorded.",
|
|
6186
|
+
}, { cwd });
|
|
6187
|
+
assert.equal(result.omxEventName, "stop");
|
|
6188
|
+
assert.equal(result.outputJson, null);
|
|
6189
|
+
}
|
|
6190
|
+
finally {
|
|
6191
|
+
await rm(cwd, { recursive: true, force: true });
|
|
6192
|
+
}
|
|
6193
|
+
});
|
|
5859
6194
|
it("returns Stop continuation output while Ralph is active without an explicit session pin", async () => {
|
|
5860
6195
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-"));
|
|
5861
6196
|
try {
|