oh-my-codex 0.16.3 → 0.17.0
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__/generator.test.js +2 -0
- package/dist/catalog/__tests__/generator.test.js.map +1 -1
- 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 +175 -7
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +147 -12
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-serve.test.js +4 -0
- package/dist/cli/__tests__/mcp-serve.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 +10 -5
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +299 -27
- 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 +91 -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 +214 -23
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +17 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +152 -24
- 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/mcp-serve.d.ts.map +1 -1
- package/dist/cli/mcp-serve.js +4 -0
- package/dist/cli/mcp-serve.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +23 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +203 -1
- 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 +140 -51
- 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 +70 -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 +143 -9
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +85 -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 +14 -13
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +108 -8
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +15 -3
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +233 -129
- 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 +9 -2
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/hooks/__tests__/design-skill.test.d.ts +2 -0
- package/dist/hooks/__tests__/design-skill.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/design-skill.test.js +55 -0
- package/dist/hooks/__tests__/design-skill.test.js.map +1 -0
- 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__/notify-hook-tmux-heal.test.js +265 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.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/__tests__/skill-guidance-contract.test.js +41 -0
- package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
- 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 +12 -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 +2 -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 +47 -2
- package/dist/hooks/prompt-guidance-contract.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__/bootstrap.test.js +3 -0
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/hermes-bridge.test.d.ts +2 -0
- package/dist/mcp/__tests__/hermes-bridge.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/hermes-bridge.test.js +374 -0
- package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -0
- package/dist/mcp/__tests__/state-paths.test.js +155 -11
- 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/bootstrap.d.ts +1 -1
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +2 -0
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/hermes-bridge.d.ts +81 -0
- package/dist/mcp/hermes-bridge.d.ts.map +1 -0
- package/dist/mcp/hermes-bridge.js +400 -0
- package/dist/mcp/hermes-bridge.js.map +1 -0
- package/dist/mcp/hermes-server.d.ts +269 -0
- package/dist/mcp/hermes-server.d.ts.map +1 -0
- package/dist/mcp/hermes-server.js +121 -0
- package/dist/mcp/hermes-server.js.map +1 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +64 -11
- 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 +88 -27
- 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 +407 -15
- 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 +1 -0
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +177 -71
- 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/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +91 -2
- package/dist/scripts/notify-hook/tmux-injection.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/mode-state-context.d.ts +2 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +21 -0
- package/dist/state/mode-state-context.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 +245 -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 +52 -2
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +301 -15
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/utils/__tests__/paths.test.js +31 -1
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/paths.d.ts +6 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +18 -0
- package/dist/utils/paths.js.map +1 -1
- package/dist/wiki/lifecycle.js +4 -4
- 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 +13 -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/design/SKILL.md +180 -0
- 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/skill/SKILL.md +2 -1
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
- package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +175 -64
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
- package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +2 -2
- 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/design/SKILL.md +180 -0
- package/skills/doctor/SKILL.md +2 -2
- package/skills/ecomode/SKILL.md +105 -1
- package/skills/frontend-ui-ux/SKILL.md +6 -24
- 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/skill/SKILL.md +2 -1
- 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 +175 -64
- package/skills/ultrawork/SKILL.md +8 -8
- package/skills/visual-ralph/SKILL.md +2 -2
- package/skills/web-clone/SKILL.md +348 -1
- package/skills/wiki/SKILL.md +13 -13
- package/src/scripts/__tests__/codex-native-hook.test.ts +437 -14
- package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
- package/src/scripts/codex-native-hook.ts +205 -61
- package/src/scripts/codex-native-pre-post.ts +4 -1
- package/src/scripts/notify-dispatcher.ts +40 -1
- package/src/scripts/notify-hook/tmux-injection.ts +110 -3
- package/src/scripts/notify-hook.ts +3 -1
- package/templates/catalog-manifest.json +9 -2
|
@@ -3,7 +3,7 @@ import assert from "node:assert/strict";
|
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { cp, mkdir, mkdtemp, readFile, readdir, rm, writeFile, } from "node:fs/promises";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
|
-
import { join } from "node:path";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
7
|
import { parse as parseToml } from "@iarna/toml";
|
|
8
8
|
import { setup } from "../setup.js";
|
|
9
9
|
import { uninstall } from "../uninstall.js";
|
|
@@ -128,14 +128,71 @@ describe("notify setup scope", () => {
|
|
|
128
128
|
await rm(wd, { recursive: true, force: true });
|
|
129
129
|
}
|
|
130
130
|
});
|
|
131
|
+
it("does not preserve stale OMX dispatcher metadata as previous notify", async () => {
|
|
132
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-stale-dispatcher-notify-"));
|
|
133
|
+
try {
|
|
134
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
135
|
+
await mkdir(codexHomeDir, { recursive: true });
|
|
136
|
+
const metadataPath = join(codexHomeDir, ".omx", "notify-dispatch.json");
|
|
137
|
+
const stalePkgRoot = join(wd, "old-global", "oh-my-codex");
|
|
138
|
+
const staleDispatcher = join(stalePkgRoot, "dist", "scripts", "notify-dispatcher.js");
|
|
139
|
+
await mkdir(dirname(metadataPath), { recursive: true });
|
|
140
|
+
await writeFile(join(codexHomeDir, "config.toml"), `notify = ["node", "${staleDispatcher}", "--metadata", "${metadataPath}"]\napproval_policy = "on-failure"\n`);
|
|
141
|
+
await writeFile(metadataPath, JSON.stringify({
|
|
142
|
+
managedBy: "oh-my-codex",
|
|
143
|
+
version: 1,
|
|
144
|
+
previousNotify: [
|
|
145
|
+
"node",
|
|
146
|
+
staleDispatcher,
|
|
147
|
+
"--metadata",
|
|
148
|
+
metadataPath,
|
|
149
|
+
],
|
|
150
|
+
omxNotify: [
|
|
151
|
+
"node",
|
|
152
|
+
join(stalePkgRoot, "dist", "scripts", "notify-hook.js"),
|
|
153
|
+
],
|
|
154
|
+
dispatcherNotify: ["node", staleDispatcher, "--metadata", metadataPath],
|
|
155
|
+
}));
|
|
156
|
+
await withTempCwd(wd, async () => {
|
|
157
|
+
await setup({ scope: "user" });
|
|
158
|
+
});
|
|
159
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
160
|
+
assert.match(config, /^notify = \["node", ".*notify-hook\.js"\]$/m);
|
|
161
|
+
assert.doesNotMatch(config, /notify-dispatcher\.js/);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
await rm(wd, { recursive: true, force: true });
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
it("does not wrap stale global OMX notify hooks as user notify commands", async () => {
|
|
169
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-stale-hook-notify-"));
|
|
170
|
+
try {
|
|
171
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
172
|
+
await mkdir(codexHomeDir, { recursive: true });
|
|
173
|
+
const staleHook = join("/opt", "homebrew", "lib", "node_modules", "oh-my-codex", "dist", "scripts", "notify-hook.js");
|
|
174
|
+
await writeFile(join(codexHomeDir, "config.toml"), `notify = ["node", "${staleHook}"]\napproval_policy = "on-failure"\n`);
|
|
175
|
+
await withTempCwd(wd, async () => {
|
|
176
|
+
await setup({ scope: "user" });
|
|
177
|
+
});
|
|
178
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
179
|
+
assert.match(config, /^notify = \["node", ".*notify-hook\.js"\]$/m);
|
|
180
|
+
assert.doesNotMatch(config, /notify-dispatcher\.js/);
|
|
181
|
+
assert.doesNotMatch(config, /lib\/node_modules\/oh-my-codex\/dist\/scripts\/notify-hook\.js/);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
await rm(wd, { recursive: true, force: true });
|
|
186
|
+
}
|
|
187
|
+
});
|
|
131
188
|
});
|
|
132
189
|
async function assertProjectPluginModeArtifacts(wd) {
|
|
133
190
|
const hooks = await readFile(join(wd, ".codex", "hooks.json"), "utf-8");
|
|
134
191
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
135
192
|
const config = await readFile(join(wd, ".codex", "config.toml"), "utf-8");
|
|
136
|
-
assert.match(config, /^
|
|
193
|
+
assert.match(config, /^hooks = true$/m);
|
|
137
194
|
assert.match(config, /^goals = true$/m);
|
|
138
|
-
assert.doesNotMatch(config, /developer_instructions|notify-hook
|
|
195
|
+
assert.doesNotMatch(config, /developer_instructions|notify-hook/g);
|
|
139
196
|
assert.equal(existsSync(join(wd, ".codex", "skills", "ask", "SKILL.md")), false);
|
|
140
197
|
assert.equal(existsSync(join(wd, ".codex", "agents", "planner.toml")), false);
|
|
141
198
|
assert.equal(existsSync(join(wd, ".codex", "prompts", "executor.md")), false);
|
|
@@ -144,6 +201,7 @@ async function assertProjectPluginModeArtifacts(wd) {
|
|
|
144
201
|
assert.deepEqual(persisted, {
|
|
145
202
|
scope: "project",
|
|
146
203
|
installMode: "plugin",
|
|
204
|
+
mcpMode: "none",
|
|
147
205
|
});
|
|
148
206
|
}
|
|
149
207
|
async function captureConsoleOutput(fn) {
|
|
@@ -189,6 +247,10 @@ async function seedStalePluginDiscoveryCache(codexHomeDir) {
|
|
|
189
247
|
await writeFile(join(artifactPath, "skills", "old-only", "SKILL.md"), "# old\n");
|
|
190
248
|
return artifactPath;
|
|
191
249
|
}
|
|
250
|
+
async function packagedPluginCacheDir(codexHomeDir) {
|
|
251
|
+
const manifest = JSON.parse(await readFile(join(packageRoot, "plugins", "oh-my-codex", ".codex-plugin", "plugin.json"), "utf-8"));
|
|
252
|
+
return join(codexHomeDir, "plugins", "cache", "oh-my-codex-local", "oh-my-codex", manifest.version);
|
|
253
|
+
}
|
|
192
254
|
describe("omx setup install mode behavior", () => {
|
|
193
255
|
it("summarizes and keeps persisted setup preferences when review chooses keep", async () => {
|
|
194
256
|
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
@@ -208,7 +270,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
208
270
|
},
|
|
209
271
|
});
|
|
210
272
|
});
|
|
211
|
-
assert.match(output, /Setup preference review: keep \(scope=user, installMode=legacy\)/);
|
|
273
|
+
assert.match(output, /Setup preference review: keep \(scope=user, installMode=legacy, mcpMode=not recorded\)/);
|
|
212
274
|
assert.match(output, /Using setup scope: user \(from \.omx\/setup-scope\.json\)/);
|
|
213
275
|
assert.match(output, /Using setup install mode: legacy \(from \.omx\/setup-scope\.json\)/);
|
|
214
276
|
});
|
|
@@ -237,7 +299,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
237
299
|
},
|
|
238
300
|
});
|
|
239
301
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
240
|
-
assert.deepEqual(persisted, {
|
|
302
|
+
assert.deepEqual(persisted, {
|
|
303
|
+
scope: "user",
|
|
304
|
+
installMode: "plugin",
|
|
305
|
+
mcpMode: "none",
|
|
306
|
+
});
|
|
241
307
|
});
|
|
242
308
|
});
|
|
243
309
|
}
|
|
@@ -260,7 +326,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
260
326
|
},
|
|
261
327
|
});
|
|
262
328
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
263
|
-
assert.deepEqual(persisted, { scope: "project" });
|
|
329
|
+
assert.deepEqual(persisted, { scope: "project", mcpMode: "none" });
|
|
264
330
|
});
|
|
265
331
|
});
|
|
266
332
|
}
|
|
@@ -289,7 +355,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
289
355
|
});
|
|
290
356
|
assert.equal(reviewed, true);
|
|
291
357
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
292
|
-
assert.deepEqual(persisted, {
|
|
358
|
+
assert.deepEqual(persisted, {
|
|
359
|
+
scope: "user",
|
|
360
|
+
installMode: "plugin",
|
|
361
|
+
mcpMode: "none",
|
|
362
|
+
});
|
|
293
363
|
});
|
|
294
364
|
});
|
|
295
365
|
}
|
|
@@ -318,7 +388,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
318
388
|
});
|
|
319
389
|
assert.equal(reviewed, true);
|
|
320
390
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
321
|
-
assert.deepEqual(persisted, {
|
|
391
|
+
assert.deepEqual(persisted, {
|
|
392
|
+
scope: "user",
|
|
393
|
+
installMode: "plugin",
|
|
394
|
+
mcpMode: "none",
|
|
395
|
+
});
|
|
322
396
|
});
|
|
323
397
|
});
|
|
324
398
|
}
|
|
@@ -345,7 +419,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
345
419
|
},
|
|
346
420
|
});
|
|
347
421
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
348
|
-
assert.deepEqual(persisted, {
|
|
422
|
+
assert.deepEqual(persisted, {
|
|
423
|
+
scope: "user",
|
|
424
|
+
installMode: "legacy",
|
|
425
|
+
mcpMode: "none",
|
|
426
|
+
});
|
|
349
427
|
});
|
|
350
428
|
});
|
|
351
429
|
}
|
|
@@ -395,7 +473,43 @@ describe("omx setup install mode behavior", () => {
|
|
|
395
473
|
});
|
|
396
474
|
});
|
|
397
475
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
398
|
-
assert.deepEqual(persisted, {
|
|
476
|
+
assert.deepEqual(persisted, {
|
|
477
|
+
scope: "user",
|
|
478
|
+
installMode: "plugin",
|
|
479
|
+
mcpMode: "none",
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
finally {
|
|
483
|
+
await rm(wd, { recursive: true, force: true });
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
it("defaults setup to no first-party MCP blocks", async () => {
|
|
487
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-mcp-mode-"));
|
|
488
|
+
try {
|
|
489
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
490
|
+
await withTempCwd(wd, async () => {
|
|
491
|
+
await setup({ scope: "user", installMode: "legacy" });
|
|
492
|
+
});
|
|
493
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
494
|
+
assert.doesNotMatch(config, /^\[mcp_servers\.omx_state\]$/m);
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
finally {
|
|
498
|
+
await rm(wd, { recursive: true, force: true });
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
it("emits first-party MCP blocks when compat MCP mode is requested", async () => {
|
|
502
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-mcp-mode-"));
|
|
503
|
+
try {
|
|
504
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
505
|
+
await withTempCwd(wd, async () => {
|
|
506
|
+
await setup({ scope: "user", installMode: "legacy", mcpMode: "compat" });
|
|
507
|
+
});
|
|
508
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
509
|
+
assert.match(config, /^\[mcp_servers\.omx_state\]$/m);
|
|
510
|
+
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
511
|
+
assert.equal(persisted.mcpMode, "compat");
|
|
512
|
+
});
|
|
399
513
|
}
|
|
400
514
|
finally {
|
|
401
515
|
await rm(wd, { recursive: true, force: true });
|
|
@@ -411,7 +525,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
411
525
|
await writeFile(join(pluginDir, ".codex-plugin", "plugin.json"), JSON.stringify({ name: "oh-my-codex", version: "local" }));
|
|
412
526
|
await setup({ scope: "user" });
|
|
413
527
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
414
|
-
assert.deepEqual(persisted, {
|
|
528
|
+
assert.deepEqual(persisted, {
|
|
529
|
+
scope: "user",
|
|
530
|
+
installMode: "plugin",
|
|
531
|
+
mcpMode: "none",
|
|
532
|
+
});
|
|
415
533
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), false);
|
|
416
534
|
const hooks = await readFile(join(codexHomeDir, "hooks.json"), "utf-8");
|
|
417
535
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
@@ -431,7 +549,8 @@ describe("omx setup install mode behavior", () => {
|
|
|
431
549
|
const output = await captureConsoleOutput(async () => {
|
|
432
550
|
await setup({ scope: "user", installMode: "plugin" });
|
|
433
551
|
});
|
|
434
|
-
assert.equal(existsSync(cacheDir), false);
|
|
552
|
+
assert.equal(existsSync(join(cacheDir, "skills", "old-only", "SKILL.md")), false);
|
|
553
|
+
assert.equal(existsSync(join(await packagedPluginCacheDir(codexHomeDir), "skills", "ask", "SKILL.md")), true);
|
|
435
554
|
assert.match(output, /Invalidated 1 stale Codex plugin discovery cache entry/);
|
|
436
555
|
assert.equal(existsSync(join(codexHomeDir, "skills", "old-only", "SKILL.md")), false);
|
|
437
556
|
});
|
|
@@ -459,6 +578,24 @@ describe("omx setup install mode behavior", () => {
|
|
|
459
578
|
await rm(wd, { recursive: true, force: true });
|
|
460
579
|
}
|
|
461
580
|
});
|
|
581
|
+
it("reports plugin cache materialization during dry-run without writing cache", async () => {
|
|
582
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
583
|
+
try {
|
|
584
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
585
|
+
await withTempCwd(wd, async () => {
|
|
586
|
+
const output = await captureConsoleOutput(async () => {
|
|
587
|
+
await setup({ scope: "user", installMode: "plugin", dryRun: true });
|
|
588
|
+
});
|
|
589
|
+
const cacheDir = await packagedPluginCacheDir(codexHomeDir);
|
|
590
|
+
assert.equal(existsSync(cacheDir), false);
|
|
591
|
+
assert.match(output, /Would install local Codex plugin cache/);
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
finally {
|
|
596
|
+
await rm(wd, { recursive: true, force: true });
|
|
597
|
+
}
|
|
598
|
+
});
|
|
462
599
|
it("does not prompt for install mode during project-scoped setup", async () => {
|
|
463
600
|
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
464
601
|
let promptCalls = 0;
|
|
@@ -474,7 +611,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
474
611
|
});
|
|
475
612
|
assert.equal(promptCalls, 0);
|
|
476
613
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
477
|
-
assert.deepEqual(persisted, { scope: "project" });
|
|
614
|
+
assert.deepEqual(persisted, { scope: "project", mcpMode: "none" });
|
|
478
615
|
}
|
|
479
616
|
finally {
|
|
480
617
|
await rm(wd, { recursive: true, force: true });
|
|
@@ -488,11 +625,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
488
625
|
await setup({ scope: "user", installMode: "plugin" });
|
|
489
626
|
await setup({ scope: "project" });
|
|
490
627
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
491
|
-
assert.deepEqual(persisted, { scope: "project" });
|
|
628
|
+
assert.deepEqual(persisted, { scope: "project", mcpMode: "none" });
|
|
492
629
|
assert.equal(existsSync(join(wd, ".codex", "skills", "ask", "SKILL.md")), true);
|
|
493
630
|
await setup({ scope: "project" });
|
|
494
631
|
const repeatedPersisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
495
|
-
assert.deepEqual(repeatedPersisted, { scope: "project" });
|
|
632
|
+
assert.deepEqual(repeatedPersisted, { scope: "project", mcpMode: "none" });
|
|
496
633
|
assert.equal(existsSync(join(wd, ".codex", "agents", "planner.toml")), true);
|
|
497
634
|
assert.equal(existsSync(join(wd, ".codex", "prompts", "executor.md")), true);
|
|
498
635
|
});
|
|
@@ -510,7 +647,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
510
647
|
await setup({ scope: "project", installMode: "plugin" });
|
|
511
648
|
await setup({ scope: "user" });
|
|
512
649
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
513
|
-
assert.deepEqual(persisted, {
|
|
650
|
+
assert.deepEqual(persisted, {
|
|
651
|
+
scope: "user",
|
|
652
|
+
installMode: "legacy",
|
|
653
|
+
mcpMode: "none",
|
|
654
|
+
});
|
|
514
655
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), true);
|
|
515
656
|
assert.equal(existsSync(join(codexHomeDir, "agents", "planner.toml")), true);
|
|
516
657
|
assert.equal(existsSync(join(codexHomeDir, "prompts", "executor.md")), true);
|
|
@@ -549,7 +690,14 @@ describe("omx setup install mode behavior", () => {
|
|
|
549
690
|
assert.equal(parsed.marketplaces?.other?.source, "/tmp/other");
|
|
550
691
|
assert.equal((config.match(/^\[marketplaces\.oh-my-codex-local\]$/gm) ?? [])
|
|
551
692
|
.length, 1);
|
|
552
|
-
assert.match(
|
|
693
|
+
assert.equal((config.match(/^\[plugins\."oh-my-codex@oh-my-codex-local"\]$/gm) ?? [])
|
|
694
|
+
.length, 1);
|
|
695
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.enabled, true);
|
|
696
|
+
const cacheDir = await packagedPluginCacheDir(codexHomeDir);
|
|
697
|
+
assert.equal(existsSync(join(cacheDir, ".codex-plugin", "plugin.json")), true);
|
|
698
|
+
assert.equal(existsSync(join(cacheDir, "skills", "ask", "SKILL.md")), true);
|
|
699
|
+
assert.match(config, /^hooks = true$/m);
|
|
700
|
+
assert.doesNotMatch(config, /^codex_hooks = true$/m);
|
|
553
701
|
assert.doesNotMatch(config, /\[mcp_servers\./);
|
|
554
702
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), false);
|
|
555
703
|
assert.equal(existsSync(join(codexHomeDir, "agents", "planner.toml")), false);
|
|
@@ -561,6 +709,67 @@ describe("omx setup install mode behavior", () => {
|
|
|
561
709
|
await rm(wd, { recursive: true, force: true });
|
|
562
710
|
}
|
|
563
711
|
});
|
|
712
|
+
it("enables the local Codex plugin while preserving plugin subtable policy", async () => {
|
|
713
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
714
|
+
try {
|
|
715
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
716
|
+
await withTempCwd(wd, async () => {
|
|
717
|
+
const configPath = join(codexHomeDir, "config.toml");
|
|
718
|
+
await writeFile(configPath, [
|
|
719
|
+
"[plugins.\"oh-my-codex@oh-my-codex-local\"]",
|
|
720
|
+
"enabled = false",
|
|
721
|
+
"",
|
|
722
|
+
"[plugins.\"oh-my-codex@oh-my-codex-local\".mcp_servers.omx_state]",
|
|
723
|
+
"enabled = false",
|
|
724
|
+
"",
|
|
725
|
+
].join("\n"));
|
|
726
|
+
await setup({ scope: "user", installMode: "plugin", force: true });
|
|
727
|
+
await setup({ scope: "user", installMode: "plugin", force: true });
|
|
728
|
+
const config = await readFile(configPath, "utf-8");
|
|
729
|
+
const parsed = parseToml(config);
|
|
730
|
+
assert.equal((config.match(/^\[plugins\."oh-my-codex@oh-my-codex-local"\]$/gm) ?? [])
|
|
731
|
+
.length, 1);
|
|
732
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.enabled, true);
|
|
733
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.mcp_servers
|
|
734
|
+
?.omx_state?.enabled, false);
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
finally {
|
|
739
|
+
await rm(wd, { recursive: true, force: true });
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
it("enables plugin MCP subtables only when compat MCP mode is requested", async () => {
|
|
743
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
744
|
+
try {
|
|
745
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
746
|
+
await withTempCwd(wd, async () => {
|
|
747
|
+
const configPath = join(codexHomeDir, "config.toml");
|
|
748
|
+
await setup({
|
|
749
|
+
scope: "user",
|
|
750
|
+
installMode: "plugin",
|
|
751
|
+
mcpMode: "compat",
|
|
752
|
+
force: true,
|
|
753
|
+
});
|
|
754
|
+
let parsed = parseToml(await readFile(configPath, "utf-8"));
|
|
755
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.mcp_servers
|
|
756
|
+
?.omx_state?.enabled, true);
|
|
757
|
+
await setup({
|
|
758
|
+
scope: "user",
|
|
759
|
+
installMode: "plugin",
|
|
760
|
+
mcpMode: "none",
|
|
761
|
+
force: true,
|
|
762
|
+
});
|
|
763
|
+
parsed = parseToml(await readFile(configPath, "utf-8"));
|
|
764
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.mcp_servers
|
|
765
|
+
?.omx_state?.enabled, false);
|
|
766
|
+
});
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
finally {
|
|
770
|
+
await rm(wd, { recursive: true, force: true });
|
|
771
|
+
}
|
|
772
|
+
});
|
|
564
773
|
it("reports plugin marketplace registration during dry-run without mutating config", async () => {
|
|
565
774
|
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
566
775
|
try {
|
|
@@ -593,13 +802,13 @@ describe("omx setup install mode behavior", () => {
|
|
|
593
802
|
const parsed = parseToml(config);
|
|
594
803
|
const managedHookStateKeys = Object.keys(parsed.hooks?.state ?? {}).filter((key) => key.includes(`${codexHomeDir}/hooks.json:`));
|
|
595
804
|
assert.equal(managedHookStateKeys.length, 7);
|
|
596
|
-
assert.match(config, /^
|
|
597
|
-
assert.doesNotMatch(config, /^
|
|
805
|
+
assert.match(config, /^hooks = true$/m);
|
|
806
|
+
assert.doesNotMatch(config, /^codex_hooks = true$/m);
|
|
598
807
|
assert.match(config, /^goals = true$/m);
|
|
599
808
|
assert.match(config, /^\[hooks\.state\.".*hooks\.json:pre_tool_use:0:0"\]$/m);
|
|
600
809
|
assert.equal((config.match(/^\[hooks\.state\.".*hooks\.json:pre_tool_use:0:0"\]$/gm) ?? []).length, 1);
|
|
601
810
|
assert.match(config, /^trusted_hash = "sha256:[a-f0-9]{64}"$/m);
|
|
602
|
-
assert.doesNotMatch(config, /developer_instructions|notify-hook
|
|
811
|
+
assert.doesNotMatch(config, /developer_instructions|notify-hook/g);
|
|
603
812
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), false);
|
|
604
813
|
assert.equal(existsSync(join(codexHomeDir, "agents", "planner.toml")), false);
|
|
605
814
|
assert.equal(existsSync(join(codexHomeDir, "prompts", "executor.md")), false);
|
|
@@ -634,8 +843,10 @@ describe("omx setup install mode behavior", () => {
|
|
|
634
843
|
assert.match(config, /Setup-owned prompt files and native-agent TOML defaults are intentionally omitted unless explicitly installed/);
|
|
635
844
|
assert.doesNotMatch(config, /Native subagents live in \.codex\/agents/);
|
|
636
845
|
assert.doesNotMatch(config, /Treat installed prompts as narrower execution surfaces/);
|
|
637
|
-
assert.match(config, /^
|
|
638
|
-
assert.doesNotMatch(config, /notify-hook
|
|
846
|
+
assert.match(config, /^hooks = true$/m);
|
|
847
|
+
assert.doesNotMatch(config, /notify-hook/);
|
|
848
|
+
assert.doesNotMatch(config, /^\s*\[mcp_servers[.\]]/m);
|
|
849
|
+
assert.match(config, /mcp_servers\.omx_state]\nenabled = false/);
|
|
639
850
|
const agentsMd = await readFile(join(codexHomeDir, "AGENTS.md"), "utf-8");
|
|
640
851
|
assert.match(agentsMd, /oh-my-codex - Intelligent Multi-Agent Orchestration/);
|
|
641
852
|
assert.match(agentsMd, /<!-- omx:generated:agents-md -->/);
|
|
@@ -695,7 +906,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
695
906
|
});
|
|
696
907
|
const config = await readFile(configPath, "utf-8");
|
|
697
908
|
assert.match(config, /^developer_instructions = "custom"$/m);
|
|
698
|
-
assert.match(config, /^
|
|
909
|
+
assert.match(config, /^hooks = true$/m);
|
|
699
910
|
assert.equal((config.match(/^developer_instructions\s*=/gm) ?? []).length, 1);
|
|
700
911
|
});
|
|
701
912
|
});
|
|
@@ -721,7 +932,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
721
932
|
assert.match(config, /You have oh-my-codex installed/);
|
|
722
933
|
assert.doesNotMatch(config, /^developer_instructions = "custom"$/m);
|
|
723
934
|
assert.equal((config.match(/^developer_instructions\s*=/gm) ?? []).length, 1);
|
|
724
|
-
assert.match(config, /^
|
|
935
|
+
assert.match(config, /^hooks = true$/m);
|
|
725
936
|
assert.match(config, /^\[hooks\.state\.".*hooks\.json:pre_tool_use:0:0"\]$/m);
|
|
726
937
|
});
|
|
727
938
|
});
|
|
@@ -730,6 +941,27 @@ describe("omx setup install mode behavior", () => {
|
|
|
730
941
|
await rm(wd, { recursive: true, force: true });
|
|
731
942
|
}
|
|
732
943
|
});
|
|
944
|
+
it("uses legacy codex_hooks only when the installed Codex reports that hook feature", async () => {
|
|
945
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
946
|
+
try {
|
|
947
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
948
|
+
await withTempCwd(wd, async () => {
|
|
949
|
+
await setup({
|
|
950
|
+
scope: "user",
|
|
951
|
+
installMode: "plugin",
|
|
952
|
+
codexFeaturesProbe: () => "codex_hooks experimental true\n",
|
|
953
|
+
codexVersionProbe: () => "codex-cli 0.129.0",
|
|
954
|
+
});
|
|
955
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
956
|
+
assert.match(config, /^codex_hooks = true$/m);
|
|
957
|
+
assert.doesNotMatch(config, /^hooks = true$/m);
|
|
958
|
+
});
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
finally {
|
|
962
|
+
await rm(wd, { recursive: true, force: true });
|
|
963
|
+
}
|
|
964
|
+
});
|
|
733
965
|
it("preserves existing user hooks while installing plugin-mode native hooks", async () => {
|
|
734
966
|
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
735
967
|
try {
|
|
@@ -743,7 +975,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
743
975
|
assert.match(hooks, /"UserPromptSubmit"/);
|
|
744
976
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
745
977
|
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
746
|
-
assert.match(config, /^
|
|
978
|
+
assert.match(config, /^hooks = true$/m);
|
|
747
979
|
});
|
|
748
980
|
});
|
|
749
981
|
}
|
|
@@ -760,6 +992,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
760
992
|
assert.deepEqual(persisted, {
|
|
761
993
|
scope: "project",
|
|
762
994
|
installMode: "plugin",
|
|
995
|
+
mcpMode: "none",
|
|
763
996
|
});
|
|
764
997
|
await setup({ scope: "project" });
|
|
765
998
|
assert.equal(existsSync(join(wd, ".codex", "skills", "ask", "SKILL.md")), false);
|
|
@@ -781,7 +1014,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
781
1014
|
await writeFile(join(wd, ".omx", "setup-scope.json"), JSON.stringify({ scope: "project", installMode: "plugin" }));
|
|
782
1015
|
await setup({ scope: "project", installMode: "legacy" });
|
|
783
1016
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
784
|
-
assert.deepEqual(persisted, { scope: "project" });
|
|
1017
|
+
assert.deepEqual(persisted, { scope: "project", mcpMode: "none" });
|
|
785
1018
|
assert.equal(existsSync(join(wd, ".codex", "skills", "ask", "SKILL.md")), true);
|
|
786
1019
|
assert.equal(existsSync(join(wd, ".codex", "agents", "planner.toml")), true);
|
|
787
1020
|
assert.equal(existsSync(join(wd, ".codex", "prompts", "executor.md")), true);
|
|
@@ -803,6 +1036,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
803
1036
|
assert.deepEqual(persisted, {
|
|
804
1037
|
scope: "user",
|
|
805
1038
|
installMode: "legacy",
|
|
1039
|
+
mcpMode: "none",
|
|
806
1040
|
});
|
|
807
1041
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), true);
|
|
808
1042
|
assert.equal(existsSync(join(codexHomeDir, "agents", "planner.toml")), true);
|
|
@@ -814,6 +1048,44 @@ describe("omx setup install mode behavior", () => {
|
|
|
814
1048
|
await rm(wd, { recursive: true, force: true });
|
|
815
1049
|
}
|
|
816
1050
|
});
|
|
1051
|
+
it("dedupes plugin-mode hook trust state when switching user setup back to legacy", async () => {
|
|
1052
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
1053
|
+
try {
|
|
1054
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
1055
|
+
await withTempCwd(wd, async () => {
|
|
1056
|
+
const configPath = join(codexHomeDir, "config.toml");
|
|
1057
|
+
await setup({ scope: "user", installMode: "plugin", force: true });
|
|
1058
|
+
const pluginConfig = await readFile(configPath, "utf-8");
|
|
1059
|
+
const staleUnfencedPluginConfig = pluginConfig
|
|
1060
|
+
.split(/\r?\n/)
|
|
1061
|
+
.filter((line) => line.trim() !== "# OMX-owned Codex hook trust state" &&
|
|
1062
|
+
line.trim() !==
|
|
1063
|
+
"# Trusts only setup-managed codex-native-hook.js wrappers." &&
|
|
1064
|
+
line.trim() !== "# End OMX-owned Codex hook trust state")
|
|
1065
|
+
.join("\n");
|
|
1066
|
+
await writeFile(configPath, staleUnfencedPluginConfig);
|
|
1067
|
+
assert.doesNotThrow(() => parseToml(staleUnfencedPluginConfig));
|
|
1068
|
+
await setup({ scope: "user", installMode: "legacy", force: true });
|
|
1069
|
+
const legacyConfig = await readFile(configPath, "utf-8");
|
|
1070
|
+
assert.doesNotThrow(() => parseToml(legacyConfig));
|
|
1071
|
+
assert.equal(legacyConfig
|
|
1072
|
+
.split(/\r?\n/)
|
|
1073
|
+
.filter((line) => line.trim() ===
|
|
1074
|
+
`[hooks.state."${join(codexHomeDir, "hooks.json")}:post_compact:0:0"]`).length, 1, "legacy setup should replace stale plugin-mode hook trust state instead of duplicating it");
|
|
1075
|
+
assert.match(legacyConfig, /# OMX-owned Codex hook trust state[\s\S]*# End OMX-owned Codex hook trust state/);
|
|
1076
|
+
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
1077
|
+
assert.deepEqual(persisted, {
|
|
1078
|
+
scope: "user",
|
|
1079
|
+
installMode: "legacy",
|
|
1080
|
+
mcpMode: "none",
|
|
1081
|
+
});
|
|
1082
|
+
});
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
finally {
|
|
1086
|
+
await rm(wd, { recursive: true, force: true });
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
817
1089
|
it("installs project-scoped native hooks when plugin mode is explicitly requested", async () => {
|
|
818
1090
|
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
819
1091
|
try {
|
|
@@ -902,7 +1174,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
902
1174
|
const hooks = await readFile(hooksPath, "utf-8");
|
|
903
1175
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
904
1176
|
const config = await readFile(configPath, "utf-8");
|
|
905
|
-
assert.match(config, /^
|
|
1177
|
+
assert.match(config, /^hooks = true$/m);
|
|
906
1178
|
assert.doesNotMatch(config, /^\s*(?:notify|developer_instructions)\s*=|^\s*\[mcp_servers[.\]]/m);
|
|
907
1179
|
});
|
|
908
1180
|
});
|