oh-my-codex 0.18.1 → 0.18.2
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 +4 -2
- package/dist/agents/__tests__/definitions.test.js +14 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +19 -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 +30 -0
- package/dist/agents/definitions.js.map +1 -1
- package/dist/agents/native-config.d.ts +1 -0
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +4 -0
- package/dist/agents/native-config.js.map +1 -1
- package/dist/catalog/__tests__/generator.test.js +4 -0
- package/dist/catalog/__tests__/generator.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +61 -5
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +161 -21
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +51 -3
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js +2 -2
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +178 -7
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +7 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +143 -43
- package/dist/cli/index.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +3 -3
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +1 -0
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2 -4
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +14 -0
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +100 -1
- package/dist/config/generator.js.map +1 -1
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js +21 -0
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +3 -0
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +45 -2
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +17 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +170 -15
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts +2 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js +320 -0
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js +12 -0
- package/dist/hooks/__tests__/prompt-guidance-wave-two.test.js.map +1 -1
- package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts +2 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js +35 -0
- package/dist/hooks/__tests__/research-workflow-boundaries.test.js.map +1 -0
- package/dist/hooks/keyword-detector.d.ts +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +28 -6
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +1 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
- package/dist/hooks/prompt-guidance-contract.js +11 -0
- package/dist/hooks/prompt-guidance-contract.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +22 -0
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +121 -10
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/render.test.js +84 -0
- package/dist/hud/__tests__/render.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +51 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +69 -23
- package/dist/hud/__tests__/tmux.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 +8 -3
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +6 -3
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +26 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts +2 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +62 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.d.ts +10 -3
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +59 -10
- package/dist/hud/tmux.js.map +1 -1
- package/dist/hud/types.d.ts +22 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js +63 -1
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +410 -4
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +29 -2
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +41 -6
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/question/__tests__/ui.test.js +43 -10
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/ui.d.ts +12 -0
- package/dist/question/ui.d.ts.map +1 -1
- package/dist/question/ui.js +83 -46
- package/dist/question/ui.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +200 -10
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +23 -0
- package/dist/ralplan/consensus-gate.d.ts.map +1 -0
- package/dist/ralplan/consensus-gate.js +212 -0
- package/dist/ralplan/consensus-gate.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +25 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +144 -8
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +626 -7
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/docs-site-contract.test.d.ts +2 -0
- package/dist/scripts/__tests__/docs-site-contract.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/docs-site-contract.test.js +42 -0
- package/dist/scripts/__tests__/docs-site-contract.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js +115 -2
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/run-test-files.test.js +57 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-agents.test.js +2 -2
- 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 +214 -34
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +188 -4
- package/dist/scripts/notify-dispatcher.js.map +1 -1
- package/dist/scripts/run-test-files.js +13 -0
- package/dist/scripts/run-test-files.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +6 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +7 -0
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +4 -3
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +36 -44
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +58 -18
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +10 -20
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +15 -6
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +50 -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 +28 -2
- 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 +16 -4
- package/plugins/oh-my-codex/skills/autoresearch/SKILL.md +4 -0
- package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/best-practice-research/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/plan/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/prometheus-strict/README.md +35 -0
- package/plugins/oh-my-codex/skills/prometheus-strict/SKILL.md +219 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +18 -3
- package/prompts/prometheus-strict-metis.md +274 -0
- package/prompts/prometheus-strict-momus.md +82 -0
- package/prompts/prometheus-strict-oracle.md +107 -0
- package/prompts/researcher.md +22 -3
- package/skills/autopilot/SKILL.md +16 -4
- package/skills/autoresearch/SKILL.md +4 -0
- package/skills/autoresearch-goal/SKILL.md +1 -1
- package/skills/best-practice-research/SKILL.md +1 -1
- package/skills/pipeline/SKILL.md +1 -1
- package/skills/plan/SKILL.md +1 -1
- package/skills/prometheus-strict/README.md +35 -0
- package/skills/prometheus-strict/SKILL.md +219 -0
- package/skills/ralplan/SKILL.md +18 -3
- package/src/scripts/__tests__/codex-native-hook.test.ts +769 -8
- package/src/scripts/__tests__/docs-site-contract.test.ts +47 -0
- package/src/scripts/__tests__/notify-dispatcher.test.ts +132 -3
- package/src/scripts/__tests__/run-test-files.test.ts +67 -0
- package/src/scripts/__tests__/verify-native-agents.test.ts +2 -2
- package/src/scripts/codex-native-hook.ts +237 -30
- package/src/scripts/notify-dispatcher.ts +202 -4
- package/src/scripts/run-test-files.ts +13 -0
- package/templates/catalog-manifest.json +22 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { describe, it } from 'node:test';
|
|
5
|
+
|
|
6
|
+
const root = process.cwd();
|
|
7
|
+
|
|
8
|
+
function read(path: string): string {
|
|
9
|
+
return readFileSync(join(root, path), 'utf-8');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const docsPages = ['docs/index.html', 'docs/getting-started.html', 'docs/agents.html', 'docs/skills.html', 'docs/integrations.html'];
|
|
13
|
+
|
|
14
|
+
describe('public docs site contract', () => {
|
|
15
|
+
it('keeps every repo-owned docs HTML page linked to an existing stylesheet', () => {
|
|
16
|
+
for (const page of docsPages) {
|
|
17
|
+
const content = read(page);
|
|
18
|
+
const hrefs = [...content.matchAll(/<link\s+[^>]*rel="stylesheet"[^>]*href="([^"]+)"/g)].map((match) => match[1]);
|
|
19
|
+
assert.ok(hrefs.length > 0, `${page} should link a stylesheet`);
|
|
20
|
+
for (const href of hrefs) {
|
|
21
|
+
assert.ok(!href.startsWith('http'), `${page} should use a repo-owned relative stylesheet, got ${href}`);
|
|
22
|
+
const resolved = join(root, dirname(page), href);
|
|
23
|
+
assert.ok(existsSync(resolved), `${page} stylesheet must exist: ${href}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('defines CSS for the layout classes used by the static docs pages', () => {
|
|
29
|
+
const css = read('docs/style.css');
|
|
30
|
+
assert.match(css, /(^|\n)\.grid\s*,\s*\n\.card-grid\s*\{/, 'docs/style.css must style .grid cards used by docs pages');
|
|
31
|
+
for (const page of docsPages) {
|
|
32
|
+
const content = read(page);
|
|
33
|
+
if (content.includes('class="grid"')) {
|
|
34
|
+
assert.match(css, /(^|\n)\.grid\s*,/, `${page} uses .grid, so docs/style.css must style it`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('documents research workflow boundaries on the public skills page', () => {
|
|
40
|
+
const content = read('docs/skills.html');
|
|
41
|
+
assert.match(content, /Research and Planning Boundaries/);
|
|
42
|
+
assert.match(content, /\$best-practice-research[\s\S]*ordinary pre-planning wrapper/);
|
|
43
|
+
assert.match(content, /\$autoresearch[\s\S]*bounded validator-gated research deliverable/);
|
|
44
|
+
assert.match(content, /\$autoresearch-goal[\s\S]*Codex goal-mode version/);
|
|
45
|
+
assert.match(content, /Autoresearch findings gathered before planning should feed into <code>\$ralplan<\/code> as evidence/);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -6,16 +6,145 @@ import { tmpdir } from "node:os";
|
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { spawnSync } from "node:child_process";
|
|
8
8
|
|
|
9
|
-
function runDispatcher(
|
|
9
|
+
function runDispatcher(
|
|
10
|
+
metadataPath: string,
|
|
11
|
+
payload: Record<string, unknown> = { type: "test" },
|
|
12
|
+
env: NodeJS.ProcessEnv = {},
|
|
13
|
+
): void {
|
|
10
14
|
const dispatcherScript = join(process.cwd(), "dist", "scripts", "notify-dispatcher.js");
|
|
11
15
|
const result = spawnSync(
|
|
12
16
|
process.execPath,
|
|
13
|
-
[dispatcherScript, "--metadata", metadataPath, JSON.stringify(
|
|
14
|
-
{ encoding: "utf-8", windowsHide: true },
|
|
17
|
+
[dispatcherScript, "--metadata", metadataPath, JSON.stringify(payload)],
|
|
18
|
+
{ encoding: "utf-8", env: { ...process.env, ...env }, windowsHide: true },
|
|
15
19
|
);
|
|
16
20
|
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
17
21
|
}
|
|
18
22
|
|
|
23
|
+
describe("notify dispatcher turn-ended storm guard", () => {
|
|
24
|
+
it("coalesces rapid turn-ended dispatcher callbacks to one OMX notify run", () => {
|
|
25
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-rapid-"));
|
|
26
|
+
try {
|
|
27
|
+
const omxMarker = join(wd, "omx-ran");
|
|
28
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
29
|
+
writeFileSync(omxHook, `import { appendFileSync } from "node:fs"; appendFileSync(${JSON.stringify(omxMarker)}, "omx|");\n`);
|
|
30
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
31
|
+
writeFileSync(metadataPath, JSON.stringify({ managedBy: "oh-my-codex", version: 1, omxNotify: [process.execPath, omxHook] }));
|
|
32
|
+
|
|
33
|
+
for (let index = 0; index < 10; index += 1) {
|
|
34
|
+
runDispatcher(metadataPath, { type: "agent-turn-complete", thread_id: "desktop-thread", turn_id: `queued-${index}` });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "omx|");
|
|
38
|
+
} finally {
|
|
39
|
+
rmSync(wd, { recursive: true, force: true });
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("allows separate turn-ended identities to dispatch independently", () => {
|
|
44
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-identities-"));
|
|
45
|
+
try {
|
|
46
|
+
const omxMarker = join(wd, "omx-ran");
|
|
47
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
48
|
+
writeFileSync(omxHook, `import { appendFileSync } from "node:fs"; appendFileSync(${JSON.stringify(omxMarker)}, "omx|");\n`);
|
|
49
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
50
|
+
writeFileSync(metadataPath, JSON.stringify({ managedBy: "oh-my-codex", version: 1, omxNotify: [process.execPath, omxHook] }));
|
|
51
|
+
|
|
52
|
+
runDispatcher(metadataPath, { type: "agent-turn-complete", thread_id: "desktop-thread-a", turn_id: "queued-a" });
|
|
53
|
+
runDispatcher(metadataPath, { type: "agent-turn-complete", thread_id: "desktop-thread-b", turn_id: "queued-b" });
|
|
54
|
+
|
|
55
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "omx|omx|");
|
|
56
|
+
} finally {
|
|
57
|
+
rmSync(wd, { recursive: true, force: true });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("coalesces same-identity turn-ended callbacks after a slow notify hook completes", () => {
|
|
62
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-slow-"));
|
|
63
|
+
try {
|
|
64
|
+
const omxMarker = join(wd, "omx-ran");
|
|
65
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
66
|
+
writeFileSync(omxHook, `import { appendFileSync } from "node:fs"; await new Promise((resolve) => setTimeout(resolve, 1500)); appendFileSync(${JSON.stringify(omxMarker)}, "omx|");\n`);
|
|
67
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
68
|
+
writeFileSync(metadataPath, JSON.stringify({ managedBy: "oh-my-codex", version: 1, omxNotify: [process.execPath, omxHook] }));
|
|
69
|
+
const env = { OMX_NOTIFY_DISPATCH_MIN_INTERVAL_MS: "1000" };
|
|
70
|
+
|
|
71
|
+
runDispatcher(metadataPath, { type: "agent-turn-complete", thread_id: "slow-thread", turn_id: "queued-a" }, env);
|
|
72
|
+
runDispatcher(metadataPath, { type: "agent-turn-complete", thread_id: "slow-thread", turn_id: "queued-b" }, env);
|
|
73
|
+
|
|
74
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "omx|");
|
|
75
|
+
} finally {
|
|
76
|
+
rmSync(wd, { recursive: true, force: true });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("prunes expired turn-ended identity guard state", () => {
|
|
81
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-prune-"));
|
|
82
|
+
try {
|
|
83
|
+
const omxMarker = join(wd, "omx-ran");
|
|
84
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
85
|
+
writeFileSync(omxHook, `import { appendFileSync } from "node:fs"; appendFileSync(${JSON.stringify(omxMarker)}, "omx|");\n`);
|
|
86
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
87
|
+
const guardPath = join(wd, "notify-dispatch.guard.json");
|
|
88
|
+
writeFileSync(metadataPath, JSON.stringify({ managedBy: "oh-my-codex", version: 1, omxNotify: [process.execPath, omxHook] }));
|
|
89
|
+
writeFileSync(guardPath, JSON.stringify({
|
|
90
|
+
lastDispatchByIdentity: {
|
|
91
|
+
"thread_id:expired": Date.now() - 11 * 60_000,
|
|
92
|
+
"thread_id:recent": Date.now(),
|
|
93
|
+
},
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
runDispatcher(metadataPath, { type: "agent-turn-complete", thread_id: "fresh-thread", turn_id: "queued-fresh" });
|
|
97
|
+
|
|
98
|
+
const guard = JSON.parse(readFileSync(guardPath, "utf-8"));
|
|
99
|
+
assert.equal("thread_id:expired" in guard.lastDispatchByIdentity, false);
|
|
100
|
+
assert.equal(typeof guard.lastDispatchByIdentity["thread_id:recent"], "number");
|
|
101
|
+
assert.equal(typeof guard.lastDispatchByIdentity["thread_id:fresh-thread"], "number");
|
|
102
|
+
} finally {
|
|
103
|
+
rmSync(wd, { recursive: true, force: true });
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("drops stale turn-ended dispatcher callbacks before spawning notify hooks", () => {
|
|
108
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-stale-event-"));
|
|
109
|
+
try {
|
|
110
|
+
const omxMarker = join(wd, "omx-ran");
|
|
111
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
112
|
+
writeFileSync(omxHook, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(omxMarker)}, "ran");\n`);
|
|
113
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
114
|
+
writeFileSync(metadataPath, JSON.stringify({ managedBy: "oh-my-codex", version: 1, omxNotify: [process.execPath, omxHook] }));
|
|
115
|
+
|
|
116
|
+
runDispatcher(metadataPath, {
|
|
117
|
+
type: "agent-turn-complete",
|
|
118
|
+
timestamp: new Date(Date.now() - 10 * 60_000).toISOString(),
|
|
119
|
+
thread_id: "desktop-thread",
|
|
120
|
+
turn_id: "stale-turn",
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
assert.equal(existsSync(omxMarker), false);
|
|
124
|
+
} finally {
|
|
125
|
+
rmSync(wd, { recursive: true, force: true });
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("preserves normal non-turn notify dispatches", () => {
|
|
130
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-normal-"));
|
|
131
|
+
try {
|
|
132
|
+
const omxMarker = join(wd, "omx-ran");
|
|
133
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
134
|
+
writeFileSync(omxHook, `import { appendFileSync } from "node:fs"; appendFileSync(${JSON.stringify(omxMarker)}, "omx|");\n`);
|
|
135
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
136
|
+
writeFileSync(metadataPath, JSON.stringify({ managedBy: "oh-my-codex", version: 1, omxNotify: [process.execPath, omxHook] }));
|
|
137
|
+
|
|
138
|
+
runDispatcher(metadataPath, { type: "test", id: 1 });
|
|
139
|
+
runDispatcher(metadataPath, { type: "test", id: 2 });
|
|
140
|
+
|
|
141
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "omx|omx|");
|
|
142
|
+
} finally {
|
|
143
|
+
rmSync(wd, { recursive: true, force: true });
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
19
148
|
describe("notify dispatcher previousNotify guard", () => {
|
|
20
149
|
it("skips stale OMX-managed previousNotify dispatcher entries", () => {
|
|
21
150
|
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-stale-"));
|
|
@@ -147,4 +147,71 @@ describe('run-test-files diagnostics', () => {
|
|
|
147
147
|
rmSync(wd, { recursive: true, force: true });
|
|
148
148
|
}
|
|
149
149
|
});
|
|
150
|
+
|
|
151
|
+
it('sanitizes live OMX runtime state env from child test processes by default', () => {
|
|
152
|
+
const wd = mkdtempSync(join(tmpdir(), 'omx-run-test-files-'));
|
|
153
|
+
try {
|
|
154
|
+
const testsDir = join(wd, '__tests__');
|
|
155
|
+
mkdirSync(testsDir, { recursive: true });
|
|
156
|
+
writeFileSync(
|
|
157
|
+
join(testsDir, 'env-clean.test.js'),
|
|
158
|
+
[
|
|
159
|
+
"import { test } from 'node:test';",
|
|
160
|
+
"import assert from 'node:assert/strict';",
|
|
161
|
+
"test('runtime env is clean', () => {",
|
|
162
|
+
" assert.equal(process.env.OMX_ROOT, undefined);",
|
|
163
|
+
" assert.equal(process.env.OMX_STATE_ROOT, undefined);",
|
|
164
|
+
" assert.equal(process.env.OMX_TEAM_STATE_ROOT, undefined);",
|
|
165
|
+
" assert.equal(process.env.OMX_SESSION_ID, undefined);",
|
|
166
|
+
" assert.equal(process.env.CODEX_SESSION_ID, undefined);",
|
|
167
|
+
" assert.equal(process.env.SESSION_ID, undefined);",
|
|
168
|
+
"});",
|
|
169
|
+
'',
|
|
170
|
+
].join('\n'),
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const result = runCompiledRunner(wd, {
|
|
174
|
+
OMX_ROOT: '/tmp/live-omx-root',
|
|
175
|
+
OMX_STATE_ROOT: '/tmp/live-omx-state-root',
|
|
176
|
+
OMX_TEAM_STATE_ROOT: '/tmp/live-team-state-root',
|
|
177
|
+
OMX_SESSION_ID: 'live-omx-session',
|
|
178
|
+
CODEX_SESSION_ID: 'live-codex-session',
|
|
179
|
+
SESSION_ID: 'live-shell-session',
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
183
|
+
} finally {
|
|
184
|
+
rmSync(wd, { recursive: true, force: true });
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('can preserve live OMX runtime state env for explicit diagnostics', () => {
|
|
189
|
+
const wd = mkdtempSync(join(tmpdir(), 'omx-run-test-files-'));
|
|
190
|
+
try {
|
|
191
|
+
const testsDir = join(wd, '__tests__');
|
|
192
|
+
mkdirSync(testsDir, { recursive: true });
|
|
193
|
+
writeFileSync(
|
|
194
|
+
join(testsDir, 'env-preserve.test.js'),
|
|
195
|
+
[
|
|
196
|
+
"import { test } from 'node:test';",
|
|
197
|
+
"import assert from 'node:assert/strict';",
|
|
198
|
+
"test('runtime env is preserved', () => {",
|
|
199
|
+
" assert.equal(process.env.OMX_ROOT, '/tmp/live-omx-root');",
|
|
200
|
+
" assert.equal(process.env.OMX_SESSION_ID, 'live-omx-session');",
|
|
201
|
+
"});",
|
|
202
|
+
'',
|
|
203
|
+
].join('\n'),
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const result = runCompiledRunner(wd, {
|
|
207
|
+
OMX_NODE_TEST_PRESERVE_RUNTIME_ENV: '1',
|
|
208
|
+
OMX_ROOT: '/tmp/live-omx-root',
|
|
209
|
+
OMX_SESSION_ID: 'live-omx-session',
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
213
|
+
} finally {
|
|
214
|
+
rmSync(wd, { recursive: true, force: true });
|
|
215
|
+
}
|
|
216
|
+
});
|
|
150
217
|
});
|
|
@@ -174,13 +174,13 @@ describe("verify-native-agents", () => {
|
|
|
174
174
|
);
|
|
175
175
|
});
|
|
176
176
|
|
|
177
|
-
it("fails if the plugin manifest declares setup-owned native-agent fields", async () => {
|
|
177
|
+
it("allows plugin-scoped hooks but fails if the plugin manifest declares setup-owned native-agent fields", async () => {
|
|
178
178
|
await rejectsWithCode("native_agent_plugin_boundary_violation", () =>
|
|
179
179
|
verifyNativeAgents({
|
|
180
180
|
manifest: manifest([{ name: "executor", category: "build", status: "active" }]),
|
|
181
181
|
definitions: { executor: definition },
|
|
182
182
|
promptNames: new Set(["executor"]),
|
|
183
|
-
pluginManifest: { agents: "./agents/" },
|
|
183
|
+
pluginManifest: { agents: "./agents/", hooks: "./hooks/hooks.json" },
|
|
184
184
|
}),
|
|
185
185
|
);
|
|
186
186
|
|