oh-my-codex 0.16.3 → 0.16.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 +5 -5
- package/Cargo.toml +1 -1
- package/README.md +3 -3
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -0
- package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
- package/dist/cli/__tests__/cleanup.test.js +27 -0
- package/dist/cli/__tests__/cleanup.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -5
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +101 -6
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +131 -2
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +2 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +47 -0
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +2 -2
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +272 -26
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-refresh.test.js +85 -3
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +1 -1
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -1
- package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +108 -0
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +69 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +54 -8
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/cleanup.d.ts.map +1 -1
- package/dist/cli/cleanup.js +8 -4
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.d.ts +9 -0
- package/dist/cli/codex-feature-probe.d.ts.map +1 -0
- package/dist/cli/codex-feature-probe.js +28 -0
- package/dist/cli/codex-feature-probe.js.map +1 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +152 -17
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +9 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +135 -17
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.js +8 -8
- package/dist/cli/mcp-parity.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +3 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +88 -0
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +21 -0
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/setup-preferences.d.ts +4 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +7 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +5 -3
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +114 -44
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +64 -5
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +2 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +12 -3
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
- package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
- package/dist/config/__tests__/codex-feature-flags.test.js +35 -0
- package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
- package/dist/config/__tests__/codex-hooks.test.js +7 -0
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +70 -9
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +116 -11
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/__tests__/wiki-config-contract.test.js +6 -3
- package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
- package/dist/config/codex-feature-flags.d.ts +21 -0
- package/dist/config/codex-feature-flags.d.ts.map +1 -0
- package/dist/config/codex-feature-flags.js +56 -0
- package/dist/config/codex-feature-flags.js.map +1 -0
- package/dist/config/codex-hooks.d.ts +2 -0
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +25 -3
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +11 -2
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +221 -123
- package/dist/config/generator.js.map +1 -1
- package/dist/config/omx-first-party-mcp.d.ts +3 -1
- package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
- package/dist/config/omx-first-party-mcp.js +2 -2
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +92 -2
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +125 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
- package/dist/hooks/agents-overlay.js +2 -2
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +1 -0
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +7 -5
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +164 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +4 -5
- package/dist/hud/state.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +61 -0
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +166 -0
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +23 -2
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +22 -0
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/__tests__/base-tmux-pane.test.js +57 -26
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -0
- package/dist/modes/base.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +316 -0
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +481 -0
- package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
- package/dist/planning/__tests__/artifacts.test.js +533 -4
- package/dist/planning/__tests__/artifacts.test.js.map +1 -1
- package/dist/planning/__tests__/context-pack-status.test.js +524 -0
- package/dist/planning/__tests__/context-pack-status.test.js.map +1 -1
- package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
- package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
- package/dist/planning/__tests__/markdown-structure.test.js +459 -0
- package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +523 -1
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -1
- package/dist/planning/artifacts.d.ts +1 -1
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +227 -28
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/planning/context-pack-status.d.ts +25 -0
- package/dist/planning/context-pack-status.d.ts.map +1 -1
- package/dist/planning/context-pack-status.js +272 -31
- package/dist/planning/context-pack-status.js.map +1 -1
- package/dist/planning/markdown-structure.d.ts +20 -0
- package/dist/planning/markdown-structure.d.ts.map +1 -0
- package/dist/planning/markdown-structure.js +137 -0
- package/dist/planning/markdown-structure.js.map +1 -0
- package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
- package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
- package/dist/ralph/__tests__/completion-audit.test.js +121 -0
- package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
- package/dist/ralph/completion-audit.d.ts +8 -0
- package/dist/ralph/completion-audit.d.ts.map +1 -0
- package/dist/ralph/completion-audit.js +99 -0
- package/dist/ralph/completion-audit.js.map +1 -0
- package/dist/scripts/__tests__/codex-native-hook.test.js +220 -13
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js +126 -0
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +133 -54
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +4 -2
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/notify-dispatcher.js +30 -1
- package/dist/scripts/notify-dispatcher.js.map +1 -1
- package/dist/scripts/notify-hook.js +3 -1
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +102 -27
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +9 -3
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +7 -0
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +25 -8
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts +1 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +22 -15
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.js +3 -3
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js +39 -0
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +5 -0
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +497 -2
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +1 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +8 -0
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/approved-execution.d.ts.map +1 -1
- package/dist/team/approved-execution.js +3 -0
- package/dist/team/approved-execution.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +43 -0
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +4 -0
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +2 -6
- package/dist/team/state.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +124 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +21 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +44 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +197 -13
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/wiki/lifecycle.js +1 -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/.mcp.json +5 -5
- package/plugins/oh-my-codex/skills/analyze/SKILL.md +0 -2
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -3
- package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +5 -7
- package/plugins/oh-my-codex/skills/doctor/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/pipeline/SKILL.md +3 -3
- package/plugins/oh-my-codex/skills/plan/SKILL.md +3 -6
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +9 -10
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +21 -24
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
- package/plugins/oh-my-codex/skills/wiki/SKILL.md +13 -13
- package/skills/analyze/SKILL.md +0 -2
- package/skills/ask-claude/SKILL.md +5 -3
- package/skills/ask-gemini/SKILL.md +5 -3
- package/skills/autopilot/SKILL.md +2 -2
- package/skills/code-review/SKILL.md +1 -3
- package/skills/deep-interview/SKILL.md +5 -7
- package/skills/doctor/SKILL.md +2 -2
- package/skills/ecomode/SKILL.md +105 -1
- package/skills/frontend-ui-ux/SKILL.md +4 -26
- package/skills/git-master/SKILL.md +2 -4
- package/skills/omx-setup/SKILL.md +3 -3
- package/skills/pipeline/SKILL.md +3 -3
- package/skills/plan/SKILL.md +3 -6
- package/skills/ralph/SKILL.md +9 -10
- package/skills/swarm/SKILL.md +5 -3
- package/skills/tdd/SKILL.md +95 -1
- package/skills/ultragoal/SKILL.md +36 -3
- package/skills/ultraqa/SKILL.md +21 -24
- package/skills/ultrawork/SKILL.md +8 -8
- package/skills/web-clone/SKILL.md +348 -1
- package/skills/wiki/SKILL.md +13 -13
- package/src/scripts/__tests__/codex-native-hook.test.ts +231 -13
- package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
- package/src/scripts/codex-native-hook.ts +160 -43
- package/src/scripts/codex-native-pre-post.ts +4 -1
- package/src/scripts/notify-dispatcher.ts +40 -1
- package/src/scripts/notify-hook.ts +3 -1
|
@@ -24,6 +24,7 @@ import { writeSessionStart } from "../../hooks/session.js";
|
|
|
24
24
|
import { resetTriageConfigCache } from "../../hooks/triage-config.js";
|
|
25
25
|
import { executeStateOperation } from "../../state/operations.js";
|
|
26
26
|
import { OMX_TMUX_HUD_OWNER_ENV } from "../../hud/reconcile.js";
|
|
27
|
+
import { readAllState } from "../../hud/state.js";
|
|
27
28
|
import { writePage } from "../../wiki/storage.js";
|
|
28
29
|
import { WIKI_SCHEMA_VERSION } from "../../wiki/types.js";
|
|
29
30
|
|
|
@@ -236,7 +237,7 @@ describe("codex native hook config", () => {
|
|
|
236
237
|
matcher?: string;
|
|
237
238
|
hooks?: Array<Record<string, unknown>>;
|
|
238
239
|
};
|
|
239
|
-
assert.equal(sessionStart.matcher, "startup|resume");
|
|
240
|
+
assert.equal(sessionStart.matcher, "startup|resume|clear");
|
|
240
241
|
assert.equal(sessionStart.hooks?.[0]?.statusMessage, undefined);
|
|
241
242
|
|
|
242
243
|
const preToolUse = config.hooks.PreToolUse[0] as {
|
|
@@ -1217,7 +1218,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1217
1218
|
assert.equal(result.omxEventName, "keyword-detector");
|
|
1218
1219
|
assert.equal(result.skillState?.skill, "ralplan");
|
|
1219
1220
|
assert.ok(result.outputJson, "UserPromptSubmit should emit developer context");
|
|
1220
|
-
assert.match(JSON.stringify(result.outputJson), /
|
|
1221
|
+
assert.match(JSON.stringify(result.outputJson), /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1221
1222
|
|
|
1222
1223
|
assert.equal(
|
|
1223
1224
|
existsSync(join(cwd, ".omx", "state", "skill-active-state.json")),
|
|
@@ -1240,6 +1241,112 @@ describe("codex native hook dispatch", () => {
|
|
|
1240
1241
|
}
|
|
1241
1242
|
});
|
|
1242
1243
|
|
|
1244
|
+
it("records boxed keyword activation mode detail and skill state under OMX_ROOT", async () => {
|
|
1245
|
+
const root = await mkdtemp(join(tmpdir(), "omx-native-hook-boxed-"));
|
|
1246
|
+
const cwd = join(root, "source");
|
|
1247
|
+
const omxRoot = join(root, "box");
|
|
1248
|
+
const sessionId = "sess-boxed-ralplan";
|
|
1249
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
1250
|
+
const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
|
|
1251
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
1252
|
+
const previousOmxSessionId = process.env.OMX_SESSION_ID;
|
|
1253
|
+
try {
|
|
1254
|
+
await mkdir(cwd, { recursive: true });
|
|
1255
|
+
process.env.OMX_ROOT = omxRoot;
|
|
1256
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1257
|
+
delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1258
|
+
process.env.OMX_SESSION_ID = sessionId;
|
|
1259
|
+
|
|
1260
|
+
const result = await dispatchCodexNativeHook(
|
|
1261
|
+
{
|
|
1262
|
+
hook_event_name: "UserPromptSubmit",
|
|
1263
|
+
cwd,
|
|
1264
|
+
session_id: sessionId,
|
|
1265
|
+
thread_id: "thread-boxed",
|
|
1266
|
+
turn_id: "turn-boxed",
|
|
1267
|
+
prompt: "$ralplan implement issue #1307",
|
|
1268
|
+
},
|
|
1269
|
+
{ cwd },
|
|
1270
|
+
);
|
|
1271
|
+
|
|
1272
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
1273
|
+
assert.equal(result.skillState?.skill, "ralplan");
|
|
1274
|
+
|
|
1275
|
+
const boxedSessionDir = join(omxRoot, ".omx", "state", "sessions", sessionId);
|
|
1276
|
+
assert.equal(existsSync(join(boxedSessionDir, "skill-active-state.json")), true);
|
|
1277
|
+
assert.equal(existsSync(join(boxedSessionDir, "ralplan-state.json")), true);
|
|
1278
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "skill-active-state.json")), false);
|
|
1279
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "ralplan-state.json")), false);
|
|
1280
|
+
|
|
1281
|
+
const hudState = await readAllState(cwd);
|
|
1282
|
+
assert.equal(hudState.ralplan?.active, true);
|
|
1283
|
+
assert.equal(hudState.ralplan?.current_phase, "planning");
|
|
1284
|
+
} finally {
|
|
1285
|
+
if (typeof previousOmxRoot === "string") process.env.OMX_ROOT = previousOmxRoot;
|
|
1286
|
+
else delete process.env.OMX_ROOT;
|
|
1287
|
+
if (typeof previousOmxStateRoot === "string") process.env.OMX_STATE_ROOT = previousOmxStateRoot;
|
|
1288
|
+
else delete process.env.OMX_STATE_ROOT;
|
|
1289
|
+
if (typeof previousTeamStateRoot === "string") process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
1290
|
+
else delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1291
|
+
if (typeof previousOmxSessionId === "string") process.env.OMX_SESSION_ID = previousOmxSessionId;
|
|
1292
|
+
else delete process.env.OMX_SESSION_ID;
|
|
1293
|
+
await rm(root, { recursive: true, force: true });
|
|
1294
|
+
}
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
it("records native keyword activation mode detail and skill state under OMX_TEAM_STATE_ROOT", async () => {
|
|
1298
|
+
const root = await mkdtemp(join(tmpdir(), "omx-native-hook-team-root-"));
|
|
1299
|
+
const cwd = join(root, "source");
|
|
1300
|
+
const teamStateRoot = join(root, "team-state");
|
|
1301
|
+
const sessionId = "sess-team-root-ralplan";
|
|
1302
|
+
const previousOmxRoot = process.env.OMX_ROOT;
|
|
1303
|
+
const previousOmxStateRoot = process.env.OMX_STATE_ROOT;
|
|
1304
|
+
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
1305
|
+
const previousOmxSessionId = process.env.OMX_SESSION_ID;
|
|
1306
|
+
try {
|
|
1307
|
+
await mkdir(cwd, { recursive: true });
|
|
1308
|
+
delete process.env.OMX_ROOT;
|
|
1309
|
+
delete process.env.OMX_STATE_ROOT;
|
|
1310
|
+
process.env.OMX_TEAM_STATE_ROOT = teamStateRoot;
|
|
1311
|
+
process.env.OMX_SESSION_ID = sessionId;
|
|
1312
|
+
|
|
1313
|
+
const result = await dispatchCodexNativeHook(
|
|
1314
|
+
{
|
|
1315
|
+
hook_event_name: "UserPromptSubmit",
|
|
1316
|
+
cwd,
|
|
1317
|
+
session_id: sessionId,
|
|
1318
|
+
thread_id: "thread-team-root",
|
|
1319
|
+
turn_id: "turn-team-root",
|
|
1320
|
+
prompt: "$ralplan implement issue #1307",
|
|
1321
|
+
},
|
|
1322
|
+
{ cwd },
|
|
1323
|
+
);
|
|
1324
|
+
|
|
1325
|
+
assert.equal(result.omxEventName, "keyword-detector");
|
|
1326
|
+
assert.equal(result.skillState?.skill, "ralplan");
|
|
1327
|
+
|
|
1328
|
+
const teamSessionDir = join(teamStateRoot, "sessions", sessionId);
|
|
1329
|
+
assert.equal(existsSync(join(teamSessionDir, "skill-active-state.json")), true);
|
|
1330
|
+
assert.equal(existsSync(join(teamSessionDir, "ralplan-state.json")), true);
|
|
1331
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "skill-active-state.json")), false);
|
|
1332
|
+
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", sessionId, "ralplan-state.json")), false);
|
|
1333
|
+
|
|
1334
|
+
const hudState = await readAllState(cwd);
|
|
1335
|
+
assert.equal(hudState.ralplan?.active, true);
|
|
1336
|
+
assert.equal(hudState.ralplan?.current_phase, "planning");
|
|
1337
|
+
} finally {
|
|
1338
|
+
if (typeof previousOmxRoot === "string") process.env.OMX_ROOT = previousOmxRoot;
|
|
1339
|
+
else delete process.env.OMX_ROOT;
|
|
1340
|
+
if (typeof previousOmxStateRoot === "string") process.env.OMX_STATE_ROOT = previousOmxStateRoot;
|
|
1341
|
+
else delete process.env.OMX_STATE_ROOT;
|
|
1342
|
+
if (typeof previousTeamStateRoot === "string") process.env.OMX_TEAM_STATE_ROOT = previousTeamStateRoot;
|
|
1343
|
+
else delete process.env.OMX_TEAM_STATE_ROOT;
|
|
1344
|
+
if (typeof previousOmxSessionId === "string") process.env.OMX_SESSION_ID = previousOmxSessionId;
|
|
1345
|
+
else delete process.env.OMX_SESSION_ID;
|
|
1346
|
+
await rm(root, { recursive: true, force: true });
|
|
1347
|
+
}
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1243
1350
|
it("warns completion-like prompts when active goal workflows need Codex snapshot reconciliation", async () => {
|
|
1244
1351
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-goal-warning-"));
|
|
1245
1352
|
try {
|
|
@@ -1474,7 +1581,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1474
1581
|
(result.outputJson as { hookSpecificOutput?: { additionalContext?: string } })?.hookSpecificOutput?.additionalContext || "",
|
|
1475
1582
|
);
|
|
1476
1583
|
assert.match(message, /\$oh-my-codex:ralplan" -> ralplan/);
|
|
1477
|
-
assert.match(message, /
|
|
1584
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1478
1585
|
assert.equal(existsSync(join(cwd, ".omx", "state", "sessions", "sess-plugin-1", "ralplan-state.json")), true);
|
|
1479
1586
|
} finally {
|
|
1480
1587
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -1691,7 +1798,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1691
1798
|
(result.outputJson as { hookSpecificOutput?: { additionalContext?: string } })?.hookSpecificOutput?.additionalContext || "",
|
|
1692
1799
|
);
|
|
1693
1800
|
assert.match(message, /\$ralph" -> ralph/);
|
|
1694
|
-
assert.match(message, /
|
|
1801
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1695
1802
|
assert.match(message, /Prompt-side `\$ralph` activation seeds Ralph workflow state only; it does not invoke `omx ralph`\./);
|
|
1696
1803
|
assert.match(message, /Use `omx ralph --prd \.\.\.` only when you explicitly want the PRD-gated CLI startup path\./);
|
|
1697
1804
|
} finally {
|
|
@@ -1721,7 +1828,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1721
1828
|
(result.outputJson as { hookSpecificOutput?: { additionalContext?: string } })?.hookSpecificOutput?.additionalContext || "",
|
|
1722
1829
|
);
|
|
1723
1830
|
assert.match(message, /\$oh-my-codex:ralph" -> ralph/);
|
|
1724
|
-
assert.match(message, /
|
|
1831
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1725
1832
|
assert.match(message, /Prompt-side `\$ralph` activation seeds Ralph workflow state only; it does not invoke `omx ralph`\./);
|
|
1726
1833
|
} finally {
|
|
1727
1834
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -1803,7 +1910,7 @@ describe("codex native hook dispatch", () => {
|
|
|
1803
1910
|
(result.outputJson as { hookSpecificOutput?: { additionalContext?: string } })?.hookSpecificOutput?.additionalContext || "",
|
|
1804
1911
|
);
|
|
1805
1912
|
assert.match(message, /\$deep-interview" -> deep-interview/);
|
|
1806
|
-
assert.match(message, /
|
|
1913
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
1807
1914
|
assert.match(message, /Deep-interview is active, but this session is not attached to tmux/);
|
|
1808
1915
|
assert.match(message, /Do not invoke `omx question`, `omx hud`, or `omx team`/);
|
|
1809
1916
|
assert.match(message, /native structured question tool when available/);
|
|
@@ -2279,8 +2386,11 @@ export async function onHookEvent(event) {
|
|
|
2279
2386
|
|
|
2280
2387
|
assert.match(JSON.stringify(denied.outputJson), /denied workflow keyword/i);
|
|
2281
2388
|
assert.match(JSON.stringify(denied.outputJson), /Unsupported workflow overlap: team \+ autopilot\./);
|
|
2282
|
-
assert.match(JSON.stringify(denied.outputJson),
|
|
2283
|
-
assert.match(JSON.stringify(denied.outputJson),
|
|
2389
|
+
assert.match(JSON.stringify(denied.outputJson), /omx state clear --input/);
|
|
2390
|
+
assert.match(JSON.stringify(denied.outputJson), /mode\\":\\"<mode>/);
|
|
2391
|
+
assert.match(JSON.stringify(denied.outputJson), /--json/);
|
|
2392
|
+
assert.match(JSON.stringify(denied.outputJson), /explicit MCP compatibility is enabled/);
|
|
2393
|
+
assert.match(JSON.stringify(denied.outputJson), /`omx_state\.\*` tools/);
|
|
2284
2394
|
assert.equal(
|
|
2285
2395
|
existsSync(join(cwd, ".omx", "state", "sessions", "sess-deny-1", "autopilot-state.json")),
|
|
2286
2396
|
false,
|
|
@@ -2357,7 +2467,7 @@ export async function onHookEvent(event) {
|
|
|
2357
2467
|
assert.match(message, /\$ralph" -> ralph/);
|
|
2358
2468
|
assert.doesNotMatch(message, /mode transiting:/);
|
|
2359
2469
|
assert.match(message, /planning preserved over simultaneous execution follow-up; deferred skills: team, ralph\./);
|
|
2360
|
-
assert.match(message, /
|
|
2470
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
2361
2471
|
assert.doesNotMatch(message, /Use the durable OMX team runtime via `omx team \.\.\.`/);
|
|
2362
2472
|
} finally {
|
|
2363
2473
|
await rm(cwd, { recursive: true, force: true });
|
|
@@ -2389,7 +2499,7 @@ export async function onHookEvent(event) {
|
|
|
2389
2499
|
assert.match(message, /\$oh-my-codex:ralph" -> ralph/);
|
|
2390
2500
|
assert.doesNotMatch(message, /mode transiting:/);
|
|
2391
2501
|
assert.match(message, /planning preserved over simultaneous execution follow-up; deferred skills: team, ralph\./);
|
|
2392
|
-
assert.match(message, /
|
|
2502
|
+
assert.match(message, /use CLI-first state updates via `omx state write\/read\/clear --input '<json>' --json`/);
|
|
2393
2503
|
} finally {
|
|
2394
2504
|
await rm(cwd, { recursive: true, force: true });
|
|
2395
2505
|
}
|
|
@@ -4499,7 +4609,7 @@ exit 0
|
|
|
4499
4609
|
);
|
|
4500
4610
|
assert.match(
|
|
4501
4611
|
additionalContext,
|
|
4502
|
-
/omx state
|
|
4612
|
+
/omx state write --input/,
|
|
4503
4613
|
);
|
|
4504
4614
|
assert.match(
|
|
4505
4615
|
additionalContext,
|
|
@@ -4747,7 +4857,7 @@ exit 0
|
|
|
4747
4857
|
assert.equal(hookSpecificOutput?.hookEventName, "PostToolUse");
|
|
4748
4858
|
assert.match(
|
|
4749
4859
|
String(hookSpecificOutput?.additionalContext || ""),
|
|
4750
|
-
/Retry via CLI parity with `omx state
|
|
4860
|
+
/Retry via CLI parity with `omx state write --input '\{\}' --json`\./,
|
|
4751
4861
|
);
|
|
4752
4862
|
assert.match(
|
|
4753
4863
|
String(hookSpecificOutput?.additionalContext || ""),
|
|
@@ -4833,7 +4943,7 @@ exit 0
|
|
|
4833
4943
|
hookSpecificOutput: {
|
|
4834
4944
|
hookEventName: "PostToolUse",
|
|
4835
4945
|
additionalContext:
|
|
4836
|
-
"Clear MCP transport-death signal detected. Preserve current team/runtime state. Retry via CLI parity with `omx state
|
|
4946
|
+
"Clear MCP transport-death signal detected. Preserve current team/runtime state. Retry via CLI parity with `omx state write --input '{\"mode\":\"team\",\"active\":true}' --json`. OMX MCP servers are plain Node stdio processes, so they still shut down when stdin/transport closes. If this happened during team runtime, inspect first with `omx team status <team>` or `omx team api read-stall-state --input '{\"team_name\":\"<team>\"}' --json`, and only force cleanup after capturing needed state. For root-cause debugging, rerun with `OMX_MCP_TRANSPORT_DEBUG=1` to log why the stdio transport closed.",
|
|
4837
4947
|
},
|
|
4838
4948
|
});
|
|
4839
4949
|
|
|
@@ -6253,6 +6363,41 @@ exit 0
|
|
|
6253
6363
|
}
|
|
6254
6364
|
});
|
|
6255
6365
|
|
|
6366
|
+
it("ignores stale source-root team Stop fallback when OMX_TEAM_STATE_ROOT is authoritative", async () => {
|
|
6367
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-team-stale-source-root-"));
|
|
6368
|
+
const teamStateRoot = join(cwd, "shared-team-state");
|
|
6369
|
+
const priorTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
6370
|
+
try {
|
|
6371
|
+
process.env.OMX_TEAM_STATE_ROOT = teamStateRoot;
|
|
6372
|
+
await mkdir(join(cwd, ".omx", "state"), { recursive: true });
|
|
6373
|
+
await mkdir(join(teamStateRoot, "team", "stale-source-team"), { recursive: true });
|
|
6374
|
+
await writeJson(join(cwd, ".omx", "state", "team-state.json"), {
|
|
6375
|
+
active: true,
|
|
6376
|
+
team_name: "stale-source-team",
|
|
6377
|
+
current_phase: "team-exec",
|
|
6378
|
+
});
|
|
6379
|
+
await writeJson(join(teamStateRoot, "team", "stale-source-team", "phase.json"), {
|
|
6380
|
+
current_phase: "team-exec",
|
|
6381
|
+
});
|
|
6382
|
+
|
|
6383
|
+
const result = await dispatchCodexNativeHook(
|
|
6384
|
+
{
|
|
6385
|
+
hook_event_name: "Stop",
|
|
6386
|
+
cwd,
|
|
6387
|
+
session_id: "sess-stale-source-team",
|
|
6388
|
+
},
|
|
6389
|
+
{ cwd },
|
|
6390
|
+
);
|
|
6391
|
+
|
|
6392
|
+
assert.equal(result.omxEventName, "stop");
|
|
6393
|
+
assert.equal(result.outputJson, null);
|
|
6394
|
+
} finally {
|
|
6395
|
+
if (typeof priorTeamStateRoot === "string") process.env.OMX_TEAM_STATE_ROOT = priorTeamStateRoot;
|
|
6396
|
+
else delete process.env.OMX_TEAM_STATE_ROOT;
|
|
6397
|
+
await rm(cwd, { recursive: true, force: true });
|
|
6398
|
+
}
|
|
6399
|
+
});
|
|
6400
|
+
|
|
6256
6401
|
it("returns Stop continuation output from canonical team state rooted via OMX_TEAM_STATE_ROOT", async () => {
|
|
6257
6402
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-team-env-root-"));
|
|
6258
6403
|
const previousTeamStateRoot = process.env.OMX_TEAM_STATE_ROOT;
|
|
@@ -7288,6 +7433,79 @@ exit 0
|
|
|
7288
7433
|
}
|
|
7289
7434
|
});
|
|
7290
7435
|
|
|
7436
|
+
it("blocks Codex App Stop when Ralph is marked complete without completion-audit evidence", async () => {
|
|
7437
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralph-complete-audit-missing-"));
|
|
7438
|
+
try {
|
|
7439
|
+
const sessionId = "sess-ralph-complete-missing";
|
|
7440
|
+
const statePath = join(cwd, ".omx", "state", "sessions", sessionId, "ralph-state.json");
|
|
7441
|
+
await writeJson(join(cwd, ".omx", "state", "session.json"), { session_id: sessionId, native_session_id: sessionId, cwd });
|
|
7442
|
+
await writeJson(statePath, {
|
|
7443
|
+
active: false,
|
|
7444
|
+
mode: "ralph",
|
|
7445
|
+
current_phase: "complete",
|
|
7446
|
+
session_id: sessionId,
|
|
7447
|
+
completed_at: "2026-05-10T12:00:00.000Z",
|
|
7448
|
+
});
|
|
7449
|
+
|
|
7450
|
+
const result = await dispatchCodexNativeHook(
|
|
7451
|
+
{
|
|
7452
|
+
hook_event_name: "Stop",
|
|
7453
|
+
cwd,
|
|
7454
|
+
session_id: sessionId,
|
|
7455
|
+
last_assistant_message: "Done. Ralph complete.",
|
|
7456
|
+
},
|
|
7457
|
+
{ cwd },
|
|
7458
|
+
);
|
|
7459
|
+
|
|
7460
|
+
assert.equal(result.omxEventName, "stop");
|
|
7461
|
+
assert.match(String(result.outputJson?.reason), /Ralph completion audit is missing required evidence/);
|
|
7462
|
+
assert.equal(result.outputJson?.stopReason, "ralph_completion_audit_missing_completion_audit");
|
|
7463
|
+
const reopened = JSON.parse(await readFile(statePath, "utf-8")) as Record<string, unknown>;
|
|
7464
|
+
assert.equal(reopened.active, true);
|
|
7465
|
+
assert.equal(reopened.current_phase, "verifying");
|
|
7466
|
+
assert.equal(reopened.completion_audit_gate, "blocked");
|
|
7467
|
+
assert.equal(reopened.completion_audit_missing_reason, "missing_completion_audit");
|
|
7468
|
+
assert.equal(typeof reopened.completed_at, "undefined");
|
|
7469
|
+
} finally {
|
|
7470
|
+
await rm(cwd, { recursive: true, force: true });
|
|
7471
|
+
}
|
|
7472
|
+
});
|
|
7473
|
+
|
|
7474
|
+
it("allows Codex App Stop when complete Ralph state carries checklist and verification evidence", async () => {
|
|
7475
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-ralph-complete-audit-present-"));
|
|
7476
|
+
try {
|
|
7477
|
+
const sessionId = "sess-ralph-complete-present";
|
|
7478
|
+
await writeJson(join(cwd, ".omx", "state", "session.json"), { session_id: sessionId, native_session_id: sessionId, cwd });
|
|
7479
|
+
await writeJson(join(cwd, ".omx", "state", "sessions", sessionId, "ralph-state.json"), {
|
|
7480
|
+
active: false,
|
|
7481
|
+
mode: "ralph",
|
|
7482
|
+
current_phase: "complete",
|
|
7483
|
+
session_id: sessionId,
|
|
7484
|
+
completed_at: "2026-05-10T12:00:00.000Z",
|
|
7485
|
+
completion_audit: {
|
|
7486
|
+
passed: true,
|
|
7487
|
+
prompt_to_artifact_checklist: ["issue #2260 fixed", "tests added"],
|
|
7488
|
+
verification_evidence: ["node --test dist/scripts/__tests__/codex-native-hook.test.js"],
|
|
7489
|
+
},
|
|
7490
|
+
});
|
|
7491
|
+
|
|
7492
|
+
const result = await dispatchCodexNativeHook(
|
|
7493
|
+
{
|
|
7494
|
+
hook_event_name: "Stop",
|
|
7495
|
+
cwd,
|
|
7496
|
+
session_id: sessionId,
|
|
7497
|
+
last_assistant_message: "Done with completion audit evidence recorded.",
|
|
7498
|
+
},
|
|
7499
|
+
{ cwd },
|
|
7500
|
+
);
|
|
7501
|
+
|
|
7502
|
+
assert.equal(result.omxEventName, "stop");
|
|
7503
|
+
assert.equal(result.outputJson, null);
|
|
7504
|
+
} finally {
|
|
7505
|
+
await rm(cwd, { recursive: true, force: true });
|
|
7506
|
+
}
|
|
7507
|
+
});
|
|
7508
|
+
|
|
7291
7509
|
it("returns Stop continuation output while Ralph is active without an explicit session pin", async () => {
|
|
7292
7510
|
const cwd = await mkdtemp(join(tmpdir(), "omx-native-hook-stop-"));
|
|
7293
7511
|
try {
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
|
|
9
|
+
function runDispatcher(metadataPath: string): void {
|
|
10
|
+
const dispatcherScript = join(process.cwd(), "dist", "scripts", "notify-dispatcher.js");
|
|
11
|
+
const result = spawnSync(
|
|
12
|
+
process.execPath,
|
|
13
|
+
[dispatcherScript, "--metadata", metadataPath, JSON.stringify({ type: "test" })],
|
|
14
|
+
{ encoding: "utf-8", windowsHide: true },
|
|
15
|
+
);
|
|
16
|
+
assert.equal(result.status, 0, result.stderr || result.stdout);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("notify dispatcher previousNotify guard", () => {
|
|
20
|
+
it("skips stale OMX-managed previousNotify dispatcher entries", () => {
|
|
21
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-stale-"));
|
|
22
|
+
try {
|
|
23
|
+
const oldPkgScripts = join(wd, "global", "oh-my-codex", "dist", "scripts");
|
|
24
|
+
mkdirSync(oldPkgScripts, { recursive: true });
|
|
25
|
+
const stalePreviousMarker = join(wd, "stale-previous-ran");
|
|
26
|
+
const omxMarker = join(wd, "omx-ran");
|
|
27
|
+
const staleDispatcher = join(oldPkgScripts, "notify-dispatcher.js");
|
|
28
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
29
|
+
writeFileSync(staleDispatcher, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(stalePreviousMarker)}, "ran");\n`);
|
|
30
|
+
writeFileSync(omxHook, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(omxMarker)}, "ran");\n`);
|
|
31
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
32
|
+
writeFileSync(
|
|
33
|
+
metadataPath,
|
|
34
|
+
JSON.stringify({
|
|
35
|
+
managedBy: "oh-my-codex",
|
|
36
|
+
version: 1,
|
|
37
|
+
previousNotify: [process.execPath, staleDispatcher, "--metadata", metadataPath],
|
|
38
|
+
omxNotify: [process.execPath, omxHook],
|
|
39
|
+
dispatcherNotify: [
|
|
40
|
+
process.execPath,
|
|
41
|
+
join(process.cwd(), "dist", "scripts", "notify-dispatcher.js"),
|
|
42
|
+
"--metadata",
|
|
43
|
+
metadataPath,
|
|
44
|
+
],
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
runDispatcher(metadataPath);
|
|
49
|
+
|
|
50
|
+
assert.equal(existsSync(stalePreviousMarker), false);
|
|
51
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "ran");
|
|
52
|
+
} finally {
|
|
53
|
+
rmSync(wd, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("skips stale OMX-managed previousNotify dispatcher entries behind node flags", () => {
|
|
58
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-flagged-stale-"));
|
|
59
|
+
try {
|
|
60
|
+
const oldPkgScripts = join(wd, "global", "oh-my-codex", "dist", "scripts");
|
|
61
|
+
mkdirSync(oldPkgScripts, { recursive: true });
|
|
62
|
+
const stalePreviousMarker = join(wd, "stale-previous-ran");
|
|
63
|
+
const omxMarker = join(wd, "omx-ran");
|
|
64
|
+
const staleDispatcher = join(oldPkgScripts, "notify-dispatcher.js");
|
|
65
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
66
|
+
writeFileSync(staleDispatcher, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(stalePreviousMarker)}, "ran");\n`);
|
|
67
|
+
writeFileSync(omxHook, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(omxMarker)}, "ran");\n`);
|
|
68
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
69
|
+
writeFileSync(
|
|
70
|
+
metadataPath,
|
|
71
|
+
JSON.stringify({
|
|
72
|
+
managedBy: "oh-my-codex",
|
|
73
|
+
version: 1,
|
|
74
|
+
previousNotify: [
|
|
75
|
+
process.execPath,
|
|
76
|
+
"--no-warnings",
|
|
77
|
+
staleDispatcher,
|
|
78
|
+
"--metadata",
|
|
79
|
+
metadataPath,
|
|
80
|
+
],
|
|
81
|
+
omxNotify: [process.execPath, omxHook],
|
|
82
|
+
}),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
runDispatcher(metadataPath);
|
|
86
|
+
|
|
87
|
+
assert.equal(existsSync(stalePreviousMarker), false);
|
|
88
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "ran");
|
|
89
|
+
} finally {
|
|
90
|
+
rmSync(wd, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("preserves and runs real user previousNotify entries", () => {
|
|
95
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-user-"));
|
|
96
|
+
try {
|
|
97
|
+
const userMarker = join(wd, "user-ran");
|
|
98
|
+
const omxMarker = join(wd, "omx-ran");
|
|
99
|
+
const userScript = join(wd, "user-notify.js");
|
|
100
|
+
const omxHook = join(wd, "current-notify-hook.js");
|
|
101
|
+
writeFileSync(userScript, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(userMarker)}, "ran");\n`);
|
|
102
|
+
writeFileSync(omxHook, `import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(omxMarker)}, "ran");\n`);
|
|
103
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
104
|
+
writeFileSync(
|
|
105
|
+
metadataPath,
|
|
106
|
+
JSON.stringify({
|
|
107
|
+
managedBy: "oh-my-codex",
|
|
108
|
+
version: 1,
|
|
109
|
+
previousNotify: [process.execPath, userScript],
|
|
110
|
+
omxNotify: [process.execPath, omxHook],
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
runDispatcher(metadataPath);
|
|
115
|
+
|
|
116
|
+
assert.equal(readFileSync(userMarker, "utf-8"), "ran");
|
|
117
|
+
assert.equal(readFileSync(omxMarker, "utf-8"), "ran");
|
|
118
|
+
} finally {
|
|
119
|
+
rmSync(wd, { recursive: true, force: true });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("does not mistake real user notify arguments for managed entrypoints", () => {
|
|
124
|
+
const wd = mkdtempSync(join(tmpdir(), "omx-notify-dispatcher-user-arg-"));
|
|
125
|
+
try {
|
|
126
|
+
const userMarker = join(wd, "user-ran");
|
|
127
|
+
const userScript = join(wd, "user-notify.js");
|
|
128
|
+
writeFileSync(
|
|
129
|
+
userScript,
|
|
130
|
+
`import { writeFileSync } from "node:fs"; writeFileSync(${JSON.stringify(userMarker)}, process.argv.slice(2).join("\\n"));\n`,
|
|
131
|
+
);
|
|
132
|
+
const metadataPath = join(wd, "notify-dispatch.json");
|
|
133
|
+
writeFileSync(
|
|
134
|
+
metadataPath,
|
|
135
|
+
JSON.stringify({
|
|
136
|
+
managedBy: "oh-my-codex",
|
|
137
|
+
version: 1,
|
|
138
|
+
previousNotify: [
|
|
139
|
+
process.execPath,
|
|
140
|
+
userScript,
|
|
141
|
+
"/opt/homebrew/lib/node_modules/oh-my-codex/dist/scripts/notify-hook.js",
|
|
142
|
+
],
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
runDispatcher(metadataPath);
|
|
147
|
+
|
|
148
|
+
assert.match(readFileSync(userMarker, "utf-8"), /notify-hook\.js/);
|
|
149
|
+
} finally {
|
|
150
|
+
rmSync(wd, { recursive: true, force: true });
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|