oh-my-codex 0.18.2 → 0.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +1 -1
- package/dist/agents/__tests__/definitions.test.js +9 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +1 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/definitions.d.ts.map +1 -1
- package/dist/agents/definitions.js +10 -0
- package/dist/agents/definitions.js.map +1 -1
- package/dist/auth/__tests__/config-sessions.test.d.ts +2 -0
- package/dist/auth/__tests__/config-sessions.test.d.ts.map +1 -0
- package/dist/auth/__tests__/config-sessions.test.js +48 -0
- package/dist/auth/__tests__/config-sessions.test.js.map +1 -0
- package/dist/auth/__tests__/quota-rotation.test.d.ts +2 -0
- package/dist/auth/__tests__/quota-rotation.test.d.ts.map +1 -0
- package/dist/auth/__tests__/quota-rotation.test.js +33 -0
- package/dist/auth/__tests__/quota-rotation.test.js.map +1 -0
- package/dist/auth/__tests__/redact.test.d.ts +2 -0
- package/dist/auth/__tests__/redact.test.d.ts.map +1 -0
- package/dist/auth/__tests__/redact.test.js +20 -0
- package/dist/auth/__tests__/redact.test.js.map +1 -0
- package/dist/auth/__tests__/storage.test.d.ts +2 -0
- package/dist/auth/__tests__/storage.test.d.ts.map +1 -0
- package/dist/auth/__tests__/storage.test.js +108 -0
- package/dist/auth/__tests__/storage.test.js.map +1 -0
- package/dist/auth/config.d.ts +9 -0
- package/dist/auth/config.d.ts.map +1 -0
- package/dist/auth/config.js +77 -0
- package/dist/auth/config.js.map +1 -0
- package/dist/auth/hotswap.d.ts +36 -0
- package/dist/auth/hotswap.d.ts.map +1 -0
- package/dist/auth/hotswap.js +159 -0
- package/dist/auth/hotswap.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/paths.d.ts +12 -0
- package/dist/auth/paths.d.ts.map +1 -0
- package/dist/auth/paths.js +78 -0
- package/dist/auth/paths.js.map +1 -0
- package/dist/auth/quota-detector.d.ts +10 -0
- package/dist/auth/quota-detector.d.ts.map +1 -0
- package/dist/auth/quota-detector.js +40 -0
- package/dist/auth/quota-detector.js.map +1 -0
- package/dist/auth/redact.d.ts +2 -0
- package/dist/auth/redact.d.ts.map +1 -0
- package/dist/auth/redact.js +26 -0
- package/dist/auth/redact.js.map +1 -0
- package/dist/auth/rotation.d.ts +9 -0
- package/dist/auth/rotation.d.ts.map +1 -0
- package/dist/auth/rotation.js +26 -0
- package/dist/auth/rotation.js.map +1 -0
- package/dist/auth/sessions.d.ts +15 -0
- package/dist/auth/sessions.d.ts.map +1 -0
- package/dist/auth/sessions.js +62 -0
- package/dist/auth/sessions.js.map +1 -0
- package/dist/auth/storage.d.ts +27 -0
- package/dist/auth/storage.d.ts.map +1 -0
- package/dist/auth/storage.js +111 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/cli/__tests__/auth.test.d.ts +2 -0
- package/dist/cli/__tests__/auth.test.d.ts.map +1 -0
- package/dist/cli/__tests__/auth.test.js +168 -0
- package/dist/cli/__tests__/auth.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js +51 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/explore.test.js +20 -0
- package/dist/cli/__tests__/explore.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +10 -0
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/nested-help-routing.test.js +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +30 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +47 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/auth.d.ts +4 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +89 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +19 -7
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.d.ts.map +1 -1
- package/dist/cli/explore.js +12 -0
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +20 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +104 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +11 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/config/__tests__/deep-interview.test.d.ts +2 -0
- package/dist/config/__tests__/deep-interview.test.d.ts.map +1 -0
- package/dist/config/__tests__/deep-interview.test.js +239 -0
- package/dist/config/__tests__/deep-interview.test.js.map +1 -0
- package/dist/config/__tests__/generator-idempotent.test.js +123 -0
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/deep-interview.d.ts +22 -0
- package/dist/config/deep-interview.d.ts.map +1 -0
- package/dist/config/deep-interview.js +151 -0
- package/dist/config/deep-interview.js.map +1 -0
- package/dist/config/generator.d.ts +5 -2
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +106 -36
- package/dist/config/generator.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +2 -0
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/explore-routing.test.js +1 -0
- package/dist/hooks/__tests__/explore-routing.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +301 -0
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/deep-interview-config-instruction.d.ts +3 -0
- package/dist/hooks/deep-interview-config-instruction.d.ts.map +1 -0
- package/dist/hooks/deep-interview-config-instruction.js +47 -0
- package/dist/hooks/deep-interview-config-instruction.js.map +1 -0
- package/dist/hooks/explore-routing.d.ts.map +1 -1
- package/dist/hooks/explore-routing.js +1 -0
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +5 -0
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +52 -8
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +4 -4
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +94 -9
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +103 -1
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/reconcile.d.ts +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +8 -0
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/tmux.d.ts +7 -0
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +46 -9
- package/dist/hud/tmux.js.map +1 -1
- package/dist/question/deep-interview.d.ts +2 -0
- package/dist/question/deep-interview.d.ts.map +1 -1
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +387 -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 +24 -2
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/state/__tests__/planning-gate.test.d.ts +2 -0
- package/dist/state/__tests__/planning-gate.test.d.ts.map +1 -0
- package/dist/state/__tests__/planning-gate.test.js +219 -0
- package/dist/state/__tests__/planning-gate.test.js.map +1 -0
- package/dist/state/workflow-transition.d.ts +23 -0
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +63 -0
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +86 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +7 -0
- package/dist/team/tmux-session.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/deep-interview/SKILL.md +10 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +6 -2
- package/prompts/scholastic.md +11 -0
- package/skills/deep-interview/SKILL.md +10 -0
- package/skills/ralplan/SKILL.md +6 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +485 -0
- package/src/scripts/codex-native-hook.ts +23 -1
- package/templates/catalog-manifest.json +5 -0
|
@@ -14,6 +14,7 @@ import { writeSessionStart } from "../../hooks/session.js";
|
|
|
14
14
|
import { resetTriageConfigCache } from "../../hooks/triage-config.js";
|
|
15
15
|
import { executeStateOperation } from "../../state/operations.js";
|
|
16
16
|
import { OMX_TMUX_HUD_OWNER_ENV } from "../../hud/reconcile.js";
|
|
17
|
+
import { OMX_TMUX_HUD_LEADER_PANE_ENV } from "../../hud/tmux.js";
|
|
17
18
|
import { readAllState } from "../../hud/state.js";
|
|
18
19
|
import { renderHud } from "../../hud/render.js";
|
|
19
20
|
import { getLegacyWikiDir, serializePage, writePage } from "../../wiki/storage.js";
|
|
@@ -42,6 +43,21 @@ async function writeJson(path, value) {
|
|
|
42
43
|
await mkdir(dirname(path), { recursive: true }).catch(() => { });
|
|
43
44
|
await writeFile(path, JSON.stringify(value, null, 2));
|
|
44
45
|
}
|
|
46
|
+
async function withIsolatedHome(prefix, run) {
|
|
47
|
+
const homeDir = await mkdtemp(join(tmpdir(), `omx-native-hook-home-${prefix}-`));
|
|
48
|
+
const previousHome = process.env.HOME;
|
|
49
|
+
try {
|
|
50
|
+
process.env.HOME = homeDir;
|
|
51
|
+
return await run(homeDir);
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
if (typeof previousHome === "string")
|
|
55
|
+
process.env.HOME = previousHome;
|
|
56
|
+
else
|
|
57
|
+
delete process.env.HOME;
|
|
58
|
+
await rm(homeDir, { recursive: true, force: true });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
45
61
|
async function withLoreGuardConfig(value, prefix, run) {
|
|
46
62
|
const cwd = await mkdtemp(join(tmpdir(), `omx-native-hook-pretool-git-commit-lore-${prefix}-`));
|
|
47
63
|
const codexHome = await mkdtemp(join(tmpdir(), `omx-native-hook-codex-home-lore-${prefix}-`));
|
|
@@ -1291,6 +1307,308 @@ describe("codex native hook dispatch", () => {
|
|
|
1291
1307
|
await rm(cwd, { recursive: true, force: true });
|
|
1292
1308
|
}
|
|
1293
1309
|
});
|
|
1310
|
+
it("injects deep-interview config overrides into UserPromptSubmit developer context", async () => {
|
|
1311
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-deep-interview-config-"));
|
|
1312
|
+
try {
|
|
1313
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
1314
|
+
await writeFile(join(cwd, ".omx", "config.toml"), `[omx.deepInterview]
|
|
1315
|
+
defaultProfile = "standard"
|
|
1316
|
+
standardThreshold = 0.05
|
|
1317
|
+
standardMaxRounds = 15
|
|
1318
|
+
enableChallengeModes = false
|
|
1319
|
+
`);
|
|
1320
|
+
const result = await dispatchCodexNativeHook({
|
|
1321
|
+
hook_event_name: "UserPromptSubmit",
|
|
1322
|
+
cwd,
|
|
1323
|
+
session_id: "sess-deep-interview-config",
|
|
1324
|
+
thread_id: "thread-1",
|
|
1325
|
+
turn_id: "turn-1",
|
|
1326
|
+
prompt: "$deep-interview prove config reflection",
|
|
1327
|
+
}, { cwd });
|
|
1328
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
1329
|
+
assert.equal(result.skillState?.skill, "deep-interview");
|
|
1330
|
+
const serializedOutput = JSON.stringify(result.outputJson);
|
|
1331
|
+
assert.match(serializedOutput, /Deep-interview config override active/);
|
|
1332
|
+
assert.match(serializedOutput, /threshold=0\.05/);
|
|
1333
|
+
assert.match(serializedOutput, /max_rounds=15/);
|
|
1334
|
+
assert.match(serializedOutput, /enableChallengeModes=false/);
|
|
1335
|
+
const modeState = JSON.parse(await readFile(join(cwd, ".omx", "state", "sessions", "sess-deep-interview-config", "deep-interview-state.json"), "utf-8"));
|
|
1336
|
+
assert.equal(modeState.profile, "standard");
|
|
1337
|
+
assert.equal(modeState.threshold, 0.05);
|
|
1338
|
+
assert.equal(modeState.max_rounds, 15);
|
|
1339
|
+
}
|
|
1340
|
+
finally {
|
|
1341
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1342
|
+
}
|
|
1343
|
+
});
|
|
1344
|
+
it("proves UserPromptSubmit context changes before and after adding deep-interview config", async () => {
|
|
1345
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-deep-interview-config-before-after-"));
|
|
1346
|
+
const sessionId = "sess-deep-interview-config-before-after";
|
|
1347
|
+
try {
|
|
1348
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
1349
|
+
const before = await withIsolatedHome("deep-interview-config-before-after", async () => (dispatchCodexNativeHook({
|
|
1350
|
+
hook_event_name: "UserPromptSubmit",
|
|
1351
|
+
cwd,
|
|
1352
|
+
session_id: sessionId,
|
|
1353
|
+
thread_id: "thread-before-after",
|
|
1354
|
+
turn_id: "turn-before",
|
|
1355
|
+
prompt: "$deep-interview prove before config context",
|
|
1356
|
+
}, { cwd })));
|
|
1357
|
+
const beforeOutput = JSON.stringify(before.outputJson);
|
|
1358
|
+
const beforeState = JSON.parse(await readFile(join(cwd, ".omx", "state", "sessions", sessionId, "deep-interview-state.json"), "utf-8"));
|
|
1359
|
+
assert.equal(before.skillState?.skill, "deep-interview");
|
|
1360
|
+
assert.doesNotMatch(beforeOutput, /Deep-interview config override active/);
|
|
1361
|
+
assert.equal(before.skillState?.deep_interview_config, undefined);
|
|
1362
|
+
assert.equal(beforeState.deep_interview_config, undefined);
|
|
1363
|
+
assert.equal(beforeState.threshold, undefined);
|
|
1364
|
+
assert.equal(beforeState.max_rounds, undefined);
|
|
1365
|
+
await writeFile(join(cwd, ".omx", "config.toml"), `[omx.deepInterview]
|
|
1366
|
+
defaultProfile = "standard"
|
|
1367
|
+
standardThreshold = 0.05
|
|
1368
|
+
standardMaxRounds = 15
|
|
1369
|
+
`);
|
|
1370
|
+
const after = await dispatchCodexNativeHook({
|
|
1371
|
+
hook_event_name: "UserPromptSubmit",
|
|
1372
|
+
cwd,
|
|
1373
|
+
session_id: sessionId,
|
|
1374
|
+
thread_id: "thread-before-after",
|
|
1375
|
+
turn_id: "turn-after",
|
|
1376
|
+
prompt: "$deep-interview prove after config context",
|
|
1377
|
+
}, { cwd });
|
|
1378
|
+
const afterOutput = JSON.stringify(after.outputJson);
|
|
1379
|
+
const afterState = JSON.parse(await readFile(join(cwd, ".omx", "state", "sessions", sessionId, "deep-interview-state.json"), "utf-8"));
|
|
1380
|
+
assert.equal(after.skillState?.deep_interview_config?.profile, "standard");
|
|
1381
|
+
assert.match(afterOutput, /Deep-interview config override active/);
|
|
1382
|
+
assert.match(afterOutput, /threshold=0\.05/);
|
|
1383
|
+
assert.match(afterOutput, /max_rounds=15/);
|
|
1384
|
+
assert.equal(afterState.deep_interview_config?.profile, "standard");
|
|
1385
|
+
assert.equal(afterState.threshold, 0.05);
|
|
1386
|
+
assert.equal(afterState.max_rounds, 15);
|
|
1387
|
+
}
|
|
1388
|
+
finally {
|
|
1389
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
it("injects deep-interview config for mixed workflow prompts that defer execution modes", async () => {
|
|
1393
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-deep-interview-config-mixed-"));
|
|
1394
|
+
const sessionId = "sess-deep-interview-config-mixed";
|
|
1395
|
+
try {
|
|
1396
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
1397
|
+
await writeFile(join(cwd, ".omx", "config.toml"), `[omx.deepInterview]
|
|
1398
|
+
defaultProfile = "deep"
|
|
1399
|
+
deepThreshold = 0.13
|
|
1400
|
+
deepMaxRounds = 21
|
|
1401
|
+
enableChallengeModes = false
|
|
1402
|
+
`);
|
|
1403
|
+
const result = await withIsolatedHome("deep-interview-config-mixed", async () => (dispatchCodexNativeHook({
|
|
1404
|
+
hook_event_name: "UserPromptSubmit",
|
|
1405
|
+
cwd,
|
|
1406
|
+
session_id: sessionId,
|
|
1407
|
+
thread_id: "thread-mixed-config",
|
|
1408
|
+
turn_id: "turn-mixed-config",
|
|
1409
|
+
prompt: "$autopilot $deep-interview prove mixed config context",
|
|
1410
|
+
}, { cwd })));
|
|
1411
|
+
const serializedOutput = JSON.stringify(result.outputJson);
|
|
1412
|
+
const modeState = JSON.parse(await readFile(join(cwd, ".omx", "state", "sessions", sessionId, "deep-interview-state.json"), "utf-8"));
|
|
1413
|
+
assert.equal(result.skillState?.skill, "deep-interview");
|
|
1414
|
+
assert.deepEqual(result.skillState?.deferred_skills, ["autopilot"]);
|
|
1415
|
+
assert.equal(result.skillState?.deep_interview_config?.profile, "deep");
|
|
1416
|
+
assert.equal(result.skillState?.deep_interview_config?.threshold, 0.13);
|
|
1417
|
+
assert.equal(result.skillState?.deep_interview_config?.maxRounds, 21);
|
|
1418
|
+
assert.equal(result.skillState?.deep_interview_config?.enableChallengeModes, false);
|
|
1419
|
+
assert.match(serializedOutput, /Deep-interview config override active/);
|
|
1420
|
+
assert.match(serializedOutput, /profile=deep/);
|
|
1421
|
+
assert.match(serializedOutput, /threshold=0\.13/);
|
|
1422
|
+
assert.match(serializedOutput, /max_rounds=21/);
|
|
1423
|
+
assert.match(serializedOutput, /enableChallengeModes=false/);
|
|
1424
|
+
assert.equal(modeState.deep_interview_config?.profile, "deep");
|
|
1425
|
+
assert.equal(modeState.profile, "deep");
|
|
1426
|
+
assert.equal(modeState.threshold, 0.13);
|
|
1427
|
+
assert.equal(modeState.max_rounds, 21);
|
|
1428
|
+
assert.equal(modeState.enable_challenge_modes, false);
|
|
1429
|
+
}
|
|
1430
|
+
finally {
|
|
1431
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1432
|
+
}
|
|
1433
|
+
});
|
|
1434
|
+
it("keeps deep-interview config override context on continuation prompts", async () => {
|
|
1435
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-deep-interview-config-continuation-"));
|
|
1436
|
+
const sessionId = "sess-deep-interview-config-continuation";
|
|
1437
|
+
try {
|
|
1438
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
1439
|
+
await writeFile(join(cwd, ".omx", "config.toml"), `[omx.deepInterview]
|
|
1440
|
+
defaultProfile = "standard"
|
|
1441
|
+
standardThreshold = 0.05
|
|
1442
|
+
standardMaxRounds = 15
|
|
1443
|
+
`);
|
|
1444
|
+
await dispatchCodexNativeHook({
|
|
1445
|
+
hook_event_name: "UserPromptSubmit",
|
|
1446
|
+
cwd,
|
|
1447
|
+
session_id: sessionId,
|
|
1448
|
+
thread_id: "thread-continuation",
|
|
1449
|
+
turn_id: "turn-start",
|
|
1450
|
+
prompt: "$deep-interview prove config continuation",
|
|
1451
|
+
}, { cwd });
|
|
1452
|
+
const continued = await dispatchCodexNativeHook({
|
|
1453
|
+
hook_event_name: "UserPromptSubmit",
|
|
1454
|
+
cwd,
|
|
1455
|
+
session_id: sessionId,
|
|
1456
|
+
thread_id: "thread-continuation",
|
|
1457
|
+
turn_id: "turn-continue",
|
|
1458
|
+
prompt: "continue",
|
|
1459
|
+
}, { cwd });
|
|
1460
|
+
const serializedOutput = JSON.stringify(continued.outputJson);
|
|
1461
|
+
const modeState = JSON.parse(await readFile(join(cwd, ".omx", "state", "sessions", sessionId, "deep-interview-state.json"), "utf-8"));
|
|
1462
|
+
assert.equal(continued.skillState?.skill, "deep-interview");
|
|
1463
|
+
assert.match(serializedOutput, /Deep-interview config override active/);
|
|
1464
|
+
assert.match(serializedOutput, /threshold=0\.05/);
|
|
1465
|
+
assert.match(serializedOutput, /max_rounds=15/);
|
|
1466
|
+
assert.equal(modeState.profile, "standard");
|
|
1467
|
+
assert.equal(modeState.threshold, 0.05);
|
|
1468
|
+
assert.equal(modeState.max_rounds, 15);
|
|
1469
|
+
}
|
|
1470
|
+
finally {
|
|
1471
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
it("keeps explicit deep-interview profile flags reflected on continuation prompts", async () => {
|
|
1475
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-deep-interview-config-profile-continuation-"));
|
|
1476
|
+
const sessionId = "sess-deep-interview-config-profile-continuation";
|
|
1477
|
+
try {
|
|
1478
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
1479
|
+
await writeFile(join(cwd, ".omx", "config.toml"), `[omx.deepInterview]
|
|
1480
|
+
defaultProfile = "standard"
|
|
1481
|
+
standardThreshold = 0.22
|
|
1482
|
+
standardMaxRounds = 13
|
|
1483
|
+
deepThreshold = 0.13
|
|
1484
|
+
deepMaxRounds = 21
|
|
1485
|
+
`);
|
|
1486
|
+
await dispatchCodexNativeHook({
|
|
1487
|
+
hook_event_name: "UserPromptSubmit",
|
|
1488
|
+
cwd,
|
|
1489
|
+
session_id: sessionId,
|
|
1490
|
+
thread_id: "thread-profile-continuation",
|
|
1491
|
+
turn_id: "turn-start",
|
|
1492
|
+
prompt: "$deep-interview --deep prove explicit profile continuation",
|
|
1493
|
+
}, { cwd });
|
|
1494
|
+
const continued = await dispatchCodexNativeHook({
|
|
1495
|
+
hook_event_name: "UserPromptSubmit",
|
|
1496
|
+
cwd,
|
|
1497
|
+
session_id: sessionId,
|
|
1498
|
+
thread_id: "thread-profile-continuation",
|
|
1499
|
+
turn_id: "turn-continue",
|
|
1500
|
+
prompt: "continue",
|
|
1501
|
+
}, { cwd });
|
|
1502
|
+
const serializedOutput = JSON.stringify(continued.outputJson);
|
|
1503
|
+
const modeState = JSON.parse(await readFile(join(cwd, ".omx", "state", "sessions", sessionId, "deep-interview-state.json"), "utf-8"));
|
|
1504
|
+
assert.equal(continued.skillState?.skill, "deep-interview");
|
|
1505
|
+
assert.equal(continued.skillState?.deep_interview_config?.profile, "deep");
|
|
1506
|
+
assert.match(serializedOutput, /Deep-interview config override active/);
|
|
1507
|
+
assert.match(serializedOutput, /profile=deep/);
|
|
1508
|
+
assert.match(serializedOutput, /threshold=0\.13/);
|
|
1509
|
+
assert.match(serializedOutput, /max_rounds=21/);
|
|
1510
|
+
assert.equal(modeState.deep_interview_config?.profile, "deep");
|
|
1511
|
+
assert.equal(modeState.profile, "deep");
|
|
1512
|
+
assert.equal(modeState.threshold, 0.13);
|
|
1513
|
+
assert.equal(modeState.max_rounds, 21);
|
|
1514
|
+
}
|
|
1515
|
+
finally {
|
|
1516
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1517
|
+
}
|
|
1518
|
+
});
|
|
1519
|
+
it("keeps the documented deep-interview Suggested Config reflected in UserPromptSubmit context", async () => {
|
|
1520
|
+
const skillDoc = await readFile(join(process.cwd(), "skills", "deep-interview", "SKILL.md"), "utf-8");
|
|
1521
|
+
const markerIndex = skillDoc.indexOf("## Suggested Config (optional)");
|
|
1522
|
+
assert.notEqual(markerIndex, -1);
|
|
1523
|
+
const configMatch = skillDoc.slice(markerIndex).match(/```toml\n([\s\S]*?)\n```/);
|
|
1524
|
+
assert.ok(configMatch);
|
|
1525
|
+
const documentedConfig = configMatch[1]?.trimEnd();
|
|
1526
|
+
assert.ok(documentedConfig);
|
|
1527
|
+
assert.match(documentedConfig, /standardThreshold = 0\.20/);
|
|
1528
|
+
assert.match(documentedConfig, /standardMaxRounds = 12/);
|
|
1529
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-deep-interview-doc-config-"));
|
|
1530
|
+
const sessionId = "sess-deep-interview-doc-config";
|
|
1531
|
+
try {
|
|
1532
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
1533
|
+
await writeFile(join(cwd, ".omx", "config.toml"), `${documentedConfig}\n`);
|
|
1534
|
+
const result = await dispatchCodexNativeHook({
|
|
1535
|
+
hook_event_name: "UserPromptSubmit",
|
|
1536
|
+
cwd,
|
|
1537
|
+
session_id: sessionId,
|
|
1538
|
+
thread_id: "thread-doc-config",
|
|
1539
|
+
turn_id: "turn-doc-config",
|
|
1540
|
+
prompt: "$deep-interview prove documented config context",
|
|
1541
|
+
}, { cwd });
|
|
1542
|
+
const serializedOutput = JSON.stringify(result.outputJson);
|
|
1543
|
+
const modeState = JSON.parse(await readFile(join(cwd, ".omx", "state", "sessions", sessionId, "deep-interview-state.json"), "utf-8"));
|
|
1544
|
+
assert.equal(result.skillState?.deep_interview_config?.profile, "standard");
|
|
1545
|
+
assert.equal(result.skillState?.deep_interview_config?.threshold, 0.2);
|
|
1546
|
+
assert.equal(result.skillState?.deep_interview_config?.maxRounds, 12);
|
|
1547
|
+
assert.match(serializedOutput, /Deep-interview config override active/);
|
|
1548
|
+
assert.match(serializedOutput, /profile=standard/);
|
|
1549
|
+
assert.match(serializedOutput, /threshold=0\.2/);
|
|
1550
|
+
assert.match(serializedOutput, /max_rounds=12/);
|
|
1551
|
+
assert.equal(modeState.deep_interview_config?.profile, "standard");
|
|
1552
|
+
assert.equal(modeState.profile, "standard");
|
|
1553
|
+
assert.equal(modeState.threshold, 0.2);
|
|
1554
|
+
assert.equal(modeState.max_rounds, 12);
|
|
1555
|
+
}
|
|
1556
|
+
finally {
|
|
1557
|
+
await rm(cwd, { recursive: true, force: true });
|
|
1558
|
+
}
|
|
1559
|
+
});
|
|
1560
|
+
it("injects deep-interview config overrides when state is boxed under OMX_ROOT", async () => {
|
|
1561
|
+
const root = await mkdtemp(join(tmpdir(), "omx-native-hook-deep-interview-config-boxed-"));
|
|
1562
|
+
const cwd = join(root, "source");
|
|
1563
|
+
const omxRoot = join(root, "box");
|
|
1564
|
+
const sessionId = "sess-boxed-deep-interview-config";
|
|
1565
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
1566
|
+
const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
|
|
1567
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
1568
|
+
try {
|
|
1569
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
1570
|
+
await writeFile(join(cwd, ".omx", "config.toml"), `[omx.deepInterview]
|
|
1571
|
+
defaultProfile = "standard"
|
|
1572
|
+
standardThreshold = 0.05
|
|
1573
|
+
standardMaxRounds = 15
|
|
1574
|
+
`);
|
|
1575
|
+
process.env.OMX_ROOT = omxRoot;
|
|
1576
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1577
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1578
|
+
const result = await dispatchCodexNativeHook({
|
|
1579
|
+
hook_event_name: "UserPromptSubmit",
|
|
1580
|
+
cwd,
|
|
1581
|
+
session_id: sessionId,
|
|
1582
|
+
thread_id: "thread-boxed",
|
|
1583
|
+
turn_id: "turn-boxed",
|
|
1584
|
+
prompt: "$deep-interview prove boxed config reflection",
|
|
1585
|
+
}, { cwd });
|
|
1586
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
1587
|
+
assert.equal(result.skillState?.initialized_state_path, `.omx/state/sessions/${sessionId}/deep-interview-state.json`);
|
|
1588
|
+
const boxedStatePath = join(omxRoot, ".omx", "state", "sessions", sessionId, "deep-interview-state.json");
|
|
1589
|
+
assert.equal(existsSync(boxedStatePath), true);
|
|
1590
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "deep-interview-state.json")), false);
|
|
1591
|
+
const serializedOutput = JSON.stringify(result.outputJson);
|
|
1592
|
+
assert.match(serializedOutput, /Deep-interview config override active/);
|
|
1593
|
+
assert.match(serializedOutput, /threshold=0\.05/);
|
|
1594
|
+
assert.match(serializedOutput, /max_rounds=15/);
|
|
1595
|
+
}
|
|
1596
|
+
finally {
|
|
1597
|
+
if (typeof previousOmxRoot === "string")
|
|
1598
|
+
process.env.OMX_ROOT = previousOmxRoot;
|
|
1599
|
+
else
|
|
1600
|
+
delete process.env.OMX_ROOT;
|
|
1601
|
+
if (typeof previousOmxStateRoot === "string")
|
|
1602
|
+
process.env.OMX_STATE_ROOT = previousOmxStateRoot;
|
|
1603
|
+
else
|
|
1604
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1605
|
+
if (typeof previousTeamStateRoot === "string")
|
|
1606
|
+
process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
1607
|
+
else
|
|
1608
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1609
|
+
await rm(root, { recursive: true, force: true });
|
|
1610
|
+
}
|
|
1611
|
+
});
|
|
1294
1612
|
it("records boxed keyword activation mode detail and skill state under OMX_ROOT", async () => {
|
|
1295
1613
|
const root = await mkdtemp(join(tmpdir(), "omx-native-hook-boxed-"));
|
|
1296
1614
|
const cwd = join(root, "source");
|
|
@@ -2925,6 +3243,75 @@ esac
|
|
|
2925
3243
|
await rm(cwd, { recursive: true, force: true });
|
|
2926
3244
|
}
|
|
2927
3245
|
});
|
|
3246
|
+
it("reuses an existing owner-tagged HUD pane when UserPromptSubmit revives with the canonical session id", async () => {
|
|
3247
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-reuse-"));
|
|
3248
|
+
const originalTmux = process.env.TMUX;
|
|
3249
|
+
const originalTmuxPane = process.env.TMUX_PANE;
|
|
3250
|
+
const originalPath = process.env.PATH;
|
|
3251
|
+
const originalHudOwner = process.env[OMX_TMUX_HUD_OWNER_ENV];
|
|
3252
|
+
try {
|
|
3253
|
+
process.env.TMUX = "1";
|
|
3254
|
+
process.env.TMUX_PANE = "%1";
|
|
3255
|
+
process.env[OMX_TMUX_HUD_OWNER_ENV] = "1";
|
|
3256
|
+
const canonicalSessionId = "omx-canonical-hud-reuse";
|
|
3257
|
+
const nativeSessionId = "codex-native-hud-reuse";
|
|
3258
|
+
await mkdir(join(cwd, ".omx", "state", "sessions", canonicalSessionId), { recursive: true });
|
|
3259
|
+
await writeSessionStart(cwd, canonicalSessionId);
|
|
3260
|
+
const binDir = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-reuse-bin-"));
|
|
3261
|
+
const tmuxLog = join(cwd, "tmux.log");
|
|
3262
|
+
await writeFile(join(binDir, "tmux"), `#!/usr/bin/env bash
|
|
3263
|
+
set -euo pipefail
|
|
3264
|
+
printf '%s\n' "$*" >> ${JSON.stringify(tmuxLog)}
|
|
3265
|
+
case "$1" in
|
|
3266
|
+
list-panes)
|
|
3267
|
+
printf '%%1\tcodex\tcodex\n'
|
|
3268
|
+
printf '%%2\tnode\texec env OMX_TMUX_HUD_OWNER='"'"'1'"'"' ${OMX_TMUX_HUD_LEADER_PANE_ENV}='"'"'%%1'"'"' /node /omx.js hud --watch\n'
|
|
3269
|
+
;;
|
|
3270
|
+
display-message)
|
|
3271
|
+
printf '80\t24\n'
|
|
3272
|
+
;;
|
|
3273
|
+
resize-pane)
|
|
3274
|
+
;;
|
|
3275
|
+
split-window)
|
|
3276
|
+
printf '%%9\n'
|
|
3277
|
+
;;
|
|
3278
|
+
esac
|
|
3279
|
+
`);
|
|
3280
|
+
await chmod(join(binDir, "tmux"), 0o755);
|
|
3281
|
+
process.env.PATH = `${binDir}:${originalPath}`;
|
|
3282
|
+
const result = await dispatchCodexNativeHook({
|
|
3283
|
+
hook_event_name: "UserPromptSubmit",
|
|
3284
|
+
cwd,
|
|
3285
|
+
session_id: nativeSessionId,
|
|
3286
|
+
thread_id: "thread-hud-reuse",
|
|
3287
|
+
turn_id: "turn-hud-reuse",
|
|
3288
|
+
prompt: "$ralplan prepare plan",
|
|
3289
|
+
}, { cwd });
|
|
3290
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
3291
|
+
const tmuxCalls = await readFile(tmuxLog, "utf-8");
|
|
3292
|
+
assert.match(tmuxCalls, /list-panes -t %1 -F/);
|
|
3293
|
+
assert.match(tmuxCalls, /resize-pane -t %2 -y 3/);
|
|
3294
|
+
assert.doesNotMatch(tmuxCalls, /split-window/);
|
|
3295
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", canonicalSessionId, "ralplan-state.json")), true);
|
|
3296
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", nativeSessionId, "ralplan-state.json")), false);
|
|
3297
|
+
}
|
|
3298
|
+
finally {
|
|
3299
|
+
if (originalTmux === undefined)
|
|
3300
|
+
delete process.env.TMUX;
|
|
3301
|
+
else
|
|
3302
|
+
process.env.TMUX = originalTmux;
|
|
3303
|
+
if (originalTmuxPane === undefined)
|
|
3304
|
+
delete process.env.TMUX_PANE;
|
|
3305
|
+
else
|
|
3306
|
+
process.env.TMUX_PANE = originalTmuxPane;
|
|
3307
|
+
if (originalHudOwner === undefined)
|
|
3308
|
+
delete process.env[OMX_TMUX_HUD_OWNER_ENV];
|
|
3309
|
+
else
|
|
3310
|
+
process.env[OMX_TMUX_HUD_OWNER_ENV] = originalHudOwner;
|
|
3311
|
+
process.env.PATH = originalPath;
|
|
3312
|
+
await rm(cwd, { recursive: true, force: true });
|
|
3313
|
+
}
|
|
3314
|
+
});
|
|
2928
3315
|
it("skips prompt-submit HUD reconciliation inside unowned tmux panes", async () => {
|
|
2929
3316
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-hud-unowned-"));
|
|
2930
3317
|
const originalTmux = process.env.TMUX;
|