oh-my-codex 0.18.3 → 0.18.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 +6 -6
- package/Cargo.toml +1 -1
- package/README.md +1 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js +37 -3
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +8 -7
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +63 -5
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +56 -17
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +2 -2
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +109 -12
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts +1 -0
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +6 -0
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +11 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/question.d.ts.map +1 -1
- package/dist/cli/question.js +5 -1
- package/dist/cli/question.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +18 -54
- package/dist/cli/setup.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +5 -5
- package/dist/config/generator.d.ts +8 -2
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +48 -4
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +9 -9
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +10 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js +13 -0
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/explore-routing.test.js +10 -13
- package/dist/hooks/__tests__/explore-routing.test.js.map +1 -1
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js +13 -15
- package/dist/hooks/__tests__/explore-sparkshell-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +33 -0
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +60 -0
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/explore-routing.d.ts.map +1 -1
- package/dist/hooks/explore-routing.js +8 -14
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +15 -10
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +23 -0
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/index.d.ts +1 -1
- package/dist/hud/index.d.ts.map +1 -1
- package/dist/hud/index.js +24 -2
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +15 -0
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/question/__tests__/deep-interview.test.js +80 -7
- package/dist/question/__tests__/deep-interview.test.js.map +1 -1
- package/dist/question/__tests__/policy.test.js +83 -9
- package/dist/question/__tests__/policy.test.js.map +1 -1
- package/dist/question/autopilot-wait.d.ts +10 -0
- package/dist/question/autopilot-wait.d.ts.map +1 -0
- package/dist/question/autopilot-wait.js +134 -0
- package/dist/question/autopilot-wait.js.map +1 -0
- package/dist/question/deep-interview.d.ts.map +1 -1
- package/dist/question/deep-interview.js +4 -0
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/question/policy.d.ts +1 -0
- package/dist/question/policy.d.ts.map +1 -1
- package/dist/question/policy.js +19 -0
- package/dist/question/policy.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +331 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +45 -3
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-hook.js +13 -0
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/subagents/__tests__/tracker.test.js +69 -0
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/tracker.d.ts +5 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +16 -0
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +126 -0
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +126 -8
- package/dist/ultragoal/artifacts.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/skills/autopilot/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +4 -4
- package/plugins/oh-my-codex/skills/plan/SKILL.md +5 -5
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -5
- package/prompts/executor.md +1 -1
- package/prompts/explore-harness.md +2 -2
- package/prompts/explore.md +1 -1
- package/prompts/planner.md +1 -1
- package/prompts/sisyphus-lite.md +1 -1
- package/skills/autopilot/SKILL.md +2 -2
- package/skills/deep-interview/SKILL.md +1 -1
- package/skills/omx-setup/SKILL.md +4 -4
- package/skills/plan/SKILL.md +5 -5
- package/skills/ralph/SKILL.md +1 -1
- package/skills/ralplan/SKILL.md +5 -5
- package/src/scripts/__tests__/codex-native-hook.test.ts +368 -0
- package/src/scripts/codex-native-hook.ts +50 -2
- package/src/scripts/notify-hook.ts +15 -0
- package/templates/AGENTS.md +3 -3
|
@@ -43,6 +43,18 @@ async function writeJson(path, value) {
|
|
|
43
43
|
await mkdir(dirname(path), { recursive: true }).catch(() => { });
|
|
44
44
|
await writeFile(path, JSON.stringify(value, null, 2));
|
|
45
45
|
}
|
|
46
|
+
async function setTeamPaneIds(cwd, teamName, paneIds) {
|
|
47
|
+
for (const fileName of ["config.json", "manifest.v2.json"]) {
|
|
48
|
+
const filePath = join(cwd, ".omx", "state", "team", teamName, fileName);
|
|
49
|
+
const parsed = JSON.parse(await readFile(filePath, "utf-8"));
|
|
50
|
+
parsed.leader_pane_id = paneIds.leaderPaneId;
|
|
51
|
+
parsed.workers = (parsed.workers ?? []).map((worker) => ({
|
|
52
|
+
...worker,
|
|
53
|
+
pane_id: worker.name ? paneIds.workerPaneIds[worker.name] ?? worker.pane_id ?? null : worker.pane_id ?? null,
|
|
54
|
+
}));
|
|
55
|
+
await writeJson(filePath, parsed);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
46
58
|
async function withIsolatedHome(prefix, run) {
|
|
47
59
|
const homeDir = await mkdtemp(join(tmpdir(), `omx-native-hook-home-${prefix}-`));
|
|
48
60
|
const previousHome = process.env.HOME;
|
|
@@ -192,6 +204,7 @@ const TEAM_STOP_COMMIT_GUIDANCE = " If system-generated worker auto-checkpoint c
|
|
|
192
204
|
const DEFAULT_AUTO_NUDGE_RESPONSE = "continue with the current task only if it is already authorized";
|
|
193
205
|
const TEAM_ENV_KEYS = [
|
|
194
206
|
"OMX_TEAM_WORKER",
|
|
207
|
+
"OMX_TEAM_INTERNAL_WORKER",
|
|
195
208
|
"OMX_TEAM_STATE_ROOT",
|
|
196
209
|
"OMX_TEAM_LEADER_CWD",
|
|
197
210
|
"OMX_SESSION_ID",
|
|
@@ -1923,6 +1936,36 @@ standardMaxRounds = 15
|
|
|
1923
1936
|
await rm(cwd, { recursive: true, force: true });
|
|
1924
1937
|
}
|
|
1925
1938
|
});
|
|
1939
|
+
it("does not repeat ultragoal Stop recovery after a safe completed-aggregate microgoal blocker is recorded", async () => {
|
|
1940
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ultragoal-aggregate-blocked-stop-"));
|
|
1941
|
+
try {
|
|
1942
|
+
await writeJson(join(cwd, ".omx", "ultragoal", "goals.json"), {
|
|
1943
|
+
version: 1,
|
|
1944
|
+
codexGoalMode: "aggregate",
|
|
1945
|
+
activeGoalId: "G001-demo",
|
|
1946
|
+
goals: [{
|
|
1947
|
+
id: "G001-demo",
|
|
1948
|
+
status: "in_progress",
|
|
1949
|
+
objective: "Demo goal",
|
|
1950
|
+
failureReason: "aggregate Codex goal already complete and unreconcilable while repo-native .omx/ultragoal/goals.json still has an in-progress microgoal; stop the recovery loop",
|
|
1951
|
+
}],
|
|
1952
|
+
});
|
|
1953
|
+
const result = await dispatchCodexNativeHook({
|
|
1954
|
+
hook_event_name: "Stop",
|
|
1955
|
+
cwd,
|
|
1956
|
+
session_id: "sess-ultragoal-aggregate-blocked-stop",
|
|
1957
|
+
thread_id: "thread-ultragoal-aggregate-blocked-stop",
|
|
1958
|
+
stop_hook_active: true,
|
|
1959
|
+
last_assistant_message: "Goal complete.",
|
|
1960
|
+
}, { cwd });
|
|
1961
|
+
assert.notEqual(result.outputJson?.decision, "block");
|
|
1962
|
+
assert.notEqual(result.outputJson?.stopReason, "ultragoal_codex_goal_snapshot_required");
|
|
1963
|
+
assert.doesNotMatch(JSON.stringify(result.outputJson), /omx ultragoal checkpoint --goal-id G001-demo --status complete/);
|
|
1964
|
+
}
|
|
1965
|
+
finally {
|
|
1966
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1967
|
+
}
|
|
1968
|
+
});
|
|
1926
1969
|
it("does not block ultragoal Stop after task-scoped reconciliation finishes exploded bookkeeping", async () => {
|
|
1927
1970
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ultragoal-reconciled-stop-"));
|
|
1928
1971
|
try {
|
|
@@ -3170,6 +3213,178 @@ export async function onHookEvent(event) {
|
|
|
3170
3213
|
await rm(cwd, { recursive: true, force: true });
|
|
3171
3214
|
}
|
|
3172
3215
|
});
|
|
3216
|
+
it("skips prompt-submit HUD reconciliation for confirmed team worker panes", async () => {
|
|
3217
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-team-worker-skip-"));
|
|
3218
|
+
try {
|
|
3219
|
+
const teamName = "hud-worker-skip";
|
|
3220
|
+
await initTeamState(teamName, "skip worker HUD reconcile", "executor", 1, cwd);
|
|
3221
|
+
await setTeamPaneIds(cwd, teamName, {
|
|
3222
|
+
leaderPaneId: "%42",
|
|
3223
|
+
workerPaneIds: { "worker-1": "%10" },
|
|
3224
|
+
});
|
|
3225
|
+
process.env.TMUX = "1";
|
|
3226
|
+
process.env.TMUX_PANE = "%10";
|
|
3227
|
+
process.env.OMX_TEAM_INTERNAL_WORKER = `${teamName}/worker-1`;
|
|
3228
|
+
process.env.OMX_TEAM_WORKER = `${teamName}/worker-1`;
|
|
3229
|
+
process.env[OMX_TMUX_HUD_OWNER_ENV] = "1";
|
|
3230
|
+
let reconcileCalls = 0;
|
|
3231
|
+
const result = await dispatchCodexNativeHook({
|
|
3232
|
+
hook_event_name: "UserPromptSubmit",
|
|
3233
|
+
cwd,
|
|
3234
|
+
session_id: "sess-hud-team-worker",
|
|
3235
|
+
prompt: "$ralplan prepare plan",
|
|
3236
|
+
}, {
|
|
3237
|
+
cwd,
|
|
3238
|
+
reconcileHudForPromptSubmitFn: async () => {
|
|
3239
|
+
reconcileCalls += 1;
|
|
3240
|
+
return { status: "recreated", paneId: "%9", desiredHeight: 3, duplicateCount: 0 };
|
|
3241
|
+
},
|
|
3242
|
+
});
|
|
3243
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
3244
|
+
assert.equal(reconcileCalls, 0);
|
|
3245
|
+
}
|
|
3246
|
+
finally {
|
|
3247
|
+
await rm(cwd, { recursive: true, force: true });
|
|
3248
|
+
}
|
|
3249
|
+
});
|
|
3250
|
+
it("preserves prompt-submit HUD reconciliation for team leader panes", async () => {
|
|
3251
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-team-leader-preserve-"));
|
|
3252
|
+
try {
|
|
3253
|
+
const teamName = "hud-leader-keep";
|
|
3254
|
+
await initTeamState(teamName, "preserve leader HUD reconcile", "executor", 1, cwd);
|
|
3255
|
+
await setTeamPaneIds(cwd, teamName, {
|
|
3256
|
+
leaderPaneId: "%42",
|
|
3257
|
+
workerPaneIds: { "worker-1": "%10" },
|
|
3258
|
+
});
|
|
3259
|
+
process.env.TMUX = "1";
|
|
3260
|
+
process.env.TMUX_PANE = "%42";
|
|
3261
|
+
process.env[OMX_TMUX_HUD_OWNER_ENV] = "1";
|
|
3262
|
+
let reconcileCall = null;
|
|
3263
|
+
const result = await dispatchCodexNativeHook({
|
|
3264
|
+
hook_event_name: "UserPromptSubmit",
|
|
3265
|
+
cwd,
|
|
3266
|
+
session_id: "sess-hud-team-leader",
|
|
3267
|
+
prompt: "$ralplan prepare plan",
|
|
3268
|
+
}, {
|
|
3269
|
+
cwd,
|
|
3270
|
+
reconcileHudForPromptSubmitFn: async (hookCwd, deps = {}) => {
|
|
3271
|
+
reconcileCall = { cwd: hookCwd, sessionId: deps.sessionId };
|
|
3272
|
+
return { status: "recreated", paneId: "%9", desiredHeight: 3, duplicateCount: 0 };
|
|
3273
|
+
},
|
|
3274
|
+
});
|
|
3275
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
3276
|
+
assert.deepEqual(reconcileCall, { cwd, sessionId: "sess-hud-team-leader" });
|
|
3277
|
+
}
|
|
3278
|
+
finally {
|
|
3279
|
+
await rm(cwd, { recursive: true, force: true });
|
|
3280
|
+
}
|
|
3281
|
+
});
|
|
3282
|
+
it("preserves prompt-submit HUD reconciliation when worker pane detection is ambiguous", async () => {
|
|
3283
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-team-worker-ambiguous-"));
|
|
3284
|
+
try {
|
|
3285
|
+
const teamName = "hud-worker-ambiguous";
|
|
3286
|
+
await initTeamState(teamName, "fail closed for ambiguous worker HUD reconcile", "executor", 1, cwd);
|
|
3287
|
+
await setTeamPaneIds(cwd, teamName, {
|
|
3288
|
+
leaderPaneId: "%42",
|
|
3289
|
+
workerPaneIds: { "worker-1": "%10" },
|
|
3290
|
+
});
|
|
3291
|
+
process.env.TMUX = "1";
|
|
3292
|
+
process.env.TMUX_PANE = "%99";
|
|
3293
|
+
process.env.OMX_TEAM_INTERNAL_WORKER = `${teamName}/worker-1`;
|
|
3294
|
+
process.env.OMX_TEAM_WORKER = `${teamName}/worker-1`;
|
|
3295
|
+
process.env[OMX_TMUX_HUD_OWNER_ENV] = "1";
|
|
3296
|
+
let reconcileCalls = 0;
|
|
3297
|
+
const result = await dispatchCodexNativeHook({
|
|
3298
|
+
hook_event_name: "UserPromptSubmit",
|
|
3299
|
+
cwd,
|
|
3300
|
+
session_id: "sess-hud-team-worker-ambiguous",
|
|
3301
|
+
prompt: "$ralplan prepare plan",
|
|
3302
|
+
}, {
|
|
3303
|
+
cwd,
|
|
3304
|
+
reconcileHudForPromptSubmitFn: async () => {
|
|
3305
|
+
reconcileCalls += 1;
|
|
3306
|
+
return { status: "recreated", paneId: "%9", desiredHeight: 3, duplicateCount: 0 };
|
|
3307
|
+
},
|
|
3308
|
+
});
|
|
3309
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
3310
|
+
assert.equal(reconcileCalls, 1);
|
|
3311
|
+
}
|
|
3312
|
+
finally {
|
|
3313
|
+
await rm(cwd, { recursive: true, force: true });
|
|
3314
|
+
}
|
|
3315
|
+
});
|
|
3316
|
+
it("preserves prompt-submit HUD reconciliation for native subagents even with worker pane env", async () => {
|
|
3317
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-subagent-worker-preserve-"));
|
|
3318
|
+
try {
|
|
3319
|
+
const teamName = "hud-subagent-keep";
|
|
3320
|
+
await initTeamState(teamName, "preserve subagent HUD reconcile", "executor", 1, cwd);
|
|
3321
|
+
await setTeamPaneIds(cwd, teamName, {
|
|
3322
|
+
leaderPaneId: "%42",
|
|
3323
|
+
workerPaneIds: { "worker-1": "%10" },
|
|
3324
|
+
});
|
|
3325
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
3326
|
+
const canonicalSessionId = "sess-subagent-hud-parent";
|
|
3327
|
+
const leaderNativeSessionId = "native-subagent-hud-parent";
|
|
3328
|
+
const childNativeSessionId = "native-subagent-hud-child";
|
|
3329
|
+
const nowIso = new Date().toISOString();
|
|
3330
|
+
await writeJson(join(stateDir, "session.json"), {
|
|
3331
|
+
session_id: canonicalSessionId,
|
|
3332
|
+
native_session_id: leaderNativeSessionId,
|
|
3333
|
+
});
|
|
3334
|
+
await writeJson(join(stateDir, "subagent-tracking.json"), {
|
|
3335
|
+
schemaVersion: 1,
|
|
3336
|
+
sessions: {
|
|
3337
|
+
[canonicalSessionId]: {
|
|
3338
|
+
session_id: canonicalSessionId,
|
|
3339
|
+
leader_thread_id: leaderNativeSessionId,
|
|
3340
|
+
updated_at: nowIso,
|
|
3341
|
+
threads: {
|
|
3342
|
+
[leaderNativeSessionId]: {
|
|
3343
|
+
thread_id: leaderNativeSessionId,
|
|
3344
|
+
kind: "leader",
|
|
3345
|
+
first_seen_at: nowIso,
|
|
3346
|
+
last_seen_at: nowIso,
|
|
3347
|
+
turn_count: 1,
|
|
3348
|
+
},
|
|
3349
|
+
[childNativeSessionId]: {
|
|
3350
|
+
thread_id: childNativeSessionId,
|
|
3351
|
+
kind: "subagent",
|
|
3352
|
+
first_seen_at: nowIso,
|
|
3353
|
+
last_seen_at: nowIso,
|
|
3354
|
+
turn_count: 1,
|
|
3355
|
+
mode: "verifier",
|
|
3356
|
+
},
|
|
3357
|
+
},
|
|
3358
|
+
},
|
|
3359
|
+
},
|
|
3360
|
+
});
|
|
3361
|
+
process.env.TMUX = "1";
|
|
3362
|
+
process.env.TMUX_PANE = "%10";
|
|
3363
|
+
process.env.OMX_TEAM_INTERNAL_WORKER = `${teamName}/worker-1`;
|
|
3364
|
+
process.env.OMX_TEAM_WORKER = `${teamName}/worker-1`;
|
|
3365
|
+
process.env[OMX_TMUX_HUD_OWNER_ENV] = "1";
|
|
3366
|
+
let reconcileCall = null;
|
|
3367
|
+
const result = await dispatchCodexNativeHook({
|
|
3368
|
+
hook_event_name: "UserPromptSubmit",
|
|
3369
|
+
cwd,
|
|
3370
|
+
session_id: childNativeSessionId,
|
|
3371
|
+
thread_id: childNativeSessionId,
|
|
3372
|
+
turn_id: "turn-subagent-hud-child",
|
|
3373
|
+
prompt: "Review the worker patch literally; do not activate $ralplan.",
|
|
3374
|
+
}, {
|
|
3375
|
+
cwd,
|
|
3376
|
+
reconcileHudForPromptSubmitFn: async (hookCwd, deps = {}) => {
|
|
3377
|
+
reconcileCall = { cwd: hookCwd, sessionId: deps.sessionId };
|
|
3378
|
+
return { status: "recreated", paneId: "%9", desiredHeight: 3, duplicateCount: 0 };
|
|
3379
|
+
},
|
|
3380
|
+
});
|
|
3381
|
+
assert.equal(result.outputJson, null);
|
|
3382
|
+
assert.deepEqual(reconcileCall, { cwd, sessionId: canonicalSessionId });
|
|
3383
|
+
}
|
|
3384
|
+
finally {
|
|
3385
|
+
await rm(cwd, { recursive: true, force: true });
|
|
3386
|
+
}
|
|
3387
|
+
});
|
|
3173
3388
|
it("runs prompt-submit HUD reconciliation as a best-effort tmux-only side effect", async () => {
|
|
3174
3389
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-reconcile-"));
|
|
3175
3390
|
const originalTmux = process.env.TMUX;
|
|
@@ -7650,6 +7865,65 @@ exit 0
|
|
|
7650
7865
|
await rm(cwd, { recursive: true, force: true });
|
|
7651
7866
|
}
|
|
7652
7867
|
});
|
|
7868
|
+
it("does not report ralplan subagent waiting when notify-fallback already recorded completion", async () => {
|
|
7869
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-skill-subagent-complete-"));
|
|
7870
|
+
try {
|
|
7871
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
7872
|
+
const now = new Date().toISOString();
|
|
7873
|
+
await mkdir(join(stateDir, "sessions", "sess-stop-skill-subagent-complete"), { recursive: true });
|
|
7874
|
+
await writeJson(join(stateDir, "session.json"), { session_id: "sess-stop-skill-subagent-complete" });
|
|
7875
|
+
await writeJson(join(stateDir, "sessions", "sess-stop-skill-subagent-complete", "skill-active-state.json"), {
|
|
7876
|
+
active: true,
|
|
7877
|
+
skill: "ralplan",
|
|
7878
|
+
phase: "planning",
|
|
7879
|
+
});
|
|
7880
|
+
await writeJson(join(stateDir, "sessions", "sess-stop-skill-subagent-complete", "ralplan-state.json"), {
|
|
7881
|
+
active: true,
|
|
7882
|
+
current_phase: "planning",
|
|
7883
|
+
});
|
|
7884
|
+
await writeJson(join(stateDir, "subagent-tracking.json"), {
|
|
7885
|
+
schemaVersion: 1,
|
|
7886
|
+
sessions: {
|
|
7887
|
+
"sess-stop-skill-subagent-complete": {
|
|
7888
|
+
session_id: "sess-stop-skill-subagent-complete",
|
|
7889
|
+
leader_thread_id: "leader-1",
|
|
7890
|
+
updated_at: now,
|
|
7891
|
+
threads: {
|
|
7892
|
+
"leader-1": {
|
|
7893
|
+
thread_id: "leader-1",
|
|
7894
|
+
kind: "leader",
|
|
7895
|
+
first_seen_at: now,
|
|
7896
|
+
last_seen_at: now,
|
|
7897
|
+
turn_count: 1,
|
|
7898
|
+
},
|
|
7899
|
+
"sub-1": {
|
|
7900
|
+
thread_id: "sub-1",
|
|
7901
|
+
kind: "subagent",
|
|
7902
|
+
first_seen_at: now,
|
|
7903
|
+
last_seen_at: now,
|
|
7904
|
+
completed_at: now,
|
|
7905
|
+
last_completed_turn_id: "turn-complete-1",
|
|
7906
|
+
completion_source: "notify-fallback-watcher",
|
|
7907
|
+
turn_count: 2,
|
|
7908
|
+
},
|
|
7909
|
+
},
|
|
7910
|
+
},
|
|
7911
|
+
},
|
|
7912
|
+
});
|
|
7913
|
+
const result = await dispatchCodexNativeHook({
|
|
7914
|
+
hook_event_name: "Stop",
|
|
7915
|
+
cwd,
|
|
7916
|
+
session_id: "sess-stop-skill-subagent-complete",
|
|
7917
|
+
}, { cwd });
|
|
7918
|
+
assert.equal(result.omxEventName, "stop");
|
|
7919
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
7920
|
+
assert.doesNotMatch(String(result.outputJson?.reason ?? ""), /waiting for 1 active native subagent thread/);
|
|
7921
|
+
assert.equal(result.outputJson?.stopReason, "skill_ralplan_planning_continue_artifact");
|
|
7922
|
+
}
|
|
7923
|
+
finally {
|
|
7924
|
+
await rm(cwd, { recursive: true, force: true });
|
|
7925
|
+
}
|
|
7926
|
+
});
|
|
7653
7927
|
it("does not block on stale root ralplan skill when the explicit session-scoped canonical skill state is absent", async () => {
|
|
7654
7928
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-stale-root-skill-"));
|
|
7655
7929
|
try {
|
|
@@ -11368,4 +11642,61 @@ describe("codex native hook triage integration", () => {
|
|
|
11368
11642
|
}
|
|
11369
11643
|
});
|
|
11370
11644
|
});
|
|
11645
|
+
describe('native Stop autopilot deep-interview wait', () => {
|
|
11646
|
+
it('does not force continued execution while autopilot is waiting on a deep-interview omx question', async () => {
|
|
11647
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-native-hook-autopilot-question-wait-'));
|
|
11648
|
+
try {
|
|
11649
|
+
const sessionId = 'sess-autopilot-wait';
|
|
11650
|
+
const sessionDir = join(cwd, '.omx', 'state', 'sessions', sessionId);
|
|
11651
|
+
await writeJson(join(cwd, '.omx', 'state', 'session.json'), { session_id: sessionId });
|
|
11652
|
+
await writeJson(join(sessionDir, 'autopilot-state.json'), {
|
|
11653
|
+
mode: 'autopilot',
|
|
11654
|
+
active: true,
|
|
11655
|
+
current_phase: 'waiting-for-user',
|
|
11656
|
+
run_outcome: 'blocked_on_user',
|
|
11657
|
+
lifecycle_outcome: 'askuserQuestion',
|
|
11658
|
+
session_id: sessionId,
|
|
11659
|
+
state: {
|
|
11660
|
+
deep_interview_question: {
|
|
11661
|
+
status: 'waiting_for_user',
|
|
11662
|
+
source: 'omx-question',
|
|
11663
|
+
obligation_id: 'obligation-stop-1',
|
|
11664
|
+
previous_phase: 'deep-interview',
|
|
11665
|
+
},
|
|
11666
|
+
},
|
|
11667
|
+
});
|
|
11668
|
+
await writeJson(join(sessionDir, 'deep-interview-state.json'), {
|
|
11669
|
+
mode: 'deep-interview',
|
|
11670
|
+
active: false,
|
|
11671
|
+
current_phase: 'intent-first',
|
|
11672
|
+
lifecycle_outcome: 'askuserQuestion',
|
|
11673
|
+
run_outcome: 'blocked_on_user',
|
|
11674
|
+
session_id: sessionId,
|
|
11675
|
+
question_enforcement: {
|
|
11676
|
+
obligation_id: 'obligation-stop-1',
|
|
11677
|
+
source: 'omx-question',
|
|
11678
|
+
status: 'pending',
|
|
11679
|
+
lifecycle_outcome: 'askuserQuestion',
|
|
11680
|
+
requested_at: '2026-04-19T00:00:00.000Z',
|
|
11681
|
+
},
|
|
11682
|
+
});
|
|
11683
|
+
await writeJson(join(sessionDir, 'skill-active-state.json'), {
|
|
11684
|
+
active: true,
|
|
11685
|
+
skill: 'autopilot',
|
|
11686
|
+
phase: 'deep-interview',
|
|
11687
|
+
session_id: sessionId,
|
|
11688
|
+
active_skills: [{ skill: 'autopilot', phase: 'deep-interview', active: true, session_id: sessionId }],
|
|
11689
|
+
});
|
|
11690
|
+
const result = await dispatchCodexNativeHook({
|
|
11691
|
+
hook_event_name: 'Stop',
|
|
11692
|
+
session_id: sessionId,
|
|
11693
|
+
thread_id: 'thread-autopilot-wait',
|
|
11694
|
+
}, { cwd });
|
|
11695
|
+
assert.equal(result.outputJson, null);
|
|
11696
|
+
}
|
|
11697
|
+
finally {
|
|
11698
|
+
await rm(cwd, { recursive: true, force: true });
|
|
11699
|
+
}
|
|
11700
|
+
});
|
|
11701
|
+
});
|
|
11371
11702
|
//# sourceMappingURL=codex-native-hook.test.js.map
|