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
package/dist/config/generator.js
CHANGED
|
@@ -11,15 +11,19 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { readFile, writeFile } from "fs/promises";
|
|
13
13
|
import { existsSync } from "fs";
|
|
14
|
-
import { join } from "path";
|
|
14
|
+
import { join, resolve } from "path";
|
|
15
15
|
import TOML from "@iarna/toml";
|
|
16
16
|
import { AGENT_DEFINITIONS } from "../agents/definitions.js";
|
|
17
17
|
import { DEFAULT_FRONTIER_MODEL } from "./models.js";
|
|
18
|
-
import {
|
|
18
|
+
import { DEFAULT_CODEX_HOOK_FEATURE_FLAG, CODEX_HOOK_FEATURE_FLAGS, formatCodexHookFeatureFlagLine, normalizeCodexHookFeatureFlag, } from "./codex-feature-flags.js";
|
|
19
|
+
import { OMX_FIRST_PARTY_MCP_SERVER_NAMES, getOmxFirstPartySetupMcpServers, } from "./omx-first-party-mcp.js";
|
|
19
20
|
import { buildManagedCodexHookTrustToml } from "./codex-hooks.js";
|
|
20
21
|
function escapeTomlString(value) {
|
|
21
22
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
22
23
|
}
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
23
27
|
// ---------------------------------------------------------------------------
|
|
24
28
|
// Top-level OMX keys (must live before any [table] header)
|
|
25
29
|
// ---------------------------------------------------------------------------
|
|
@@ -183,13 +187,68 @@ function parseRootKeyValues(config) {
|
|
|
183
187
|
}
|
|
184
188
|
return values;
|
|
185
189
|
}
|
|
186
|
-
function
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
function getDefaultNotifyCommand(pkgRoot) {
|
|
191
|
+
return ["node", join(pkgRoot, "dist", "scripts", "notify-hook.js")];
|
|
192
|
+
}
|
|
193
|
+
export function formatTomlStringArray(values) {
|
|
194
|
+
return `[${values.map((value) => `"${escapeTomlString(value)}"`).join(", ")}]`;
|
|
195
|
+
}
|
|
196
|
+
export function getRootTomlArray(config, key) {
|
|
197
|
+
const raw = parseRootKeyValues(config).get(key);
|
|
198
|
+
if (!raw)
|
|
199
|
+
return null;
|
|
200
|
+
try {
|
|
201
|
+
const parsed = TOML.parse(`${key} = ${raw}`);
|
|
202
|
+
const value = parsed[key];
|
|
203
|
+
if (!Array.isArray(value) ||
|
|
204
|
+
!value.every((item) => typeof item === "string")) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function resolveNotifyEntrypoint(command) {
|
|
214
|
+
if (!/(?:^|[\\/])node(?:\.exe)?$/i.test(command[0] ?? "")) {
|
|
215
|
+
return command[0];
|
|
216
|
+
}
|
|
217
|
+
return command.slice(1).find((arg) => !arg.startsWith("-"));
|
|
218
|
+
}
|
|
219
|
+
export function isOmxManagedNotifyCommand(command, pkgRoot) {
|
|
220
|
+
if (!command)
|
|
221
|
+
return false;
|
|
222
|
+
const entrypoint = resolveNotifyEntrypoint(command);
|
|
223
|
+
if (!entrypoint)
|
|
224
|
+
return false;
|
|
225
|
+
if (!/(?:^|[\\/])notify-(?:hook|dispatcher)\.js$/.test(entrypoint)) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
const managedScripts = pkgRoot
|
|
229
|
+
? new Set([
|
|
230
|
+
resolve(pkgRoot, "dist", "scripts", "notify-hook.js"),
|
|
231
|
+
resolve(pkgRoot, "dist", "scripts", "notify-dispatcher.js"),
|
|
232
|
+
])
|
|
233
|
+
: new Set();
|
|
234
|
+
if (pkgRoot && managedScripts.has(resolve(entrypoint)))
|
|
235
|
+
return true;
|
|
236
|
+
return /(?:^|[\\/])oh-my-codex(?:[\\/]|$)/.test(entrypoint);
|
|
237
|
+
}
|
|
238
|
+
export function sanitizePreviousNotifyCommand(command, pkgRoot) {
|
|
239
|
+
if (!command || command.length === 0)
|
|
240
|
+
return null;
|
|
241
|
+
if (isOmxManagedNotifyCommand(command, pkgRoot))
|
|
242
|
+
return null;
|
|
243
|
+
return [...command];
|
|
244
|
+
}
|
|
245
|
+
function getOmxTopLevelLines(pkgRoot, existingConfig = "", modelOverride, notifyCommand = getDefaultNotifyCommand(pkgRoot)) {
|
|
189
246
|
const rootValues = parseRootKeyValues(existingConfig);
|
|
190
247
|
const lines = [
|
|
191
248
|
"# oh-my-codex top-level settings (must be before any [table])",
|
|
192
|
-
|
|
249
|
+
...(notifyCommand === false
|
|
250
|
+
? []
|
|
251
|
+
: [`notify = ${formatTomlStringArray(notifyCommand)}`]),
|
|
193
252
|
'model_reasoning_effort = "medium"',
|
|
194
253
|
`developer_instructions = "${escapeTomlString(OMX_DEVELOPER_INSTRUCTIONS)}"`,
|
|
195
254
|
];
|
|
@@ -280,8 +339,18 @@ function stripRootLevelKeys(config, keys) {
|
|
|
280
339
|
}
|
|
281
340
|
return result.join("\n");
|
|
282
341
|
}
|
|
283
|
-
function
|
|
342
|
+
function escapeRegExp(value) {
|
|
343
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
344
|
+
}
|
|
345
|
+
function stripOrphanedManagedNotify(config, pkgRoot) {
|
|
346
|
+
const rootNotify = getRootTomlArray(config, "notify");
|
|
347
|
+
if (rootNotify &&
|
|
348
|
+
!isOmxManagedNotifyCommand(rootNotify, pkgRoot)) {
|
|
349
|
+
return config;
|
|
350
|
+
}
|
|
351
|
+
const managedHookPath = escapeRegExp(resolve(pkgRoot, "dist", "scripts", "notify-hook.js"));
|
|
284
352
|
return config
|
|
353
|
+
.replace(new RegExp(`^\\s*notify\\s*=\\s*\\["node",\\s*"${managedHookPath}"\\]\\s*$(\\n)?`, "gm"), "")
|
|
285
354
|
.replace(/^\s*notify\s*=\s*\["node",\s*".*notify-hook\.js"\]\s*$(\n)?/gm, "")
|
|
286
355
|
.replace(/\n?\s*"node",\s*\n\s*".*notify-hook\.js",\s*\n\s*\]\s*(?=\n|$)/g, "");
|
|
287
356
|
}
|
|
@@ -295,16 +364,56 @@ export function stripOmxTopLevelKeys(config) {
|
|
|
295
364
|
// ---------------------------------------------------------------------------
|
|
296
365
|
// [features] upsert
|
|
297
366
|
// ---------------------------------------------------------------------------
|
|
298
|
-
function
|
|
367
|
+
function isFeatureFlagLine(line, featureFlag) {
|
|
368
|
+
return new RegExp(`^\\s*${featureFlag}\\s*=`).test(line);
|
|
369
|
+
}
|
|
370
|
+
function isAnyCodexHookFeatureFlagLine(line) {
|
|
371
|
+
return CODEX_HOOK_FEATURE_FLAGS.some((flag) => isFeatureFlagLine(line, flag));
|
|
372
|
+
}
|
|
373
|
+
function upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag) {
|
|
374
|
+
const featureFlag = normalizeCodexHookFeatureFlag(codexHookFeatureFlag);
|
|
375
|
+
let featureFlagIdx = -1;
|
|
376
|
+
let fallbackAliasIdx = -1;
|
|
377
|
+
for (let i = featuresStart + 1; i < sectionEnd; i++) {
|
|
378
|
+
if (isFeatureFlagLine(lines[i], featureFlag)) {
|
|
379
|
+
featureFlagIdx = i;
|
|
380
|
+
}
|
|
381
|
+
else if (isAnyCodexHookFeatureFlagLine(lines[i]) && fallbackAliasIdx < 0) {
|
|
382
|
+
fallbackAliasIdx = i;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (featureFlagIdx < 0 && fallbackAliasIdx >= 0) {
|
|
386
|
+
featureFlagIdx = fallbackAliasIdx;
|
|
387
|
+
}
|
|
388
|
+
if (featureFlagIdx >= 0) {
|
|
389
|
+
lines[featureFlagIdx] = formatCodexHookFeatureFlagLine(featureFlag);
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
lines.splice(sectionEnd, 0, formatCodexHookFeatureFlagLine(featureFlag));
|
|
393
|
+
featureFlagIdx = sectionEnd;
|
|
394
|
+
sectionEnd += 1;
|
|
395
|
+
}
|
|
396
|
+
for (let i = sectionEnd - 1; i > featuresStart; i--) {
|
|
397
|
+
if (i !== featureFlagIdx && isAnyCodexHookFeatureFlagLine(lines[i])) {
|
|
398
|
+
lines.splice(i, 1);
|
|
399
|
+
sectionEnd -= 1;
|
|
400
|
+
if (featureFlagIdx > i)
|
|
401
|
+
featureFlagIdx -= 1;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return { sectionEnd, featureFlagIndex: featureFlagIdx };
|
|
405
|
+
}
|
|
406
|
+
function upsertFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG) {
|
|
299
407
|
const lines = config.split(/\r?\n/);
|
|
300
408
|
const featuresStart = lines.findIndex((line) => /^\s*\[features\]\s*$/.test(line));
|
|
409
|
+
const hookFeatureFlagLine = formatCodexHookFeatureFlagLine(codexHookFeatureFlag);
|
|
301
410
|
if (featuresStart < 0) {
|
|
302
411
|
const base = config.trimEnd();
|
|
303
412
|
const featureBlock = [
|
|
304
413
|
"[features]",
|
|
305
414
|
"multi_agent = true",
|
|
306
415
|
"child_agents_md = true",
|
|
307
|
-
|
|
416
|
+
hookFeatureFlagLine,
|
|
308
417
|
"goals = true",
|
|
309
418
|
"",
|
|
310
419
|
].join("\n");
|
|
@@ -330,9 +439,6 @@ function upsertFeatureFlags(config) {
|
|
|
330
439
|
}
|
|
331
440
|
let multiAgentIdx = -1;
|
|
332
441
|
let childAgentsIdx = -1;
|
|
333
|
-
let hooksIdx = -1;
|
|
334
|
-
let legacyCodexHooksIdx = -1;
|
|
335
|
-
let goalsIdx = -1;
|
|
336
442
|
for (let i = featuresStart + 1; i < sectionEnd; i++) {
|
|
337
443
|
if (/^\s*multi_agent\s*=/.test(lines[i])) {
|
|
338
444
|
multiAgentIdx = i;
|
|
@@ -340,15 +446,6 @@ function upsertFeatureFlags(config) {
|
|
|
340
446
|
else if (/^\s*child_agents_md\s*=/.test(lines[i])) {
|
|
341
447
|
childAgentsIdx = i;
|
|
342
448
|
}
|
|
343
|
-
else if (/^\s*hooks\s*=/.test(lines[i])) {
|
|
344
|
-
hooksIdx = i;
|
|
345
|
-
}
|
|
346
|
-
else if (/^\s*codex_hooks\s*=/.test(lines[i])) {
|
|
347
|
-
legacyCodexHooksIdx = i;
|
|
348
|
-
}
|
|
349
|
-
else if (/^\s*goals\s*=/.test(lines[i])) {
|
|
350
|
-
goalsIdx = i;
|
|
351
|
-
}
|
|
352
449
|
}
|
|
353
450
|
if (multiAgentIdx >= 0) {
|
|
354
451
|
lines[multiAgentIdx] = "multi_agent = true";
|
|
@@ -364,22 +461,13 @@ function upsertFeatureFlags(config) {
|
|
|
364
461
|
lines.splice(sectionEnd, 0, "child_agents_md = true");
|
|
365
462
|
sectionEnd += 1;
|
|
366
463
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (goalsIdx > legacyCodexHooksIdx)
|
|
373
|
-
goalsIdx -= 1;
|
|
464
|
+
({ sectionEnd } = upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
|
|
465
|
+
let goalsIdx = -1;
|
|
466
|
+
for (let i = featuresStart + 1; i < sectionEnd; i++) {
|
|
467
|
+
if (/^\s*goals\s*=/.test(lines[i])) {
|
|
468
|
+
goalsIdx = i;
|
|
374
469
|
}
|
|
375
470
|
}
|
|
376
|
-
else if (legacyCodexHooksIdx >= 0) {
|
|
377
|
-
lines[legacyCodexHooksIdx] = "codex_hooks = true";
|
|
378
|
-
}
|
|
379
|
-
else {
|
|
380
|
-
lines.splice(sectionEnd, 0, "codex_hooks = true");
|
|
381
|
-
sectionEnd += 1;
|
|
382
|
-
}
|
|
383
471
|
if (goalsIdx >= 0) {
|
|
384
472
|
lines[goalsIdx] = "goals = true";
|
|
385
473
|
}
|
|
@@ -391,12 +479,58 @@ function upsertFeatureFlags(config) {
|
|
|
391
479
|
const OMX_HOOK_TRUST_START_MARKER = "# OMX-owned Codex hook trust state";
|
|
392
480
|
const OMX_HOOK_TRUST_END_MARKER = "# End OMX-owned Codex hook trust state";
|
|
393
481
|
export function stripManagedCodexHookTrustState(config) {
|
|
394
|
-
const
|
|
395
|
-
|
|
482
|
+
const lines = config.split(/\r?\n/);
|
|
483
|
+
const kept = [];
|
|
484
|
+
for (let i = 0; i < lines.length;) {
|
|
485
|
+
const trimmed = lines[i].trim();
|
|
486
|
+
if (trimmed !== OMX_HOOK_TRUST_START_MARKER) {
|
|
487
|
+
kept.push(lines[i]);
|
|
488
|
+
i += 1;
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const nextEndIdx = lines.findIndex((line, index) => index > i && line.trim() === OMX_HOOK_TRUST_END_MARKER);
|
|
492
|
+
const nextStartIdx = lines.findIndex((line, index) => index > i && line.trim() === OMX_HOOK_TRUST_START_MARKER);
|
|
493
|
+
if (nextEndIdx === -1 || (nextStartIdx !== -1 && nextStartIdx < nextEndIdx)) {
|
|
494
|
+
kept.push(lines[i]);
|
|
495
|
+
i += 1;
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
i = nextEndIdx + 1;
|
|
499
|
+
}
|
|
500
|
+
return kept.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
501
|
+
}
|
|
502
|
+
function managedCodexHookTrustStateHeaders(hookTrustToml) {
|
|
503
|
+
const headers = new Set();
|
|
504
|
+
for (const line of hookTrustToml.split(/\r?\n/)) {
|
|
505
|
+
const trimmed = line.trim();
|
|
506
|
+
if (/^\[hooks\.state\./.test(trimmed)) {
|
|
507
|
+
headers.add(trimmed);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return headers;
|
|
511
|
+
}
|
|
512
|
+
function stripUnfencedManagedCodexHookTrustState(config, hookTrustToml) {
|
|
513
|
+
const managedHeaders = managedCodexHookTrustStateHeaders(hookTrustToml);
|
|
514
|
+
if (managedHeaders.size === 0)
|
|
515
|
+
return config;
|
|
516
|
+
const lines = config.split(/\r?\n/);
|
|
517
|
+
const kept = [];
|
|
518
|
+
for (let i = 0; i < lines.length;) {
|
|
519
|
+
if (!managedHeaders.has(lines[i].trim())) {
|
|
520
|
+
kept.push(lines[i]);
|
|
521
|
+
i += 1;
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
i += 1;
|
|
525
|
+
while (i < lines.length && !TOML_TABLE_HEADER_PATTERN.test(lines[i])) {
|
|
526
|
+
i += 1;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return kept.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
396
530
|
}
|
|
397
531
|
export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile) {
|
|
398
|
-
const stripped = stripManagedCodexHookTrustState(config);
|
|
399
532
|
const hookTrustToml = buildManagedCodexHookTrustToml(codexHooksFile, pkgRoot);
|
|
533
|
+
const stripped = stripUnfencedManagedCodexHookTrustState(stripManagedCodexHookTrustState(config), hookTrustToml);
|
|
400
534
|
if (!hookTrustToml)
|
|
401
535
|
return `${stripped}\n`;
|
|
402
536
|
return [
|
|
@@ -409,14 +543,15 @@ export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile
|
|
|
409
543
|
"",
|
|
410
544
|
].filter((line, index) => index !== 0 || line.length > 0).join("\n");
|
|
411
545
|
}
|
|
412
|
-
export function upsertPluginModeRuntimeFeatureFlags(config) {
|
|
546
|
+
export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG) {
|
|
413
547
|
const lines = config.split(/\r?\n/);
|
|
414
548
|
const featuresStart = lines.findIndex((line) => /^\s*\[features\]\s*$/.test(line));
|
|
549
|
+
const hookFeatureFlagLine = formatCodexHookFeatureFlagLine(codexHookFeatureFlag);
|
|
415
550
|
if (featuresStart < 0) {
|
|
416
551
|
const base = config.trimEnd();
|
|
417
552
|
const featureBlock = [
|
|
418
553
|
"[features]",
|
|
419
|
-
|
|
554
|
+
hookFeatureFlagLine,
|
|
420
555
|
"goals = true",
|
|
421
556
|
"",
|
|
422
557
|
].join("\n");
|
|
@@ -440,36 +575,13 @@ export function upsertPluginModeRuntimeFeatureFlags(config) {
|
|
|
440
575
|
sectionEnd -= 1;
|
|
441
576
|
}
|
|
442
577
|
}
|
|
443
|
-
|
|
444
|
-
let legacyCodexHooksIdx = -1;
|
|
578
|
+
({ sectionEnd } = upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
|
|
445
579
|
let goalsIdx = -1;
|
|
446
580
|
for (let i = featuresStart + 1; i < sectionEnd; i++) {
|
|
447
|
-
if (/^\s*
|
|
448
|
-
hooksIdx = i;
|
|
449
|
-
}
|
|
450
|
-
else if (/^\s*codex_hooks\s*=/.test(lines[i])) {
|
|
451
|
-
legacyCodexHooksIdx = i;
|
|
452
|
-
}
|
|
453
|
-
else if (/^\s*goals\s*=/.test(lines[i])) {
|
|
581
|
+
if (/^\s*goals\s*=/.test(lines[i])) {
|
|
454
582
|
goalsIdx = i;
|
|
455
583
|
}
|
|
456
584
|
}
|
|
457
|
-
if (hooksIdx >= 0) {
|
|
458
|
-
lines[hooksIdx] = "codex_hooks = true";
|
|
459
|
-
if (legacyCodexHooksIdx >= 0) {
|
|
460
|
-
lines.splice(legacyCodexHooksIdx, 1);
|
|
461
|
-
sectionEnd--;
|
|
462
|
-
if (goalsIdx > legacyCodexHooksIdx)
|
|
463
|
-
goalsIdx--;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
else if (legacyCodexHooksIdx >= 0) {
|
|
467
|
-
lines[legacyCodexHooksIdx] = "codex_hooks = true";
|
|
468
|
-
}
|
|
469
|
-
else {
|
|
470
|
-
lines.splice(sectionEnd, 0, "codex_hooks = true");
|
|
471
|
-
sectionEnd++;
|
|
472
|
-
}
|
|
473
585
|
if (goalsIdx >= 0) {
|
|
474
586
|
lines[goalsIdx] = "goals = true";
|
|
475
587
|
}
|
|
@@ -681,6 +793,29 @@ export function stripOmxFeatureFlags(config) {
|
|
|
681
793
|
}
|
|
682
794
|
return filtered.join("\n");
|
|
683
795
|
}
|
|
796
|
+
/**
|
|
797
|
+
* Preserve native Codex hook enablement without re-adding other OMX feature
|
|
798
|
+
* flags. Used by uninstall when user-owned hooks remain in hooks.json.
|
|
799
|
+
*/
|
|
800
|
+
export function upsertCodexHooksFeatureFlag(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG) {
|
|
801
|
+
const lines = config.split(/\r?\n/);
|
|
802
|
+
const featuresStart = lines.findIndex((line) => /^\s*\[features\]\s*$/.test(line));
|
|
803
|
+
const hookFeatureFlagLine = formatCodexHookFeatureFlagLine(codexHookFeatureFlag);
|
|
804
|
+
if (featuresStart < 0) {
|
|
805
|
+
const base = config.trimEnd();
|
|
806
|
+
const featureBlock = ["[features]", hookFeatureFlagLine, ""].join("\n");
|
|
807
|
+
return base.length === 0 ? featureBlock : `${base}\n${featureBlock}`;
|
|
808
|
+
}
|
|
809
|
+
let sectionEnd = lines.length;
|
|
810
|
+
for (let i = featuresStart + 1; i < lines.length; i++) {
|
|
811
|
+
if (/^\s*\[\[?[^\]]+\]?\]\s*$/.test(lines[i])) {
|
|
812
|
+
sectionEnd = i;
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag);
|
|
817
|
+
return lines.join("\n");
|
|
818
|
+
}
|
|
684
819
|
export function stripOmxEnvSettings(config) {
|
|
685
820
|
let lines = config.split(/\r?\n/);
|
|
686
821
|
lines = stripTomlTableKey(lines, /^\s*\[env\]\s*$/, OMX_EXPLORE_CMD_ENV);
|
|
@@ -694,6 +829,13 @@ export function stripOmxEnvSettings(config) {
|
|
|
694
829
|
* Check whether a TOML table name belongs to a legacy OMX-managed agent entry.
|
|
695
830
|
* Handles both `agents.name` and `agents."name"` forms.
|
|
696
831
|
*/
|
|
832
|
+
function isOmxFirstPartyMcpSection(tableName) {
|
|
833
|
+
const match = tableName.match(/^mcp_servers\.(?:"([^"]+)"|([A-Za-z0-9_-]+))$/);
|
|
834
|
+
const name = match?.[1] ?? match?.[2];
|
|
835
|
+
return Boolean(name &&
|
|
836
|
+
(OMX_FIRST_PARTY_MCP_SERVER_NAMES.includes(name) ||
|
|
837
|
+
name === "omx_team_run"));
|
|
838
|
+
}
|
|
697
839
|
function isLegacyOmxAgentSection(tableName) {
|
|
698
840
|
const m = tableName.match(/^agents\.(?:"([^"]+)"|(\w[\w-]*))$/);
|
|
699
841
|
if (!m)
|
|
@@ -706,7 +848,8 @@ function isLegacyOmxAgentSection(tableName) {
|
|
|
706
848
|
* This covers legacy configs that were written before markers were added,
|
|
707
849
|
* or configs where the marker was accidentally removed.
|
|
708
850
|
*
|
|
709
|
-
* Targets:
|
|
851
|
+
* Targets: exact first-party [mcp_servers.<name>] entries, retired
|
|
852
|
+
* [mcp_servers.omx_team_run], and legacy [agents.<name>] entries.
|
|
710
853
|
*/
|
|
711
854
|
function stripOrphanedOmxSections(config) {
|
|
712
855
|
const lines = config.split(/\r?\n/);
|
|
@@ -720,7 +863,7 @@ function stripOrphanedOmxSections(config) {
|
|
|
720
863
|
// Note: [tui] is NOT stripped here because it could be user-owned.
|
|
721
864
|
// The marker-based stripExistingOmxBlocks already handles [tui]
|
|
722
865
|
// when it lives inside the OMX marker block.
|
|
723
|
-
const isOmxSection =
|
|
866
|
+
const isOmxSection = isOmxFirstPartyMcpSection(tableName) ||
|
|
724
867
|
isLegacyOmxAgentSection(tableName);
|
|
725
868
|
if (isOmxSection) {
|
|
726
869
|
// Remove preceding OMX comment lines and blank lines
|
|
@@ -960,6 +1103,72 @@ export function stripExistingSharedMcpRegistryBlock(config) {
|
|
|
960
1103
|
}
|
|
961
1104
|
return { cleaned, removed };
|
|
962
1105
|
}
|
|
1106
|
+
function getExistingSharedMcpRegistryBlocks(config) {
|
|
1107
|
+
const blocks = [];
|
|
1108
|
+
let cursor = 0;
|
|
1109
|
+
while (cursor < config.length) {
|
|
1110
|
+
const markerIdx = config.indexOf(SHARED_MCP_REGISTRY_MARKER, cursor);
|
|
1111
|
+
if (markerIdx < 0)
|
|
1112
|
+
break;
|
|
1113
|
+
let blockStart = config.lastIndexOf("\n", markerIdx);
|
|
1114
|
+
blockStart = blockStart >= 0 ? blockStart + 1 : 0;
|
|
1115
|
+
const previousLineEnd = blockStart - 1;
|
|
1116
|
+
if (previousLineEnd >= 0) {
|
|
1117
|
+
const previousLineStart = config.lastIndexOf("\n", previousLineEnd - 1);
|
|
1118
|
+
const previousLine = config.slice(previousLineStart + 1, previousLineEnd);
|
|
1119
|
+
if (/^# =+$/.test(previousLine.trim())) {
|
|
1120
|
+
blockStart = previousLineStart >= 0 ? previousLineStart + 1 : 0;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
let blockEnd = config.length;
|
|
1124
|
+
const endIdx = config.indexOf(SHARED_MCP_REGISTRY_END_MARKER, markerIdx);
|
|
1125
|
+
if (endIdx >= 0) {
|
|
1126
|
+
const endLineBreak = config.indexOf("\n", endIdx);
|
|
1127
|
+
blockEnd = endLineBreak >= 0 ? endLineBreak + 1 : config.length;
|
|
1128
|
+
}
|
|
1129
|
+
blocks.push(config.slice(blockStart, blockEnd));
|
|
1130
|
+
cursor = blockEnd;
|
|
1131
|
+
}
|
|
1132
|
+
return blocks;
|
|
1133
|
+
}
|
|
1134
|
+
export function extractSharedMcpRegistryServersFromConfig(config) {
|
|
1135
|
+
const servers = [];
|
|
1136
|
+
let sourcePath;
|
|
1137
|
+
for (const block of getExistingSharedMcpRegistryBlocks(config)) {
|
|
1138
|
+
sourcePath ??= block.match(/^# Source:\s*(.+?)\s*$/m)?.[1];
|
|
1139
|
+
let parsed;
|
|
1140
|
+
try {
|
|
1141
|
+
parsed = TOML.parse(block);
|
|
1142
|
+
}
|
|
1143
|
+
catch {
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
if (!isRecord(parsed) || !isRecord(parsed.mcp_servers))
|
|
1147
|
+
continue;
|
|
1148
|
+
for (const [name, value] of Object.entries(parsed.mcp_servers)) {
|
|
1149
|
+
if (!isRecord(value) || typeof value.command !== "string")
|
|
1150
|
+
continue;
|
|
1151
|
+
const args = Array.isArray(value.args)
|
|
1152
|
+
? value.args.filter((arg) => typeof arg === "string")
|
|
1153
|
+
: [];
|
|
1154
|
+
const enabled = typeof value.enabled === "boolean" ? value.enabled : true;
|
|
1155
|
+
const timeoutCandidate = typeof value.startup_timeout_sec === "number"
|
|
1156
|
+
? value.startup_timeout_sec
|
|
1157
|
+
: value.startupTimeoutSec;
|
|
1158
|
+
const startupTimeoutSec = typeof timeoutCandidate === "number" && Number.isFinite(timeoutCandidate)
|
|
1159
|
+
? timeoutCandidate
|
|
1160
|
+
: undefined;
|
|
1161
|
+
servers.push({
|
|
1162
|
+
name,
|
|
1163
|
+
command: value.command,
|
|
1164
|
+
args,
|
|
1165
|
+
enabled,
|
|
1166
|
+
...(startupTimeoutSec !== undefined ? { startupTimeoutSec } : {}),
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
return { servers, sourcePath };
|
|
1171
|
+
}
|
|
963
1172
|
function toMcpServerTableKey(name) {
|
|
964
1173
|
if (/^[A-Za-z0-9_-]+$/.test(name)) {
|
|
965
1174
|
return `mcp_servers.${name}`;
|
|
@@ -1079,11 +1288,25 @@ function getSharedMcpRegistryBlock(servers, sourcePath, existingConfig) {
|
|
|
1079
1288
|
lines.push(SHARED_MCP_REGISTRY_END_MARKER);
|
|
1080
1289
|
return lines.join("\n");
|
|
1081
1290
|
}
|
|
1291
|
+
export function mergeSharedMcpRegistryBlock(config, servers, sourcePath) {
|
|
1292
|
+
const stripped = stripExistingSharedMcpRegistryBlock(config);
|
|
1293
|
+
const existing = stripped.cleaned;
|
|
1294
|
+
const sharedRegistryBlock = getSharedMcpRegistryBlock(servers, sourcePath, existing);
|
|
1295
|
+
const body = existing.trimEnd();
|
|
1296
|
+
const merged = sharedRegistryBlock
|
|
1297
|
+
? body
|
|
1298
|
+
? `${body}\n\n${sharedRegistryBlock}\n`
|
|
1299
|
+
: `${sharedRegistryBlock}\n`
|
|
1300
|
+
: body
|
|
1301
|
+
? `${body}\n`
|
|
1302
|
+
: "";
|
|
1303
|
+
return addDefaultLauncherMcpStartupTimeouts(merged);
|
|
1304
|
+
}
|
|
1082
1305
|
/**
|
|
1083
1306
|
* OMX table-section block (MCP servers, TUI).
|
|
1084
1307
|
* Contains ONLY [table] sections — no bare keys.
|
|
1085
1308
|
*/
|
|
1086
|
-
function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAULT_STATUS_LINE_PRESET, codexHooksFile) {
|
|
1309
|
+
function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAULT_STATUS_LINE_PRESET, codexHooksFile, includeFirstPartyMcp = false) {
|
|
1087
1310
|
const lines = [
|
|
1088
1311
|
"",
|
|
1089
1312
|
"# ============================================================",
|
|
@@ -1091,17 +1314,19 @@ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAUL
|
|
|
1091
1314
|
"# Managed by omx setup - manual edits preserved on next setup",
|
|
1092
1315
|
"# ============================================================",
|
|
1093
1316
|
];
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
.
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1317
|
+
if (includeFirstPartyMcp) {
|
|
1318
|
+
for (const server of getOmxFirstPartySetupMcpServers(pkgRoot)) {
|
|
1319
|
+
lines.push("");
|
|
1320
|
+
lines.push(server.title);
|
|
1321
|
+
lines.push(`[mcp_servers.${server.name}]`);
|
|
1322
|
+
lines.push(`command = "${escapeTomlString(server.command)}"`);
|
|
1323
|
+
lines.push(`args = [${server.args
|
|
1324
|
+
.map((arg) => `"${escapeTomlString(arg)}"`)
|
|
1325
|
+
.join(", ")}]`);
|
|
1326
|
+
lines.push(`enabled = ${server.enabled ? "true" : "false"}`);
|
|
1327
|
+
if (typeof server.startupTimeoutSec === "number") {
|
|
1328
|
+
lines.push(`startup_timeout_sec = ${server.startupTimeoutSec}`);
|
|
1329
|
+
}
|
|
1105
1330
|
}
|
|
1106
1331
|
}
|
|
1107
1332
|
const hookTrustToml = buildManagedCodexHookTrustToml(codexHooksFile, pkgRoot);
|
|
@@ -1157,13 +1382,22 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1157
1382
|
const stripped = stripExistingSharedMcpRegistryBlock(existing);
|
|
1158
1383
|
existing = stripped.cleaned;
|
|
1159
1384
|
}
|
|
1385
|
+
const userNotifyToPreserve = options.notifyCommand === false &&
|
|
1386
|
+
!isOmxManagedNotifyCommand(getRootTomlArray(existing, "notify"), pkgRoot)
|
|
1387
|
+
? getRootTomlArray(existing, "notify")
|
|
1388
|
+
: null;
|
|
1160
1389
|
existing = stripOmxTopLevelKeys(existing);
|
|
1161
|
-
|
|
1390
|
+
if (userNotifyToPreserve) {
|
|
1391
|
+
existing = `${`notify = ${formatTomlStringArray(userNotifyToPreserve)}`}\n${existing.trimStart()}`;
|
|
1392
|
+
}
|
|
1393
|
+
existing = stripOrphanedManagedNotify(existing, pkgRoot);
|
|
1394
|
+
existing = stripManagedCodexHookTrustState(existing);
|
|
1395
|
+
existing = stripUnfencedManagedCodexHookTrustState(existing, buildManagedCodexHookTrustToml(options.codexHooksFile, pkgRoot));
|
|
1162
1396
|
if (options.modelOverride) {
|
|
1163
1397
|
existing = stripRootLevelKeys(existing, ["model"]);
|
|
1164
1398
|
}
|
|
1165
1399
|
existing = stripOrphanedOmxSections(existing);
|
|
1166
|
-
existing = upsertFeatureFlags(existing);
|
|
1400
|
+
existing = upsertFeatureFlags(existing, options.codexHookFeatureFlag);
|
|
1167
1401
|
existing = upsertEnvSettings(existing);
|
|
1168
1402
|
existing = upsertAgentsSettings(existing);
|
|
1169
1403
|
const tuiUpsert = includeTui
|
|
@@ -1172,8 +1406,10 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1172
1406
|
})
|
|
1173
1407
|
: { cleaned: existing, hadExistingTui: false };
|
|
1174
1408
|
existing = tuiUpsert.cleaned;
|
|
1175
|
-
const topLines = getOmxTopLevelLines(pkgRoot, existing, options.modelOverride
|
|
1176
|
-
|
|
1409
|
+
const topLines = getOmxTopLevelLines(pkgRoot, existing, options.modelOverride, options.notifyCommand === undefined
|
|
1410
|
+
? getDefaultNotifyCommand(pkgRoot)
|
|
1411
|
+
: options.notifyCommand);
|
|
1412
|
+
const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile, options.includeFirstPartyMcp === true);
|
|
1177
1413
|
const sharedRegistryBlock = getSharedMcpRegistryBlock(options.sharedMcpServers ?? [], options.sharedMcpRegistrySource, existing);
|
|
1178
1414
|
let body = existing.trimEnd();
|
|
1179
1415
|
if (sharedRegistryBlock) {
|