oh-my-codex 0.16.2 → 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 +137 -6
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +303 -4
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +58 -0
- package/dist/cli/__tests__/launch-fallback.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 +48 -0
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +8 -0
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +350 -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 +269 -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 +90 -6
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +109 -19
- package/dist/cli/__tests__/update.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 +168 -16
- 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 +168 -20
- 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 +177 -43
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/team.d.ts.map +1 -1
- package/dist/cli/team.js +54 -15
- package/dist/cli/team.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 +76 -5
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update.d.ts +10 -2
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +99 -5
- package/dist/cli/update.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 +188 -4
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +129 -10
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +148 -7
- 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 +40 -4
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +204 -18
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/generator.d.ts +19 -1
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +319 -83
- 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-fallback-watcher.test.js +29 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +10 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +1 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts +2 -0
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +176 -0
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -0
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +148 -0
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +3 -0
- package/dist/hooks/__tests__/notify-hook-session-scope.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__/wiki-docs-contract.test.js +1 -2
- package/dist/hooks/__tests__/wiki-docs-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 +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 +597 -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.d.ts +2 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.d.ts.map +1 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +612 -0
- package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -0
- package/dist/planning/artifacts.d.ts +7 -2
- package/dist/planning/artifacts.d.ts.map +1 -1
- package/dist/planning/artifacts.js +279 -26
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/planning/context-pack-status.d.ts +31 -0
- package/dist/planning/context-pack-status.d.ts.map +1 -1
- package/dist/planning/context-pack-status.js +291 -25
- 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/ralph/persistence.d.ts +1 -1
- package/dist/ralph/persistence.d.ts.map +1 -1
- package/dist/ralph/persistence.js +8 -2
- package/dist/ralph/persistence.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +359 -24
- 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 +142 -76
- 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.d.ts +7 -0
- package/dist/scripts/notify-dispatcher.d.ts.map +1 -0
- package/dist/scripts/notify-dispatcher.js +87 -0
- package/dist/scripts/notify-dispatcher.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +4 -0
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +96 -8
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +6 -2
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.js +3 -3
- package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
- package/dist/scripts/notify-hook.js +127 -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 +84 -1
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +178 -19
- 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 +45 -0
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/approved-execution.d.ts +1 -0
- package/dist/team/approved-execution.d.ts.map +1 -1
- package/dist/team/approved-execution.js +53 -0
- package/dist/team/approved-execution.js.map +1 -1
- package/dist/team/delivery-log.d.ts.map +1 -1
- package/dist/team/delivery-log.js +8 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +104 -18
- package/dist/team/runtime.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/mailbox.d.ts +1 -0
- package/dist/team/state/mailbox.d.ts.map +1 -1
- package/dist/team/state/mailbox.js +10 -1
- package/dist/team/state/mailbox.js.map +1 -1
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +5 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +3 -7
- package/dist/team/state.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts +7 -2
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +17 -4
- package/dist/team/worker-bootstrap.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 +389 -24
- package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
- package/src/scripts/codex-native-hook.ts +168 -64
- package/src/scripts/codex-native-pre-post.ts +4 -1
- package/src/scripts/notify-dispatcher.ts +113 -0
- package/src/scripts/notify-fallback-watcher.ts +6 -2
- package/src/scripts/notify-hook/ralph-session-resume.ts +117 -8
- package/src/scripts/notify-hook/state-io.ts +4 -2
- package/src/scripts/notify-hook/visual-verdict.ts +3 -3
- package/src/scripts/notify-hook.ts +119 -1
|
@@ -3,9 +3,10 @@ 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
|
+
import { uninstall } from "../uninstall.js";
|
|
9
10
|
const packageRoot = process.cwd();
|
|
10
11
|
async function withTempCwd(wd, fn) {
|
|
11
12
|
const previousCwd = process.cwd();
|
|
@@ -58,13 +59,140 @@ async function withIsolatedUserHome(wd, fn) {
|
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
}
|
|
62
|
+
describe("notify setup scope", () => {
|
|
63
|
+
it("does not write unsupported project-scope notify", async () => {
|
|
64
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-project-no-notify-"));
|
|
65
|
+
try {
|
|
66
|
+
await withTempCwd(wd, async () => {
|
|
67
|
+
await setup({ scope: "project" });
|
|
68
|
+
});
|
|
69
|
+
const config = await readFile(join(wd, ".codex", "config.toml"), "utf-8");
|
|
70
|
+
assert.doesNotMatch(config, /^notify\s*=/m);
|
|
71
|
+
assert.doesNotMatch(config, /notify-hook\.js/);
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
await rm(wd, { recursive: true, force: true });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
it("preserves existing user project-scope notify while suppressing OMX notify", async () => {
|
|
78
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-project-user-notify-"));
|
|
79
|
+
try {
|
|
80
|
+
await mkdir(join(wd, ".codex"), { recursive: true });
|
|
81
|
+
await writeFile(join(wd, ".codex", "config.toml"), 'notify = ["node", "/tmp/notify-hook.js"]\napproval_policy = "never"\n');
|
|
82
|
+
await withTempCwd(wd, async () => {
|
|
83
|
+
await setup({ scope: "project" });
|
|
84
|
+
});
|
|
85
|
+
const config = await readFile(join(wd, ".codex", "config.toml"), "utf-8");
|
|
86
|
+
assert.match(config, /^notify = \["node", "\/tmp\/notify-hook\.js"\]$/m);
|
|
87
|
+
assert.doesNotMatch(config, /oh-my-codex.*notify-hook\.js/);
|
|
88
|
+
assert.match(config, /^approval_policy = "never"$/m);
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
await rm(wd, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
it("wraps and restores an existing user notify", async () => {
|
|
95
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-user-notify-"));
|
|
96
|
+
try {
|
|
97
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
98
|
+
await mkdir(codexHomeDir, { recursive: true });
|
|
99
|
+
await writeFile(join(codexHomeDir, "config.toml"), 'notify = ["node", "/tmp/user-notify.js"]\napproval_policy = "on-failure"\n');
|
|
100
|
+
await withTempCwd(wd, async () => {
|
|
101
|
+
await setup({ scope: "user" });
|
|
102
|
+
});
|
|
103
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
104
|
+
assert.match(config, /^notify = \["node", ".*notify-dispatcher\.js", "--metadata", ".*notify-dispatch\.json"\]$/m);
|
|
105
|
+
const metadataPath = join(codexHomeDir, ".omx", "notify-dispatch.json");
|
|
106
|
+
const metadata = JSON.parse(await readFile(metadataPath, "utf-8"));
|
|
107
|
+
assert.deepEqual(metadata.previousNotify, ["node", "/tmp/user-notify.js"]);
|
|
108
|
+
assert.deepEqual(metadata.omxNotify?.slice(0, 1), ["node"]);
|
|
109
|
+
await withTempCwd(wd, async () => {
|
|
110
|
+
await setup({ scope: "user" });
|
|
111
|
+
});
|
|
112
|
+
const rerunConfig = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
113
|
+
assert.match(rerunConfig, /notify-dispatcher\.js/);
|
|
114
|
+
const rerunMetadata = JSON.parse(await readFile(metadataPath, "utf-8"));
|
|
115
|
+
assert.deepEqual(rerunMetadata.previousNotify, [
|
|
116
|
+
"node",
|
|
117
|
+
"/tmp/user-notify.js",
|
|
118
|
+
]);
|
|
119
|
+
await withTempCwd(wd, async () => {
|
|
120
|
+
await uninstall({ scope: "user" });
|
|
121
|
+
});
|
|
122
|
+
const restored = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
123
|
+
assert.match(restored, new RegExp('^notify = \\["node", "/tmp/user-notify\\.js"\\]$', "m"));
|
|
124
|
+
assert.doesNotMatch(restored, /notify-dispatcher\.js/);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
await rm(wd, { recursive: true, force: true });
|
|
129
|
+
}
|
|
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
|
+
});
|
|
188
|
+
});
|
|
61
189
|
async function assertProjectPluginModeArtifacts(wd) {
|
|
62
190
|
const hooks = await readFile(join(wd, ".codex", "hooks.json"), "utf-8");
|
|
63
191
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
64
192
|
const config = await readFile(join(wd, ".codex", "config.toml"), "utf-8");
|
|
65
|
-
assert.match(config, /^
|
|
193
|
+
assert.match(config, /^hooks = true$/m);
|
|
66
194
|
assert.match(config, /^goals = true$/m);
|
|
67
|
-
assert.doesNotMatch(config, /developer_instructions|notify-hook
|
|
195
|
+
assert.doesNotMatch(config, /developer_instructions|notify-hook/g);
|
|
68
196
|
assert.equal(existsSync(join(wd, ".codex", "skills", "ask", "SKILL.md")), false);
|
|
69
197
|
assert.equal(existsSync(join(wd, ".codex", "agents", "planner.toml")), false);
|
|
70
198
|
assert.equal(existsSync(join(wd, ".codex", "prompts", "executor.md")), false);
|
|
@@ -73,6 +201,7 @@ async function assertProjectPluginModeArtifacts(wd) {
|
|
|
73
201
|
assert.deepEqual(persisted, {
|
|
74
202
|
scope: "project",
|
|
75
203
|
installMode: "plugin",
|
|
204
|
+
mcpMode: "none",
|
|
76
205
|
});
|
|
77
206
|
}
|
|
78
207
|
async function captureConsoleOutput(fn) {
|
|
@@ -137,7 +266,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
137
266
|
},
|
|
138
267
|
});
|
|
139
268
|
});
|
|
140
|
-
assert.match(output, /Setup preference review: keep \(scope=user, installMode=legacy\)/);
|
|
269
|
+
assert.match(output, /Setup preference review: keep \(scope=user, installMode=legacy, mcpMode=not recorded\)/);
|
|
141
270
|
assert.match(output, /Using setup scope: user \(from \.omx\/setup-scope\.json\)/);
|
|
142
271
|
assert.match(output, /Using setup install mode: legacy \(from \.omx\/setup-scope\.json\)/);
|
|
143
272
|
});
|
|
@@ -166,7 +295,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
166
295
|
},
|
|
167
296
|
});
|
|
168
297
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
169
|
-
assert.deepEqual(persisted, {
|
|
298
|
+
assert.deepEqual(persisted, {
|
|
299
|
+
scope: "user",
|
|
300
|
+
installMode: "plugin",
|
|
301
|
+
mcpMode: "none",
|
|
302
|
+
});
|
|
170
303
|
});
|
|
171
304
|
});
|
|
172
305
|
}
|
|
@@ -189,7 +322,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
189
322
|
},
|
|
190
323
|
});
|
|
191
324
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
192
|
-
assert.deepEqual(persisted, { scope: "project" });
|
|
325
|
+
assert.deepEqual(persisted, { scope: "project", mcpMode: "none" });
|
|
193
326
|
});
|
|
194
327
|
});
|
|
195
328
|
}
|
|
@@ -218,7 +351,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
218
351
|
});
|
|
219
352
|
assert.equal(reviewed, true);
|
|
220
353
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
221
|
-
assert.deepEqual(persisted, {
|
|
354
|
+
assert.deepEqual(persisted, {
|
|
355
|
+
scope: "user",
|
|
356
|
+
installMode: "plugin",
|
|
357
|
+
mcpMode: "none",
|
|
358
|
+
});
|
|
222
359
|
});
|
|
223
360
|
});
|
|
224
361
|
}
|
|
@@ -247,7 +384,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
247
384
|
});
|
|
248
385
|
assert.equal(reviewed, true);
|
|
249
386
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
250
|
-
assert.deepEqual(persisted, {
|
|
387
|
+
assert.deepEqual(persisted, {
|
|
388
|
+
scope: "user",
|
|
389
|
+
installMode: "plugin",
|
|
390
|
+
mcpMode: "none",
|
|
391
|
+
});
|
|
251
392
|
});
|
|
252
393
|
});
|
|
253
394
|
}
|
|
@@ -274,7 +415,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
274
415
|
},
|
|
275
416
|
});
|
|
276
417
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
277
|
-
assert.deepEqual(persisted, {
|
|
418
|
+
assert.deepEqual(persisted, {
|
|
419
|
+
scope: "user",
|
|
420
|
+
installMode: "legacy",
|
|
421
|
+
mcpMode: "none",
|
|
422
|
+
});
|
|
278
423
|
});
|
|
279
424
|
});
|
|
280
425
|
}
|
|
@@ -324,7 +469,43 @@ describe("omx setup install mode behavior", () => {
|
|
|
324
469
|
});
|
|
325
470
|
});
|
|
326
471
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
327
|
-
assert.deepEqual(persisted, {
|
|
472
|
+
assert.deepEqual(persisted, {
|
|
473
|
+
scope: "user",
|
|
474
|
+
installMode: "plugin",
|
|
475
|
+
mcpMode: "none",
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
finally {
|
|
479
|
+
await rm(wd, { recursive: true, force: true });
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
it("defaults setup to no first-party MCP blocks", async () => {
|
|
483
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-mcp-mode-"));
|
|
484
|
+
try {
|
|
485
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
486
|
+
await withTempCwd(wd, async () => {
|
|
487
|
+
await setup({ scope: "user", installMode: "legacy" });
|
|
488
|
+
});
|
|
489
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
490
|
+
assert.doesNotMatch(config, /^\[mcp_servers\.omx_state\]$/m);
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
finally {
|
|
494
|
+
await rm(wd, { recursive: true, force: true });
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
it("emits first-party MCP blocks when compat MCP mode is requested", async () => {
|
|
498
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-mcp-mode-"));
|
|
499
|
+
try {
|
|
500
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
501
|
+
await withTempCwd(wd, async () => {
|
|
502
|
+
await setup({ scope: "user", installMode: "legacy", mcpMode: "compat" });
|
|
503
|
+
});
|
|
504
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
505
|
+
assert.match(config, /^\[mcp_servers\.omx_state\]$/m);
|
|
506
|
+
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
507
|
+
assert.equal(persisted.mcpMode, "compat");
|
|
508
|
+
});
|
|
328
509
|
}
|
|
329
510
|
finally {
|
|
330
511
|
await rm(wd, { recursive: true, force: true });
|
|
@@ -340,7 +521,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
340
521
|
await writeFile(join(pluginDir, ".codex-plugin", "plugin.json"), JSON.stringify({ name: "oh-my-codex", version: "local" }));
|
|
341
522
|
await setup({ scope: "user" });
|
|
342
523
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
343
|
-
assert.deepEqual(persisted, {
|
|
524
|
+
assert.deepEqual(persisted, {
|
|
525
|
+
scope: "user",
|
|
526
|
+
installMode: "plugin",
|
|
527
|
+
mcpMode: "none",
|
|
528
|
+
});
|
|
344
529
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), false);
|
|
345
530
|
const hooks = await readFile(join(codexHomeDir, "hooks.json"), "utf-8");
|
|
346
531
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
@@ -403,7 +588,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
403
588
|
});
|
|
404
589
|
assert.equal(promptCalls, 0);
|
|
405
590
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
406
|
-
assert.deepEqual(persisted, { scope: "project" });
|
|
591
|
+
assert.deepEqual(persisted, { scope: "project", mcpMode: "none" });
|
|
407
592
|
}
|
|
408
593
|
finally {
|
|
409
594
|
await rm(wd, { recursive: true, force: true });
|
|
@@ -417,11 +602,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
417
602
|
await setup({ scope: "user", installMode: "plugin" });
|
|
418
603
|
await setup({ scope: "project" });
|
|
419
604
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
420
|
-
assert.deepEqual(persisted, { scope: "project" });
|
|
605
|
+
assert.deepEqual(persisted, { scope: "project", mcpMode: "none" });
|
|
421
606
|
assert.equal(existsSync(join(wd, ".codex", "skills", "ask", "SKILL.md")), true);
|
|
422
607
|
await setup({ scope: "project" });
|
|
423
608
|
const repeatedPersisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
424
|
-
assert.deepEqual(repeatedPersisted, { scope: "project" });
|
|
609
|
+
assert.deepEqual(repeatedPersisted, { scope: "project", mcpMode: "none" });
|
|
425
610
|
assert.equal(existsSync(join(wd, ".codex", "agents", "planner.toml")), true);
|
|
426
611
|
assert.equal(existsSync(join(wd, ".codex", "prompts", "executor.md")), true);
|
|
427
612
|
});
|
|
@@ -439,7 +624,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
439
624
|
await setup({ scope: "project", installMode: "plugin" });
|
|
440
625
|
await setup({ scope: "user" });
|
|
441
626
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
442
|
-
assert.deepEqual(persisted, {
|
|
627
|
+
assert.deepEqual(persisted, {
|
|
628
|
+
scope: "user",
|
|
629
|
+
installMode: "legacy",
|
|
630
|
+
mcpMode: "none",
|
|
631
|
+
});
|
|
443
632
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), true);
|
|
444
633
|
assert.equal(existsSync(join(codexHomeDir, "agents", "planner.toml")), true);
|
|
445
634
|
assert.equal(existsSync(join(codexHomeDir, "prompts", "executor.md")), true);
|
|
@@ -478,7 +667,11 @@ describe("omx setup install mode behavior", () => {
|
|
|
478
667
|
assert.equal(parsed.marketplaces?.other?.source, "/tmp/other");
|
|
479
668
|
assert.equal((config.match(/^\[marketplaces\.oh-my-codex-local\]$/gm) ?? [])
|
|
480
669
|
.length, 1);
|
|
481
|
-
assert.match(
|
|
670
|
+
assert.equal((config.match(/^\[plugins\."oh-my-codex@oh-my-codex-local"\]$/gm) ?? [])
|
|
671
|
+
.length, 1);
|
|
672
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.enabled, true);
|
|
673
|
+
assert.match(config, /^hooks = true$/m);
|
|
674
|
+
assert.doesNotMatch(config, /^codex_hooks = true$/m);
|
|
482
675
|
assert.doesNotMatch(config, /\[mcp_servers\./);
|
|
483
676
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), false);
|
|
484
677
|
assert.equal(existsSync(join(codexHomeDir, "agents", "planner.toml")), false);
|
|
@@ -490,6 +683,67 @@ describe("omx setup install mode behavior", () => {
|
|
|
490
683
|
await rm(wd, { recursive: true, force: true });
|
|
491
684
|
}
|
|
492
685
|
});
|
|
686
|
+
it("enables the local Codex plugin while preserving plugin subtable policy", async () => {
|
|
687
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
688
|
+
try {
|
|
689
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
690
|
+
await withTempCwd(wd, async () => {
|
|
691
|
+
const configPath = join(codexHomeDir, "config.toml");
|
|
692
|
+
await writeFile(configPath, [
|
|
693
|
+
"[plugins.\"oh-my-codex@oh-my-codex-local\"]",
|
|
694
|
+
"enabled = false",
|
|
695
|
+
"",
|
|
696
|
+
"[plugins.\"oh-my-codex@oh-my-codex-local\".mcp_servers.omx_state]",
|
|
697
|
+
"enabled = false",
|
|
698
|
+
"",
|
|
699
|
+
].join("\n"));
|
|
700
|
+
await setup({ scope: "user", installMode: "plugin", force: true });
|
|
701
|
+
await setup({ scope: "user", installMode: "plugin", force: true });
|
|
702
|
+
const config = await readFile(configPath, "utf-8");
|
|
703
|
+
const parsed = parseToml(config);
|
|
704
|
+
assert.equal((config.match(/^\[plugins\."oh-my-codex@oh-my-codex-local"\]$/gm) ?? [])
|
|
705
|
+
.length, 1);
|
|
706
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.enabled, true);
|
|
707
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.mcp_servers
|
|
708
|
+
?.omx_state?.enabled, false);
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
finally {
|
|
713
|
+
await rm(wd, { recursive: true, force: true });
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
it("enables plugin MCP subtables only when compat MCP mode is requested", async () => {
|
|
717
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
718
|
+
try {
|
|
719
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
720
|
+
await withTempCwd(wd, async () => {
|
|
721
|
+
const configPath = join(codexHomeDir, "config.toml");
|
|
722
|
+
await setup({
|
|
723
|
+
scope: "user",
|
|
724
|
+
installMode: "plugin",
|
|
725
|
+
mcpMode: "compat",
|
|
726
|
+
force: true,
|
|
727
|
+
});
|
|
728
|
+
let parsed = parseToml(await readFile(configPath, "utf-8"));
|
|
729
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.mcp_servers
|
|
730
|
+
?.omx_state?.enabled, true);
|
|
731
|
+
await setup({
|
|
732
|
+
scope: "user",
|
|
733
|
+
installMode: "plugin",
|
|
734
|
+
mcpMode: "none",
|
|
735
|
+
force: true,
|
|
736
|
+
});
|
|
737
|
+
parsed = parseToml(await readFile(configPath, "utf-8"));
|
|
738
|
+
assert.equal(parsed.plugins?.["oh-my-codex@oh-my-codex-local"]?.mcp_servers
|
|
739
|
+
?.omx_state?.enabled, false);
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
finally {
|
|
744
|
+
await rm(wd, { recursive: true, force: true });
|
|
745
|
+
}
|
|
746
|
+
});
|
|
493
747
|
it("reports plugin marketplace registration during dry-run without mutating config", async () => {
|
|
494
748
|
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
495
749
|
try {
|
|
@@ -514,15 +768,21 @@ describe("omx setup install mode behavior", () => {
|
|
|
514
768
|
try {
|
|
515
769
|
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
516
770
|
await withTempCwd(wd, async () => {
|
|
771
|
+
await setup({ scope: "user", installMode: "plugin" });
|
|
517
772
|
await setup({ scope: "user", installMode: "plugin" });
|
|
518
773
|
const hooks = await readFile(join(codexHomeDir, "hooks.json"), "utf-8");
|
|
519
774
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
520
775
|
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
521
|
-
|
|
776
|
+
const parsed = parseToml(config);
|
|
777
|
+
const managedHookStateKeys = Object.keys(parsed.hooks?.state ?? {}).filter((key) => key.includes(`${codexHomeDir}/hooks.json:`));
|
|
778
|
+
assert.equal(managedHookStateKeys.length, 7);
|
|
779
|
+
assert.match(config, /^hooks = true$/m);
|
|
780
|
+
assert.doesNotMatch(config, /^codex_hooks = true$/m);
|
|
522
781
|
assert.match(config, /^goals = true$/m);
|
|
523
782
|
assert.match(config, /^\[hooks\.state\.".*hooks\.json:pre_tool_use:0:0"\]$/m);
|
|
783
|
+
assert.equal((config.match(/^\[hooks\.state\.".*hooks\.json:pre_tool_use:0:0"\]$/gm) ?? []).length, 1);
|
|
524
784
|
assert.match(config, /^trusted_hash = "sha256:[a-f0-9]{64}"$/m);
|
|
525
|
-
assert.doesNotMatch(config, /developer_instructions|notify-hook
|
|
785
|
+
assert.doesNotMatch(config, /developer_instructions|notify-hook/g);
|
|
526
786
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), false);
|
|
527
787
|
assert.equal(existsSync(join(codexHomeDir, "agents", "planner.toml")), false);
|
|
528
788
|
assert.equal(existsSync(join(codexHomeDir, "prompts", "executor.md")), false);
|
|
@@ -557,8 +817,10 @@ describe("omx setup install mode behavior", () => {
|
|
|
557
817
|
assert.match(config, /Setup-owned prompt files and native-agent TOML defaults are intentionally omitted unless explicitly installed/);
|
|
558
818
|
assert.doesNotMatch(config, /Native subagents live in \.codex\/agents/);
|
|
559
819
|
assert.doesNotMatch(config, /Treat installed prompts as narrower execution surfaces/);
|
|
560
|
-
assert.match(config, /^
|
|
561
|
-
assert.doesNotMatch(config, /notify-hook
|
|
820
|
+
assert.match(config, /^hooks = true$/m);
|
|
821
|
+
assert.doesNotMatch(config, /notify-hook/);
|
|
822
|
+
assert.doesNotMatch(config, /^\s*\[mcp_servers[.\]]/m);
|
|
823
|
+
assert.match(config, /mcp_servers\.omx_state]\nenabled = false/);
|
|
562
824
|
const agentsMd = await readFile(join(codexHomeDir, "AGENTS.md"), "utf-8");
|
|
563
825
|
assert.match(agentsMd, /oh-my-codex - Intelligent Multi-Agent Orchestration/);
|
|
564
826
|
assert.match(agentsMd, /<!-- omx:generated:agents-md -->/);
|
|
@@ -618,7 +880,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
618
880
|
});
|
|
619
881
|
const config = await readFile(configPath, "utf-8");
|
|
620
882
|
assert.match(config, /^developer_instructions = "custom"$/m);
|
|
621
|
-
assert.match(config, /^
|
|
883
|
+
assert.match(config, /^hooks = true$/m);
|
|
622
884
|
assert.equal((config.match(/^developer_instructions\s*=/gm) ?? []).length, 1);
|
|
623
885
|
});
|
|
624
886
|
});
|
|
@@ -644,7 +906,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
644
906
|
assert.match(config, /You have oh-my-codex installed/);
|
|
645
907
|
assert.doesNotMatch(config, /^developer_instructions = "custom"$/m);
|
|
646
908
|
assert.equal((config.match(/^developer_instructions\s*=/gm) ?? []).length, 1);
|
|
647
|
-
assert.match(config, /^
|
|
909
|
+
assert.match(config, /^hooks = true$/m);
|
|
648
910
|
assert.match(config, /^\[hooks\.state\.".*hooks\.json:pre_tool_use:0:0"\]$/m);
|
|
649
911
|
});
|
|
650
912
|
});
|
|
@@ -653,6 +915,27 @@ describe("omx setup install mode behavior", () => {
|
|
|
653
915
|
await rm(wd, { recursive: true, force: true });
|
|
654
916
|
}
|
|
655
917
|
});
|
|
918
|
+
it("uses legacy codex_hooks only when the installed Codex reports that hook feature", async () => {
|
|
919
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
920
|
+
try {
|
|
921
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
922
|
+
await withTempCwd(wd, async () => {
|
|
923
|
+
await setup({
|
|
924
|
+
scope: "user",
|
|
925
|
+
installMode: "plugin",
|
|
926
|
+
codexFeaturesProbe: () => "codex_hooks experimental true\n",
|
|
927
|
+
codexVersionProbe: () => "codex-cli 0.129.0",
|
|
928
|
+
});
|
|
929
|
+
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
930
|
+
assert.match(config, /^codex_hooks = true$/m);
|
|
931
|
+
assert.doesNotMatch(config, /^hooks = true$/m);
|
|
932
|
+
});
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
finally {
|
|
936
|
+
await rm(wd, { recursive: true, force: true });
|
|
937
|
+
}
|
|
938
|
+
});
|
|
656
939
|
it("preserves existing user hooks while installing plugin-mode native hooks", async () => {
|
|
657
940
|
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
658
941
|
try {
|
|
@@ -666,7 +949,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
666
949
|
assert.match(hooks, /"UserPromptSubmit"/);
|
|
667
950
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
668
951
|
const config = await readFile(join(codexHomeDir, "config.toml"), "utf-8");
|
|
669
|
-
assert.match(config, /^
|
|
952
|
+
assert.match(config, /^hooks = true$/m);
|
|
670
953
|
});
|
|
671
954
|
});
|
|
672
955
|
}
|
|
@@ -683,6 +966,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
683
966
|
assert.deepEqual(persisted, {
|
|
684
967
|
scope: "project",
|
|
685
968
|
installMode: "plugin",
|
|
969
|
+
mcpMode: "none",
|
|
686
970
|
});
|
|
687
971
|
await setup({ scope: "project" });
|
|
688
972
|
assert.equal(existsSync(join(wd, ".codex", "skills", "ask", "SKILL.md")), false);
|
|
@@ -704,7 +988,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
704
988
|
await writeFile(join(wd, ".omx", "setup-scope.json"), JSON.stringify({ scope: "project", installMode: "plugin" }));
|
|
705
989
|
await setup({ scope: "project", installMode: "legacy" });
|
|
706
990
|
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
707
|
-
assert.deepEqual(persisted, { scope: "project" });
|
|
991
|
+
assert.deepEqual(persisted, { scope: "project", mcpMode: "none" });
|
|
708
992
|
assert.equal(existsSync(join(wd, ".codex", "skills", "ask", "SKILL.md")), true);
|
|
709
993
|
assert.equal(existsSync(join(wd, ".codex", "agents", "planner.toml")), true);
|
|
710
994
|
assert.equal(existsSync(join(wd, ".codex", "prompts", "executor.md")), true);
|
|
@@ -726,6 +1010,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
726
1010
|
assert.deepEqual(persisted, {
|
|
727
1011
|
scope: "user",
|
|
728
1012
|
installMode: "legacy",
|
|
1013
|
+
mcpMode: "none",
|
|
729
1014
|
});
|
|
730
1015
|
assert.equal(existsSync(join(codexHomeDir, "skills", "ask", "SKILL.md")), true);
|
|
731
1016
|
assert.equal(existsSync(join(codexHomeDir, "agents", "planner.toml")), true);
|
|
@@ -737,6 +1022,44 @@ describe("omx setup install mode behavior", () => {
|
|
|
737
1022
|
await rm(wd, { recursive: true, force: true });
|
|
738
1023
|
}
|
|
739
1024
|
});
|
|
1025
|
+
it("dedupes plugin-mode hook trust state when switching user setup back to legacy", async () => {
|
|
1026
|
+
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
1027
|
+
try {
|
|
1028
|
+
await withIsolatedUserHome(wd, async (codexHomeDir) => {
|
|
1029
|
+
await withTempCwd(wd, async () => {
|
|
1030
|
+
const configPath = join(codexHomeDir, "config.toml");
|
|
1031
|
+
await setup({ scope: "user", installMode: "plugin", force: true });
|
|
1032
|
+
const pluginConfig = await readFile(configPath, "utf-8");
|
|
1033
|
+
const staleUnfencedPluginConfig = pluginConfig
|
|
1034
|
+
.split(/\r?\n/)
|
|
1035
|
+
.filter((line) => line.trim() !== "# OMX-owned Codex hook trust state" &&
|
|
1036
|
+
line.trim() !==
|
|
1037
|
+
"# Trusts only setup-managed codex-native-hook.js wrappers." &&
|
|
1038
|
+
line.trim() !== "# End OMX-owned Codex hook trust state")
|
|
1039
|
+
.join("\n");
|
|
1040
|
+
await writeFile(configPath, staleUnfencedPluginConfig);
|
|
1041
|
+
assert.doesNotThrow(() => parseToml(staleUnfencedPluginConfig));
|
|
1042
|
+
await setup({ scope: "user", installMode: "legacy", force: true });
|
|
1043
|
+
const legacyConfig = await readFile(configPath, "utf-8");
|
|
1044
|
+
assert.doesNotThrow(() => parseToml(legacyConfig));
|
|
1045
|
+
assert.equal(legacyConfig
|
|
1046
|
+
.split(/\r?\n/)
|
|
1047
|
+
.filter((line) => line.trim() ===
|
|
1048
|
+
`[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");
|
|
1049
|
+
assert.match(legacyConfig, /# OMX-owned Codex hook trust state[\s\S]*# End OMX-owned Codex hook trust state/);
|
|
1050
|
+
const persisted = JSON.parse(await readFile(join(wd, ".omx", "setup-scope.json"), "utf-8"));
|
|
1051
|
+
assert.deepEqual(persisted, {
|
|
1052
|
+
scope: "user",
|
|
1053
|
+
installMode: "legacy",
|
|
1054
|
+
mcpMode: "none",
|
|
1055
|
+
});
|
|
1056
|
+
});
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
finally {
|
|
1060
|
+
await rm(wd, { recursive: true, force: true });
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
740
1063
|
it("installs project-scoped native hooks when plugin mode is explicitly requested", async () => {
|
|
741
1064
|
const wd = await mkdtemp(join(tmpdir(), "omx-setup-install-mode-"));
|
|
742
1065
|
try {
|
|
@@ -771,7 +1094,7 @@ describe("omx setup install mode behavior", () => {
|
|
|
771
1094
|
await setup({ scope: "project", installMode: "plugin" });
|
|
772
1095
|
});
|
|
773
1096
|
assert.match(pluginOutput, /Using setup install mode: plugin/);
|
|
774
|
-
assert.match(pluginOutput, /Native Codex hooks and runtime feature flags refresh complete .*
|
|
1097
|
+
assert.match(pluginOutput, /Native Codex hooks and runtime feature flags refresh complete .*hooks, goals/);
|
|
775
1098
|
assert.doesNotMatch(pluginOutput, /user-scope skill delivery mode/);
|
|
776
1099
|
assert.doesNotMatch(pluginOutput, /Native agent defaults configured.*TOML files written to \.codex\/agents\//);
|
|
777
1100
|
assert.doesNotMatch(pluginOutput, /Use role\/workflow keywords like \$architect, \$executor, and \$plan/);
|
|
@@ -825,8 +1148,8 @@ describe("omx setup install mode behavior", () => {
|
|
|
825
1148
|
const hooks = await readFile(hooksPath, "utf-8");
|
|
826
1149
|
assert.match(hooks, /codex-native-hook\.js/);
|
|
827
1150
|
const config = await readFile(configPath, "utf-8");
|
|
828
|
-
assert.match(config, /^
|
|
829
|
-
assert.doesNotMatch(config,
|
|
1151
|
+
assert.match(config, /^hooks = true$/m);
|
|
1152
|
+
assert.doesNotMatch(config, /^\s*(?:notify|developer_instructions)\s*=|^\s*\[mcp_servers[.\]]/m);
|
|
830
1153
|
});
|
|
831
1154
|
});
|
|
832
1155
|
}
|