oh-my-codex 0.21.13 → 0.21.15
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 +17 -0
- package/dist/adapt/herdr/__tests__/wiring.test.js +21 -0
- package/dist/adapt/herdr/__tests__/wiring.test.js.map +1 -1
- package/dist/adapt/herdr/wiring.d.ts.map +1 -1
- package/dist/adapt/herdr/wiring.js +5 -0
- package/dist/adapt/herdr/wiring.js.map +1 -1
- package/dist/auth/__tests__/hotswap.test.js +28 -0
- package/dist/auth/__tests__/hotswap.test.js.map +1 -1
- package/dist/auth/hotswap.d.ts +1 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +4 -1
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +196 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +2 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +14 -1
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/session-timeline.test.d.ts +2 -0
- package/dist/cli/__tests__/session-timeline.test.d.ts.map +1 -0
- package/dist/cli/__tests__/session-timeline.test.js +155 -0
- package/dist/cli/__tests__/session-timeline.test.js.map +1 -0
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +1 -0
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +1 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +11 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +7 -0
- package/dist/cli/session-search.js.map +1 -1
- package/dist/cli/session-timeline.d.ts +9 -0
- package/dist/cli/session-timeline.d.ts.map +1 -0
- package/dist/cli/session-timeline.js +174 -0
- package/dist/cli/session-timeline.js.map +1 -0
- package/dist/config/__tests__/codex-hooks.test.js +3 -1
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +1 -0
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +1 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +5 -0
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/evals/astra-defaults/__tests__/collector.test.js +51 -23
- package/dist/evals/astra-defaults/__tests__/collector.test.js.map +1 -1
- package/dist/evals/astra-defaults/collector.d.ts +2 -0
- package/dist/evals/astra-defaults/collector.d.ts.map +1 -1
- package/dist/evals/astra-defaults/collector.js +19 -8
- package/dist/evals/astra-defaults/collector.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js +143 -0
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +120 -28
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/runtime.d.ts.map +1 -1
- package/dist/hooks/extensibility/runtime.js +1 -0
- package/dist/hooks/extensibility/runtime.js.map +1 -1
- package/dist/hooks/extensibility/types.d.ts +2 -0
- package/dist/hooks/extensibility/types.d.ts.map +1 -1
- package/dist/hooks/native/types.d.ts +1 -1
- package/dist/hooks/native/types.d.ts.map +1 -1
- package/dist/hooks/native/types.js.map +1 -1
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js +200 -2
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
- package/dist/notifications/lifecycle-dedupe.d.ts +10 -0
- package/dist/notifications/lifecycle-dedupe.d.ts.map +1 -1
- package/dist/notifications/lifecycle-dedupe.js +175 -19
- package/dist/notifications/lifecycle-dedupe.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +278 -6
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/native-hook-protocol.test.d.ts +2 -0
- package/dist/scripts/__tests__/native-hook-protocol.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/native-hook-protocol.test.js +329 -0
- package/dist/scripts/__tests__/native-hook-protocol.test.js.map +1 -0
- package/dist/scripts/__tests__/smoke-packed-install.test.js +7 -6
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/codex-execution-surface.d.ts +1 -1
- package/dist/scripts/codex-execution-surface.d.ts.map +1 -1
- package/dist/scripts/codex-execution-surface.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +124 -13
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/hook-payload-guard.d.ts +1 -1
- package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
- package/dist/scripts/hook-payload-guard.js +1 -0
- package/dist/scripts/hook-payload-guard.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +2 -2
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +12 -1
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/session-history/__tests__/timeline.test.d.ts +2 -0
- package/dist/session-history/__tests__/timeline.test.d.ts.map +1 -0
- package/dist/session-history/__tests__/timeline.test.js +459 -0
- package/dist/session-history/__tests__/timeline.test.js.map +1 -0
- package/dist/session-history/export.d.ts +2 -3
- package/dist/session-history/export.d.ts.map +1 -1
- package/dist/session-history/export.js +5 -66
- package/dist/session-history/export.js.map +1 -1
- package/dist/session-history/timeline.d.ts +97 -0
- package/dist/session-history/timeline.d.ts.map +1 -0
- package/dist/session-history/timeline.js +325 -0
- package/dist/session-history/timeline.js.map +1 -0
- package/dist/session-history/transcript.d.ts +16 -0
- package/dist/session-history/transcript.d.ts.map +1 -0
- package/dist/session-history/transcript.js +111 -0
- package/dist/session-history/transcript.js.map +1 -0
- package/dist/subagents/tracker.d.ts +6 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +32 -0
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +12 -3
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +25 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +30 -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 +9 -1
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/wiki/__tests__/session-hooks.test.js +26 -0
- package/dist/wiki/__tests__/session-hooks.test.js.map +1 -1
- package/dist/wiki/lifecycle.d.ts.map +1 -1
- package/dist/wiki/lifecycle.js +6 -1
- package/dist/wiki/lifecycle.js.map +1 -1
- package/package.json +1 -1
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +85 -18
- package/plugins/oh-my-codex/hooks/hooks.json +10 -0
- package/src/scripts/__tests__/codex-native-hook.test.ts +273 -5
- package/src/scripts/__tests__/native-hook-protocol.test.ts +362 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +7 -6
- package/src/scripts/codex-execution-surface.ts +1 -0
- package/src/scripts/codex-native-hook.ts +130 -11
- package/src/scripts/hook-payload-guard.ts +1 -0
- package/src/scripts/smoke-packed-install.ts +12 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-hook-protocol.test.d.ts","sourceRoot":"","sources":["../../../src/scripts/__tests__/native-hook-protocol.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdir, mkdtemp, readFile, readdir, realpath, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
8
|
+
import { MANAGED_HOOK_EVENTS, buildManagedCodexHooksConfig } from "../../config/codex-hooks.js";
|
|
9
|
+
import { writeSessionStart } from "../../hooks/session.js";
|
|
10
|
+
import { createSubagentTrackingState, readSubagentTrackingState, recordNativeSubagentAuthorityObservation, recordSubagentTurn, withCrossProcessFileLockSync } from "../../subagents/tracker.js";
|
|
11
|
+
import { dispatchCodexNativeHook, mapCodexHookEventToOmxEvent } from "../codex-native-hook.js";
|
|
12
|
+
import { CODEX_HOOK_EVENT_NAMES, extractRawCodexHookEventName, MAX_NATIVE_STDIN_JSON_BYTES } from "../hook-payload-guard.js";
|
|
13
|
+
import { MANAGED_CODEX_HOOK_EVENTS } from "../smoke-packed-install.js";
|
|
14
|
+
describe("native hook protocol compatibility", () => {
|
|
15
|
+
let cwd;
|
|
16
|
+
let env;
|
|
17
|
+
const sessionId = "omx-protocol-session";
|
|
18
|
+
const parentId = "native-parent";
|
|
19
|
+
const agentId = "native-child";
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
env = { ...process.env };
|
|
22
|
+
for (const key of Object.keys(process.env)) {
|
|
23
|
+
if (key.startsWith("OMX_") || key === "CODEX_THREAD_ID")
|
|
24
|
+
delete process.env[key];
|
|
25
|
+
}
|
|
26
|
+
cwd = await realpath(await mkdtemp(join(tmpdir(), "omx-native-protocol-")));
|
|
27
|
+
process.env.CODEX_HOME = join(cwd, "codex-home");
|
|
28
|
+
await mkdir(process.env.CODEX_HOME);
|
|
29
|
+
});
|
|
30
|
+
afterEach(async () => {
|
|
31
|
+
process.env = env;
|
|
32
|
+
await rm(cwd, { recursive: true, force: true });
|
|
33
|
+
});
|
|
34
|
+
function stop(overrides = {}) {
|
|
35
|
+
return {
|
|
36
|
+
hook_event_name: "SubagentStop",
|
|
37
|
+
cwd,
|
|
38
|
+
session_id: parentId,
|
|
39
|
+
agent_id: agentId,
|
|
40
|
+
agent_type: "executor",
|
|
41
|
+
turn_id: "child-turn-1",
|
|
42
|
+
transcript_path: null,
|
|
43
|
+
agent_transcript_path: null,
|
|
44
|
+
last_assistant_message: null,
|
|
45
|
+
stop_hook_active: false,
|
|
46
|
+
...overrides,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async function start() {
|
|
50
|
+
await writeSessionStart(cwd, sessionId, { nativeSessionId: parentId, pid: process.pid });
|
|
51
|
+
}
|
|
52
|
+
function runNativeHookCli(input = JSON.stringify(stop())) {
|
|
53
|
+
return spawnSync(process.execPath, [join(process.cwd(), "dist/scripts/codex-native-hook.js")], {
|
|
54
|
+
cwd, env: process.env, input, encoding: "utf8", timeout: 10_000,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async function captureLifecycle(notifications) {
|
|
58
|
+
await writeFile(join(process.env.CODEX_HOME, ".omx-config.json"), JSON.stringify({
|
|
59
|
+
notifications: { enabled: true, ...notifications },
|
|
60
|
+
}));
|
|
61
|
+
const eventsPath = join(cwd, "child-events.jsonl");
|
|
62
|
+
await mkdir(join(cwd, ".omx/hooks"), { recursive: true });
|
|
63
|
+
await writeFile(join(cwd, ".omx/hooks/capture.mjs"), `import { appendFileSync } from 'node:fs';\nexport function onHookEvent(event) { appendFileSync(${JSON.stringify(eventsPath)}, JSON.stringify(event) + '\\n'); }\n`);
|
|
64
|
+
return eventsPath;
|
|
65
|
+
}
|
|
66
|
+
for (const notifications of [
|
|
67
|
+
{ verbosity: "session", includeChildAgents: true },
|
|
68
|
+
{ verbosity: "agent" },
|
|
69
|
+
{ verbosity: "verbose" },
|
|
70
|
+
{ verbosity: "session" },
|
|
71
|
+
{ verbosity: "minimal" },
|
|
72
|
+
]) {
|
|
73
|
+
it(`applies the SubagentStop lifecycle policy for ${JSON.stringify(notifications)}`, async () => {
|
|
74
|
+
await start();
|
|
75
|
+
const eventsPath = await captureLifecycle(notifications);
|
|
76
|
+
await dispatchCodexNativeHook(stop());
|
|
77
|
+
assert.ok((await readSubagentTrackingState(cwd)).sessions[sessionId].threads[agentId].completed_at);
|
|
78
|
+
if (notifications.includeChildAgents !== true && !["agent", "verbose"].includes(notifications.verbosity)) {
|
|
79
|
+
assert.equal(existsSync(eventsPath), false);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
await dispatchCodexNativeHook(stop({ stop_hook_active: true, stopHookActive: true }));
|
|
83
|
+
const events = (await readFile(eventsPath, "utf8")).trim().split("\n").map(line => JSON.parse(line));
|
|
84
|
+
assert.equal(events.length, 1);
|
|
85
|
+
assert.equal(events[0].event, "subagent-stop");
|
|
86
|
+
assert.equal(events[0].source, "native");
|
|
87
|
+
assert.equal(events[0].session_id, sessionId);
|
|
88
|
+
assert.equal(events[0].thread_id, agentId);
|
|
89
|
+
assert.equal(events[0].turn_id, "child-turn-1");
|
|
90
|
+
assert.equal(events[0].context.native_session_id, agentId);
|
|
91
|
+
assert.equal(events[0].context.payload.session_id, parentId);
|
|
92
|
+
assert.equal(events[0].context.payload.stop_hook_active, undefined);
|
|
93
|
+
assert.equal(events[0].context.payload.stopHookActive, undefined);
|
|
94
|
+
await dispatchCodexNativeHook(stop({ turn_id: "child-turn-2" }));
|
|
95
|
+
assert.equal((await readFile(eventsPath, "utf8")).trim().split("\n").length, 2);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
it("deduplicates interleaved child and turn replays independently", async () => {
|
|
99
|
+
await start();
|
|
100
|
+
const eventsPath = await captureLifecycle({ includeChildAgents: true });
|
|
101
|
+
await dispatchCodexNativeHook(stop());
|
|
102
|
+
await dispatchCodexNativeHook(stop({ agent_id: "other-child" }));
|
|
103
|
+
await dispatchCodexNativeHook(stop());
|
|
104
|
+
await dispatchCodexNativeHook(stop({ turn_id: "child-turn-2" }));
|
|
105
|
+
await dispatchCodexNativeHook(stop());
|
|
106
|
+
const events = (await readFile(eventsPath, "utf8")).trim().split("\n").map(line => JSON.parse(line));
|
|
107
|
+
assert.deepEqual(events.map(event => [event.thread_id, event.turn_id]), [
|
|
108
|
+
[agentId, "child-turn-1"], ["other-child", "child-turn-1"], [agentId, "child-turn-2"],
|
|
109
|
+
]);
|
|
110
|
+
});
|
|
111
|
+
it("deduplicates lifecycle hooks when legacy Stop and SubagentStop report the same child turn", async () => {
|
|
112
|
+
await start();
|
|
113
|
+
const eventsPath = await captureLifecycle({ includeChildAgents: true });
|
|
114
|
+
const legacyFirstChild = "legacy-first-child";
|
|
115
|
+
const nativeFirstChild = "native-first-child";
|
|
116
|
+
for (const childThreadId of [legacyFirstChild, nativeFirstChild]) {
|
|
117
|
+
recordNativeSubagentAuthorityObservation(cwd, {
|
|
118
|
+
sessionIds: [sessionId], childThreadId, parentThreadId: parentId,
|
|
119
|
+
rootNativeSessionId: parentId, authorityEvidence: "valid",
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
await dispatchCodexNativeHook({
|
|
123
|
+
hook_event_name: "Stop", cwd, session_id: legacyFirstChild,
|
|
124
|
+
thread_id: legacyFirstChild, turn_id: "turn-legacy-first", stop_hook_active: true,
|
|
125
|
+
});
|
|
126
|
+
await dispatchCodexNativeHook(stop({ agent_id: legacyFirstChild, turn_id: "turn-legacy-first" }));
|
|
127
|
+
await dispatchCodexNativeHook(stop({ agent_id: nativeFirstChild, turn_id: "turn-native-first" }));
|
|
128
|
+
await dispatchCodexNativeHook({
|
|
129
|
+
hook_event_name: "Stop", cwd, session_id: nativeFirstChild,
|
|
130
|
+
thread_id: nativeFirstChild, turn_id: "turn-native-first", stop_hook_active: true,
|
|
131
|
+
});
|
|
132
|
+
const events = (await readFile(eventsPath, "utf8")).trim().split("\n").map(line => JSON.parse(line));
|
|
133
|
+
assert.deepEqual(events.map(event => [event.event, event.thread_id, event.turn_id]), [
|
|
134
|
+
["stop", legacyFirstChild, "turn-legacy-first"],
|
|
135
|
+
["subagent-stop", nativeFirstChild, "turn-native-first"],
|
|
136
|
+
]);
|
|
137
|
+
});
|
|
138
|
+
it("does not deduplicate separate SubagentStop completions when turn IDs are absent", async () => {
|
|
139
|
+
await start();
|
|
140
|
+
const eventsPath = await captureLifecycle({ includeChildAgents: true });
|
|
141
|
+
await dispatchCodexNativeHook(stop({ turn_id: null }));
|
|
142
|
+
await dispatchCodexNativeHook(stop({ turn_id: null }));
|
|
143
|
+
const events = (await readFile(eventsPath, "utf8")).trim().split("\n").map(line => JSON.parse(line));
|
|
144
|
+
assert.equal(events.length, 2);
|
|
145
|
+
assert.deepEqual(events.map(event => event.event), ["subagent-stop", "subagent-stop"]);
|
|
146
|
+
assert.deepEqual(events.map(event => event.turn_id), [undefined, undefined]);
|
|
147
|
+
});
|
|
148
|
+
it("does not treat missing turn IDs as proof of a duplicate completion", () => {
|
|
149
|
+
const first = recordSubagentTurn(createSubagentTrackingState(), {
|
|
150
|
+
sessionId, threadId: agentId, kind: "subagent", completed: true,
|
|
151
|
+
completionSource: "native_stop_event",
|
|
152
|
+
});
|
|
153
|
+
const second = recordSubagentTurn(first, {
|
|
154
|
+
sessionId, threadId: agentId, kind: "subagent", completed: true,
|
|
155
|
+
completionSource: "native_stop_event",
|
|
156
|
+
});
|
|
157
|
+
assert.equal(second.sessions[sessionId].threads[agentId].turn_count, first.sessions[sessionId].threads[agentId].turn_count + 1);
|
|
158
|
+
});
|
|
159
|
+
it("keeps malformed tracker authority bytes intact and returns CLI no-op with a diagnostic", async () => {
|
|
160
|
+
await start();
|
|
161
|
+
const eventsPath = await captureLifecycle({ includeChildAgents: true });
|
|
162
|
+
const trackerPath = join(cwd, ".omx/state/subagent-tracking.json");
|
|
163
|
+
const malformed = '{"schemaVersion":1,"sessions":{"preserve-authority":';
|
|
164
|
+
await writeFile(trackerPath, malformed);
|
|
165
|
+
const result = runNativeHookCli();
|
|
166
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
167
|
+
assert.deepEqual(JSON.parse(result.stdout), {});
|
|
168
|
+
assert.equal(await readFile(trackerPath, "utf8"), malformed);
|
|
169
|
+
assert.equal(existsSync(eventsPath), false);
|
|
170
|
+
const logDir = join(cwd, ".omx/logs");
|
|
171
|
+
const logFile = (await readdir(logDir)).find(name => name.startsWith("native-hook-"));
|
|
172
|
+
assert.ok(logFile);
|
|
173
|
+
const diagnostic = await readFile(join(logDir, logFile), "utf8");
|
|
174
|
+
assert.match(diagnostic, /native_subagent_completion_tracking_error/);
|
|
175
|
+
assert.match(diagnostic, /Malformed subagent tracker authority state/);
|
|
176
|
+
});
|
|
177
|
+
it("returns CLI no-op without dispatch or mutation when the tracker lock stays held", async () => {
|
|
178
|
+
await start();
|
|
179
|
+
const eventsPath = await captureLifecycle({ includeChildAgents: true });
|
|
180
|
+
recordNativeSubagentAuthorityObservation(cwd, {
|
|
181
|
+
sessionIds: [sessionId], childThreadId: agentId, parentThreadId: parentId,
|
|
182
|
+
rootNativeSessionId: parentId, authorityEvidence: "valid",
|
|
183
|
+
});
|
|
184
|
+
const trackerPath = join(cwd, ".omx/state/subagent-tracking.json");
|
|
185
|
+
const before = await readFile(trackerPath, "utf8");
|
|
186
|
+
const result = withCrossProcessFileLockSync(trackerPath, () => runNativeHookCli());
|
|
187
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
188
|
+
assert.deepEqual(JSON.parse(result.stdout), {});
|
|
189
|
+
assert.equal(await readFile(trackerPath, "utf8"), before);
|
|
190
|
+
assert.equal(existsSync(eventsPath), false);
|
|
191
|
+
});
|
|
192
|
+
it("rejects unbound identities before opted-in SubagentStop lifecycle dispatch", async () => {
|
|
193
|
+
await start();
|
|
194
|
+
const eventsPath = await captureLifecycle({ includeChildAgents: true });
|
|
195
|
+
for (const overrides of [{ session_id: "foreign-parent" }, { agent_id: parentId }, { agent_id: null }]) {
|
|
196
|
+
await dispatchCodexNativeHook(stop(overrides));
|
|
197
|
+
}
|
|
198
|
+
assert.equal(existsSync(eventsPath), false);
|
|
199
|
+
assert.equal(existsSync(join(cwd, ".omx/state/subagent-tracking.json")), false);
|
|
200
|
+
});
|
|
201
|
+
it("keeps setup, bounded input parsing, dispatch, plugin, and packed smoke event rosters aligned", async () => {
|
|
202
|
+
assert.deepEqual(CODEX_HOOK_EVENT_NAMES, MANAGED_HOOK_EVENTS);
|
|
203
|
+
assert.deepEqual(MANAGED_CODEX_HOOK_EVENTS, MANAGED_HOOK_EVENTS);
|
|
204
|
+
const plugin = JSON.parse(await readFile(join(process.cwd(), "plugins/oh-my-codex/hooks/hooks.json"), "utf8"));
|
|
205
|
+
assert.deepEqual(Object.keys(plugin.hooks), [...MANAGED_HOOK_EVENTS]);
|
|
206
|
+
const config = buildManagedCodexHooksConfig("/repo");
|
|
207
|
+
assert.deepEqual(Object.keys(config.hooks), [...MANAGED_HOOK_EVENTS]);
|
|
208
|
+
for (const event of MANAGED_HOOK_EVENTS) {
|
|
209
|
+
assert.equal(extractRawCodexHookEventName(JSON.stringify({ hook_event_name: event })), event);
|
|
210
|
+
assert.ok(mapCodexHookEventToOmxEvent(event));
|
|
211
|
+
assert.match(config.hooks[event][0].hooks[0].command, /codex-native-hook\.js/);
|
|
212
|
+
}
|
|
213
|
+
assert.equal(mapCodexHookEventToOmxEvent("SubagentStop"), "subagent-stop");
|
|
214
|
+
});
|
|
215
|
+
it("records the child, accepts nullable optional fields, and never changes the leader pointer or grants authority", async () => {
|
|
216
|
+
await start();
|
|
217
|
+
const pointer = join(cwd, ".omx/state/session.json");
|
|
218
|
+
const before = await readFile(pointer, "utf8");
|
|
219
|
+
const modePath = join(cwd, ".omx/state/autopilot-state.json");
|
|
220
|
+
const activeMode = JSON.stringify({ active: true, current_phase: "implementation", session_id: sessionId });
|
|
221
|
+
await writeFile(modePath, activeMode);
|
|
222
|
+
const result = await dispatchCodexNativeHook(stop({ future_field: { ignored: true } }));
|
|
223
|
+
assert.equal(result.hookEventName, "SubagentStop");
|
|
224
|
+
assert.equal(result.omxEventName, "subagent-stop");
|
|
225
|
+
assert.equal(result.outputJson, null);
|
|
226
|
+
assert.equal(await readFile(pointer, "utf8"), before);
|
|
227
|
+
assert.equal(await readFile(modePath, "utf8"), activeMode);
|
|
228
|
+
const state = await readSubagentTrackingState(cwd);
|
|
229
|
+
const thread = state.sessions[sessionId].threads[agentId];
|
|
230
|
+
assert.equal(thread.kind, "subagent");
|
|
231
|
+
assert.equal(thread.mode, "executor");
|
|
232
|
+
assert.equal(thread.completion_source, "native_stop_event");
|
|
233
|
+
assert.equal(thread.last_completed_turn_id, "child-turn-1");
|
|
234
|
+
assert.ok(thread.completed_at);
|
|
235
|
+
assert.equal(thread.direct_child_root_id, undefined);
|
|
236
|
+
assert.equal(state.sessions[sessionId].threads[parentId], undefined);
|
|
237
|
+
assert.equal(state.sessions[parentId], undefined);
|
|
238
|
+
});
|
|
239
|
+
it("completes the child in every existing correlated tracker partition", async () => {
|
|
240
|
+
await start();
|
|
241
|
+
recordNativeSubagentAuthorityObservation(cwd, {
|
|
242
|
+
sessionIds: [sessionId, parentId, "previous-canonical-session"],
|
|
243
|
+
childThreadId: agentId,
|
|
244
|
+
parentThreadId: parentId,
|
|
245
|
+
rootNativeSessionId: parentId,
|
|
246
|
+
authorityEvidence: "valid",
|
|
247
|
+
});
|
|
248
|
+
await dispatchCodexNativeHook(stop());
|
|
249
|
+
const state = await readSubagentTrackingState(cwd);
|
|
250
|
+
for (const partitionId of [sessionId, parentId, "previous-canonical-session"]) {
|
|
251
|
+
const thread = state.sessions[partitionId]?.threads[agentId];
|
|
252
|
+
assert.equal(thread?.kind, "subagent");
|
|
253
|
+
assert.equal(thread?.completion_source, "native_stop_event");
|
|
254
|
+
assert.equal(thread?.last_completed_turn_id, "child-turn-1");
|
|
255
|
+
assert.ok(thread?.completed_at);
|
|
256
|
+
assert.equal(thread?.status, "closed");
|
|
257
|
+
assert.equal(thread?.direct_child_root_id, parentId);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
it("deduplicates replays and legacy Stop for the same child turn, but records a new turn", async () => {
|
|
261
|
+
await start();
|
|
262
|
+
recordNativeSubagentAuthorityObservation(cwd, {
|
|
263
|
+
sessionIds: [sessionId], childThreadId: agentId, parentThreadId: parentId,
|
|
264
|
+
rootNativeSessionId: parentId, authorityEvidence: "valid",
|
|
265
|
+
});
|
|
266
|
+
const legacy = { hook_event_name: "Stop", cwd, session_id: sessionId, thread_id: agentId,
|
|
267
|
+
turn_id: "child-turn-1", stop_hook_active: true };
|
|
268
|
+
await dispatchCodexNativeHook(legacy);
|
|
269
|
+
const first = (await readSubagentTrackingState(cwd)).sessions[sessionId].threads[agentId];
|
|
270
|
+
await Promise.all([dispatchCodexNativeHook(stop()), dispatchCodexNativeHook(stop())]);
|
|
271
|
+
await dispatchCodexNativeHook(legacy);
|
|
272
|
+
const replay = (await readSubagentTrackingState(cwd)).sessions[sessionId].threads[agentId];
|
|
273
|
+
assert.deepEqual(replay, first);
|
|
274
|
+
await dispatchCodexNativeHook(stop({ turn_id: "child-turn-2" }));
|
|
275
|
+
const next = (await readSubagentTrackingState(cwd)).sessions[sessionId].threads[agentId];
|
|
276
|
+
assert.equal(next.turn_count, first.turn_count + 1);
|
|
277
|
+
assert.equal(next.last_completed_turn_id, "child-turn-2");
|
|
278
|
+
});
|
|
279
|
+
it("ignores absent, malformed, conflicting, foreign, or leader identities without creating tracking state", async () => {
|
|
280
|
+
await start();
|
|
281
|
+
for (const overrides of [
|
|
282
|
+
{ agent_id: null }, { agent_id: "" }, { agent_id: {} }, { agent_id: "../escape" },
|
|
283
|
+
{ agent_id: parentId }, { agent_id: sessionId }, { session_id: null },
|
|
284
|
+
{ session_id: "" }, { session_id: {} }, { session_id: "other-session" },
|
|
285
|
+
{ sessionId: "conflicting-session" },
|
|
286
|
+
]) {
|
|
287
|
+
const result = await dispatchCodexNativeHook(stop(overrides));
|
|
288
|
+
assert.equal(result.outputJson, null);
|
|
289
|
+
assert.equal(existsSync(join(cwd, ".omx/state/subagent-tracking.json")), false, JSON.stringify(overrides));
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
it("does not promote a legacy child Stop without thread_id into its own leader session", async () => {
|
|
293
|
+
await start();
|
|
294
|
+
recordNativeSubagentAuthorityObservation(cwd, {
|
|
295
|
+
sessionIds: [sessionId], childThreadId: agentId, parentThreadId: parentId,
|
|
296
|
+
rootNativeSessionId: parentId, authorityEvidence: "valid",
|
|
297
|
+
});
|
|
298
|
+
const before = await readSubagentTrackingState(cwd);
|
|
299
|
+
await dispatchCodexNativeHook({
|
|
300
|
+
hook_event_name: "Stop", cwd, session_id: agentId,
|
|
301
|
+
turn_id: "child-turn-1", stop_hook_active: true,
|
|
302
|
+
});
|
|
303
|
+
assert.deepEqual(await readSubagentTrackingState(cwd), before);
|
|
304
|
+
await dispatchCodexNativeHook(stop());
|
|
305
|
+
const state = await readSubagentTrackingState(cwd);
|
|
306
|
+
assert.equal(state.sessions[agentId], undefined);
|
|
307
|
+
assert.ok(state.sessions[sessionId].threads[agentId].completed_at);
|
|
308
|
+
});
|
|
309
|
+
it("does not bootstrap a root session from a standalone SubagentStop", async () => {
|
|
310
|
+
assert.equal((await dispatchCodexNativeHook(stop())).outputJson, null);
|
|
311
|
+
assert.equal(existsSync(join(cwd, ".omx")), false);
|
|
312
|
+
});
|
|
313
|
+
it("does not apply leader Stop behavior to malformed SubagentStop input", async () => {
|
|
314
|
+
await start();
|
|
315
|
+
const result = runNativeHookCli('{"hook_event_name":"SubagentStop",');
|
|
316
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
317
|
+
assert.deepEqual(JSON.parse(result.stdout), {});
|
|
318
|
+
});
|
|
319
|
+
it("does not block an oversized SubagentStop completion", async () => {
|
|
320
|
+
await start();
|
|
321
|
+
const result = runNativeHookCli(JSON.stringify({
|
|
322
|
+
...stop(),
|
|
323
|
+
oversized_field: "x".repeat(MAX_NATIVE_STDIN_JSON_BYTES),
|
|
324
|
+
}));
|
|
325
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
326
|
+
assert.deepEqual(JSON.parse(result.stdout), {});
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
//# sourceMappingURL=native-hook-protocol.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-hook-protocol.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/native-hook-protocol.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -395,7 +395,7 @@ test('packed lifecycle requires enabled command handlers and integer hook metada
|
|
|
395
395
|
assert.doesNotThrow(() => parseCodexHooksListResult(valid, project, hooksPath), `${source} is a valid hook source`);
|
|
396
396
|
}
|
|
397
397
|
});
|
|
398
|
-
test('packed lifecycle requires exactly
|
|
398
|
+
test('packed lifecycle requires exactly eight generated OMX trust keys and an isolated approval target', () => {
|
|
399
399
|
const hooks = MANAGED_CODEX_HOOK_EVENTS.map((event, index) => ({
|
|
400
400
|
event,
|
|
401
401
|
command: 'node /tmp/omx/dist/scripts/codex-native-hook.js',
|
|
@@ -410,8 +410,8 @@ test('packed lifecycle requires exactly seven generated OMX trust keys and an is
|
|
|
410
410
|
assert.throws(() => assertGeneratedTrustMatchesCodex({
|
|
411
411
|
...trust,
|
|
412
412
|
'/tmp/project/.codex/hooks.json:foreign:0:0': 'sha256:foreign',
|
|
413
|
-
}, hooks), /exactly the
|
|
414
|
-
assert.throws(() => assertGeneratedTrustMatchesCodex(Object.fromEntries(Object.entries(trust).slice(0, -1)), hooks), /exactly the
|
|
413
|
+
}, hooks), /exactly the 8 current OMX hooks with no stale keys/);
|
|
414
|
+
assert.throws(() => assertGeneratedTrustMatchesCodex(Object.fromEntries(Object.entries(trust).slice(0, -1)), hooks), /exactly the 8 current OMX hooks with no stale keys/);
|
|
415
415
|
assert.doesNotThrow(() => assertCodexBatchWriteResult({
|
|
416
416
|
filePath: '/tmp/isolated-codex-home/config.toml',
|
|
417
417
|
status: 'ok',
|
|
@@ -449,10 +449,10 @@ test('packed lifecycle fails closed on malformed project hooks.state entries and
|
|
|
449
449
|
assert.throws(() => generatedHookTrustState(`[hooks.state]\n${malformedEntry}`), /invalid hooks\.state entry first/);
|
|
450
450
|
}
|
|
451
451
|
const staleRawTrust = generatedHookTrustState(`${validConfig}\nforeign = { trusted_hash = "sha256:foreign" }`);
|
|
452
|
-
assert.throws(() => assertGeneratedTrustMatchesCodex(staleRawTrust, hooks), /exactly the
|
|
452
|
+
assert.throws(() => assertGeneratedTrustMatchesCodex(staleRawTrust, hooks), /exactly the 8 current OMX hooks with no stale keys/);
|
|
453
453
|
const protoRawTrust = generatedHookTrustState(`${validConfig}\n__proto__ = { trusted_hash = "sha256:proto" }`);
|
|
454
454
|
assert.equal(Object.hasOwn(protoRawTrust, '__proto__'), true);
|
|
455
|
-
assert.throws(() => assertGeneratedTrustMatchesCodex(protoRawTrust, hooks), /exactly the
|
|
455
|
+
assert.throws(() => assertGeneratedTrustMatchesCodex(protoRawTrust, hooks), /exactly the 8 current OMX hooks with no stale keys/);
|
|
456
456
|
});
|
|
457
457
|
test('packed lifecycle treats only the production command grammar as managed ownership', () => {
|
|
458
458
|
const hooks = MANAGED_CODEX_HOOK_EVENTS.map((event, index) => ({
|
|
@@ -879,6 +879,7 @@ test('packed install smoke covers every installed native hook event with minimal
|
|
|
879
879
|
'UserPromptSubmit',
|
|
880
880
|
'PreCompact',
|
|
881
881
|
'PostCompact',
|
|
882
|
+
'SubagentStop',
|
|
882
883
|
'Stop',
|
|
883
884
|
]);
|
|
884
885
|
for (const eventName of PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS) {
|
|
@@ -1093,7 +1094,7 @@ test('packed install native hook stdout validation allows empty or JSON output o
|
|
|
1093
1094
|
assert.doesNotThrow(() => validateHookStdout('Stop', '{}\n'));
|
|
1094
1095
|
assert.throws(() => validateHookStdout('UserPromptSubmit', '{not json'), /native hook UserPromptSubmit emitted invalid JSON stdout/);
|
|
1095
1096
|
});
|
|
1096
|
-
test('packed lifecycle and native hook smoke share the
|
|
1097
|
+
test('packed lifecycle and native hook smoke share the managed event names', () => {
|
|
1097
1098
|
assert.deepEqual(MANAGED_CODEX_HOOK_EVENTS, PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS);
|
|
1098
1099
|
});
|
|
1099
1100
|
test('packed install native hook stdout validation enforces event output contracts', () => {
|