oh-my-codex 0.18.7 → 0.18.9
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 +12 -12
- package/Cargo.toml +1 -1
- package/README.md +5 -5
- package/crates/omx-sparkshell/tests/execution.rs +1 -1
- package/dist/agents/__tests__/native-config.test.js +42 -1
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/definitions.d.ts +8 -0
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +1 -0
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/native-config.d.ts +5 -1
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +17 -2
- package/dist/agents/native-config.js.map +1 -1
- package/dist/autopilot/__tests__/fsm.test.js +3 -0
- package/dist/autopilot/__tests__/fsm.test.js.map +1 -1
- package/dist/autopilot/fsm.js +2 -2
- package/dist/autopilot/fsm.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +4 -2
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +512 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +39 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +98 -6
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +28 -8
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +26 -9
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +13 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +14 -0
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +50 -1
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +89 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +65 -0
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/state.test.js +21 -0
- package/dist/cli/__tests__/state.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +2 -2
- package/dist/cli/__tests__/update.test.js +323 -18
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +8 -1
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +21 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +143 -28
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +14 -2
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +62 -15
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +3 -1
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +2 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +4 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +3 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +166 -27
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/state.d.ts.map +1 -1
- package/dist/cli/state.js +8 -1
- package/dist/cli/state.js.map +1 -1
- package/dist/cli/tmux-hook.d.ts.map +1 -1
- package/dist/cli/tmux-hook.js +16 -0
- package/dist/cli/tmux-hook.js.map +1 -1
- package/dist/cli/update.d.ts +22 -3
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +312 -26
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/version.d.ts.map +1 -1
- package/dist/cli/version.js +5 -9
- package/dist/cli/version.js.map +1 -1
- package/dist/compat/__tests__/doctor-contract.test.js +12 -1
- package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +1 -0
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/generator.d.ts +2 -2
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +2 -2
- package/dist/config/generator.js.map +1 -1
- package/dist/config/team-mode.d.ts +12 -0
- package/dist/config/team-mode.d.ts.map +1 -0
- package/dist/config/team-mode.js +91 -0
- package/dist/config/team-mode.js.map +1 -0
- package/dist/hooks/__tests__/agents-overlay.test.js +88 -0
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.js +12 -0
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js +30 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +423 -3
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +189 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +35 -2
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +3 -3
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-guidance-contract.test.js +21 -0
- package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
- package/dist/hooks/agents-overlay.d.ts.map +1 -1
- package/dist/hooks/agents-overlay.js +36 -50
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js +31 -0
- package/dist/hooks/extensibility/__tests__/plugin-runner.test.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner.js +17 -21
- package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +258 -12
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +6 -0
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hooks/session.d.ts +1 -0
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/authority.test.js +435 -32
- package/dist/hud/__tests__/authority.test.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +2 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +42 -0
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +642 -15
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/render.test.js +61 -0
- package/dist/hud/__tests__/render.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +160 -4
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +180 -21
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/authority.d.ts +5 -0
- package/dist/hud/authority.d.ts.map +1 -1
- package/dist/hud/authority.js +324 -28
- package/dist/hud/authority.js.map +1 -1
- package/dist/hud/index.d.ts +3 -2
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +42 -19
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts +3 -3
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +128 -19
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +35 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +65 -80
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.d.ts +24 -6
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +136 -38
- package/dist/hud/tmux.js.map +1 -1
- package/dist/hud/types.d.ts +11 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +71 -1
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +32 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +113 -17
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +4 -4
- package/dist/question/__tests__/renderer.test.js +566 -1
- package/dist/question/__tests__/renderer.test.js.map +1 -1
- package/dist/question/renderer.d.ts +9 -1
- package/dist/question/renderer.d.ts.map +1 -1
- package/dist/question/renderer.js +246 -70
- package/dist/question/renderer.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +837 -101
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-state-io.test.js +72 -1
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-tmux-injection.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-tmux-injection.test.js +57 -0
- package/dist/scripts/__tests__/notify-tmux-injection.test.js.map +1 -0
- package/dist/scripts/__tests__/run-test-files.test.js +74 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-agents.test.js +65 -0
- package/dist/scripts/__tests__/verify-native-agents.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +107 -39
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/eval/eval-parity-smoke.js +1 -1
- package/dist/scripts/eval/eval-parity-smoke.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +3 -1
- package/dist/scripts/notify-hook/auto-nudge.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 +3 -10
- 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 +62 -38
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +7 -0
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts +7 -0
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +24 -18
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +75 -11
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/run-test-files.js +193 -22
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js +61 -3
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/verify-native-agents.d.ts.map +1 -1
- package/dist/scripts/verify-native-agents.js +58 -1
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +113 -0
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +3 -16
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +25 -0
- 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 +57 -2
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +7 -39
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +10 -14
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +1 -1
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +9 -4
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +195 -2
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +4 -2
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +3 -2
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/tmux-session.d.ts +2 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +142 -12
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/utils/__tests__/platform-command.test.js +16 -1
- package/dist/utils/__tests__/platform-command.test.js.map +1 -1
- package/dist/utils/__tests__/version.test.d.ts +2 -0
- package/dist/utils/__tests__/version.test.d.ts.map +1 -0
- package/dist/utils/__tests__/version.test.js +51 -0
- package/dist/utils/__tests__/version.test.js.map +1 -0
- package/dist/utils/paths.d.ts +8 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +16 -4
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/platform-command.d.ts +9 -0
- package/dist/utils/platform-command.d.ts.map +1 -1
- package/dist/utils/platform-command.js +15 -0
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/utils/version.d.ts +7 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +67 -0
- package/dist/utils/version.js.map +1 -0
- package/dist/verification/__tests__/ci-rust-gates.test.js +89 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js +16 -2
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
- package/package.json +11 -10
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +334 -21
- package/plugins/oh-my-codex/hooks/hooks.json +1 -2
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +3 -1
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +7 -7
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +51 -11
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +22 -22
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +9 -0
- package/skills/autopilot/SKILL.md +3 -1
- package/skills/code-review/SKILL.md +7 -7
- package/skills/deep-interview/SKILL.md +51 -11
- package/skills/ralph/SKILL.md +22 -22
- package/skills/ultraqa/SKILL.md +9 -0
- package/src/scripts/__tests__/codex-native-hook.test.ts +946 -98
- package/src/scripts/__tests__/notify-state-io.test.ts +95 -0
- package/src/scripts/__tests__/notify-tmux-injection.test.ts +82 -0
- package/src/scripts/__tests__/run-test-files.test.ts +102 -0
- package/src/scripts/__tests__/verify-native-agents.test.ts +75 -0
- package/src/scripts/codex-native-hook.ts +123 -34
- package/src/scripts/demo-team-e2e.sh +10 -7
- package/src/scripts/eval/eval-parity-smoke.ts +1 -1
- package/src/scripts/notify-hook/auto-nudge.ts +3 -1
- package/src/scripts/notify-hook/ralph-session-resume.ts +2 -8
- package/src/scripts/notify-hook/state-io.ts +75 -37
- package/src/scripts/notify-hook/team-leader-nudge.ts +7 -0
- package/src/scripts/notify-hook/tmux-injection.ts +35 -19
- package/src/scripts/notify-hook.ts +91 -4
- package/src/scripts/prepare-build.js +83 -0
- package/src/scripts/run-test-files.ts +192 -22
- package/src/scripts/sync-plugin-mirror.ts +98 -9
- package/src/scripts/verify-native-agents.ts +65 -1
- package/src/scripts/postinstall-bootstrap.js +0 -23
|
@@ -46,6 +46,23 @@ async function writeJson(path, value) {
|
|
|
46
46
|
await mkdir(dirname(path), { recursive: true }).catch(() => { });
|
|
47
47
|
await writeFile(path, JSON.stringify(value, null, 2));
|
|
48
48
|
}
|
|
49
|
+
async function writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId) {
|
|
50
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
51
|
+
await writeJson(join(stateDir, "session.json"), {
|
|
52
|
+
session_id: sessionId,
|
|
53
|
+
native_session_id: nativeSessionId,
|
|
54
|
+
cwd,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async function writeSessionSkillActiveState(stateDir, sessionId, skill, phase) {
|
|
58
|
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
59
|
+
active: true,
|
|
60
|
+
skill,
|
|
61
|
+
phase,
|
|
62
|
+
session_id: sessionId,
|
|
63
|
+
active_skills: [{ skill, phase, active: true, session_id: sessionId }],
|
|
64
|
+
});
|
|
65
|
+
}
|
|
49
66
|
async function setTeamPaneIds(cwd, teamName, paneIds) {
|
|
50
67
|
for (const fileName of ["config.json", "manifest.v2.json"]) {
|
|
51
68
|
const filePath = join(cwd, ".omx", "state", "team", teamName, fileName);
|
|
@@ -1280,12 +1297,16 @@ describe("codex native hook dispatch", () => {
|
|
|
1280
1297
|
}, {
|
|
1281
1298
|
cwd,
|
|
1282
1299
|
reconcileHudForPromptSubmitFn: async (hookCwd, deps = {}) => {
|
|
1283
|
-
reconcileCall = { cwd: hookCwd, sessionId: deps.sessionId };
|
|
1300
|
+
reconcileCall = { cwd: hookCwd, sessionId: deps.sessionId, sessionIds: deps.sessionIds };
|
|
1284
1301
|
return { status: "recreated", paneId: "%9", desiredHeight: 3, duplicateCount: 0 };
|
|
1285
1302
|
},
|
|
1286
1303
|
});
|
|
1287
1304
|
assert.equal(promptResult.omxEventName, "keyword-detector");
|
|
1288
|
-
assert.deepEqual(reconcileCall, {
|
|
1305
|
+
assert.deepEqual(reconcileCall, {
|
|
1306
|
+
cwd,
|
|
1307
|
+
sessionId: ownerSessionId,
|
|
1308
|
+
sessionIds: [ownerSessionId, nativeSessionId],
|
|
1309
|
+
});
|
|
1289
1310
|
}
|
|
1290
1311
|
finally {
|
|
1291
1312
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -1315,12 +1336,16 @@ describe("codex native hook dispatch", () => {
|
|
|
1315
1336
|
}, {
|
|
1316
1337
|
cwd,
|
|
1317
1338
|
reconcileHudForPromptSubmitFn: async (hookCwd, deps = {}) => {
|
|
1318
|
-
reconcileCall = { cwd: hookCwd, sessionId: deps.sessionId };
|
|
1339
|
+
reconcileCall = { cwd: hookCwd, sessionId: deps.sessionId, sessionIds: deps.sessionIds };
|
|
1319
1340
|
return { status: "recreated", paneId: "%9", desiredHeight: 3, duplicateCount: 0 };
|
|
1320
1341
|
},
|
|
1321
1342
|
});
|
|
1322
1343
|
assert.equal(promptResult.omxEventName, "keyword-detector");
|
|
1323
|
-
assert.deepEqual(reconcileCall, {
|
|
1344
|
+
assert.deepEqual(reconcileCall, {
|
|
1345
|
+
cwd,
|
|
1346
|
+
sessionId: canonicalSessionId,
|
|
1347
|
+
sessionIds: [canonicalSessionId, nativeSessionId],
|
|
1348
|
+
});
|
|
1324
1349
|
}
|
|
1325
1350
|
finally {
|
|
1326
1351
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -1457,6 +1482,46 @@ describe("codex native hook dispatch", () => {
|
|
|
1457
1482
|
await rm(cwd, { recursive: true, force: true });
|
|
1458
1483
|
}
|
|
1459
1484
|
});
|
|
1485
|
+
it("includes repo-local .omx project-memory during SessionStart when OMX_ROOT is boxed", async () => {
|
|
1486
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-session-boxed-memory-"));
|
|
1487
|
+
const boxedRoot = await mkdtemp(join(tmpdir(), "omx-native-hook-boxed-root-"));
|
|
1488
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
1489
|
+
try {
|
|
1490
|
+
process.env.OMX_ROOT = boxedRoot;
|
|
1491
|
+
await writeJson(join(cwd, ".omx", "project-memory.json"), {
|
|
1492
|
+
techStack: "Repo-local CLI memory",
|
|
1493
|
+
conventions: "SessionStart should load CLI-written project memory",
|
|
1494
|
+
directives: [
|
|
1495
|
+
{ directive: "Prefer repo-local .omx project memory over boxed runtime fallback.", priority: "high" },
|
|
1496
|
+
],
|
|
1497
|
+
});
|
|
1498
|
+
await writeJson(join(boxedRoot, ".omx", "project-memory.json"), {
|
|
1499
|
+
techStack: "Boxed runtime memory should not win",
|
|
1500
|
+
notes: [{ category: "runtime", content: "stale boxed runtime note", timestamp: new Date().toISOString() }],
|
|
1501
|
+
});
|
|
1502
|
+
const result = await dispatchCodexNativeHook({
|
|
1503
|
+
hook_event_name: "SessionStart",
|
|
1504
|
+
cwd,
|
|
1505
|
+
session_id: "sess-boxed-memory-1",
|
|
1506
|
+
}, { cwd, sessionOwnerPid: 43210 });
|
|
1507
|
+
const additionalContext = String(result.outputJson?.hookSpecificOutput?.additionalContext ?? "");
|
|
1508
|
+
assert.match(additionalContext, /\[Project memory\]/);
|
|
1509
|
+
assert.match(additionalContext, /source: \.omx\/project-memory\.json/);
|
|
1510
|
+
assert.match(additionalContext, /Repo-local CLI memory/);
|
|
1511
|
+
assert.match(additionalContext, /SessionStart should load CLI-written project memory/);
|
|
1512
|
+
assert.match(additionalContext, /Prefer repo-local \.omx project memory over boxed runtime fallback\./);
|
|
1513
|
+
assert.doesNotMatch(additionalContext, /Boxed runtime memory should not win/);
|
|
1514
|
+
assert.doesNotMatch(additionalContext, /stale boxed runtime note/);
|
|
1515
|
+
}
|
|
1516
|
+
finally {
|
|
1517
|
+
if (previousOmxRoot === undefined)
|
|
1518
|
+
delete process.env.OMX_ROOT;
|
|
1519
|
+
else
|
|
1520
|
+
process.env.OMX_ROOT = previousOmxRoot;
|
|
1521
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1522
|
+
await rm(boxedRoot, { recursive: true, force: true });
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1460
1525
|
it("prefers repository project-memory.json during SessionStart while preserving legacy wiki guidance", async () => {
|
|
1461
1526
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-session-root-memory-legacy-wiki-"));
|
|
1462
1527
|
try {
|
|
@@ -2853,6 +2918,13 @@ standardMaxRounds = 15
|
|
|
2853
2918
|
assert.match(message, /Do not advance from deep-interview to ralplan merely because the first question was answered/);
|
|
2854
2919
|
assert.match(message, /Planner output has been reviewed sequentially by Architect and then Critic/);
|
|
2855
2920
|
assert.match(message, /do not hand off to Ultragoal or implementation until .*ralplan_architect_review.*ralplan_critic_review/);
|
|
2921
|
+
const autopilotState = JSON.parse(await readFile(join(cwd, ".omx", "state", "sessions", "sess-autopilot-ralplan-gate", "autopilot-state.json"), "utf-8"));
|
|
2922
|
+
const snapshotPath = autopilotState.state?.handoff_artifacts?.context_snapshot_path ?? "";
|
|
2923
|
+
assert.match(snapshotPath, /^\.omx\/context\/implement-issue-2430-\d{8}T\d{6}Z\.md$/);
|
|
2924
|
+
const snapshot = await readFile(join(cwd, snapshotPath), "utf-8");
|
|
2925
|
+
assert.match(snapshot, /activation prompt \/ task seed: \$autopilot implement issue #2430/);
|
|
2926
|
+
assert.match(snapshot, /scope note: this seed captures the Autopilot activation prompt/);
|
|
2927
|
+
assert.match(snapshot, /constraints: follow deep-interview -> ralplan -> ultragoal -> code-review -> ultraqa/);
|
|
2856
2928
|
}
|
|
2857
2929
|
finally {
|
|
2858
2930
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -4172,7 +4244,54 @@ esac
|
|
|
4172
4244
|
await rm(cwd, { recursive: true, force: true });
|
|
4173
4245
|
}
|
|
4174
4246
|
});
|
|
4175
|
-
it("
|
|
4247
|
+
it("skips prompt-submit HUD reconciliation during doctor smoke validation", async () => {
|
|
4248
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-doctor-smoke-hud-"));
|
|
4249
|
+
const originalTmux = process.env.TMUX;
|
|
4250
|
+
const originalTmuxPane = process.env.TMUX_PANE;
|
|
4251
|
+
const originalHudOwner = process.env[OMX_TMUX_HUD_OWNER_ENV];
|
|
4252
|
+
const originalDoctorSmoke = process.env.OMX_NATIVE_HOOK_DOCTOR_SMOKE;
|
|
4253
|
+
try {
|
|
4254
|
+
process.env.TMUX = "1";
|
|
4255
|
+
process.env.TMUX_PANE = "%1";
|
|
4256
|
+
process.env[OMX_TMUX_HUD_OWNER_ENV] = "1";
|
|
4257
|
+
process.env.OMX_NATIVE_HOOK_DOCTOR_SMOKE = "1";
|
|
4258
|
+
let reconcileCalled = false;
|
|
4259
|
+
const result = await dispatchCodexNativeHook({
|
|
4260
|
+
hook_event_name: "UserPromptSubmit",
|
|
4261
|
+
cwd,
|
|
4262
|
+
session_id: "omx-doctor-plugin-hook-smoke",
|
|
4263
|
+
prompt: "$ralplan doctor plugin hook smoke test",
|
|
4264
|
+
}, {
|
|
4265
|
+
cwd,
|
|
4266
|
+
reconcileHudForPromptSubmitFn: async () => {
|
|
4267
|
+
reconcileCalled = true;
|
|
4268
|
+
return { status: "recreated", paneId: "%9", desiredHeight: 3, duplicateCount: 0 };
|
|
4269
|
+
},
|
|
4270
|
+
});
|
|
4271
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
4272
|
+
assert.equal(reconcileCalled, false);
|
|
4273
|
+
}
|
|
4274
|
+
finally {
|
|
4275
|
+
if (originalTmux === undefined)
|
|
4276
|
+
delete process.env.TMUX;
|
|
4277
|
+
else
|
|
4278
|
+
process.env.TMUX = originalTmux;
|
|
4279
|
+
if (originalTmuxPane === undefined)
|
|
4280
|
+
delete process.env.TMUX_PANE;
|
|
4281
|
+
else
|
|
4282
|
+
process.env.TMUX_PANE = originalTmuxPane;
|
|
4283
|
+
if (originalHudOwner === undefined)
|
|
4284
|
+
delete process.env[OMX_TMUX_HUD_OWNER_ENV];
|
|
4285
|
+
else
|
|
4286
|
+
process.env[OMX_TMUX_HUD_OWNER_ENV] = originalHudOwner;
|
|
4287
|
+
if (originalDoctorSmoke === undefined)
|
|
4288
|
+
delete process.env.OMX_NATIVE_HOOK_DOCTOR_SMOKE;
|
|
4289
|
+
else
|
|
4290
|
+
process.env.OMX_NATIVE_HOOK_DOCTOR_SMOKE = originalDoctorSmoke;
|
|
4291
|
+
await rm(cwd, { recursive: true, force: true });
|
|
4292
|
+
}
|
|
4293
|
+
});
|
|
4294
|
+
it("recreates a leader-only HUD pane when UserPromptSubmit revives with the canonical session id", async () => {
|
|
4176
4295
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-reuse-"));
|
|
4177
4296
|
const originalTmux = process.env.TMUX;
|
|
4178
4297
|
const originalTmuxPane = process.env.TMUX_PANE;
|
|
@@ -4219,8 +4338,8 @@ esac
|
|
|
4219
4338
|
assert.equal(result.omxEventName, "keyword-detector");
|
|
4220
4339
|
const tmuxCalls = await readFile(tmuxLog, "utf-8");
|
|
4221
4340
|
assert.match(tmuxCalls, /list-panes -t %1 -F/);
|
|
4222
|
-
assert.match(tmuxCalls,
|
|
4223
|
-
assert.
|
|
4341
|
+
assert.match(tmuxCalls, /split-window/);
|
|
4342
|
+
assert.match(tmuxCalls, new RegExp(`resize-pane -t %9 -y ${HUD_TMUX_HEIGHT_LINES}`));
|
|
4224
4343
|
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", canonicalSessionId, "ralplan-state.json")), true);
|
|
4225
4344
|
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", nativeSessionId, "ralplan-state.json")), false);
|
|
4226
4345
|
}
|
|
@@ -11483,7 +11602,7 @@ exit 0
|
|
|
11483
11602
|
}, { cwd });
|
|
11484
11603
|
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11485
11604
|
assert.equal(result.outputJson?.decision, "block");
|
|
11486
|
-
assert.match(String(result.outputJson?.reason ?? ""), /Ralplan is active .*implementation\/write tools are blocked/i);
|
|
11605
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
11487
11606
|
assert.match(String(result.outputJson?.hookSpecificOutput?.additionalContext ?? ""), /\$ultragoal.*\$team.*\$ralph/i);
|
|
11488
11607
|
}
|
|
11489
11608
|
finally {
|
|
@@ -11525,120 +11644,146 @@ exit 0
|
|
|
11525
11644
|
}, { cwd });
|
|
11526
11645
|
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11527
11646
|
assert.equal(result.outputJson?.decision, "block");
|
|
11528
|
-
assert.match(String(result.outputJson?.reason ?? ""), /Ralplan is active .*implementation\/write tools are blocked/i);
|
|
11647
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
11529
11648
|
}
|
|
11530
11649
|
finally {
|
|
11531
11650
|
await rm(cwd, { recursive: true, force: true });
|
|
11532
11651
|
}
|
|
11533
11652
|
});
|
|
11534
|
-
it("
|
|
11535
|
-
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-
|
|
11653
|
+
it("blocks implementation writes when Autopilot ralplan is visible only in skill-active phase", async () => {
|
|
11654
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-skill-ralplan-pretool-block-"));
|
|
11536
11655
|
try {
|
|
11537
11656
|
const stateDir = join(cwd, ".omx", "state");
|
|
11538
|
-
const sessionId = "sess-autopilot-ralplan-
|
|
11657
|
+
const sessionId = "sess-autopilot-skill-ralplan-pretool-block";
|
|
11539
11658
|
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
11540
11659
|
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
11541
11660
|
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
11542
11661
|
active: true,
|
|
11543
11662
|
skill: "autopilot",
|
|
11544
|
-
phase: "ralplan",
|
|
11663
|
+
phase: "autopilot:ralplan",
|
|
11545
11664
|
session_id: sessionId,
|
|
11546
|
-
active_skills: [{ skill: "autopilot", phase: "ralplan", active: true, session_id: sessionId }],
|
|
11665
|
+
active_skills: [{ skill: "autopilot", phase: "autopilot:ralplan", active: true, session_id: sessionId }],
|
|
11547
11666
|
});
|
|
11548
11667
|
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11549
11668
|
active: true,
|
|
11550
11669
|
mode: "autopilot",
|
|
11551
|
-
current_phase: "
|
|
11670
|
+
current_phase: "planning",
|
|
11552
11671
|
session_id: sessionId,
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
outcome: "finish",
|
|
11559
|
-
lifecycle_outcome: "finished",
|
|
11560
|
-
current_phase: "complete",
|
|
11561
|
-
completed_at: "2026-05-30T00:00:00.000Z",
|
|
11562
|
-
updated_at: "2026-05-30T00:00:00.000Z",
|
|
11672
|
+
state: {
|
|
11673
|
+
handoff_artifacts: {
|
|
11674
|
+
ralplan_consensus_gate: { required: true, complete: false },
|
|
11675
|
+
},
|
|
11676
|
+
},
|
|
11563
11677
|
});
|
|
11564
11678
|
const result = await dispatchCodexNativeHook({
|
|
11565
11679
|
hook_event_name: "PreToolUse",
|
|
11566
11680
|
cwd,
|
|
11567
11681
|
session_id: sessionId,
|
|
11568
|
-
thread_id: "thread-autopilot-ralplan-
|
|
11682
|
+
thread_id: "thread-autopilot-skill-ralplan-pretool-block",
|
|
11569
11683
|
tool_name: "Edit",
|
|
11570
11684
|
tool_input: { file_path: "src/runtime.ts" },
|
|
11571
11685
|
}, { cwd });
|
|
11572
11686
|
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11573
|
-
assert.equal(result.outputJson,
|
|
11687
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
11688
|
+
assert.match(String(result.outputJson?.reason ?? ""), /Autopilot planning is active .*implementation\/write tools are blocked/i);
|
|
11574
11689
|
}
|
|
11575
11690
|
finally {
|
|
11576
11691
|
await rm(cwd, { recursive: true, force: true });
|
|
11577
11692
|
}
|
|
11578
11693
|
});
|
|
11579
|
-
it("
|
|
11580
|
-
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-
|
|
11694
|
+
it("ignores stale Autopilot ralplan skill mirrors after detail state leaves planning", async () => {
|
|
11695
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-stale-ralplan-mirror-"));
|
|
11581
11696
|
try {
|
|
11582
11697
|
const stateDir = join(cwd, ".omx", "state");
|
|
11583
|
-
const sessionId = "sess-autopilot-ralplan-
|
|
11698
|
+
const sessionId = "sess-autopilot-stale-ralplan-mirror";
|
|
11584
11699
|
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
11585
11700
|
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
11586
11701
|
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
11587
11702
|
active: true,
|
|
11588
11703
|
skill: "autopilot",
|
|
11589
|
-
phase: "ralplan",
|
|
11704
|
+
phase: "autopilot:ralplan",
|
|
11590
11705
|
session_id: sessionId,
|
|
11591
|
-
active_skills: [{ skill: "autopilot", phase: "ralplan", active: true, session_id: sessionId }],
|
|
11706
|
+
active_skills: [{ skill: "autopilot", phase: "autopilot:ralplan", active: true, session_id: sessionId }],
|
|
11707
|
+
});
|
|
11708
|
+
for (const phase of ["ultragoal", "code-review", "completing", "complete"]) {
|
|
11709
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11710
|
+
active: true,
|
|
11711
|
+
mode: "autopilot",
|
|
11712
|
+
current_phase: phase,
|
|
11713
|
+
session_id: sessionId,
|
|
11714
|
+
});
|
|
11715
|
+
const result = await dispatchCodexNativeHook({
|
|
11716
|
+
hook_event_name: "PreToolUse",
|
|
11717
|
+
cwd,
|
|
11718
|
+
session_id: sessionId,
|
|
11719
|
+
thread_id: "thread-autopilot-stale-ralplan-mirror",
|
|
11720
|
+
tool_name: "Edit",
|
|
11721
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
11722
|
+
}, { cwd });
|
|
11723
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11724
|
+
assert.equal(result.outputJson, null, `stale skill-active ralplan mirror must not block when Autopilot detail phase is ${phase}`);
|
|
11725
|
+
}
|
|
11726
|
+
}
|
|
11727
|
+
finally {
|
|
11728
|
+
await rm(cwd, { recursive: true, force: true });
|
|
11729
|
+
}
|
|
11730
|
+
});
|
|
11731
|
+
it("allows explicit blank Autopilot detail phase to use a ralplan skill mirror", async () => {
|
|
11732
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-blank-phase-mirror-"));
|
|
11733
|
+
try {
|
|
11734
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
11735
|
+
const sessionId = "sess-autopilot-blank-phase-mirror";
|
|
11736
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
11737
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
11738
|
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
11739
|
+
active: true,
|
|
11740
|
+
skill: "autopilot",
|
|
11741
|
+
phase: "autopilot:ralplan",
|
|
11742
|
+
session_id: sessionId,
|
|
11743
|
+
active_skills: [{ skill: "autopilot", phase: "autopilot:ralplan", active: true, session_id: sessionId }],
|
|
11592
11744
|
});
|
|
11593
11745
|
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11594
11746
|
active: true,
|
|
11595
11747
|
mode: "autopilot",
|
|
11596
|
-
current_phase: "
|
|
11748
|
+
current_phase: "",
|
|
11597
11749
|
session_id: sessionId,
|
|
11598
11750
|
});
|
|
11599
11751
|
const result = await dispatchCodexNativeHook({
|
|
11600
11752
|
hook_event_name: "PreToolUse",
|
|
11601
11753
|
cwd,
|
|
11602
11754
|
session_id: sessionId,
|
|
11603
|
-
thread_id: "thread-autopilot-
|
|
11604
|
-
tool_name: "
|
|
11605
|
-
tool_input: {
|
|
11755
|
+
thread_id: "thread-autopilot-blank-phase-mirror",
|
|
11756
|
+
tool_name: "Edit",
|
|
11757
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
11606
11758
|
}, { cwd });
|
|
11607
11759
|
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11608
11760
|
assert.equal(result.outputJson?.decision, "block");
|
|
11609
|
-
assert.match(String(result.outputJson?.reason ?? ""), /
|
|
11761
|
+
assert.match(String(result.outputJson?.reason ?? ""), /Autopilot planning is active .*implementation\/write tools are blocked/i);
|
|
11610
11762
|
}
|
|
11611
11763
|
finally {
|
|
11612
11764
|
await rm(cwd, { recursive: true, force: true });
|
|
11613
11765
|
}
|
|
11614
11766
|
});
|
|
11615
|
-
it("
|
|
11616
|
-
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-
|
|
11767
|
+
it("does not block implementation writes from Autopilot ralplan detail state without canonical skill state", async () => {
|
|
11768
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-no-canonical-"));
|
|
11617
11769
|
try {
|
|
11618
11770
|
const stateDir = join(cwd, ".omx", "state");
|
|
11619
|
-
const sessionId = "sess-ralplan-
|
|
11771
|
+
const sessionId = "sess-autopilot-ralplan-no-canonical";
|
|
11620
11772
|
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
11621
11773
|
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
11622
|
-
await writeJson(join(stateDir, "sessions", sessionId, "
|
|
11623
|
-
active: true,
|
|
11624
|
-
skill: "ralplan",
|
|
11625
|
-
phase: "planning",
|
|
11626
|
-
session_id: sessionId,
|
|
11627
|
-
active_skills: [{ skill: "ralplan", phase: "planning", active: true, session_id: sessionId }],
|
|
11628
|
-
});
|
|
11629
|
-
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
11774
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11630
11775
|
active: true,
|
|
11631
|
-
mode: "
|
|
11632
|
-
current_phase: "
|
|
11776
|
+
mode: "autopilot",
|
|
11777
|
+
current_phase: "ralplan",
|
|
11633
11778
|
session_id: sessionId,
|
|
11634
11779
|
});
|
|
11635
11780
|
const result = await dispatchCodexNativeHook({
|
|
11636
11781
|
hook_event_name: "PreToolUse",
|
|
11637
11782
|
cwd,
|
|
11638
11783
|
session_id: sessionId,
|
|
11639
|
-
thread_id: "thread-ralplan-
|
|
11640
|
-
tool_name: "
|
|
11641
|
-
tool_input: { file_path: "
|
|
11784
|
+
thread_id: "thread-autopilot-ralplan-no-canonical",
|
|
11785
|
+
tool_name: "Edit",
|
|
11786
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
11642
11787
|
}, { cwd });
|
|
11643
11788
|
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11644
11789
|
assert.equal(result.outputJson, null);
|
|
@@ -11647,143 +11792,677 @@ exit 0
|
|
|
11647
11792
|
await rm(cwd, { recursive: true, force: true });
|
|
11648
11793
|
}
|
|
11649
11794
|
});
|
|
11650
|
-
it("
|
|
11651
|
-
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-pretool-
|
|
11795
|
+
it("allows implementation writes when terminal Autopilot run-state shadows stale supervised ralplan state", async () => {
|
|
11796
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-terminal-pretool-"));
|
|
11652
11797
|
try {
|
|
11653
11798
|
const stateDir = join(cwd, ".omx", "state");
|
|
11654
|
-
const sessionId = "sess-ralplan-pretool
|
|
11799
|
+
const sessionId = "sess-autopilot-ralplan-terminal-pretool";
|
|
11655
11800
|
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
11656
11801
|
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
11657
11802
|
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
11658
11803
|
active: true,
|
|
11659
|
-
skill: "
|
|
11660
|
-
phase: "
|
|
11804
|
+
skill: "autopilot",
|
|
11805
|
+
phase: "ralplan",
|
|
11661
11806
|
session_id: sessionId,
|
|
11662
|
-
active_skills: [{ skill: "
|
|
11807
|
+
active_skills: [{ skill: "autopilot", phase: "ralplan", active: true, session_id: sessionId }],
|
|
11663
11808
|
});
|
|
11664
|
-
await writeJson(join(stateDir, "sessions", sessionId, "
|
|
11809
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11665
11810
|
active: true,
|
|
11666
|
-
mode: "
|
|
11667
|
-
current_phase: "
|
|
11811
|
+
mode: "autopilot",
|
|
11812
|
+
current_phase: "ralplan",
|
|
11668
11813
|
session_id: sessionId,
|
|
11669
11814
|
});
|
|
11815
|
+
await writeJson(join(stateDir, "sessions", sessionId, "run-state.json"), {
|
|
11816
|
+
version: 1,
|
|
11817
|
+
active: false,
|
|
11818
|
+
mode: "autopilot",
|
|
11819
|
+
outcome: "finish",
|
|
11820
|
+
lifecycle_outcome: "finished",
|
|
11821
|
+
current_phase: "complete",
|
|
11822
|
+
completed_at: "2026-05-30T00:00:00.000Z",
|
|
11823
|
+
updated_at: "2026-05-30T00:00:00.000Z",
|
|
11824
|
+
});
|
|
11670
11825
|
const result = await dispatchCodexNativeHook({
|
|
11671
11826
|
hook_event_name: "PreToolUse",
|
|
11672
11827
|
cwd,
|
|
11673
11828
|
session_id: sessionId,
|
|
11674
|
-
thread_id: "thread-ralplan-pretool
|
|
11675
|
-
tool_name: "
|
|
11676
|
-
tool_input: {
|
|
11829
|
+
thread_id: "thread-autopilot-ralplan-terminal-pretool",
|
|
11830
|
+
tool_name: "Edit",
|
|
11831
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
11677
11832
|
}, { cwd });
|
|
11678
11833
|
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11679
|
-
assert.equal(result.outputJson
|
|
11680
|
-
assert.match(String(result.outputJson?.reason ?? ""), /Ralplan is active .*implementation\/write tools are blocked/i);
|
|
11834
|
+
assert.equal(result.outputJson, null);
|
|
11681
11835
|
}
|
|
11682
11836
|
finally {
|
|
11683
11837
|
await rm(cwd, { recursive: true, force: true });
|
|
11684
11838
|
}
|
|
11685
11839
|
});
|
|
11686
|
-
it("
|
|
11687
|
-
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-pretool-bash-
|
|
11840
|
+
it("blocks bash implementation writes while Autopilot is supervising ralplan without handoff", async () => {
|
|
11841
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-pretool-bash-block-"));
|
|
11688
11842
|
try {
|
|
11689
11843
|
const stateDir = join(cwd, ".omx", "state");
|
|
11690
|
-
const sessionId = "sess-ralplan-pretool-bash-
|
|
11844
|
+
const sessionId = "sess-autopilot-ralplan-pretool-bash-block";
|
|
11691
11845
|
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
11692
11846
|
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
11693
11847
|
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
11694
11848
|
active: true,
|
|
11695
|
-
skill: "
|
|
11696
|
-
phase: "
|
|
11849
|
+
skill: "autopilot",
|
|
11850
|
+
phase: "ralplan",
|
|
11697
11851
|
session_id: sessionId,
|
|
11698
|
-
active_skills: [{ skill: "
|
|
11852
|
+
active_skills: [{ skill: "autopilot", phase: "ralplan", active: true, session_id: sessionId }],
|
|
11699
11853
|
});
|
|
11700
|
-
await writeJson(join(stateDir, "sessions", sessionId, "
|
|
11854
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11701
11855
|
active: true,
|
|
11702
|
-
mode: "
|
|
11703
|
-
current_phase: "
|
|
11856
|
+
mode: "autopilot",
|
|
11857
|
+
current_phase: "ralplan",
|
|
11704
11858
|
session_id: sessionId,
|
|
11705
11859
|
});
|
|
11706
11860
|
const result = await dispatchCodexNativeHook({
|
|
11707
11861
|
hook_event_name: "PreToolUse",
|
|
11708
11862
|
cwd,
|
|
11709
11863
|
session_id: sessionId,
|
|
11710
|
-
thread_id: "thread-ralplan-pretool-bash-
|
|
11864
|
+
thread_id: "thread-autopilot-ralplan-pretool-bash-block",
|
|
11711
11865
|
tool_name: "Bash",
|
|
11712
|
-
tool_input: { command: "cat <<'EOF' >
|
|
11866
|
+
tool_input: { command: "cat <<'EOF' > src/runtime.ts\nimplementation\nEOF" },
|
|
11713
11867
|
}, { cwd });
|
|
11714
11868
|
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11715
|
-
assert.equal(result.outputJson,
|
|
11869
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
11870
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
11716
11871
|
}
|
|
11717
11872
|
finally {
|
|
11718
11873
|
await rm(cwd, { recursive: true, force: true });
|
|
11719
11874
|
}
|
|
11720
11875
|
});
|
|
11721
|
-
it("
|
|
11722
|
-
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-
|
|
11876
|
+
it("blocks implementation writes when ralplan and Autopilot ralplan are both active", async () => {
|
|
11877
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-autopilot-mixed-planning-"));
|
|
11723
11878
|
try {
|
|
11724
11879
|
const stateDir = join(cwd, ".omx", "state");
|
|
11725
|
-
const sessionId = "sess-ralplan-
|
|
11880
|
+
const sessionId = "sess-ralplan-autopilot-mixed-planning";
|
|
11726
11881
|
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
11727
11882
|
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
11728
11883
|
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
11729
11884
|
active: true,
|
|
11730
|
-
skill: "
|
|
11731
|
-
phase: "
|
|
11885
|
+
skill: "autopilot",
|
|
11886
|
+
phase: "ralplan",
|
|
11732
11887
|
session_id: sessionId,
|
|
11733
11888
|
active_skills: [
|
|
11734
11889
|
{ skill: "ralplan", phase: "planning", active: true, session_id: sessionId },
|
|
11735
|
-
{ skill: "
|
|
11890
|
+
{ skill: "autopilot", phase: "ralplan", active: true, session_id: sessionId },
|
|
11736
11891
|
],
|
|
11737
11892
|
});
|
|
11738
11893
|
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
11739
11894
|
active: true,
|
|
11740
11895
|
mode: "ralplan",
|
|
11741
|
-
current_phase: "
|
|
11896
|
+
current_phase: "planning",
|
|
11742
11897
|
session_id: sessionId,
|
|
11743
11898
|
});
|
|
11744
|
-
await writeJson(join(stateDir, "sessions", sessionId, "
|
|
11899
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11745
11900
|
active: true,
|
|
11746
|
-
mode: "
|
|
11747
|
-
current_phase: "
|
|
11901
|
+
mode: "autopilot",
|
|
11902
|
+
current_phase: "ralplan",
|
|
11748
11903
|
session_id: sessionId,
|
|
11749
11904
|
});
|
|
11750
11905
|
const result = await dispatchCodexNativeHook({
|
|
11751
11906
|
hook_event_name: "PreToolUse",
|
|
11752
11907
|
cwd,
|
|
11753
11908
|
session_id: sessionId,
|
|
11754
|
-
thread_id: "thread-ralplan-
|
|
11909
|
+
thread_id: "thread-ralplan-autopilot-mixed-planning",
|
|
11755
11910
|
tool_name: "Edit",
|
|
11756
11911
|
tool_input: { file_path: "src/runtime.ts" },
|
|
11757
11912
|
}, { cwd });
|
|
11758
11913
|
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11759
|
-
assert.equal(result.outputJson,
|
|
11914
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
11915
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
11760
11916
|
}
|
|
11761
11917
|
finally {
|
|
11762
11918
|
await rm(cwd, { recursive: true, force: true });
|
|
11763
11919
|
}
|
|
11764
11920
|
});
|
|
11765
|
-
it("
|
|
11766
|
-
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-
|
|
11921
|
+
it("blocks implementation writes while Autopilot is supervising replan without handoff", async () => {
|
|
11922
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-replan-pretool-block-"));
|
|
11767
11923
|
try {
|
|
11768
11924
|
const stateDir = join(cwd, ".omx", "state");
|
|
11769
|
-
|
|
11770
|
-
await
|
|
11925
|
+
const sessionId = "sess-autopilot-replan-pretool-block";
|
|
11926
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
11927
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
11928
|
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
11771
11929
|
active: true,
|
|
11772
|
-
|
|
11773
|
-
|
|
11930
|
+
skill: "autopilot",
|
|
11931
|
+
phase: "replan",
|
|
11932
|
+
session_id: sessionId,
|
|
11933
|
+
active_skills: [{ skill: "autopilot", phase: "replan", active: true, session_id: sessionId }],
|
|
11934
|
+
});
|
|
11935
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11936
|
+
active: true,
|
|
11937
|
+
mode: "autopilot",
|
|
11938
|
+
current_phase: "replan",
|
|
11939
|
+
session_id: sessionId,
|
|
11774
11940
|
});
|
|
11775
11941
|
const result = await dispatchCodexNativeHook({
|
|
11776
|
-
hook_event_name: "
|
|
11942
|
+
hook_event_name: "PreToolUse",
|
|
11777
11943
|
cwd,
|
|
11944
|
+
session_id: sessionId,
|
|
11945
|
+
thread_id: "thread-autopilot-replan-pretool-block",
|
|
11946
|
+
tool_name: "Edit",
|
|
11947
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
11778
11948
|
}, { cwd });
|
|
11779
|
-
assert.equal(result.omxEventName, "
|
|
11780
|
-
assert.equal(result.outputJson,
|
|
11949
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11950
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
11951
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
11781
11952
|
}
|
|
11782
11953
|
finally {
|
|
11783
11954
|
await rm(cwd, { recursive: true, force: true });
|
|
11784
11955
|
}
|
|
11785
11956
|
});
|
|
11786
|
-
it("
|
|
11957
|
+
it("blocks implementation writes when native Codex id maps to OMX Autopilot ralplan state", async () => {
|
|
11958
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-native-map-block-"));
|
|
11959
|
+
try {
|
|
11960
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
11961
|
+
const sessionId = "sess-autopilot-ralplan-native-map-block";
|
|
11962
|
+
const nativeSessionId = "019e-autopilot-ralplan-native";
|
|
11963
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
11964
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "autopilot", "ralplan");
|
|
11965
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11966
|
+
active: true,
|
|
11967
|
+
mode: "autopilot",
|
|
11968
|
+
current_phase: "ralplan",
|
|
11969
|
+
session_id: sessionId,
|
|
11970
|
+
});
|
|
11971
|
+
const result = await dispatchCodexNativeHook({
|
|
11972
|
+
hook_event_name: "PreToolUse",
|
|
11973
|
+
cwd,
|
|
11974
|
+
session_id: nativeSessionId,
|
|
11975
|
+
thread_id: "thread-autopilot-ralplan-native-map-block",
|
|
11976
|
+
tool_name: "apply_patch",
|
|
11977
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
11978
|
+
}, { cwd });
|
|
11979
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
11980
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
11981
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
11982
|
+
}
|
|
11983
|
+
finally {
|
|
11984
|
+
await rm(cwd, { recursive: true, force: true });
|
|
11985
|
+
}
|
|
11986
|
+
});
|
|
11987
|
+
it("blocks bash implementation writes when native Codex id maps to OMX Autopilot ralplan state", async () => {
|
|
11988
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-native-map-bash-"));
|
|
11989
|
+
try {
|
|
11990
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
11991
|
+
const sessionId = "sess-autopilot-ralplan-native-map-bash";
|
|
11992
|
+
const nativeSessionId = "019e-autopilot-ralplan-native-bash";
|
|
11993
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
11994
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "autopilot", "ralplan");
|
|
11995
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
11996
|
+
active: true,
|
|
11997
|
+
mode: "autopilot",
|
|
11998
|
+
current_phase: "ralplan",
|
|
11999
|
+
session_id: sessionId,
|
|
12000
|
+
});
|
|
12001
|
+
const result = await dispatchCodexNativeHook({
|
|
12002
|
+
hook_event_name: "PreToolUse",
|
|
12003
|
+
cwd,
|
|
12004
|
+
session_id: nativeSessionId,
|
|
12005
|
+
thread_id: "thread-autopilot-ralplan-native-map-bash",
|
|
12006
|
+
tool_name: "Bash",
|
|
12007
|
+
tool_input: { command: "cat <<'EOF' > src/runtime.ts\nimplementation\nEOF" },
|
|
12008
|
+
}, { cwd });
|
|
12009
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12010
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
12011
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
12012
|
+
}
|
|
12013
|
+
finally {
|
|
12014
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12015
|
+
}
|
|
12016
|
+
});
|
|
12017
|
+
it("blocks standalone ralplan writes when native Codex id maps to OMX session state", async () => {
|
|
12018
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-native-map-block-"));
|
|
12019
|
+
try {
|
|
12020
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12021
|
+
const sessionId = "sess-ralplan-native-map-block";
|
|
12022
|
+
const nativeSessionId = "019e-ralplan-native-map";
|
|
12023
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
12024
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "ralplan", "planning");
|
|
12025
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12026
|
+
active: true,
|
|
12027
|
+
mode: "ralplan",
|
|
12028
|
+
current_phase: "planning",
|
|
12029
|
+
session_id: sessionId,
|
|
12030
|
+
});
|
|
12031
|
+
const result = await dispatchCodexNativeHook({
|
|
12032
|
+
hook_event_name: "PreToolUse",
|
|
12033
|
+
cwd,
|
|
12034
|
+
session_id: nativeSessionId,
|
|
12035
|
+
thread_id: "thread-ralplan-native-map-block",
|
|
12036
|
+
tool_name: "Edit",
|
|
12037
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
12038
|
+
}, { cwd });
|
|
12039
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12040
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
12041
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
12042
|
+
}
|
|
12043
|
+
finally {
|
|
12044
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12045
|
+
}
|
|
12046
|
+
});
|
|
12047
|
+
it("blocks deep-interview writes when native Codex id maps to OMX session state", async () => {
|
|
12048
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-deep-interview-native-map-block-"));
|
|
12049
|
+
try {
|
|
12050
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12051
|
+
const sessionId = "sess-deep-interview-native-map-block";
|
|
12052
|
+
const nativeSessionId = "019e-deep-interview-native-map";
|
|
12053
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
12054
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "deep-interview", "interview");
|
|
12055
|
+
await writeJson(join(stateDir, "sessions", sessionId, "deep-interview-state.json"), {
|
|
12056
|
+
active: true,
|
|
12057
|
+
mode: "deep-interview",
|
|
12058
|
+
current_phase: "interview",
|
|
12059
|
+
session_id: sessionId,
|
|
12060
|
+
});
|
|
12061
|
+
const result = await dispatchCodexNativeHook({
|
|
12062
|
+
hook_event_name: "PreToolUse",
|
|
12063
|
+
cwd,
|
|
12064
|
+
session_id: nativeSessionId,
|
|
12065
|
+
thread_id: "thread-deep-interview-native-map-block",
|
|
12066
|
+
tool_name: "Edit",
|
|
12067
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
12068
|
+
}, { cwd });
|
|
12069
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12070
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
12071
|
+
assert.match(String(result.outputJson?.reason ?? ""), /Deep-interview is active .*implementation\/write tools are blocked/i);
|
|
12072
|
+
}
|
|
12073
|
+
finally {
|
|
12074
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12075
|
+
}
|
|
12076
|
+
});
|
|
12077
|
+
it("allows mapped ralplan planning artifact writes without execution handoff", async () => {
|
|
12078
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-native-map-artifact-"));
|
|
12079
|
+
try {
|
|
12080
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12081
|
+
const sessionId = "sess-ralplan-native-map-artifact";
|
|
12082
|
+
const nativeSessionId = "019e-ralplan-native-map-artifact";
|
|
12083
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
12084
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "ralplan", "planning");
|
|
12085
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12086
|
+
active: true,
|
|
12087
|
+
mode: "ralplan",
|
|
12088
|
+
current_phase: "planning",
|
|
12089
|
+
session_id: sessionId,
|
|
12090
|
+
});
|
|
12091
|
+
const result = await dispatchCodexNativeHook({
|
|
12092
|
+
hook_event_name: "PreToolUse",
|
|
12093
|
+
cwd,
|
|
12094
|
+
session_id: nativeSessionId,
|
|
12095
|
+
thread_id: "thread-ralplan-native-map-artifact",
|
|
12096
|
+
tool_name: "Bash",
|
|
12097
|
+
tool_input: { command: "cat <<'EOF' > .omx/plans/prd-native-map.md\nplanning\nEOF" },
|
|
12098
|
+
}, { cwd });
|
|
12099
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12100
|
+
assert.equal(result.outputJson, null);
|
|
12101
|
+
}
|
|
12102
|
+
finally {
|
|
12103
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12104
|
+
}
|
|
12105
|
+
});
|
|
12106
|
+
it("allows mapped implementation writes when explicit execution handoff is active", async () => {
|
|
12107
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-native-map-handoff-"));
|
|
12108
|
+
try {
|
|
12109
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12110
|
+
const sessionId = "sess-ralplan-native-map-handoff";
|
|
12111
|
+
const nativeSessionId = "019e-ralplan-native-map-handoff";
|
|
12112
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
12113
|
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
12114
|
+
active: true,
|
|
12115
|
+
skill: "ultragoal",
|
|
12116
|
+
phase: "planning",
|
|
12117
|
+
session_id: sessionId,
|
|
12118
|
+
active_skills: [
|
|
12119
|
+
{ skill: "ralplan", phase: "planning", active: true, session_id: sessionId },
|
|
12120
|
+
{ skill: "ultragoal", phase: "planning", active: true, session_id: sessionId },
|
|
12121
|
+
],
|
|
12122
|
+
});
|
|
12123
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12124
|
+
active: true,
|
|
12125
|
+
mode: "ralplan",
|
|
12126
|
+
current_phase: "complete",
|
|
12127
|
+
session_id: sessionId,
|
|
12128
|
+
});
|
|
12129
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
|
|
12130
|
+
active: true,
|
|
12131
|
+
mode: "ultragoal",
|
|
12132
|
+
current_phase: "planning",
|
|
12133
|
+
session_id: sessionId,
|
|
12134
|
+
});
|
|
12135
|
+
const result = await dispatchCodexNativeHook({
|
|
12136
|
+
hook_event_name: "PreToolUse",
|
|
12137
|
+
cwd,
|
|
12138
|
+
session_id: nativeSessionId,
|
|
12139
|
+
thread_id: "thread-ralplan-native-map-handoff",
|
|
12140
|
+
tool_name: "Edit",
|
|
12141
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
12142
|
+
}, { cwd });
|
|
12143
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12144
|
+
assert.equal(result.outputJson, null);
|
|
12145
|
+
}
|
|
12146
|
+
finally {
|
|
12147
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12148
|
+
}
|
|
12149
|
+
});
|
|
12150
|
+
it("allows mapped implementation writes when terminal Autopilot run-state shadows stale supervised ralplan state", async () => {
|
|
12151
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-native-map-terminal-"));
|
|
12152
|
+
try {
|
|
12153
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12154
|
+
const sessionId = "sess-autopilot-ralplan-native-map-terminal";
|
|
12155
|
+
const nativeSessionId = "019e-autopilot-ralplan-native-terminal";
|
|
12156
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
12157
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "autopilot", "ralplan");
|
|
12158
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
12159
|
+
active: true,
|
|
12160
|
+
mode: "autopilot",
|
|
12161
|
+
current_phase: "ralplan",
|
|
12162
|
+
session_id: sessionId,
|
|
12163
|
+
});
|
|
12164
|
+
await writeJson(join(stateDir, "sessions", sessionId, "run-state.json"), {
|
|
12165
|
+
version: 1,
|
|
12166
|
+
active: false,
|
|
12167
|
+
mode: "autopilot",
|
|
12168
|
+
outcome: "finish",
|
|
12169
|
+
lifecycle_outcome: "finished",
|
|
12170
|
+
current_phase: "complete",
|
|
12171
|
+
completed_at: "2026-05-30T00:00:00.000Z",
|
|
12172
|
+
updated_at: "2026-05-30T00:00:00.000Z",
|
|
12173
|
+
});
|
|
12174
|
+
const result = await dispatchCodexNativeHook({
|
|
12175
|
+
hook_event_name: "PreToolUse",
|
|
12176
|
+
cwd,
|
|
12177
|
+
session_id: nativeSessionId,
|
|
12178
|
+
thread_id: "thread-autopilot-ralplan-native-map-terminal",
|
|
12179
|
+
tool_name: "Edit",
|
|
12180
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
12181
|
+
}, { cwd });
|
|
12182
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12183
|
+
assert.equal(result.outputJson, null);
|
|
12184
|
+
}
|
|
12185
|
+
finally {
|
|
12186
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12187
|
+
}
|
|
12188
|
+
});
|
|
12189
|
+
it("does not block unrelated native Codex ids when current OMX session mapping does not match", async () => {
|
|
12190
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-native-map-unrelated-"));
|
|
12191
|
+
try {
|
|
12192
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12193
|
+
const sessionId = "sess-ralplan-native-map-owner";
|
|
12194
|
+
const ownerNativeSessionId = "019e-ralplan-native-owner";
|
|
12195
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, ownerNativeSessionId);
|
|
12196
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "ralplan", "planning");
|
|
12197
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12198
|
+
active: true,
|
|
12199
|
+
mode: "ralplan",
|
|
12200
|
+
current_phase: "planning",
|
|
12201
|
+
session_id: sessionId,
|
|
12202
|
+
});
|
|
12203
|
+
const result = await dispatchCodexNativeHook({
|
|
12204
|
+
hook_event_name: "PreToolUse",
|
|
12205
|
+
cwd,
|
|
12206
|
+
session_id: "019e-unrelated-native-session",
|
|
12207
|
+
thread_id: "thread-ralplan-native-map-unrelated",
|
|
12208
|
+
tool_name: "Edit",
|
|
12209
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
12210
|
+
}, { cwd });
|
|
12211
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12212
|
+
assert.equal(result.outputJson, null);
|
|
12213
|
+
}
|
|
12214
|
+
finally {
|
|
12215
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12216
|
+
}
|
|
12217
|
+
});
|
|
12218
|
+
it("blocks mapped Autopilot ralplan writes from the authoritative team state root", async () => {
|
|
12219
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-autopilot-ralplan-team-root-"));
|
|
12220
|
+
const teamStateRoot = await mkdtemp(join(tmpdir(), "omx-native-hook-team-root-"));
|
|
12221
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
12222
|
+
try {
|
|
12223
|
+
process.env.OMX_TEAM_STATE_ROOT = teamStateRoot;
|
|
12224
|
+
const stateDir = teamStateRoot;
|
|
12225
|
+
const sessionId = "sess-autopilot-ralplan-team-root";
|
|
12226
|
+
const nativeSessionId = "019e-autopilot-ralplan-team-root";
|
|
12227
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
12228
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "autopilot", "ralplan");
|
|
12229
|
+
await writeJson(join(stateDir, "sessions", sessionId, "autopilot-state.json"), {
|
|
12230
|
+
active: true,
|
|
12231
|
+
mode: "autopilot",
|
|
12232
|
+
current_phase: "ralplan",
|
|
12233
|
+
session_id: sessionId,
|
|
12234
|
+
});
|
|
12235
|
+
const result = await dispatchCodexNativeHook({
|
|
12236
|
+
hook_event_name: "PreToolUse",
|
|
12237
|
+
cwd,
|
|
12238
|
+
session_id: nativeSessionId,
|
|
12239
|
+
thread_id: "thread-autopilot-ralplan-team-root",
|
|
12240
|
+
tool_name: "Edit",
|
|
12241
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
12242
|
+
}, { cwd });
|
|
12243
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12244
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
12245
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
12246
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "session.json")), false);
|
|
12247
|
+
}
|
|
12248
|
+
finally {
|
|
12249
|
+
if (typeof previousTeamStateRoot === "string")
|
|
12250
|
+
process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
12251
|
+
else
|
|
12252
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
12253
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12254
|
+
await rm(teamStateRoot, { recursive: true, force: true });
|
|
12255
|
+
}
|
|
12256
|
+
});
|
|
12257
|
+
it("does not block unrelated native Codex ids from the authoritative team state root", async () => {
|
|
12258
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-team-root-unrelated-"));
|
|
12259
|
+
const teamStateRoot = await mkdtemp(join(tmpdir(), "omx-native-hook-team-root-unrelated-"));
|
|
12260
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
12261
|
+
try {
|
|
12262
|
+
process.env.OMX_TEAM_STATE_ROOT = teamStateRoot;
|
|
12263
|
+
const stateDir = teamStateRoot;
|
|
12264
|
+
const sessionId = "sess-ralplan-team-root-owner";
|
|
12265
|
+
const nativeSessionId = "019e-ralplan-team-root-owner";
|
|
12266
|
+
await writeNativeMappedSessionState(cwd, stateDir, sessionId, nativeSessionId);
|
|
12267
|
+
await writeSessionSkillActiveState(stateDir, sessionId, "ralplan", "planning");
|
|
12268
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12269
|
+
active: true,
|
|
12270
|
+
mode: "ralplan",
|
|
12271
|
+
current_phase: "planning",
|
|
12272
|
+
session_id: sessionId,
|
|
12273
|
+
});
|
|
12274
|
+
const result = await dispatchCodexNativeHook({
|
|
12275
|
+
hook_event_name: "PreToolUse",
|
|
12276
|
+
cwd,
|
|
12277
|
+
session_id: "019e-unrelated-team-root-native",
|
|
12278
|
+
thread_id: "thread-ralplan-team-root-unrelated",
|
|
12279
|
+
tool_name: "Edit",
|
|
12280
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
12281
|
+
}, { cwd });
|
|
12282
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12283
|
+
assert.equal(result.outputJson, null);
|
|
12284
|
+
}
|
|
12285
|
+
finally {
|
|
12286
|
+
if (typeof previousTeamStateRoot === "string")
|
|
12287
|
+
process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
12288
|
+
else
|
|
12289
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
12290
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12291
|
+
await rm(teamStateRoot, { recursive: true, force: true });
|
|
12292
|
+
}
|
|
12293
|
+
});
|
|
12294
|
+
it("allows ralplan planning artifact writes without execution handoff", async () => {
|
|
12295
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-pretool-artifact-"));
|
|
12296
|
+
try {
|
|
12297
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12298
|
+
const sessionId = "sess-ralplan-pretool-artifact";
|
|
12299
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
12300
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
12301
|
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
12302
|
+
active: true,
|
|
12303
|
+
skill: "ralplan",
|
|
12304
|
+
phase: "planning",
|
|
12305
|
+
session_id: sessionId,
|
|
12306
|
+
active_skills: [{ skill: "ralplan", phase: "planning", active: true, session_id: sessionId }],
|
|
12307
|
+
});
|
|
12308
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12309
|
+
active: true,
|
|
12310
|
+
mode: "ralplan",
|
|
12311
|
+
current_phase: "planning",
|
|
12312
|
+
session_id: sessionId,
|
|
12313
|
+
});
|
|
12314
|
+
const result = await dispatchCodexNativeHook({
|
|
12315
|
+
hook_event_name: "PreToolUse",
|
|
12316
|
+
cwd,
|
|
12317
|
+
session_id: sessionId,
|
|
12318
|
+
thread_id: "thread-ralplan-pretool-artifact",
|
|
12319
|
+
tool_name: "Write",
|
|
12320
|
+
tool_input: { file_path: ".omx/plans/prd-issue-2603.md" },
|
|
12321
|
+
}, { cwd });
|
|
12322
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12323
|
+
assert.equal(result.outputJson, null);
|
|
12324
|
+
}
|
|
12325
|
+
finally {
|
|
12326
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12327
|
+
}
|
|
12328
|
+
});
|
|
12329
|
+
it("blocks bash implementation writes while ralplan is active without execution handoff", async () => {
|
|
12330
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-pretool-bash-block-"));
|
|
12331
|
+
try {
|
|
12332
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12333
|
+
const sessionId = "sess-ralplan-pretool-bash-block";
|
|
12334
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
12335
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
12336
|
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
12337
|
+
active: true,
|
|
12338
|
+
skill: "ralplan",
|
|
12339
|
+
phase: "planning",
|
|
12340
|
+
session_id: sessionId,
|
|
12341
|
+
active_skills: [{ skill: "ralplan", phase: "planning", active: true, session_id: sessionId }],
|
|
12342
|
+
});
|
|
12343
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12344
|
+
active: true,
|
|
12345
|
+
mode: "ralplan",
|
|
12346
|
+
current_phase: "planning",
|
|
12347
|
+
session_id: sessionId,
|
|
12348
|
+
});
|
|
12349
|
+
const result = await dispatchCodexNativeHook({
|
|
12350
|
+
hook_event_name: "PreToolUse",
|
|
12351
|
+
cwd,
|
|
12352
|
+
session_id: sessionId,
|
|
12353
|
+
thread_id: "thread-ralplan-pretool-bash-block",
|
|
12354
|
+
tool_name: "Bash",
|
|
12355
|
+
tool_input: { command: "cat <<'EOF' > src/runtime.ts\nimplementation\nEOF" },
|
|
12356
|
+
}, { cwd });
|
|
12357
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12358
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
12359
|
+
assert.match(String(result.outputJson?.reason ?? ""), /(?:Ralplan|Autopilot planning) is active .*implementation\/write tools are blocked/i);
|
|
12360
|
+
}
|
|
12361
|
+
finally {
|
|
12362
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12363
|
+
}
|
|
12364
|
+
});
|
|
12365
|
+
it("allows bash planning artifact writes while ralplan is active without execution handoff", async () => {
|
|
12366
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-pretool-bash-artifact-"));
|
|
12367
|
+
try {
|
|
12368
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12369
|
+
const sessionId = "sess-ralplan-pretool-bash-artifact";
|
|
12370
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
12371
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
12372
|
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
12373
|
+
active: true,
|
|
12374
|
+
skill: "ralplan",
|
|
12375
|
+
phase: "planning",
|
|
12376
|
+
session_id: sessionId,
|
|
12377
|
+
active_skills: [{ skill: "ralplan", phase: "planning", active: true, session_id: sessionId }],
|
|
12378
|
+
});
|
|
12379
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12380
|
+
active: true,
|
|
12381
|
+
mode: "ralplan",
|
|
12382
|
+
current_phase: "planning",
|
|
12383
|
+
session_id: sessionId,
|
|
12384
|
+
});
|
|
12385
|
+
const result = await dispatchCodexNativeHook({
|
|
12386
|
+
hook_event_name: "PreToolUse",
|
|
12387
|
+
cwd,
|
|
12388
|
+
session_id: sessionId,
|
|
12389
|
+
thread_id: "thread-ralplan-pretool-bash-artifact",
|
|
12390
|
+
tool_name: "Bash",
|
|
12391
|
+
tool_input: { command: "cat <<'EOF' > .omx/plans/prd-issue-2603.md\nplanning\nEOF" },
|
|
12392
|
+
}, { cwd });
|
|
12393
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12394
|
+
assert.equal(result.outputJson, null);
|
|
12395
|
+
}
|
|
12396
|
+
finally {
|
|
12397
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12398
|
+
}
|
|
12399
|
+
});
|
|
12400
|
+
it("allows implementation writes when an explicit execution handoff is active", async () => {
|
|
12401
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralplan-pretool-handoff-"));
|
|
12402
|
+
try {
|
|
12403
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12404
|
+
const sessionId = "sess-ralplan-pretool-handoff";
|
|
12405
|
+
await mkdir(join(stateDir, "sessions", sessionId), { recursive: true });
|
|
12406
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId });
|
|
12407
|
+
await writeJson(join(stateDir, "sessions", sessionId, "skill-active-state.json"), {
|
|
12408
|
+
active: true,
|
|
12409
|
+
skill: "ultragoal",
|
|
12410
|
+
phase: "planning",
|
|
12411
|
+
session_id: sessionId,
|
|
12412
|
+
active_skills: [
|
|
12413
|
+
{ skill: "ralplan", phase: "planning", active: true, session_id: sessionId },
|
|
12414
|
+
{ skill: "ultragoal", phase: "planning", active: true, session_id: sessionId },
|
|
12415
|
+
],
|
|
12416
|
+
});
|
|
12417
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ralplan-state.json"), {
|
|
12418
|
+
active: true,
|
|
12419
|
+
mode: "ralplan",
|
|
12420
|
+
current_phase: "complete",
|
|
12421
|
+
session_id: sessionId,
|
|
12422
|
+
});
|
|
12423
|
+
await writeJson(join(stateDir, "sessions", sessionId, "ultragoal-state.json"), {
|
|
12424
|
+
active: true,
|
|
12425
|
+
mode: "ultragoal",
|
|
12426
|
+
current_phase: "planning",
|
|
12427
|
+
session_id: sessionId,
|
|
12428
|
+
});
|
|
12429
|
+
const result = await dispatchCodexNativeHook({
|
|
12430
|
+
hook_event_name: "PreToolUse",
|
|
12431
|
+
cwd,
|
|
12432
|
+
session_id: sessionId,
|
|
12433
|
+
thread_id: "thread-ralplan-pretool-handoff",
|
|
12434
|
+
tool_name: "Edit",
|
|
12435
|
+
tool_input: { file_path: "src/runtime.ts" },
|
|
12436
|
+
}, { cwd });
|
|
12437
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
12438
|
+
assert.equal(result.outputJson, null);
|
|
12439
|
+
}
|
|
12440
|
+
finally {
|
|
12441
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12442
|
+
}
|
|
12443
|
+
});
|
|
12444
|
+
it("does not block Stop from root team state without team_name when no session is known", async () => {
|
|
12445
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-root-team-no-session-no-name-"));
|
|
12446
|
+
try {
|
|
12447
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
12448
|
+
await mkdir(stateDir, { recursive: true });
|
|
12449
|
+
await writeJson(join(stateDir, "team-state.json"), {
|
|
12450
|
+
active: true,
|
|
12451
|
+
mode: "team",
|
|
12452
|
+
current_phase: "starting",
|
|
12453
|
+
});
|
|
12454
|
+
const result = await dispatchCodexNativeHook({
|
|
12455
|
+
hook_event_name: "Stop",
|
|
12456
|
+
cwd,
|
|
12457
|
+
}, { cwd });
|
|
12458
|
+
assert.equal(result.omxEventName, "stop");
|
|
12459
|
+
assert.equal(result.outputJson, null);
|
|
12460
|
+
}
|
|
12461
|
+
finally {
|
|
12462
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12463
|
+
}
|
|
12464
|
+
});
|
|
12465
|
+
it("does not block Stop from root team state without team_name for a foreign session", async () => {
|
|
11787
12466
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-root-team-foreign-no-name-"));
|
|
11788
12467
|
try {
|
|
11789
12468
|
const stateDir = join(cwd, ".omx", "state");
|
|
@@ -12291,6 +12970,63 @@ describe("codex native hook triage integration", () => {
|
|
|
12291
12970
|
await rm(cwd, { recursive: true, force: true });
|
|
12292
12971
|
}
|
|
12293
12972
|
});
|
|
12973
|
+
it("omits Team handoff guidance from autopilot prompt context when Team mode is disabled", async () => {
|
|
12974
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-autopilot-observable-no-team-"));
|
|
12975
|
+
try {
|
|
12976
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
12977
|
+
await writeJson(join(cwd, ".omx", "setup-scope.json"), {
|
|
12978
|
+
scope: "project",
|
|
12979
|
+
teamMode: "disabled",
|
|
12980
|
+
});
|
|
12981
|
+
await writeSessionStart(cwd, "sess-autopilot-observable-no-team");
|
|
12982
|
+
const result = await dispatchCodexNativeHook({
|
|
12983
|
+
hook_event_name: "UserPromptSubmit",
|
|
12984
|
+
cwd,
|
|
12985
|
+
session_id: "sess-autopilot-observable-no-team",
|
|
12986
|
+
thread_id: "thread-autopilot-observable-no-team",
|
|
12987
|
+
turn_id: "turn-autopilot-observable-no-team",
|
|
12988
|
+
prompt: "$autopilot implement issue #2430",
|
|
12989
|
+
}, { cwd });
|
|
12990
|
+
assert.equal(result.skillState?.skill, "autopilot");
|
|
12991
|
+
const additionalContext = String(result.outputJson?.hookSpecificOutput?.additionalContext ?? "");
|
|
12992
|
+
assert.match(additionalContext, /detected workflow keyword "\$autopilot" -> autopilot/);
|
|
12993
|
+
assert.match(additionalContext, /\$deep-interview -> \$ralplan -> \$ultragoal -> \$code-review -> \$ultraqa/);
|
|
12994
|
+
assert.doesNotMatch(additionalContext, /\$team/);
|
|
12995
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "team-state.json")), false);
|
|
12996
|
+
}
|
|
12997
|
+
finally {
|
|
12998
|
+
await rm(cwd, { recursive: true, force: true });
|
|
12999
|
+
}
|
|
13000
|
+
});
|
|
13001
|
+
it("ignores disabled $team before outside-tmux Team blocking so later workflows can activate", async () => {
|
|
13002
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-disabled-team-primary-"));
|
|
13003
|
+
try {
|
|
13004
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
13005
|
+
await writeJson(join(cwd, ".omx", "setup-scope.json"), {
|
|
13006
|
+
scope: "project",
|
|
13007
|
+
teamMode: "disabled",
|
|
13008
|
+
});
|
|
13009
|
+
await writeSessionStart(cwd, "sess-disabled-team-primary");
|
|
13010
|
+
const result = await dispatchCodexNativeHook({
|
|
13011
|
+
hook_event_name: "UserPromptSubmit",
|
|
13012
|
+
cwd,
|
|
13013
|
+
session_id: "sess-disabled-team-primary",
|
|
13014
|
+
thread_id: "thread-disabled-team-primary",
|
|
13015
|
+
turn_id: "turn-disabled-team-primary",
|
|
13016
|
+
prompt: "$team $ralph fix this",
|
|
13017
|
+
}, { cwd });
|
|
13018
|
+
assert.equal(result.skillState?.skill, "ralph");
|
|
13019
|
+
assert.equal(result.skillState?.transition_error, undefined);
|
|
13020
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "team-state.json")), false);
|
|
13021
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", "sess-disabled-team-primary", "ralph-state.json")), true);
|
|
13022
|
+
const additionalContext = String(result.outputJson?.hookSpecificOutput?.additionalContext ?? "");
|
|
13023
|
+
assert.match(additionalContext, /detected workflow keyword "\$ralph" -> ralph/);
|
|
13024
|
+
assert.doesNotMatch(additionalContext, /Codex App\/native outside-tmux sessions cannot activate/);
|
|
13025
|
+
}
|
|
13026
|
+
finally {
|
|
13027
|
+
await rm(cwd, { recursive: true, force: true });
|
|
13028
|
+
}
|
|
13029
|
+
});
|
|
12294
13030
|
it("makes bare autopilot command activation observable in state and prompt guidance", async () => {
|
|
12295
13031
|
const cwd = await mkdtemp(join(tmpdir(), "omx-autopilot-bare-observable-"));
|
|
12296
13032
|
try {
|