oh-my-codex 0.20.0 → 0.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +10 -1
- package/dist/adapt/__tests__/hermes.test.js.map +1 -1
- package/dist/adapt/contracts.d.ts.map +1 -1
- package/dist/agents/native-config.js.map +1 -1
- package/dist/auth/__tests__/hotswap.test.d.ts +2 -0
- package/dist/auth/__tests__/hotswap.test.d.ts.map +1 -0
- package/dist/auth/__tests__/hotswap.test.js +183 -0
- package/dist/auth/__tests__/hotswap.test.js.map +1 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +17 -4
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/auth/paths.js.map +1 -1
- package/dist/auth/storage.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +4 -4
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/completion-gate.js.map +1 -1
- package/dist/autopilot/fsm.d.ts +1 -1
- package/dist/autopilot/fsm.d.ts.map +1 -1
- package/dist/autoresearch/goal.js.map +1 -1
- package/dist/autoresearch/runtime.js.map +1 -1
- package/dist/capabilities/lockfile.js.map +1 -1
- package/dist/catalog/reader.js.map +1 -1
- package/dist/catalog/skill-mirror.js.map +1 -1
- package/dist/cli/__tests__/adapt-help.test.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/agents.test.js.map +1 -1
- package/dist/cli/__tests__/api.test.js.map +1 -1
- package/dist/cli/__tests__/ask.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch.test.js.map +1 -1
- package/dist/cli/__tests__/capabilities.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +27 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js +83 -78
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +56 -4
- package/dist/cli/__tests__/doctor-invalid-config.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-team.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +735 -14
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/imagegen-continuation.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +216 -11
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +49 -3
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +84 -12
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts +2 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.d.ts.map +1 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +128 -0
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/question.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-deslop-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +6 -0
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-deep-interview.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-prd-smoke.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +8 -3
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +187 -0
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +129 -0
- package/dist/cli/__tests__/ralplan.test.js.map +1 -0
- package/dist/cli/__tests__/resume.test.js +6 -1
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +25 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/session-search.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +79 -0
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-gh-star.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +131 -5
- package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js +285 -0
- package/dist/cli/__tests__/setup-hooks-trust-e2e.test.js.map +1 -0
- package/dist/cli/__tests__/setup-install-mode.test.js +2264 -17
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/setup-preferences.test.d.ts +2 -0
- package/dist/cli/__tests__/setup-preferences.test.d.ts.map +1 -0
- package/dist/cli/__tests__/setup-preferences.test.js +79 -0
- package/dist/cli/__tests__/setup-preferences.test.js.map +1 -0
- package/dist/cli/__tests__/setup-refresh.test.js +168 -5
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +73 -6
- package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/state.test.js +37 -0
- package/dist/cli/__tests__/state.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +61 -1
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +2067 -26
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +58 -0
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/url.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/adapt.js.map +1 -1
- package/dist/cli/agents-init.js.map +1 -1
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/api.js.map +1 -1
- package/dist/cli/ask.d.ts +1 -1
- package/dist/cli/ask.d.ts.map +1 -1
- package/dist/cli/ask.js.map +1 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/autoresearch-guided.js.map +1 -1
- package/dist/cli/autoresearch-intake.js.map +1 -1
- package/dist/cli/capabilities.js.map +1 -1
- package/dist/cli/cleanup.js.map +1 -1
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +20 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +636 -161
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +11 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +108 -20
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-serve.js.map +1 -1
- package/dist/cli/mission.js.map +1 -1
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +18 -0
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
- package/dist/cli/native-hook-claim-journal.js +239 -0
- package/dist/cli/native-hook-claim-journal.js.map +1 -0
- package/dist/cli/omx.js.map +1 -1
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/project-runtime-codex-homes.js.map +1 -1
- package/dist/cli/question.js.map +1 -1
- package/dist/cli/ralph.d.ts.map +1 -1
- package/dist/cli/ralph.js +3 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +14 -0
- package/dist/cli/ralplan.d.ts.map +1 -0
- package/dist/cli/ralplan.js +203 -0
- package/dist/cli/ralplan.js.map +1 -0
- package/dist/cli/setup-preferences.d.ts +11 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +32 -0
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +53 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1403 -400
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/star-prompt.js.map +1 -1
- package/dist/cli/state.d.ts.map +1 -1
- package/dist/cli/state.js +2 -1
- package/dist/cli/state.js.map +1 -1
- package/dist/cli/team.js.map +1 -1
- package/dist/cli/ultragoal.d.ts +5 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +34 -2
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +8 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +947 -99
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +8 -1
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/url.js.map +1 -1
- package/dist/compat/__tests__/doctor-contract.test.js +5 -1
- package/dist/compat/__tests__/doctor-contract.test.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js.map +1 -1
- package/dist/config/__tests__/codex-hooks.test.js +1287 -11
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +1049 -135
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +28 -49
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/codex-feature-flags.d.ts.map +1 -1
- package/dist/config/codex-feature-flags.js.map +1 -1
- package/dist/config/codex-hooks.d.ts +124 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +2142 -265
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/commit-lore-guard.js.map +1 -1
- package/dist/config/generator.d.ts +40 -26
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +1159 -288
- package/dist/config/generator.js.map +1 -1
- package/dist/config/mcp-registry.js.map +1 -1
- package/dist/config/models.d.ts +2 -2
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js.map +1 -1
- package/dist/config/omx-first-party-mcp.js.map +1 -1
- package/dist/config/team-mode.d.ts.map +1 -1
- package/dist/document-refresh/__tests__/enforcer.test.js.map +1 -1
- package/dist/document-refresh/enforcer.js.map +1 -1
- package/dist/exec/followup.js.map +1 -1
- package/dist/goal-workflows/artifacts.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +7 -4
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-routing-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/analyze-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/anti-slop-workflow.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +9 -3
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/code-review-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/consensus-execution-handoff.test.js.map +1 -1
- package/dist/hooks/__tests__/deep-interview-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/design-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +1372 -2
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +14 -0
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +669 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +2 -0
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js +142 -1
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-modules.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +48 -2
- package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js +61 -44
- package/dist/hooks/__tests__/notify-hook-ralph-resume.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js +3 -2
- package/dist/hooks/__tests__/notify-hook-session-idle-dedupe.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js +243 -4
- package/dist/hooks/__tests__/notify-hook-session-scope.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +8 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-visual-verdict.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/openclaw-setup-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/pre-context-gate-skills.test.js.map +1 -1
- package/dist/hooks/__tests__/prometheus-strict-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-fragments.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-test-helpers.js.map +1 -1
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts +2 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js +82 -0
- package/dist/hooks/__tests__/prompt-session-provenance.test.js.map +1 -0
- package/dist/hooks/__tests__/session.test.js +532 -11
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -1
- package/dist/hooks/__tests__/team-runtime-gating-docs-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-ralph-skill.test.js.map +1 -1
- package/dist/hooks/__tests__/visual-verdict-loop.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +5 -5
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/code-simplifier/index.js.map +1 -1
- package/dist/hooks/explore-routing.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/events.js.map +1 -1
- package/dist/hooks/extensibility/loader.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner-stdin.js.map +1 -1
- package/dist/hooks/extensibility/sdk/logging.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +33 -7
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +2228 -119
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/keyword-registry.d.ts +12 -0
- package/dist/hooks/keyword-registry.d.ts.map +1 -1
- package/dist/hooks/keyword-registry.js +41 -0
- package/dist/hooks/keyword-registry.js.map +1 -1
- package/dist/hooks/prompt-session-provenance.d.ts +87 -0
- package/dist/hooks/prompt-session-provenance.d.ts.map +1 -0
- package/dist/hooks/prompt-session-provenance.js +180 -0
- package/dist/hooks/prompt-session-provenance.js.map +1 -0
- package/dist/hooks/session.d.ts +139 -34
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1239 -317
- package/dist/hooks/session.js.map +1 -1
- package/dist/hooks/task-size-detector.js.map +1 -1
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/authority.js.map +1 -1
- package/dist/hud/constants.js.map +1 -1
- package/dist/hud/index.js.map +1 -1
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/tmux.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +146 -2
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +26 -5
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +131 -7
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +15 -2
- package/dist/mcp/__tests__/server-lifecycle.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +98 -1
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/code-intel-server.d.ts +58 -58
- package/dist/mcp/code-intel-server.d.ts.map +1 -1
- package/dist/mcp/code-intel-server.js.map +1 -1
- package/dist/mcp/hermes-bridge.js.map +1 -1
- package/dist/mcp/hermes-server.d.ts +70 -70
- package/dist/mcp/hermes-server.d.ts.map +1 -1
- package/dist/mcp/lifecycle-telemetry.js.map +1 -1
- package/dist/mcp/memory-server.d.ts +34 -34
- package/dist/mcp/memory-server.d.ts.map +1 -1
- package/dist/mcp/memory-server.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +14 -0
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +96 -20
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +47 -47
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.d.ts +4 -4
- package/dist/mcp/trace-server.d.ts.map +1 -1
- package/dist/mcp/trace-server.js.map +1 -1
- package/dist/mcp/wiki-server.d.ts +23 -23
- package/dist/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +53 -1
- package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -5
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/lifecycle-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/reply-listener.test.js.map +1 -1
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js +177 -85
- package/dist/notifications/__tests__/session-idle-tail-dedupe.test.js.map +1 -1
- package/dist/notifications/__tests__/session-registry.test.js.map +1 -1
- package/dist/notifications/__tests__/template-engine.test.js.map +1 -1
- package/dist/notifications/__tests__/verbosity.test.js.map +1 -1
- package/dist/notifications/http-client.js.map +1 -1
- package/dist/notifications/index.d.ts +4 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +3 -9
- package/dist/notifications/index.js.map +1 -1
- package/dist/notifications/lifecycle-dedupe.js.map +1 -1
- package/dist/notifications/reply-listener.d.ts.map +1 -1
- package/dist/notifications/reply-listener.js.map +1 -1
- package/dist/notifications/session-registry.js.map +1 -1
- package/dist/notifications/session-status.js.map +1 -1
- package/dist/notifications/temp-contract.js.map +1 -1
- package/dist/notifications/tmux-detector.js.map +1 -1
- package/dist/notifications/tmux.js.map +1 -1
- package/dist/openclaw/config.js.map +1 -1
- package/dist/openclaw/dispatcher.js.map +1 -1
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +8 -5
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/stages/code-review.js.map +1 -1
- package/dist/pipeline/stages/ralph-verify.js.map +1 -1
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/pipeline/stages/team-exec.js.map +1 -1
- package/dist/pipeline/stages/ultragoal.js.map +1 -1
- package/dist/pipeline/stages/ultraqa.js.map +1 -1
- package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -1
- package/dist/planning/artifact-names.js.map +1 -1
- package/dist/planning/artifacts.js.map +1 -1
- package/dist/question/__tests__/state.test.js.map +1 -1
- package/dist/question/__tests__/ui.test.js.map +1 -1
- package/dist/question/autopilot-wait.js.map +1 -1
- package/dist/question/client.d.ts.map +1 -1
- package/dist/question/client.js.map +1 -1
- package/dist/question/deep-interview.js.map +1 -1
- package/dist/question/events.js.map +1 -1
- package/dist/question/renderer.js.map +1 -1
- package/dist/question/state.d.ts.map +1 -1
- package/dist/question/state.js.map +1 -1
- package/dist/question/ui.js.map +1 -1
- package/dist/ralph/contract.d.ts +1 -1
- package/dist/ralph/contract.d.ts.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +403 -8
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +112 -14
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +3 -3
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +155 -60
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/runtime.d.ts +2 -2
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +1 -2
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js.map +1 -1
- package/dist/runtime/process-tree.js.map +1 -1
- package/dist/runtime/run-loop.js.map +1 -1
- package/dist/runtime/run-outcome.d.ts +3 -3
- package/dist/runtime/run-outcome.d.ts.map +1 -1
- package/dist/runtime/run-outcome.js.map +1 -1
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +5414 -801
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts +2 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.d.ts.map +1 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js +634 -0
- package/dist/scripts/__tests__/fixtures/issue-3138-installed-smoke.js.map +1 -0
- package/dist/scripts/__tests__/generate-release-body.test.js.map +1 -1
- package/dist/scripts/__tests__/hook-derived-watcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts +2 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js +174 -0
- package/dist/scripts/__tests__/notify-fallback-delivery.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +57 -1
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js +205 -0
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts +2 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +175 -0
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -0
- package/dist/scripts/__tests__/run-test-files.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +848 -4
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/test-reply-listener-live.test.js.map +1 -1
- package/dist/scripts/build-api.js.map +1 -1
- package/dist/scripts/build-explore-harness.js.map +1 -1
- package/dist/scripts/build-sparkshell.js.map +1 -1
- package/dist/scripts/cleanup-explore-harness.js.map +1 -1
- package/dist/scripts/codex-execution-surface.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +825 -172
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/generate-native-release-manifest.js.map +1 -1
- package/dist/scripts/generate-release-body.js.map +1 -1
- package/dist/scripts/hook-payload-guard.d.ts.map +1 -1
- package/dist/scripts/hook-payload-guard.js.map +1 -1
- package/dist/scripts/notify-fallback-delivery.d.ts +48 -0
- package/dist/scripts/notify-fallback-delivery.d.ts.map +1 -0
- package/dist/scripts/notify-fallback-delivery.js +419 -0
- package/dist/scripts/notify-fallback-delivery.js.map +1 -0
- package/dist/scripts/notify-fallback-watcher.js +136 -30
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts +18 -9
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +39 -13
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.d.ts +23 -0
- package/dist/scripts/notify-hook/managed-tmux.d.ts.map +1 -1
- package/dist/scripts/notify-hook/managed-tmux.js +122 -12
- package/dist/scripts/notify-hook/managed-tmux.js.map +1 -1
- package/dist/scripts/notify-hook/orchestration-intent.d.ts +7 -7
- package/dist/scripts/notify-hook/orchestration-intent.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts +5 -2
- package/dist/scripts/notify-hook/ralph-session-resume.d.ts.map +1 -1
- package/dist/scripts/notify-hook/ralph-session-resume.js +33 -37
- package/dist/scripts/notify-hook/ralph-session-resume.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts +17 -0
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +73 -11
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts +2 -2
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +4 -4
- package/dist/scripts/notify-hook/team-worker-posttooluse.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.d.ts +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +2 -2
- package/dist/scripts/notify-hook/tmux-injection.d.ts +8 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +25 -16
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts +1 -1
- package/dist/scripts/notify-hook/visual-verdict.d.ts.map +1 -1
- package/dist/scripts/notify-hook/visual-verdict.js +15 -13
- package/dist/scripts/notify-hook/visual-verdict.js.map +1 -1
- package/dist/scripts/notify-hook.d.ts +24 -1
- package/dist/scripts/notify-hook.d.ts.map +1 -1
- package/dist/scripts/notify-hook.js +266 -90
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/prompt-inventory.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +879 -2
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +1528 -7
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/test-reply-listener-live.js.map +1 -1
- package/dist/scripts/test-sparkshell.js.map +1 -1
- package/dist/scripts/verify-native-agents.js.map +1 -1
- package/dist/session-history/friction.js.map +1 -1
- package/dist/session-history/search.js.map +1 -1
- package/dist/sidecar/__tests__/boundary.test.js.map +1 -1
- package/dist/sidecar/collector.js.map +1 -1
- package/dist/sidecar/index.js.map +1 -1
- package/dist/sidecar/render.js.map +1 -1
- package/dist/sidecar/tmux.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +64 -15
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +19 -1
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/__tests__/workflow-transition.test.js +61 -0
- package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/operations.d.ts +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +49 -55
- package/dist/state/operations.js.map +1 -1
- package/dist/state/paths.d.ts +1 -1
- package/dist/state/paths.d.ts.map +1 -1
- package/dist/state/paths.js +1 -1
- package/dist/state/paths.js.map +1 -1
- package/dist/state/skill-active.d.ts +13 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +43 -4
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/terminal-normalization.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +20 -4
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +2 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.js +988 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.js.map +1 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts +2 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.d.ts.map +1 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +273 -0
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -0
- package/dist/subagents/__tests__/tracker.test.js +1550 -10
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/adapted-role-binding.d.ts +17 -0
- package/dist/subagents/adapted-role-binding.d.ts.map +1 -0
- package/dist/subagents/adapted-role-binding.js +75 -0
- package/dist/subagents/adapted-role-binding.js.map +1 -0
- package/dist/subagents/role-routing-marker.d.ts +10 -0
- package/dist/subagents/role-routing-marker.d.ts.map +1 -0
- package/dist/subagents/role-routing-marker.js +136 -0
- package/dist/subagents/role-routing-marker.js.map +1 -0
- package/dist/subagents/tracker.d.ts +172 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +1077 -61
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +231 -1
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/role-router.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +401 -1
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +181 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +434 -4
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/api-interop.d.ts +2 -2
- package/dist/team/api-interop.d.ts.map +1 -1
- package/dist/team/api-interop.js.map +1 -1
- package/dist/team/commit-hygiene.js.map +1 -1
- package/dist/team/contracts.d.ts +5 -5
- package/dist/team/contracts.d.ts.map +1 -1
- package/dist/team/delivery-log.js.map +1 -1
- package/dist/team/followup-planner.js.map +1 -1
- package/dist/team/goal-workflow.js.map +1 -1
- package/dist/team/idle-nudge.d.ts.map +1 -1
- package/dist/team/model-contract.d.ts +20 -1
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +267 -30
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/orchestrator.js.map +1 -1
- package/dist/team/pane-status.js.map +1 -1
- package/dist/team/phase-controller.js.map +1 -1
- package/dist/team/reminder-intents.d.ts +1 -1
- package/dist/team/reminder-intents.d.ts.map +1 -1
- package/dist/team/reminder-intents.js.map +1 -1
- package/dist/team/runtime-cli.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +83 -52
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +9 -7
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +69 -28
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch-lock.js.map +1 -1
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/state/events.js.map +1 -1
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.js.map +1 -1
- package/dist/team/team-identity.d.ts.map +1 -1
- package/dist/team/team-identity.js.map +1 -1
- package/dist/team/tmux-session.d.ts +2 -0
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +90 -42
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/team/worktree.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +4 -1
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/index.js.map +1 -1
- package/dist/utils/__tests__/agents-md.test.js +16 -0
- package/dist/utils/__tests__/agents-md.test.js.map +1 -1
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +4 -3
- package/dist/utils/agents-md.js.map +1 -1
- package/dist/utils/agents-model-table.js.map +1 -1
- package/dist/utils/package.js.map +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/utils/repo-deps.js.map +1 -1
- package/dist/utils/version.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +1 -1
- package/dist/verification/__tests__/dev-merge-issue-close-workflow.test.js.map +1 -1
- package/dist/verification/verifier.js.map +1 -1
- package/dist/visual/constants.d.ts +1 -1
- package/dist/visual/constants.d.ts.map +1 -1
- package/dist/vscode/__tests__/index.test.js.map +1 -1
- package/dist/vscode/index.js.map +1 -1
- package/dist/wiki/__tests__/cjk-tokenize.test.js.map +1 -1
- package/dist/wiki/__tests__/lint.test.js.map +1 -1
- package/dist/wiki/__tests__/query.test.js.map +1 -1
- package/dist/wiki/__tests__/storage.test.js.map +1 -1
- package/dist/wiki/__tests__/test-helpers.d.ts.map +1 -1
- package/dist/wiki/lint.js.map +1 -1
- package/dist/wiki/query.js.map +1 -1
- package/dist/wiki/storage.js.map +1 -1
- package/package.json +2 -2
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +4 -2
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +5 -2
- package/skills/omx-setup/SKILL.md +10 -5
- package/skills/ralph/SKILL.md +4 -2
- package/skills/ralplan/SKILL.md +5 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +20497 -12377
- package/src/scripts/__tests__/fixtures/issue-3138-installed-smoke.ts +734 -0
- package/src/scripts/__tests__/notify-fallback-delivery.test.ts +177 -0
- package/src/scripts/__tests__/notify-state-io.test.ts +73 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +215 -0
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +193 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +991 -4
- package/src/scripts/codex-native-hook.ts +918 -172
- package/src/scripts/notify-fallback-delivery.ts +416 -0
- package/src/scripts/notify-fallback-watcher.ts +132 -40
- package/src/scripts/notify-hook/auto-nudge.ts +43 -12
- package/src/scripts/notify-hook/managed-tmux.ts +149 -12
- package/src/scripts/notify-hook/ralph-session-resume.ts +37 -36
- package/src/scripts/notify-hook/state-io.ts +100 -13
- package/src/scripts/notify-hook/tmux-injection.ts +38 -21
- package/src/scripts/notify-hook/visual-verdict.ts +22 -12
- package/src/scripts/notify-hook.ts +335 -90
- package/src/scripts/smoke-packed-install.ts +1829 -6
package/dist/config/generator.js
CHANGED
|
@@ -13,11 +13,10 @@ import { readFile, writeFile } from "fs/promises";
|
|
|
13
13
|
import { existsSync } from "fs";
|
|
14
14
|
import { join, resolve } from "path";
|
|
15
15
|
import TOML from "@iarna/toml";
|
|
16
|
-
import { AGENT_DEFINITIONS } from "../agents/definitions.js";
|
|
17
16
|
import { DEFAULT_FRONTIER_MODEL } from "./models.js";
|
|
18
17
|
import { DEFAULT_CODEX_HOOK_FEATURE_FLAG, CODEX_HOOK_FEATURE_FLAGS, CODEX_PLUGIN_SCOPED_HOOKS_FEATURE_FLAG, formatCodexHookFeatureFlagLine, normalizeCodexHookFeatureFlag, } from "./codex-feature-flags.js";
|
|
19
18
|
import { OMX_FIRST_PARTY_MCP_SERVER_NAMES, getOmxFirstPartySetupMcpServers, } from "./omx-first-party-mcp.js";
|
|
20
|
-
import { buildManagedCodexHookTrustState, escapeTomlBasicString, } from "./codex-hooks.js";
|
|
19
|
+
import { buildManagedCodexHookTrustState, escapeTomlBasicString, ManagedCodexHooksPlanError, scanManagedCodexHookTrustStateFromContent, } from "./codex-hooks.js";
|
|
21
20
|
function escapeTomlString(value) {
|
|
22
21
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
23
22
|
}
|
|
@@ -34,25 +33,65 @@ const OMX_TOP_LEVEL_KEYS = [
|
|
|
34
33
|
"developer_instructions",
|
|
35
34
|
];
|
|
36
35
|
export const DEFAULT_SETUP_MODEL = DEFAULT_FRONTIER_MODEL;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export function getModelContextRecommendation(model) {
|
|
40
|
-
if (model !== DEFAULT_SETUP_MODEL)
|
|
41
|
-
return null;
|
|
42
|
-
return {
|
|
43
|
-
model,
|
|
44
|
-
modelContextWindow: DEFAULT_SETUP_MODEL_CONTEXT_WINDOW,
|
|
45
|
-
modelAutoCompactTokenLimit: DEFAULT_SETUP_MODEL_AUTO_COMPACT_TOKEN_LIMIT,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
36
|
+
const LEGACY_SEEDED_MODEL_CONTEXT_WINDOW = 250000;
|
|
37
|
+
const LEGACY_SEEDED_MODEL_AUTO_COMPACT_TOKEN_LIMIT = 200000;
|
|
48
38
|
const OMX_SEEDED_BEHAVIORAL_DEFAULTS_START_MARKER = "# oh-my-codex seeded behavioral defaults (uninstall removes unchanged defaults)";
|
|
49
39
|
const OMX_SEEDED_BEHAVIORAL_DEFAULTS_END_MARKER = "# End oh-my-codex seeded behavioral defaults";
|
|
50
|
-
export const OMX_DEVELOPER_INSTRUCTIONS = "You have oh-my-codex installed. AGENTS.md is the orchestration brain and main control surface. Follow AGENTS.md for skill/keyword routing, $name workflow invocation, and role-specialized subagents; when
|
|
51
|
-
export const OMX_PLUGIN_DEVELOPER_INSTRUCTIONS = '<omx version="1">You have oh-my-codex installed through Codex plugin mode. AGENTS.md is the orchestration brain and main control surface. Follow AGENTS.md for skill/keyword routing and $name workflow invocation. When
|
|
40
|
+
export const OMX_DEVELOPER_INSTRUCTIONS = "You have oh-my-codex installed. AGENTS.md is the orchestration brain and main control surface. Follow AGENTS.md for skill/keyword routing, $name workflow invocation, and role-specialized subagents; when the native surface exposes `agent_type` role routing, set `agent_type` to an installed role and never omit it for OMX work. When it does not (`role_routing_unavailable`, for example a Codex App `spawn_agent` surface exposing only `task_name`, `message`, and `fork_turns`), do not fabricate `agent_type`; follow the OMX adapted role-pass protocol by recording a pre-validated role intent in the OMX subagent ledger, and never fake the role via a prompt label. Use outcome-first, concise progress updates: state the target result, constraints, validation evidence, and stop condition before adding process detail. Native subagents live in .codex/agents and may handle independent parallel subtasks within one Codex session or team pane. Skills load from .codex/skills, not native-agent TOMLs. Treat installed prompts as narrower execution surfaces under AGENTS.md authority.";
|
|
41
|
+
export const OMX_PLUGIN_DEVELOPER_INSTRUCTIONS = '<omx version="1">You have oh-my-codex installed through Codex plugin mode. AGENTS.md is the orchestration brain and main control surface. Follow AGENTS.md for skill/keyword routing and $name workflow invocation. When the native surface exposes `agent_type` role routing, set `agent_type` to an installed role and never omit it for OMX work. When it does not (`role_routing_unavailable`, for example a Codex App `spawn_agent` surface exposing only `task_name`, `message`, and `fork_turns`), do not fabricate `agent_type`; follow the OMX adapted role-pass protocol by recording a pre-validated role intent in the OMX subagent ledger, and never fake the role via a prompt label. Registered Codex plugin marketplace surfaces supply OMX workflows and plugin-scoped companion resources when the plugin is installed; native agent roles are installed as setup-owned Codex agent TOML files in plugin mode so agent_type routing works. User-installed skills may still live under ~/.codex/skills. Use outcome-first, concise progress updates: state the target result, constraints, validation evidence, and stop condition before adding process detail.</omx>';
|
|
52
42
|
const SHARED_MCP_REGISTRY_MARKER = "oh-my-codex (OMX) Shared MCP Registry Sync";
|
|
53
43
|
const SHARED_MCP_REGISTRY_END_MARKER = "# End oh-my-codex shared MCP registry sync";
|
|
54
|
-
const
|
|
55
|
-
|
|
44
|
+
const LEGACY_MULTI_AGENT_KEYS = [
|
|
45
|
+
"features.multi_agent",
|
|
46
|
+
"agents.max_threads",
|
|
47
|
+
"agents.max_depth",
|
|
48
|
+
];
|
|
49
|
+
const LEGACY_MULTI_AGENT_VALUES = {
|
|
50
|
+
"features.multi_agent": true,
|
|
51
|
+
"agents.max_threads": 6,
|
|
52
|
+
"agents.max_depth": 2,
|
|
53
|
+
};
|
|
54
|
+
export function analyzeLegacyMultiAgentConfig(configText) {
|
|
55
|
+
let parsed;
|
|
56
|
+
try {
|
|
57
|
+
parsed = TOML.parse(configText);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const reasonCode = /duplicate|redefine|already defined/i.test(String(error))
|
|
61
|
+
? "toml-duplicate-key"
|
|
62
|
+
: "toml-parse-error";
|
|
63
|
+
return {
|
|
64
|
+
assessments: Object.fromEntries(LEGACY_MULTI_AGENT_KEYS.map((key) => [
|
|
65
|
+
key,
|
|
66
|
+
{ key, state: "invalid/duplicate", reasonCode },
|
|
67
|
+
])),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
assessments: Object.fromEntries(LEGACY_MULTI_AGENT_KEYS.map((key) => {
|
|
72
|
+
const [table, entry] = key.split(".");
|
|
73
|
+
const value = isRecord(parsed[table]) ? parsed[table][entry] : undefined;
|
|
74
|
+
if (value === undefined) {
|
|
75
|
+
return [key, { key, state: "absent", reasonCode: "key-absent" }];
|
|
76
|
+
}
|
|
77
|
+
if (value === LEGACY_MULTI_AGENT_VALUES[key]) {
|
|
78
|
+
return [
|
|
79
|
+
key,
|
|
80
|
+
{
|
|
81
|
+
key,
|
|
82
|
+
state: "retained-legacy",
|
|
83
|
+
reasonCode: "exact-legacy-value",
|
|
84
|
+
value,
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
return [
|
|
89
|
+
key,
|
|
90
|
+
{ key, state: "custom", reasonCode: "custom-value", value },
|
|
91
|
+
];
|
|
92
|
+
})),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
56
95
|
const OMX_EXPLORE_ROUTING_DEFAULT = "0";
|
|
57
96
|
const OMX_EXPLORE_CMD_ENV = "USE_OMX_EXPLORE_CMD";
|
|
58
97
|
const DEFAULT_LAUNCHER_MCP_STARTUP_TIMEOUT_SEC = 15;
|
|
@@ -97,6 +136,7 @@ const LEGACY_OMX_STATUS_LINE = statusLineForPreset(DEFAULT_STATUS_LINE_PRESET);
|
|
|
97
136
|
const OMX_PRESET_STATUS_LINE_VALUES = new Set(Object.keys(STATUS_LINE_PRESETS).map((preset) => statusLineForPreset(preset)));
|
|
98
137
|
const LEGACY_OMX_TEAM_RUN_TABLE_PATTERN = /^\s*\[mcp_servers\.(?:"omx_team_run"|omx_team_run)\]\s*$/m;
|
|
99
138
|
const OMX_CONFIG_MARKER = "oh-my-codex (OMX) Configuration";
|
|
139
|
+
const OMX_CONFIG_START_MARKER = `# ${OMX_CONFIG_MARKER}`;
|
|
100
140
|
const OMX_CONFIG_END_MARKER = "# End oh-my-codex";
|
|
101
141
|
const CODEX_MODEL_AVAILABILITY_NUX_TABLE_PATTERN = /^\s*\[tui\.model_availability_nux\]\s*(?:#.*)?$/;
|
|
102
142
|
const TOML_TABLE_HEADER_PATTERN = /^\s*\[\[?[^\]]+\]?\]\s*(?:#.*)?$/;
|
|
@@ -343,71 +383,117 @@ function getOmxTopLevelLines(pkgRoot, existingConfig = "", modelOverride, notify
|
|
|
343
383
|
`developer_instructions = "${escapeTomlString(OMX_DEVELOPER_INSTRUCTIONS)}"`,
|
|
344
384
|
];
|
|
345
385
|
const existingModel = rootValues.get("model");
|
|
346
|
-
const existingContextWindow = rootValues.get("model_context_window");
|
|
347
|
-
const existingAutoCompact = rootValues.get("model_auto_compact_token_limit");
|
|
348
386
|
const selectedModel = modelOverride ?? unwrapTomlString(existingModel) ?? DEFAULT_SETUP_MODEL;
|
|
349
387
|
if (modelOverride || !existingModel) {
|
|
350
388
|
lines.push(`model = "${selectedModel}"`);
|
|
351
389
|
}
|
|
352
|
-
if (selectedModel === DEFAULT_SETUP_MODEL) {
|
|
353
|
-
const seededBehavioralDefaults = [];
|
|
354
|
-
if (!existingContextWindow) {
|
|
355
|
-
seededBehavioralDefaults.push(`model_context_window = ${DEFAULT_SETUP_MODEL_CONTEXT_WINDOW}`);
|
|
356
|
-
}
|
|
357
|
-
if (!existingAutoCompact) {
|
|
358
|
-
seededBehavioralDefaults.push(`model_auto_compact_token_limit = ${DEFAULT_SETUP_MODEL_AUTO_COMPACT_TOKEN_LIMIT}`);
|
|
359
|
-
}
|
|
360
|
-
if (seededBehavioralDefaults.length > 0) {
|
|
361
|
-
lines.push(OMX_SEEDED_BEHAVIORAL_DEFAULTS_START_MARKER);
|
|
362
|
-
lines.push(...seededBehavioralDefaults);
|
|
363
|
-
lines.push(OMX_SEEDED_BEHAVIORAL_DEFAULTS_END_MARKER);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
390
|
return lines;
|
|
367
391
|
}
|
|
368
|
-
function
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
392
|
+
function sourceLines(config) {
|
|
393
|
+
const lines = [];
|
|
394
|
+
let start = 0;
|
|
395
|
+
for (let index = 0; index < config.length; index += 1) {
|
|
396
|
+
if (config[index] !== "\n")
|
|
397
|
+
continue;
|
|
398
|
+
lines.push({
|
|
399
|
+
content: config.slice(start, index - (index > start && config[index - 1] === "\r" ? 1 : 0)),
|
|
400
|
+
start,
|
|
401
|
+
end: index + 1,
|
|
402
|
+
});
|
|
403
|
+
start = index + 1;
|
|
404
|
+
}
|
|
405
|
+
if (start < config.length)
|
|
406
|
+
lines.push({ content: config.slice(start), start, end: config.length });
|
|
407
|
+
return lines;
|
|
381
408
|
}
|
|
382
|
-
|
|
383
|
-
const lines = config
|
|
384
|
-
const firstTable = lines.findIndex((line) =>
|
|
385
|
-
const boundary = firstTable
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
409
|
+
function analyzeOmxSeededBehavioralDefaults(config) {
|
|
410
|
+
const lines = sourceLines(config);
|
|
411
|
+
const firstTable = lines.findIndex((line) => TOML_TABLE_HEADER_PATTERN.test(line.content));
|
|
412
|
+
const boundary = firstTable < 0 ? lines.length : firstTable;
|
|
413
|
+
const starts = lines.map((line, index) => ({ line, index }))
|
|
414
|
+
.filter(({ line }) => line.content === OMX_SEEDED_BEHAVIORAL_DEFAULTS_START_MARKER);
|
|
415
|
+
const ends = lines.map((line, index) => ({ line, index }))
|
|
416
|
+
.filter(({ line }) => line.content === OMX_SEEDED_BEHAVIORAL_DEFAULTS_END_MARKER);
|
|
417
|
+
if (starts.length === 0 && ends.length === 0)
|
|
418
|
+
return { state: "absent", spans: [] };
|
|
419
|
+
if (starts.length !== 1 || ends.length !== 1 || starts[0].index >= ends[0].index) {
|
|
420
|
+
return { state: "malformed-or-ambiguous", spans: [] };
|
|
421
|
+
}
|
|
422
|
+
const rootText = lines.slice(0, boundary).map((line) => line.content).join("\n");
|
|
423
|
+
let entryStart = 0;
|
|
424
|
+
const rootEntries = splitRootLevelEntries(rootText).entries.map((entry) => {
|
|
425
|
+
const indexed = { entry, start: entryStart, end: entryStart + entry.lines.length };
|
|
426
|
+
entryStart = indexed.end;
|
|
427
|
+
return indexed;
|
|
428
|
+
});
|
|
429
|
+
const isStandaloneRootMarker = (index) => index < boundary && rootEntries.some(({ entry, start, end }) => !entry.key && start === index && end === index + 1);
|
|
430
|
+
const start = starts[0];
|
|
431
|
+
const end = ends[0];
|
|
432
|
+
if (!isStandaloneRootMarker(start.index) || !isStandaloneRootMarker(end.index)) {
|
|
433
|
+
return { state: "malformed-or-ambiguous", spans: [] };
|
|
434
|
+
}
|
|
435
|
+
const block = lines.slice(start.index, end.index + 1);
|
|
436
|
+
const exact = (body) => block.length === body.length + 2 &&
|
|
437
|
+
block[0].content === OMX_SEEDED_BEHAVIORAL_DEFAULTS_START_MARKER &&
|
|
438
|
+
block.at(-1)?.content === OMX_SEEDED_BEHAVIORAL_DEFAULTS_END_MARKER &&
|
|
439
|
+
body.every((line, index) => block[index + 1].content === line);
|
|
440
|
+
const blockSpan = [{ start: start.line.start, end: end.line.end }];
|
|
441
|
+
const markerSpans = [
|
|
442
|
+
{ start: start.line.start, end: start.line.end },
|
|
443
|
+
{ start: end.line.start, end: end.line.end },
|
|
444
|
+
];
|
|
445
|
+
if (exact([
|
|
446
|
+
`model_context_window = ${LEGACY_SEEDED_MODEL_CONTEXT_WINDOW}`,
|
|
447
|
+
`model_auto_compact_token_limit = ${LEGACY_SEEDED_MODEL_AUTO_COMPACT_TOKEN_LIMIT}`,
|
|
448
|
+
])) {
|
|
449
|
+
const hasOutsideDuplicate = rootEntries.some(({ entry, start: entryStart, end: entryEnd }) => (entryEnd <= start.index || entryStart > end.index) &&
|
|
450
|
+
(entry.key === "model_context_window" || entry.key === "model_auto_compact_token_limit"));
|
|
451
|
+
return hasOutsideDuplicate
|
|
452
|
+
? { state: "malformed-or-ambiguous", spans: [] }
|
|
453
|
+
: { state: "exact-pair", spans: blockSpan };
|
|
454
|
+
}
|
|
455
|
+
const singletonState = (singletonKey, siblingKey) => {
|
|
456
|
+
let singletonDuplicates = 0;
|
|
457
|
+
let siblingCount = 0;
|
|
458
|
+
let invalidSibling = false;
|
|
459
|
+
for (const { entry, start: entryStart, end: entryEnd } of rootEntries) {
|
|
460
|
+
const outside = entryEnd <= start.index || entryStart > end.index;
|
|
461
|
+
if (outside && entry.key === singletonKey)
|
|
462
|
+
singletonDuplicates += 1;
|
|
463
|
+
if (outside && entry.key === siblingKey) {
|
|
464
|
+
siblingCount += 1;
|
|
465
|
+
invalidSibling ||= !parseStandaloneToml(entry.lines.join("\n"));
|
|
400
466
|
}
|
|
401
|
-
index = endIndex;
|
|
402
|
-
continue;
|
|
403
|
-
}
|
|
404
|
-
if (index < boundary &&
|
|
405
|
-
trimmed === OMX_SEEDED_BEHAVIORAL_DEFAULTS_END_MARKER) {
|
|
406
|
-
continue;
|
|
407
467
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
468
|
+
if (singletonDuplicates > 0 || siblingCount > 1 || invalidSibling)
|
|
469
|
+
return "malformed-or-ambiguous";
|
|
470
|
+
return siblingCount === 1 ? "exact" : "bounded-nonremovable";
|
|
471
|
+
};
|
|
472
|
+
if (exact([`model_context_window = ${LEGACY_SEEDED_MODEL_CONTEXT_WINDOW}`])) {
|
|
473
|
+
const state = singletonState("model_context_window", "model_auto_compact_token_limit");
|
|
474
|
+
return state === "exact"
|
|
475
|
+
? { state: "exact-context-singleton", spans: blockSpan }
|
|
476
|
+
: state === "bounded-nonremovable"
|
|
477
|
+
? { state, spans: markerSpans }
|
|
478
|
+
: { state, spans: [] };
|
|
479
|
+
}
|
|
480
|
+
if (exact([`model_auto_compact_token_limit = ${LEGACY_SEEDED_MODEL_AUTO_COMPACT_TOKEN_LIMIT}`])) {
|
|
481
|
+
const state = singletonState("model_auto_compact_token_limit", "model_context_window");
|
|
482
|
+
return state === "exact"
|
|
483
|
+
? { state: "exact-auto-singleton", spans: blockSpan }
|
|
484
|
+
: state === "bounded-nonremovable"
|
|
485
|
+
? { state, spans: markerSpans }
|
|
486
|
+
: { state, spans: [] };
|
|
487
|
+
}
|
|
488
|
+
return { state: "bounded-nonremovable", spans: markerSpans };
|
|
489
|
+
}
|
|
490
|
+
export function hasExactOmxSeededBehavioralDefaultsPair(config) {
|
|
491
|
+
return analyzeOmxSeededBehavioralDefaults(config).state === "exact-pair";
|
|
492
|
+
}
|
|
493
|
+
export function stripOmxSeededBehavioralDefaults(config) {
|
|
494
|
+
return [...analyzeOmxSeededBehavioralDefaults(config).spans]
|
|
495
|
+
.sort((left, right) => right.start - left.start)
|
|
496
|
+
.reduce((result, span) => result.slice(0, span.start) + result.slice(span.end), config);
|
|
411
497
|
}
|
|
412
498
|
function stripRootLevelKeys(config, keys) {
|
|
413
499
|
const { entries, remainder } = splitRootLevelEntries(config);
|
|
@@ -511,7 +597,6 @@ function upsertFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FE
|
|
|
511
597
|
const base = config.trimEnd();
|
|
512
598
|
const featureBlock = [
|
|
513
599
|
"[features]",
|
|
514
|
-
"multi_agent = true",
|
|
515
600
|
"child_agents_md = true",
|
|
516
601
|
hookFeatureFlagLine,
|
|
517
602
|
"goals = true",
|
|
@@ -529,31 +614,19 @@ function upsertFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FE
|
|
|
529
614
|
break;
|
|
530
615
|
}
|
|
531
616
|
}
|
|
532
|
-
// Remove deprecated
|
|
533
|
-
// the misspelled singular 'goal' flag written by unreleased PR builds.
|
|
617
|
+
// Remove deprecated collab and unreleased singular goal flags.
|
|
534
618
|
for (let i = sectionEnd - 1; i > featuresStart; i--) {
|
|
535
619
|
if (/^\s*(?:collab|goal)\s*=/.test(lines[i])) {
|
|
536
620
|
lines.splice(i, 1);
|
|
537
621
|
sectionEnd -= 1;
|
|
538
622
|
}
|
|
539
623
|
}
|
|
540
|
-
let multiAgentIdx = -1;
|
|
541
624
|
let childAgentsIdx = -1;
|
|
542
625
|
for (let i = featuresStart + 1; i < sectionEnd; i++) {
|
|
543
|
-
if (/^\s*
|
|
544
|
-
multiAgentIdx = i;
|
|
545
|
-
}
|
|
546
|
-
else if (/^\s*child_agents_md\s*=/.test(lines[i])) {
|
|
626
|
+
if (/^\s*child_agents_md\s*=/.test(lines[i])) {
|
|
547
627
|
childAgentsIdx = i;
|
|
548
628
|
}
|
|
549
629
|
}
|
|
550
|
-
if (multiAgentIdx >= 0) {
|
|
551
|
-
lines[multiAgentIdx] = "multi_agent = true";
|
|
552
|
-
}
|
|
553
|
-
else {
|
|
554
|
-
lines.splice(sectionEnd, 0, "multi_agent = true");
|
|
555
|
-
sectionEnd += 1;
|
|
556
|
-
}
|
|
557
630
|
if (childAgentsIdx >= 0) {
|
|
558
631
|
lines[childAgentsIdx] = "child_agents_md = true";
|
|
559
632
|
}
|
|
@@ -721,105 +794,845 @@ export function syncProjectScopeTrustStateFromRuntime(projectConfig, runtimeConf
|
|
|
721
794
|
return block;
|
|
722
795
|
return `${stripped}\n\n${block}`;
|
|
723
796
|
}
|
|
724
|
-
function
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
797
|
+
function isMultilineTomlString(mode) {
|
|
798
|
+
return mode === "multiline-basic" || mode === "multiline-literal";
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Tracks only lexical boundaries needed to safely associate source lines with
|
|
802
|
+
* TOML statements. TOML's parser gives us semantics; this prevents source
|
|
803
|
+
* repair from treating table-like text in a multiline value as syntax.
|
|
804
|
+
*/
|
|
805
|
+
function analyzeTomlSource(config) {
|
|
806
|
+
const lines = config.split(/\r?\n/);
|
|
807
|
+
const lineStartsOutsideMultiline = [];
|
|
808
|
+
const lineHasTomlComment = [];
|
|
809
|
+
let mode;
|
|
810
|
+
let isUnambiguous = true;
|
|
811
|
+
for (const line of lines) {
|
|
812
|
+
lineStartsOutsideMultiline.push(!isMultilineTomlString(mode));
|
|
813
|
+
let hasComment = false;
|
|
814
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
815
|
+
const character = line[index];
|
|
816
|
+
if (mode === "basic") {
|
|
817
|
+
if (character === "\\") {
|
|
818
|
+
index += 1;
|
|
819
|
+
}
|
|
820
|
+
else if (character === "\"") {
|
|
821
|
+
mode = undefined;
|
|
822
|
+
}
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
if (mode === "literal") {
|
|
826
|
+
if (character === "'")
|
|
827
|
+
mode = undefined;
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
if (mode === "multiline-basic" || mode === "multiline-literal") {
|
|
831
|
+
const delimiter = mode === "multiline-basic" ? "\"" : "'";
|
|
832
|
+
if (mode === "multiline-basic" && character === "\\") {
|
|
833
|
+
index += 1;
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (character !== delimiter)
|
|
837
|
+
continue;
|
|
838
|
+
let runEnd = index + 1;
|
|
839
|
+
while (line[runEnd] === delimiter)
|
|
840
|
+
runEnd += 1;
|
|
841
|
+
if (runEnd - index >= 3) {
|
|
842
|
+
// TOML permits one or two delimiter characters immediately before
|
|
843
|
+
// the closing triple delimiter as string content.
|
|
844
|
+
mode = undefined;
|
|
845
|
+
index = runEnd - 1;
|
|
846
|
+
}
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
if (character === "#") {
|
|
850
|
+
hasComment = true;
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
853
|
+
if (character !== "\"" && character !== "'")
|
|
854
|
+
continue;
|
|
855
|
+
const isMultiline = line[index + 1] === character && line[index + 2] === character;
|
|
856
|
+
if (isMultiline) {
|
|
857
|
+
mode = character === "\"" ? "multiline-basic" : "multiline-literal";
|
|
858
|
+
index += 2;
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
mode = character === "\"" ? "basic" : "literal";
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
lineHasTomlComment.push(hasComment);
|
|
865
|
+
if (mode === "basic" || mode === "literal")
|
|
866
|
+
isUnambiguous = false;
|
|
728
867
|
}
|
|
729
|
-
|
|
868
|
+
if (isMultilineTomlString(mode))
|
|
869
|
+
isUnambiguous = false;
|
|
870
|
+
return { lines, lineStartsOutsideMultiline, lineHasTomlComment, isUnambiguous };
|
|
871
|
+
}
|
|
872
|
+
function skipTomlSourceWhitespace(line, index) {
|
|
873
|
+
let cursor = index;
|
|
874
|
+
while (line[cursor] === " " || line[cursor] === "\t")
|
|
875
|
+
cursor += 1;
|
|
876
|
+
return cursor;
|
|
877
|
+
}
|
|
878
|
+
function parseTomlSourceKeySegment(line, index) {
|
|
879
|
+
const start = skipTomlSourceWhitespace(line, index);
|
|
880
|
+
const first = line[start];
|
|
881
|
+
if (!first)
|
|
882
|
+
return undefined;
|
|
883
|
+
if (first !== '"' && first !== "'") {
|
|
884
|
+
const match = /^[A-Za-z0-9_-]+/.exec(line.slice(start));
|
|
885
|
+
if (!match)
|
|
886
|
+
return undefined;
|
|
887
|
+
return { key: match[0], end: start + match[0].length, incomplete: false };
|
|
888
|
+
}
|
|
889
|
+
let cursor = start + 1;
|
|
890
|
+
let escaped = false;
|
|
891
|
+
for (; cursor < line.length; cursor += 1) {
|
|
892
|
+
const character = line[cursor];
|
|
893
|
+
if (first === '"' && escaped) {
|
|
894
|
+
escaped = false;
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
if (first === '"' && character === "\\") {
|
|
898
|
+
escaped = true;
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
901
|
+
if (character !== first)
|
|
902
|
+
continue;
|
|
903
|
+
const token = line.slice(start, cursor + 1);
|
|
904
|
+
const parsed = safeParseToml(`${token} = true`);
|
|
905
|
+
const keys = parsed ? Object.keys(parsed) : [];
|
|
906
|
+
const hasKey = keys.length === 1;
|
|
907
|
+
return {
|
|
908
|
+
...(hasKey ? { key: keys[0] } : {}),
|
|
909
|
+
end: cursor + 1,
|
|
910
|
+
incomplete: !hasKey,
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
return { end: line.length, incomplete: true };
|
|
914
|
+
}
|
|
915
|
+
function isTomlSourceKey(segment, key) {
|
|
916
|
+
return segment.key === key;
|
|
917
|
+
}
|
|
918
|
+
function findTomlSourceAssignmentSeparator(line) {
|
|
919
|
+
let segment = parseTomlSourceKeySegment(line, 0);
|
|
920
|
+
if (!segment || segment.incomplete)
|
|
921
|
+
return undefined;
|
|
922
|
+
let cursor = skipTomlSourceWhitespace(line, segment.end);
|
|
923
|
+
while (line[cursor] === ".") {
|
|
924
|
+
segment = parseTomlSourceKeySegment(line, cursor + 1);
|
|
925
|
+
if (!segment || segment.incomplete)
|
|
926
|
+
return undefined;
|
|
927
|
+
cursor = skipTomlSourceWhitespace(line, segment.end);
|
|
928
|
+
}
|
|
929
|
+
return line[cursor] === "=" ? cursor : undefined;
|
|
930
|
+
}
|
|
931
|
+
function advancePastInlineTomlValue(line, index) {
|
|
932
|
+
let braces = 0;
|
|
933
|
+
let brackets = 0;
|
|
934
|
+
let quote;
|
|
935
|
+
let escaped = false;
|
|
936
|
+
for (let cursor = index; cursor < line.length; cursor += 1) {
|
|
937
|
+
const character = line[cursor];
|
|
938
|
+
if (quote) {
|
|
939
|
+
if (quote === '"' && escaped) {
|
|
940
|
+
escaped = false;
|
|
941
|
+
}
|
|
942
|
+
else if (quote === '"' && character === "\\") {
|
|
943
|
+
escaped = true;
|
|
944
|
+
}
|
|
945
|
+
else if (character === quote) {
|
|
946
|
+
quote = undefined;
|
|
947
|
+
}
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
if (character === '"' || character === "'") {
|
|
951
|
+
quote = character;
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
if (character === "#")
|
|
955
|
+
return line.length;
|
|
956
|
+
if (character === "{") {
|
|
957
|
+
braces += 1;
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
if (character === "}") {
|
|
961
|
+
if (braces === 0 && brackets === 0)
|
|
962
|
+
return cursor;
|
|
963
|
+
braces = Math.max(0, braces - 1);
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
966
|
+
if (character === "[") {
|
|
967
|
+
brackets += 1;
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
if (character === "]") {
|
|
971
|
+
brackets = Math.max(0, brackets - 1);
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
if (character === "," && braces === 0 && brackets === 0)
|
|
975
|
+
return cursor + 1;
|
|
976
|
+
}
|
|
977
|
+
return line.length;
|
|
978
|
+
}
|
|
979
|
+
function inlineTomlTableMaySpellStateKey(line, index) {
|
|
980
|
+
let cursor = index;
|
|
981
|
+
while (cursor < line.length) {
|
|
982
|
+
cursor = skipTomlSourceWhitespace(line, cursor);
|
|
983
|
+
// A comment cannot close the surrounding inline table.
|
|
984
|
+
if (line[cursor] === "#")
|
|
985
|
+
return true;
|
|
986
|
+
if (line[cursor] === "}")
|
|
987
|
+
return false;
|
|
988
|
+
const segment = parseTomlSourceKeySegment(line, cursor);
|
|
989
|
+
if (!segment)
|
|
990
|
+
return true;
|
|
991
|
+
if (segment.incomplete || isTomlSourceKey(segment, "state"))
|
|
992
|
+
return true;
|
|
993
|
+
cursor = skipTomlSourceWhitespace(line, segment.end);
|
|
994
|
+
if (line[cursor] !== "=")
|
|
995
|
+
return true;
|
|
996
|
+
cursor = advancePastInlineTomlValue(line, cursor + 1);
|
|
997
|
+
if (line[cursor] === "}")
|
|
998
|
+
return false;
|
|
999
|
+
}
|
|
1000
|
+
// The unclosed inline table can acquire a state member on a following
|
|
1001
|
+
// unparsed line, so it is not safe to strip the containing marker block.
|
|
1002
|
+
return true;
|
|
1003
|
+
}
|
|
1004
|
+
function lineMaySpellHooksState(line) {
|
|
1005
|
+
let cursor = skipTomlSourceWhitespace(line, 0);
|
|
1006
|
+
if (line[cursor] === "[") {
|
|
1007
|
+
if (line[cursor + 1] === "[") {
|
|
1008
|
+
cursor = skipTomlSourceWhitespace(line, cursor + 2);
|
|
1009
|
+
}
|
|
1010
|
+
else {
|
|
1011
|
+
cursor = skipTomlSourceWhitespace(line, cursor + 1);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
const hooks = parseTomlSourceKeySegment(line, cursor);
|
|
1015
|
+
if (!hooks || !isTomlSourceKey(hooks, "hooks"))
|
|
1016
|
+
return false;
|
|
1017
|
+
cursor = skipTomlSourceWhitespace(line, hooks.end);
|
|
1018
|
+
if (line[cursor] === ".") {
|
|
1019
|
+
const state = parseTomlSourceKeySegment(line, cursor + 1);
|
|
1020
|
+
// A dangling dot can be completed by a following unparsed state key.
|
|
1021
|
+
return state === undefined || state.incomplete || isTomlSourceKey(state, "state");
|
|
1022
|
+
}
|
|
1023
|
+
if (line[cursor] !== "=")
|
|
1024
|
+
return false;
|
|
1025
|
+
cursor = skipTomlSourceWhitespace(line, cursor + 1);
|
|
1026
|
+
// A bare assignment or comment cannot prove that a following unparsed line
|
|
1027
|
+
// does not continue an inline hooks table with a state member.
|
|
1028
|
+
if (cursor >= line.length || line[cursor] === "#")
|
|
1029
|
+
return true;
|
|
1030
|
+
return line[cursor] === "{" && inlineTomlTableMaySpellStateKey(line, cursor + 1);
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Detects a potential array-table opener without accepting malformed spacing
|
|
1034
|
+
* or extra opening brackets as TOML syntax. Array tables rooted at `hooks`
|
|
1035
|
+
* have no proof-owned representation, so their first key segment is enough
|
|
1036
|
+
* to retain a managed marker block rather than strip it.
|
|
1037
|
+
*/
|
|
1038
|
+
function parseTomlSourceArrayTableOpener(line) {
|
|
1039
|
+
let cursor = skipTomlSourceWhitespace(line, 0);
|
|
1040
|
+
if (line[cursor] !== "[")
|
|
730
1041
|
return undefined;
|
|
1042
|
+
const hasExactAdjacentOpener = line[cursor + 1] === "[";
|
|
1043
|
+
if (hasExactAdjacentOpener) {
|
|
1044
|
+
cursor += 2;
|
|
1045
|
+
}
|
|
1046
|
+
else {
|
|
1047
|
+
cursor = skipTomlSourceWhitespace(line, cursor + 1);
|
|
1048
|
+
if (line[cursor] !== "[")
|
|
1049
|
+
return undefined;
|
|
1050
|
+
cursor += 1;
|
|
1051
|
+
}
|
|
1052
|
+
cursor = skipTomlSourceWhitespace(line, cursor);
|
|
1053
|
+
while (line[cursor] === "[") {
|
|
1054
|
+
cursor = skipTomlSourceWhitespace(line, cursor + 1);
|
|
731
1055
|
}
|
|
1056
|
+
const firstKey = parseTomlSourceKeySegment(line, cursor);
|
|
1057
|
+
return {
|
|
1058
|
+
firstKey,
|
|
1059
|
+
openerOnly: firstKey === undefined &&
|
|
1060
|
+
(cursor >= line.length || line[cursor] === "#"),
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
function hasIncompleteTomlSourceHooksKeyPrefix(line) {
|
|
1064
|
+
let cursor = skipTomlSourceWhitespace(line, 0);
|
|
1065
|
+
let tableHeader = false;
|
|
1066
|
+
let arrayTableHeader = false;
|
|
1067
|
+
if (line[cursor] === "[") {
|
|
1068
|
+
tableHeader = true;
|
|
1069
|
+
if (line[cursor + 1] === "[") {
|
|
1070
|
+
arrayTableHeader = true;
|
|
1071
|
+
cursor = skipTomlSourceWhitespace(line, cursor + 2);
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
cursor = skipTomlSourceWhitespace(line, cursor + 1);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
const hooks = parseTomlSourceKeySegment(line, cursor);
|
|
1078
|
+
if (!hooks || !isTomlSourceKey(hooks, "hooks"))
|
|
1079
|
+
return false;
|
|
1080
|
+
cursor = skipTomlSourceWhitespace(line, hooks.end);
|
|
1081
|
+
if (!tableHeader)
|
|
1082
|
+
return cursor >= line.length || line[cursor] === "#";
|
|
1083
|
+
if (line[cursor] !== "]" || (arrayTableHeader && line[cursor + 1] !== "]")) {
|
|
1084
|
+
return true;
|
|
1085
|
+
}
|
|
1086
|
+
const suffix = line.slice(cursor + (arrayTableHeader ? 2 : 1)).trimStart();
|
|
1087
|
+
return suffix.length > 0 && !suffix.startsWith("#");
|
|
1088
|
+
}
|
|
1089
|
+
function isTomlSourceHooksKeyContinuationSeparator(line) {
|
|
1090
|
+
const cursor = skipTomlSourceWhitespace(line, 0);
|
|
1091
|
+
return line[cursor] === "." || line[cursor] === "=" || line[cursor] === "[";
|
|
732
1092
|
}
|
|
733
|
-
function
|
|
734
|
-
|
|
735
|
-
|
|
1093
|
+
function isTomlSourceBlankOrComment(line) {
|
|
1094
|
+
return /^\s*(?:#.*)?$/.test(line);
|
|
1095
|
+
}
|
|
1096
|
+
function isTomlSourceStandaloneOpeningBracket(line) {
|
|
1097
|
+
const cursor = skipTomlSourceWhitespace(line, 0);
|
|
1098
|
+
if (line[cursor] !== "[")
|
|
1099
|
+
return false;
|
|
1100
|
+
const next = skipTomlSourceWhitespace(line, cursor + 1);
|
|
1101
|
+
return next >= line.length || line[next] === "#";
|
|
1102
|
+
}
|
|
1103
|
+
function firstTomlSourceKeyFollowingOpeningBrackets(line) {
|
|
1104
|
+
let cursor = skipTomlSourceWhitespace(line, 0);
|
|
1105
|
+
while (line[cursor] === "[") {
|
|
1106
|
+
cursor = skipTomlSourceWhitespace(line, cursor + 1);
|
|
1107
|
+
}
|
|
1108
|
+
return parseTomlSourceKeySegment(line, cursor);
|
|
1109
|
+
}
|
|
1110
|
+
function lineMaySpellStateKey(line) {
|
|
1111
|
+
const state = parseTomlSourceKeySegment(line, 0);
|
|
1112
|
+
return state !== undefined && (state.incomplete || isTomlSourceKey(state, "state"));
|
|
1113
|
+
}
|
|
1114
|
+
function isTomlSourceHooksTableHeader(parsed) {
|
|
1115
|
+
const hooks = parsed?.hooks;
|
|
1116
|
+
return parsed !== undefined &&
|
|
1117
|
+
Object.keys(parsed).length === 1 &&
|
|
1118
|
+
isPlainTomlRecord(hooks) &&
|
|
1119
|
+
Object.keys(hooks).length === 0;
|
|
1120
|
+
}
|
|
1121
|
+
function hasUnprovenManagedMarkerHooksStateSyntax(source, managedMarkerRanges, parsedStatementSpans, parsedAssignmentSpans) {
|
|
1122
|
+
const parsedLines = new Set();
|
|
1123
|
+
const parsedStatementStartLines = new Set();
|
|
1124
|
+
for (const span of parsedStatementSpans) {
|
|
1125
|
+
parsedStatementStartLines.add(span.start);
|
|
1126
|
+
for (let index = span.start; index < span.end; index += 1)
|
|
1127
|
+
parsedLines.add(index);
|
|
1128
|
+
}
|
|
1129
|
+
const parsedAssignmentLines = new Set();
|
|
1130
|
+
for (const span of parsedAssignmentSpans) {
|
|
1131
|
+
for (let index = span.start; index < span.end; index += 1) {
|
|
1132
|
+
parsedAssignmentLines.add(index);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
const managedContentLines = new Set();
|
|
1136
|
+
for (const range of managedMarkerRanges) {
|
|
1137
|
+
for (let index = range.start + 1; index < range.end; index += 1) {
|
|
1138
|
+
managedContentLines.add(index);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
let insideHooksTable = false;
|
|
1142
|
+
let hasIncompleteHooksKeyPrefix = false;
|
|
1143
|
+
let hasIncompleteHooksArrayTableOpener = false;
|
|
1144
|
+
for (let index = 0; index < source.lines.length; index += 1) {
|
|
1145
|
+
if (!source.lineStartsOutsideMultiline[index]) {
|
|
1146
|
+
hasIncompleteHooksKeyPrefix = false;
|
|
1147
|
+
hasIncompleteHooksArrayTableOpener = false;
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
const line = source.lines[index] ?? "";
|
|
1151
|
+
const isParsedAssignmentLine = parsedAssignmentLines.has(index);
|
|
1152
|
+
if (!isParsedAssignmentLine) {
|
|
1153
|
+
const header = parseTomlSourceTableHeader(line);
|
|
1154
|
+
if (header?.parsed) {
|
|
1155
|
+
insideHooksTable = isTomlSourceHooksTableHeader(header.parsed);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
if (!managedContentLines.has(index)) {
|
|
1159
|
+
hasIncompleteHooksKeyPrefix = false;
|
|
1160
|
+
hasIncompleteHooksArrayTableOpener = false;
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
const isParsedStatementLine = parsedLines.has(index);
|
|
1164
|
+
const isParsedStatementStartLine = parsedStatementStartLines.has(index);
|
|
1165
|
+
if (hasIncompleteHooksKeyPrefix) {
|
|
1166
|
+
if (isTomlSourceBlankOrComment(line))
|
|
1167
|
+
continue;
|
|
1168
|
+
if (isTomlSourceHooksKeyContinuationSeparator(line))
|
|
1169
|
+
return true;
|
|
1170
|
+
hasIncompleteHooksKeyPrefix = false;
|
|
1171
|
+
}
|
|
1172
|
+
// Parsed statements can contain nested arrays whose standalone brackets and
|
|
1173
|
+
// quoted "hooks" values must not contribute to malformed-header tracking.
|
|
1174
|
+
if (hasIncompleteHooksArrayTableOpener && !isParsedStatementLine) {
|
|
1175
|
+
if (isTomlSourceBlankOrComment(line))
|
|
1176
|
+
continue;
|
|
1177
|
+
const firstKey = firstTomlSourceKeyFollowingOpeningBrackets(line);
|
|
1178
|
+
if (firstKey) {
|
|
1179
|
+
if (isTomlSourceKey(firstKey, "hooks"))
|
|
1180
|
+
return true;
|
|
1181
|
+
hasIncompleteHooksArrayTableOpener = false;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
const arrayTableOpener = !isParsedStatementLine || isParsedStatementStartLine
|
|
1185
|
+
? parseTomlSourceArrayTableOpener(line)
|
|
1186
|
+
: undefined;
|
|
1187
|
+
if (arrayTableOpener?.firstKey && isTomlSourceKey(arrayTableOpener.firstKey, "hooks")) {
|
|
1188
|
+
return true;
|
|
1189
|
+
}
|
|
1190
|
+
if (arrayTableOpener?.openerOnly && !isParsedStatementLine) {
|
|
1191
|
+
hasIncompleteHooksArrayTableOpener = true;
|
|
1192
|
+
}
|
|
1193
|
+
if (!isParsedStatementLine && isTomlSourceStandaloneOpeningBracket(line)) {
|
|
1194
|
+
hasIncompleteHooksArrayTableOpener = true;
|
|
1195
|
+
}
|
|
1196
|
+
if (isParsedStatementLine)
|
|
1197
|
+
continue;
|
|
1198
|
+
if (lineMaySpellHooksState(line) || (insideHooksTable && lineMaySpellStateKey(line))) {
|
|
1199
|
+
return true;
|
|
1200
|
+
}
|
|
1201
|
+
const hasIncompleteHooksPrefix = hasIncompleteTomlSourceHooksKeyPrefix(line);
|
|
1202
|
+
if (hasIncompleteHooksPrefix && /^\s*\[\[?/.test(line))
|
|
1203
|
+
return true;
|
|
1204
|
+
hasIncompleteHooksKeyPrefix = hasIncompleteHooksPrefix;
|
|
1205
|
+
}
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
function managedHookTrustStateExpectations(...states) {
|
|
1209
|
+
const expectations = new Map();
|
|
1210
|
+
for (const state of states) {
|
|
1211
|
+
if (!state)
|
|
1212
|
+
continue;
|
|
1213
|
+
for (const [key, entry] of Object.entries(state)) {
|
|
1214
|
+
const hashes = expectations.get(key) ?? new Set();
|
|
1215
|
+
hashes.add(entry.trusted_hash);
|
|
1216
|
+
expectations.set(key, hashes);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
return expectations;
|
|
1220
|
+
}
|
|
1221
|
+
function managedHookTrustCoordinateFamily(key) {
|
|
1222
|
+
const match = /^(.*):([a-z_]+):\d+:\d+$/.exec(key);
|
|
1223
|
+
return match ? `${match[1]}:${match[2]}` : undefined;
|
|
1224
|
+
}
|
|
1225
|
+
function expectedManagedHookTrustHashes(expectations, key, allowCoordinateDrift) {
|
|
1226
|
+
const exact = expectations.get(key);
|
|
1227
|
+
if (exact || !allowCoordinateDrift)
|
|
1228
|
+
return exact;
|
|
1229
|
+
const family = managedHookTrustCoordinateFamily(key);
|
|
1230
|
+
if (!family)
|
|
736
1231
|
return undefined;
|
|
737
|
-
const
|
|
738
|
-
|
|
1232
|
+
const hashes = new Set();
|
|
1233
|
+
for (const [expectedKey, expectedHashes] of expectations) {
|
|
1234
|
+
if (managedHookTrustCoordinateFamily(expectedKey) !== family)
|
|
1235
|
+
continue;
|
|
1236
|
+
for (const hash of expectedHashes)
|
|
1237
|
+
hashes.add(hash);
|
|
1238
|
+
}
|
|
1239
|
+
return hashes.size > 0 ? hashes : undefined;
|
|
1240
|
+
}
|
|
1241
|
+
function tomlHooksStateValue(parsed) {
|
|
1242
|
+
if (!parsed)
|
|
739
1243
|
return undefined;
|
|
740
|
-
|
|
1244
|
+
const hooks = parsed.hooks;
|
|
1245
|
+
if (!isPlainTomlRecord(hooks) || !Object.hasOwn(hooks, "state")) {
|
|
1246
|
+
return undefined;
|
|
1247
|
+
}
|
|
1248
|
+
return hooks.state;
|
|
741
1249
|
}
|
|
742
|
-
function
|
|
743
|
-
|
|
1250
|
+
function tomlHooksStateEntries(parsed) {
|
|
1251
|
+
const state = tomlHooksStateValue(parsed);
|
|
1252
|
+
return isPlainTomlRecord(state) ? state : undefined;
|
|
744
1253
|
}
|
|
745
|
-
function
|
|
746
|
-
|
|
747
|
-
if (nonBlank.length !== 1)
|
|
1254
|
+
function hasOnlyManagedHookTrustStateField(parsed, key) {
|
|
1255
|
+
if (!parsed || Object.keys(parsed).length !== 1 || !Object.hasOwn(parsed, "hooks")) {
|
|
748
1256
|
return false;
|
|
749
|
-
|
|
750
|
-
|
|
1257
|
+
}
|
|
1258
|
+
const hooks = parsed.hooks;
|
|
1259
|
+
if (!isPlainTomlRecord(hooks) || Object.keys(hooks).length !== 1 || !Object.hasOwn(hooks, "state")) {
|
|
1260
|
+
return false;
|
|
1261
|
+
}
|
|
1262
|
+
const state = hooks.state;
|
|
1263
|
+
return isPlainTomlRecord(state) &&
|
|
1264
|
+
Object.keys(state).length === 1 &&
|
|
1265
|
+
Object.hasOwn(state, key);
|
|
751
1266
|
}
|
|
752
|
-
function
|
|
753
|
-
|
|
754
|
-
|
|
1267
|
+
function parseTomlSourceTableHeader(line) {
|
|
1268
|
+
const start = line.search(/\S/);
|
|
1269
|
+
if (start === -1 || line[start] !== "[")
|
|
1270
|
+
return undefined;
|
|
1271
|
+
const array = line[start + 1] === "[";
|
|
1272
|
+
let quote;
|
|
1273
|
+
let escaped = false;
|
|
1274
|
+
for (let index = start + (array ? 2 : 1); index < line.length; index += 1) {
|
|
1275
|
+
const character = line[index];
|
|
1276
|
+
if (quote === "\"") {
|
|
1277
|
+
if (escaped) {
|
|
1278
|
+
escaped = false;
|
|
1279
|
+
}
|
|
1280
|
+
else if (character === "\\") {
|
|
1281
|
+
escaped = true;
|
|
1282
|
+
}
|
|
1283
|
+
else if (character === quote) {
|
|
1284
|
+
quote = undefined;
|
|
1285
|
+
}
|
|
1286
|
+
continue;
|
|
1287
|
+
}
|
|
1288
|
+
if (quote === "'") {
|
|
1289
|
+
if (character === quote)
|
|
1290
|
+
quote = undefined;
|
|
1291
|
+
continue;
|
|
1292
|
+
}
|
|
1293
|
+
if (character === "\"" || character === "'") {
|
|
1294
|
+
quote = character;
|
|
1295
|
+
continue;
|
|
1296
|
+
}
|
|
1297
|
+
if (character !== "]")
|
|
1298
|
+
continue;
|
|
1299
|
+
const end = array ? index + 2 : index + 1;
|
|
1300
|
+
if (array && line[index + 1] !== "]")
|
|
1301
|
+
return undefined;
|
|
1302
|
+
const suffix = line.slice(end).trimStart();
|
|
1303
|
+
if (suffix.length > 0 && !suffix.startsWith("#"))
|
|
1304
|
+
return undefined;
|
|
1305
|
+
return { parsed: safeParseToml(line.slice(start, end)) };
|
|
755
1306
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
for (let
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
1307
|
+
return undefined;
|
|
1308
|
+
}
|
|
1309
|
+
function sourceRangeHasTomlComment(source, start, end) {
|
|
1310
|
+
for (let index = start; index < end; index += 1) {
|
|
1311
|
+
if (source.lineHasTomlComment[index])
|
|
1312
|
+
return true;
|
|
1313
|
+
}
|
|
1314
|
+
return false;
|
|
1315
|
+
}
|
|
1316
|
+
function collectMarkerRanges(source, startMarker, endMarker, includeUnterminatedRange = false, inertAssignmentSpans = []) {
|
|
1317
|
+
const isInsideInertAssignment = (line) => inertAssignmentSpans.some((span) => span.start <= line && line < span.end);
|
|
1318
|
+
const ranges = [];
|
|
1319
|
+
for (let start = 0; start < source.lines.length; start += 1) {
|
|
1320
|
+
if (!source.lineStartsOutsideMultiline[start] ||
|
|
1321
|
+
isInsideInertAssignment(start) ||
|
|
1322
|
+
source.lines[start]?.trim() !== startMarker)
|
|
1323
|
+
continue;
|
|
1324
|
+
const end = source.lines.findIndex((line, index) => index > start &&
|
|
1325
|
+
source.lineStartsOutsideMultiline[index] &&
|
|
1326
|
+
!isInsideInertAssignment(index) &&
|
|
1327
|
+
line.trim() === endMarker);
|
|
1328
|
+
const nestedStart = source.lines.findIndex((line, index) => index > start &&
|
|
1329
|
+
source.lineStartsOutsideMultiline[index] &&
|
|
1330
|
+
!isInsideInertAssignment(index) &&
|
|
1331
|
+
line.trim() === startMarker);
|
|
1332
|
+
if (end === -1 || (nestedStart !== -1 && nestedStart < end)) {
|
|
1333
|
+
if (includeUnterminatedRange)
|
|
1334
|
+
ranges.push({ start, end: source.lines.length });
|
|
764
1335
|
continue;
|
|
765
1336
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1337
|
+
ranges.push({ start, end });
|
|
1338
|
+
start = end;
|
|
1339
|
+
}
|
|
1340
|
+
return ranges;
|
|
1341
|
+
}
|
|
1342
|
+
function recordManagedMarkerHooksStateSourceSpan(spans, invalidSpans, start, end, parsed, insideManagedMarkerBlock) {
|
|
1343
|
+
if (!insideManagedMarkerBlock)
|
|
1344
|
+
return;
|
|
1345
|
+
const state = tomlHooksStateValue(parsed);
|
|
1346
|
+
if (state === undefined)
|
|
1347
|
+
return;
|
|
1348
|
+
const span = { start, end };
|
|
1349
|
+
spans.push(span);
|
|
1350
|
+
if (!isPlainTomlRecord(state) || Object.keys(state).length === 0) {
|
|
1351
|
+
invalidSpans.push(span);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
function addManagedHookTrustStateSourceRepresentations(representations, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, source, start, end, parsed, insideManagedMarkerBlock, containingTableScope, fallbackKeys = []) {
|
|
1355
|
+
recordManagedMarkerHooksStateSourceSpan(markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, start, end, parsed, insideManagedMarkerBlock);
|
|
1356
|
+
const state = tomlHooksStateEntries(parsed);
|
|
1357
|
+
const hasComment = sourceRangeHasTomlComment(source, start, end);
|
|
1358
|
+
if (state) {
|
|
1359
|
+
const stateEntryCount = Object.keys(state).length;
|
|
1360
|
+
for (const [key, value] of Object.entries(state)) {
|
|
1361
|
+
const hasExactSemanticScope = hasOnlyManagedHookTrustStateField(parsed, key) &&
|
|
1362
|
+
(!containingTableScope ||
|
|
1363
|
+
(!containingTableScope.hasComment &&
|
|
1364
|
+
hasOnlyManagedHookTrustStateField(containingTableScope.parsed, key)));
|
|
1365
|
+
const entries = representations.get(key) ?? [];
|
|
1366
|
+
entries.push({
|
|
1367
|
+
start,
|
|
1368
|
+
end,
|
|
1369
|
+
stateEntryCount,
|
|
1370
|
+
value,
|
|
1371
|
+
hasComment,
|
|
1372
|
+
hasExactSemanticScope,
|
|
1373
|
+
insideManagedMarkerBlock,
|
|
1374
|
+
});
|
|
1375
|
+
representations.set(key, entries);
|
|
1376
|
+
}
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
for (const key of fallbackKeys) {
|
|
1380
|
+
const entries = representations.get(key) ?? [];
|
|
1381
|
+
entries.push({
|
|
1382
|
+
start,
|
|
1383
|
+
end,
|
|
1384
|
+
stateEntryCount: 0,
|
|
1385
|
+
value: undefined,
|
|
1386
|
+
hasComment,
|
|
1387
|
+
hasExactSemanticScope: false,
|
|
1388
|
+
insideManagedMarkerBlock,
|
|
1389
|
+
});
|
|
1390
|
+
representations.set(key, entries);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
function collectManagedHookTrustStateSourceRepresentations(config) {
|
|
1394
|
+
const source = analyzeTomlSource(config);
|
|
1395
|
+
const { lines } = source;
|
|
1396
|
+
const parsedAssignmentSpans = [];
|
|
1397
|
+
for (let cursor = 0; cursor < lines.length; cursor += 1) {
|
|
1398
|
+
if (!source.lineStartsOutsideMultiline[cursor])
|
|
1399
|
+
continue;
|
|
1400
|
+
const line = lines[cursor] ?? "";
|
|
1401
|
+
if (findTomlSourceAssignmentSeparator(line) === undefined)
|
|
1402
|
+
continue;
|
|
1403
|
+
for (let statementEnd = cursor + 1; statementEnd <= lines.length; statementEnd += 1) {
|
|
1404
|
+
if (!safeParseToml(lines.slice(cursor, statementEnd).join("\n")))
|
|
1405
|
+
continue;
|
|
1406
|
+
parsedAssignmentSpans.push({ start: cursor, end: statementEnd });
|
|
1407
|
+
cursor = statementEnd - 1;
|
|
1408
|
+
break;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
const headers = [];
|
|
1412
|
+
for (const [index, line] of lines.entries()) {
|
|
1413
|
+
if (!source.lineStartsOutsideMultiline[index])
|
|
1414
|
+
continue;
|
|
1415
|
+
const header = parseTomlSourceTableHeader(line);
|
|
1416
|
+
if (parsedAssignmentSpans.some((span) => span.start < index && index < span.end))
|
|
1417
|
+
continue;
|
|
1418
|
+
if (header)
|
|
1419
|
+
headers.push({ index, header });
|
|
1420
|
+
}
|
|
1421
|
+
const boundaries = new Set(headers.map(({ index }) => index));
|
|
1422
|
+
for (const [index, line] of lines.entries()) {
|
|
1423
|
+
if (source.lineStartsOutsideMultiline[index] &&
|
|
1424
|
+
(line.trim() === OMX_HOOK_TRUST_END_MARKER ||
|
|
1425
|
+
line.trim() === OMX_CONFIG_END_MARKER)) {
|
|
1426
|
+
boundaries.add(index);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
const sortedBoundaries = [...boundaries].sort((left, right) => left - right);
|
|
1430
|
+
const representations = new Map();
|
|
1431
|
+
const markerContainedHooksStateSpans = [];
|
|
1432
|
+
const invalidMarkerContainedHooksStateSpans = [];
|
|
1433
|
+
const parsedStatementSpans = [];
|
|
1434
|
+
const managedMarkerRanges = [
|
|
1435
|
+
...collectMarkerRanges(source, OMX_HOOK_TRUST_START_MARKER, OMX_HOOK_TRUST_END_MARKER, false, parsedAssignmentSpans),
|
|
1436
|
+
...collectMarkerRanges(source, OMX_CONFIG_START_MARKER, OMX_CONFIG_END_MARKER, true, parsedAssignmentSpans),
|
|
1437
|
+
];
|
|
1438
|
+
const isInsideManagedMarkerBlock = (start, end) => managedMarkerRanges.some((range) => start > range.start && end <= range.end);
|
|
1439
|
+
const collectAssignments = (start, end, prefix, containingTableScope) => {
|
|
1440
|
+
for (let cursor = start; cursor < end;) {
|
|
1441
|
+
const line = lines[cursor] ?? "";
|
|
1442
|
+
if (!source.lineStartsOutsideMultiline[cursor] ||
|
|
1443
|
+
line.trim().length === 0 ||
|
|
1444
|
+
line.trim() === OMX_HOOK_TRUST_START_MARKER ||
|
|
1445
|
+
line.trim() === OMX_CONFIG_START_MARKER) {
|
|
1446
|
+
cursor += 1;
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
let parsed;
|
|
1450
|
+
let statementEnd = cursor + 1;
|
|
1451
|
+
for (; statementEnd <= end; statementEnd += 1) {
|
|
1452
|
+
const statement = lines.slice(cursor, statementEnd).join("\n");
|
|
1453
|
+
parsed = safeParseToml(prefix ? `${prefix}\n${statement}` : statement);
|
|
1454
|
+
if (parsed)
|
|
1455
|
+
break;
|
|
771
1456
|
}
|
|
1457
|
+
if (!parsed) {
|
|
1458
|
+
cursor += 1;
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
parsedStatementSpans.push({ start: cursor, end: statementEnd });
|
|
1462
|
+
addManagedHookTrustStateSourceRepresentations(representations, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, source, cursor, statementEnd, parsed, isInsideManagedMarkerBlock(cursor, statementEnd), containingTableScope);
|
|
1463
|
+
cursor = statementEnd;
|
|
772
1464
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
1465
|
+
};
|
|
1466
|
+
const rootEnd = sortedBoundaries[0] ?? lines.length;
|
|
1467
|
+
collectAssignments(0, rootEnd, undefined);
|
|
1468
|
+
for (const { index, header } of headers) {
|
|
1469
|
+
const boundaryIndex = sortedBoundaries.findIndex((boundary) => boundary === index);
|
|
1470
|
+
const end = boundaryIndex === -1
|
|
1471
|
+
? lines.length
|
|
1472
|
+
: (sortedBoundaries[boundaryIndex + 1] ?? lines.length);
|
|
1473
|
+
const tableScope = {
|
|
1474
|
+
parsed: safeParseToml(lines.slice(index, end).join("\n")),
|
|
1475
|
+
hasComment: sourceRangeHasTomlComment(source, index, end),
|
|
1476
|
+
};
|
|
1477
|
+
if (tableScope.parsed)
|
|
1478
|
+
parsedStatementSpans.push({ start: index, end });
|
|
1479
|
+
const insideManagedMarkerBlock = isInsideManagedMarkerBlock(index, end);
|
|
1480
|
+
recordManagedMarkerHooksStateSourceSpan(markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, index, end, tableScope.parsed, insideManagedMarkerBlock);
|
|
1481
|
+
const headerState = tomlHooksStateEntries(header.parsed);
|
|
1482
|
+
const directKeys = Object.keys(headerState ?? {});
|
|
1483
|
+
if (directKeys.length > 0) {
|
|
1484
|
+
addManagedHookTrustStateSourceRepresentations(representations, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, source, index, end, tableScope.parsed, insideManagedMarkerBlock, undefined, directKeys);
|
|
779
1485
|
continue;
|
|
780
1486
|
}
|
|
781
|
-
|
|
782
|
-
|
|
1487
|
+
collectAssignments(index + 1, end, lines[index], tableScope);
|
|
1488
|
+
}
|
|
1489
|
+
return {
|
|
1490
|
+
source,
|
|
1491
|
+
representations,
|
|
1492
|
+
managedMarkerRanges,
|
|
1493
|
+
markerContainedHooksStateSpans,
|
|
1494
|
+
invalidMarkerContainedHooksStateSpans,
|
|
1495
|
+
parsedStatementSpans,
|
|
1496
|
+
parsedAssignmentSpans,
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
function isExactlyManagedHookTrustStateValue(value, expectedHashes) {
|
|
1500
|
+
return isPlainTomlRecord(value) &&
|
|
1501
|
+
Object.keys(value).length === 1 &&
|
|
1502
|
+
Object.hasOwn(value, "trusted_hash") &&
|
|
1503
|
+
typeof value.trusted_hash === "string" &&
|
|
1504
|
+
expectedHashes.has(value.trusted_hash);
|
|
1505
|
+
}
|
|
1506
|
+
function managedMarkerTrustStateConflicts(source, representations, managedMarkerRanges, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, parsedStatementSpans, parsedAssignmentSpans, expectations) {
|
|
1507
|
+
const conflicts = new Set();
|
|
1508
|
+
const isInsideManagedMarkerRange = (span) => managedMarkerRanges.some((range) => span.start > range.start && span.end <= range.end);
|
|
1509
|
+
if (invalidMarkerContainedHooksStateSpans.some(isInsideManagedMarkerRange) ||
|
|
1510
|
+
hasUnprovenManagedMarkerHooksStateSyntax(source, managedMarkerRanges, [...markerContainedHooksStateSpans, ...parsedStatementSpans], parsedAssignmentSpans)) {
|
|
1511
|
+
conflicts.add("marker-contained hooks.state");
|
|
1512
|
+
}
|
|
1513
|
+
for (const [key, sourceRepresentations] of representations) {
|
|
1514
|
+
for (const representation of sourceRepresentations) {
|
|
1515
|
+
if (!isInsideManagedMarkerRange(representation))
|
|
1516
|
+
continue;
|
|
1517
|
+
const expectedHashes = expectedManagedHookTrustHashes(expectations, key, true);
|
|
1518
|
+
const isExactOwnedRepresentation = expectedHashes !== undefined &&
|
|
1519
|
+
representation.stateEntryCount === 1 &&
|
|
1520
|
+
!representation.hasComment &&
|
|
1521
|
+
representation.hasExactSemanticScope &&
|
|
1522
|
+
isExactlyManagedHookTrustStateValue(representation.value, expectedHashes);
|
|
1523
|
+
if (!source.isUnambiguous || !isExactOwnedRepresentation)
|
|
1524
|
+
conflicts.add(key);
|
|
783
1525
|
}
|
|
784
|
-
kept.push(...lines.slice(i, tableEnd));
|
|
785
|
-
i = tableEnd;
|
|
786
1526
|
}
|
|
787
|
-
return
|
|
1527
|
+
return conflicts;
|
|
788
1528
|
}
|
|
789
|
-
function
|
|
790
|
-
const lines =
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
if (trimmed !== OMX_HOOK_TRUST_START_MARKER) {
|
|
795
|
-
kept.push(lines[i]);
|
|
796
|
-
i += 1;
|
|
1529
|
+
function removeEmptyManagedHookTrustStateMarkerBlocks(source, removed) {
|
|
1530
|
+
const { lines } = source;
|
|
1531
|
+
for (let start = 0; start < lines.length; start += 1) {
|
|
1532
|
+
if (!source.lineStartsOutsideMultiline[start] ||
|
|
1533
|
+
lines[start]?.trim() !== OMX_HOOK_TRUST_START_MARKER)
|
|
797
1534
|
continue;
|
|
1535
|
+
const end = lines.findIndex((line, index) => index > start &&
|
|
1536
|
+
source.lineStartsOutsideMultiline[index] &&
|
|
1537
|
+
line.trim() === OMX_HOOK_TRUST_END_MARKER);
|
|
1538
|
+
const nestedStart = lines.findIndex((line, index) => index > start &&
|
|
1539
|
+
source.lineStartsOutsideMultiline[index] &&
|
|
1540
|
+
line.trim() === OMX_HOOK_TRUST_START_MARKER);
|
|
1541
|
+
if (end === -1 || (nestedStart !== -1 && nestedStart < end))
|
|
1542
|
+
continue;
|
|
1543
|
+
let onlyOwnedMarkerContent = true;
|
|
1544
|
+
for (let index = start + 1; index < end; index += 1) {
|
|
1545
|
+
const trimmed = lines[index].trim();
|
|
1546
|
+
if (removed.has(index) ||
|
|
1547
|
+
trimmed.length === 0 ||
|
|
1548
|
+
trimmed === "# Trusts only setup-managed native hook wrappers.")
|
|
1549
|
+
continue;
|
|
1550
|
+
onlyOwnedMarkerContent = false;
|
|
1551
|
+
break;
|
|
798
1552
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
1553
|
+
if (!onlyOwnedMarkerContent)
|
|
1554
|
+
continue;
|
|
1555
|
+
removed.add(start);
|
|
1556
|
+
removed.add(end);
|
|
1557
|
+
for (let index = start + 1; index < end; index += 1) {
|
|
1558
|
+
if (lines[index]?.trim() === "# Trusts only setup-managed native hook wrappers.") {
|
|
1559
|
+
removed.add(index);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
start = end;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
function stripProofManagedCodexHookTrustStateTables(config, expectations) {
|
|
1566
|
+
const { source, representations, managedMarkerRanges, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, parsedStatementSpans, parsedAssignmentSpans, } = collectManagedHookTrustStateSourceRepresentations(config);
|
|
1567
|
+
const preservedConflictKeys = managedMarkerTrustStateConflicts(source, representations, managedMarkerRanges, markerContainedHooksStateSpans, invalidMarkerContainedHooksStateSpans, parsedStatementSpans, parsedAssignmentSpans, expectations);
|
|
1568
|
+
if (!source.isUnambiguous) {
|
|
1569
|
+
return { config, preservedConflictKeys };
|
|
1570
|
+
}
|
|
1571
|
+
const { lines } = source;
|
|
1572
|
+
const removals = new Map();
|
|
1573
|
+
const parsedConfigState = tomlHooksStateEntries(safeParseToml(config));
|
|
1574
|
+
for (const key of Object.keys(parsedConfigState ?? {})) {
|
|
1575
|
+
if (expectations.has(key) && !representations.has(key)) {
|
|
1576
|
+
preservedConflictKeys.add(key);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
for (const [key, sourceRepresentations] of representations) {
|
|
1580
|
+
const isExactOwnedRepresentation = (representation) => {
|
|
1581
|
+
const expectedHashes = expectedManagedHookTrustHashes(expectations, key, representation.insideManagedMarkerBlock);
|
|
1582
|
+
return expectedHashes !== undefined &&
|
|
1583
|
+
representation.stateEntryCount === 1 &&
|
|
1584
|
+
!representation.hasComment &&
|
|
1585
|
+
representation.hasExactSemanticScope &&
|
|
1586
|
+
isExactlyManagedHookTrustStateValue(representation.value, expectedHashes);
|
|
1587
|
+
};
|
|
1588
|
+
if (!sourceRepresentations.some((representation) => expectedManagedHookTrustHashes(expectations, key, representation.insideManagedMarkerBlock) !== undefined))
|
|
1589
|
+
continue;
|
|
1590
|
+
const mayRemoveAll = sourceRepresentations.length === 1
|
|
1591
|
+
? isExactOwnedRepresentation(sourceRepresentations[0])
|
|
1592
|
+
: sourceRepresentations.every((representation) => representation.insideManagedMarkerBlock &&
|
|
1593
|
+
isExactOwnedRepresentation(representation));
|
|
1594
|
+
if (!mayRemoveAll) {
|
|
1595
|
+
preservedConflictKeys.add(key);
|
|
804
1596
|
continue;
|
|
805
1597
|
}
|
|
806
|
-
|
|
1598
|
+
for (const representation of sourceRepresentations) {
|
|
1599
|
+
removals.set(`${representation.start}:${representation.end}`, {
|
|
1600
|
+
start: representation.start,
|
|
1601
|
+
end: representation.end,
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
if (removals.size === 0) {
|
|
1606
|
+
return { config, preservedConflictKeys };
|
|
1607
|
+
}
|
|
1608
|
+
const removed = new Set();
|
|
1609
|
+
for (const range of removals.values()) {
|
|
1610
|
+
for (let index = range.start; index < range.end; index += 1) {
|
|
1611
|
+
removed.add(index);
|
|
1612
|
+
}
|
|
807
1613
|
}
|
|
808
|
-
|
|
809
|
-
const proofStripped = options.managedTrustState
|
|
810
|
-
? stripProofManagedCodexHookTrustStateTables(withoutFenced, options.managedTrustState)
|
|
811
|
-
: { config: withoutFenced, preservedConflictKeys: new Set() };
|
|
1614
|
+
removeEmptyManagedHookTrustStateMarkerBlocks(source, removed);
|
|
812
1615
|
return {
|
|
813
|
-
config:
|
|
814
|
-
preservedConflictKeys
|
|
1616
|
+
config: lines.filter((_, index) => !removed.has(index)).join("\n").trimEnd(),
|
|
1617
|
+
preservedConflictKeys,
|
|
815
1618
|
};
|
|
816
1619
|
}
|
|
1620
|
+
function stripManagedCodexHookTrustStateForRefresh(config, priorManagedTrustState, finalManagedTrustState) {
|
|
1621
|
+
return stripProofManagedCodexHookTrustStateTables(config, managedHookTrustStateExpectations(priorManagedTrustState, finalManagedTrustState));
|
|
1622
|
+
}
|
|
1623
|
+
function rejectManagedCodexHookTrustStateConflicts(conflicts) {
|
|
1624
|
+
if (conflicts.size === 0)
|
|
1625
|
+
return;
|
|
1626
|
+
const keys = [...conflicts].sort((left, right) => left.localeCompare(right));
|
|
1627
|
+
throw new ManagedCodexHooksPlanError("managed_trust_key_conflict", `Refusing to replace existing Codex hook trust state for ${keys.join(", ")}. Remove or reconcile the conflicting [hooks.state] entry before running setup.`, { keys });
|
|
1628
|
+
}
|
|
817
1629
|
export function stripManagedCodexHookTrustState(config, options = {}) {
|
|
818
|
-
|
|
1630
|
+
const stripped = stripManagedCodexHookTrustStateForRefresh(config, options.priorManagedHookTrustState, options.managedTrustState ?? {});
|
|
1631
|
+
rejectManagedCodexHookTrustStateConflicts(stripped.preservedConflictKeys);
|
|
1632
|
+
return stripped.config;
|
|
819
1633
|
}
|
|
820
|
-
function renderManagedCodexHookTrustToml(managedTrustState
|
|
1634
|
+
function renderManagedCodexHookTrustToml(managedTrustState) {
|
|
821
1635
|
return Object.entries(managedTrustState)
|
|
822
|
-
.filter(([key]) => !excludedKeys.has(key))
|
|
823
1636
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
824
1637
|
.flatMap(([key, hookState]) => [
|
|
825
1638
|
`[hooks.state."${escapeTomlBasicString(key)}"]`,
|
|
@@ -829,21 +1642,92 @@ function renderManagedCodexHookTrustToml(managedTrustState, excludedKeys = new S
|
|
|
829
1642
|
.join("\n")
|
|
830
1643
|
.trimEnd();
|
|
831
1644
|
}
|
|
832
|
-
function
|
|
1645
|
+
function identicalLegacyHookTrustStateEntry(existing, expected) {
|
|
1646
|
+
if (!isPlainTomlRecord(existing))
|
|
1647
|
+
return false;
|
|
1648
|
+
if (!Object.hasOwn(existing, "trusted_hash") ||
|
|
1649
|
+
typeof existing.trusted_hash !== "string" ||
|
|
1650
|
+
existing.trusted_hash !== expected.trusted_hash ||
|
|
1651
|
+
Object.keys(existing).some((key) => key !== "trusted_hash" && key !== "enabled")) {
|
|
1652
|
+
return false;
|
|
1653
|
+
}
|
|
1654
|
+
return Object.hasOwn(existing, "enabled") === Object.hasOwn(expected, "enabled") &&
|
|
1655
|
+
existing.enabled === expected.enabled;
|
|
1656
|
+
}
|
|
1657
|
+
function legacyHookTrustStateConflict(keys, reason) {
|
|
1658
|
+
throw new ManagedCodexHooksPlanError("managed_trust_key_conflict", `Refusing to migrate legacy Codex hook trust state into conflicting config.toml entries for ${keys.join(", ")}.`, { keys: [...keys], ...(reason ? { reason } : {}) });
|
|
1659
|
+
}
|
|
1660
|
+
function appendLegacyHookTrustState(config, legacyTrustState) {
|
|
1661
|
+
if (!legacyTrustState || Object.keys(legacyTrustState).length === 0) {
|
|
1662
|
+
return config;
|
|
1663
|
+
}
|
|
1664
|
+
const parsed = safeParseToml(config);
|
|
1665
|
+
const keys = Object.keys(legacyTrustState).sort((left, right) => left.localeCompare(right));
|
|
1666
|
+
if (!parsed)
|
|
1667
|
+
legacyHookTrustStateConflict(keys, "config_parse_failure");
|
|
1668
|
+
const hooks = parsed.hooks;
|
|
1669
|
+
if (hooks !== undefined && !isPlainTomlRecord(hooks)) {
|
|
1670
|
+
legacyHookTrustStateConflict(keys, "hooks_table_invalid");
|
|
1671
|
+
}
|
|
1672
|
+
const hookState = isPlainTomlRecord(hooks) ? hooks.state : undefined;
|
|
1673
|
+
if (hookState !== undefined && !isPlainTomlRecord(hookState)) {
|
|
1674
|
+
legacyHookTrustStateConflict(keys, "hooks_state_table_invalid");
|
|
1675
|
+
}
|
|
1676
|
+
const existingTrustState = isPlainTomlRecord(hookState) ? hookState : {};
|
|
1677
|
+
const entriesToAppend = Object.entries(legacyTrustState)
|
|
1678
|
+
.filter(([key]) => !Object.hasOwn(existingTrustState, key));
|
|
1679
|
+
const conflictingKeys = Object.entries(legacyTrustState)
|
|
1680
|
+
.filter(([key, expected]) => Object.hasOwn(existingTrustState, key) &&
|
|
1681
|
+
!identicalLegacyHookTrustStateEntry(existingTrustState[key], expected))
|
|
1682
|
+
.map(([key]) => key)
|
|
1683
|
+
.sort((left, right) => left.localeCompare(right));
|
|
1684
|
+
if (conflictingKeys.length > 0)
|
|
1685
|
+
legacyHookTrustStateConflict(conflictingKeys);
|
|
1686
|
+
const trustToml = entriesToAppend
|
|
1687
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
1688
|
+
.flatMap(([key, state]) => [
|
|
1689
|
+
`[hooks.state."${escapeTomlBasicString(key)}"]`,
|
|
1690
|
+
`trusted_hash = "${escapeTomlBasicString(state.trusted_hash)}"`,
|
|
1691
|
+
...(typeof state.enabled === "boolean" ? [`enabled = ${state.enabled}`] : []),
|
|
1692
|
+
"",
|
|
1693
|
+
])
|
|
1694
|
+
.join("\n")
|
|
1695
|
+
.trimEnd();
|
|
1696
|
+
if (!trustToml)
|
|
1697
|
+
return config;
|
|
1698
|
+
const base = config.trimEnd();
|
|
1699
|
+
return [
|
|
1700
|
+
base,
|
|
1701
|
+
base ? "" : null,
|
|
1702
|
+
"# Migrated from legacy hooks.json state; kept in Codex config.toml because Codex 0.140 rejects top-level hooks.json state.",
|
|
1703
|
+
trustToml,
|
|
1704
|
+
"",
|
|
1705
|
+
].filter((line) => line !== null).join("\n");
|
|
1706
|
+
}
|
|
1707
|
+
function managedCodexHookOptionsFromMergeOptions(options) {
|
|
1708
|
+
return {
|
|
1709
|
+
codexHomeDir: options.codexHomeDir,
|
|
1710
|
+
platform: options.hookCommandPlatform,
|
|
1711
|
+
hooksContent: options.codexHooksContent,
|
|
1712
|
+
};
|
|
1713
|
+
}
|
|
1714
|
+
function buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, options = {}, precomputedTrustState) {
|
|
1715
|
+
if (precomputedTrustState)
|
|
1716
|
+
return precomputedTrustState;
|
|
833
1717
|
if (!codexHooksFile)
|
|
834
1718
|
return {};
|
|
835
1719
|
return buildManagedCodexHookTrustState(codexHooksFile, pkgRoot, options);
|
|
836
1720
|
}
|
|
837
1721
|
export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile, options = {}) {
|
|
838
|
-
const managedTrustState = buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, options);
|
|
839
|
-
const strippedResult =
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
return [
|
|
1722
|
+
const managedTrustState = buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, options, options.managedTrustState);
|
|
1723
|
+
const strippedResult = stripManagedCodexHookTrustStateForRefresh(config, options.priorManagedHookTrustState, managedTrustState);
|
|
1724
|
+
rejectManagedCodexHookTrustStateConflicts(strippedResult.preservedConflictKeys);
|
|
1725
|
+
const stripped = strippedResult.config.trimEnd();
|
|
1726
|
+
const hookTrustToml = renderManagedCodexHookTrustToml(managedTrustState);
|
|
1727
|
+
if (!hookTrustToml) {
|
|
1728
|
+
return appendLegacyHookTrustState(`${stripped}\n`, options.legacyHookTrustState);
|
|
1729
|
+
}
|
|
1730
|
+
return appendLegacyHookTrustState([
|
|
847
1731
|
stripped,
|
|
848
1732
|
"",
|
|
849
1733
|
OMX_HOOK_TRUST_START_MARKER,
|
|
@@ -851,7 +1735,7 @@ export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile
|
|
|
851
1735
|
hookTrustToml,
|
|
852
1736
|
OMX_HOOK_TRUST_END_MARKER,
|
|
853
1737
|
"",
|
|
854
|
-
].filter((line, index) => index !== 0 || line.length > 0).join("\n");
|
|
1738
|
+
].filter((line, index) => index !== 0 || line.length > 0).join("\n"), options.legacyHookTrustState);
|
|
855
1739
|
}
|
|
856
1740
|
export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG, options = {}) {
|
|
857
1741
|
const lines = config.split(/\r?\n/);
|
|
@@ -864,6 +1748,9 @@ export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag
|
|
|
864
1748
|
const featureBlock = [
|
|
865
1749
|
"[features]",
|
|
866
1750
|
hookFeatureFlagLine,
|
|
1751
|
+
...(options.pluginScopedHooks && options.preserveNativeHooks
|
|
1752
|
+
? [formatCodexHookFeatureFlagLine(codexHookFeatureFlag)]
|
|
1753
|
+
: []),
|
|
867
1754
|
"goals = true",
|
|
868
1755
|
"",
|
|
869
1756
|
].join("\n");
|
|
@@ -887,9 +1774,15 @@ export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag
|
|
|
887
1774
|
sectionEnd -= 1;
|
|
888
1775
|
}
|
|
889
1776
|
}
|
|
890
|
-
(
|
|
891
|
-
|
|
892
|
-
|
|
1777
|
+
if (options.pluginScopedHooks) {
|
|
1778
|
+
({ sectionEnd } = upsertPluginScopedHookFeatureFlagInSection(lines, featuresStart, sectionEnd));
|
|
1779
|
+
if (options.preserveNativeHooks) {
|
|
1780
|
+
({ sectionEnd } = upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
else {
|
|
1784
|
+
({ sectionEnd } = upsertCodexHookFeatureFlagInSection(lines, featuresStart, sectionEnd, codexHookFeatureFlag));
|
|
1785
|
+
}
|
|
893
1786
|
let goalsIdx = -1;
|
|
894
1787
|
for (let i = featuresStart + 1; i < sectionEnd; i++) {
|
|
895
1788
|
if (/^\s*goals\s*=/.test(lines[i])) {
|
|
@@ -1015,52 +1908,12 @@ function upsertEnvSettings(config) {
|
|
|
1015
1908
|
}
|
|
1016
1909
|
return lines.join("\n");
|
|
1017
1910
|
}
|
|
1018
|
-
function upsertAgentsSettings(config) {
|
|
1019
|
-
const lines = config.split(/\r?\n/);
|
|
1020
|
-
const agentsStart = lines.findIndex((line) => /^\s*\[agents\]\s*$/.test(line));
|
|
1021
|
-
if (agentsStart < 0) {
|
|
1022
|
-
const base = config.trimEnd();
|
|
1023
|
-
const agentsBlock = [
|
|
1024
|
-
"[agents]",
|
|
1025
|
-
`max_threads = ${OMX_AGENTS_MAX_THREADS}`,
|
|
1026
|
-
`max_depth = ${OMX_AGENTS_MAX_DEPTH}`,
|
|
1027
|
-
"",
|
|
1028
|
-
].join("\n");
|
|
1029
|
-
if (base.length === 0)
|
|
1030
|
-
return agentsBlock;
|
|
1031
|
-
return `${base}\n\n${agentsBlock}`;
|
|
1032
|
-
}
|
|
1033
|
-
let sectionEnd = lines.length;
|
|
1034
|
-
for (let i = agentsStart + 1; i < lines.length; i++) {
|
|
1035
|
-
if (/^\s*\[\[?[^\]]+\]?\]\s*$/.test(lines[i])) {
|
|
1036
|
-
sectionEnd = i;
|
|
1037
|
-
break;
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
let maxThreadsIdx = -1;
|
|
1041
|
-
let maxDepthIdx = -1;
|
|
1042
|
-
for (let i = agentsStart + 1; i < sectionEnd; i++) {
|
|
1043
|
-
if (/^\s*max_threads\s*=/.test(lines[i])) {
|
|
1044
|
-
maxThreadsIdx = i;
|
|
1045
|
-
}
|
|
1046
|
-
else if (/^\s*max_depth\s*=/.test(lines[i])) {
|
|
1047
|
-
maxDepthIdx = i;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
if (maxThreadsIdx < 0) {
|
|
1051
|
-
lines.splice(sectionEnd, 0, `max_threads = ${OMX_AGENTS_MAX_THREADS}`);
|
|
1052
|
-
sectionEnd += 1;
|
|
1053
|
-
}
|
|
1054
|
-
if (maxDepthIdx < 0) {
|
|
1055
|
-
lines.splice(sectionEnd, 0, `max_depth = ${OMX_AGENTS_MAX_DEPTH}`);
|
|
1056
|
-
}
|
|
1057
|
-
return lines.join("\n");
|
|
1058
|
-
}
|
|
1059
1911
|
/**
|
|
1060
1912
|
* Remove OMX-owned feature flags from the [features] section.
|
|
1913
|
+
* If `preserveMultiAgent` is set, retain multi_agent unchanged.
|
|
1061
1914
|
* If the section becomes empty after removal, remove the section header too.
|
|
1062
1915
|
*/
|
|
1063
|
-
export function stripOmxFeatureFlags(config) {
|
|
1916
|
+
export function stripOmxFeatureFlags(config, options = {}) {
|
|
1064
1917
|
const lines = config.split(/\r?\n/);
|
|
1065
1918
|
const featuresStart = lines.findIndex((line) => /^\s*\[features\]\s*$/.test(line));
|
|
1066
1919
|
if (featuresStart < 0)
|
|
@@ -1073,7 +1926,7 @@ export function stripOmxFeatureFlags(config) {
|
|
|
1073
1926
|
}
|
|
1074
1927
|
}
|
|
1075
1928
|
const omxFlags = [
|
|
1076
|
-
"multi_agent",
|
|
1929
|
+
...(options.preserveMultiAgent ? [] : ["multi_agent"]),
|
|
1077
1930
|
"child_agents_md",
|
|
1078
1931
|
"hooks",
|
|
1079
1932
|
"codex_hooks",
|
|
@@ -1139,10 +1992,6 @@ export function stripOmxEnvSettings(config) {
|
|
|
1139
1992
|
// ---------------------------------------------------------------------------
|
|
1140
1993
|
// Orphaned OMX table sections (no marker block)
|
|
1141
1994
|
// ---------------------------------------------------------------------------
|
|
1142
|
-
/**
|
|
1143
|
-
* Check whether a TOML table name belongs to a legacy OMX-managed agent entry.
|
|
1144
|
-
* Handles both `agents.name` and `agents."name"` forms.
|
|
1145
|
-
*/
|
|
1146
1995
|
function isOmxFirstPartyMcpSection(tableName) {
|
|
1147
1996
|
const match = tableName.match(/^mcp_servers\.(?:"([^"]+)"|([A-Za-z0-9_-]+))$/);
|
|
1148
1997
|
const name = match?.[1] ?? match?.[2];
|
|
@@ -1150,20 +1999,10 @@ function isOmxFirstPartyMcpSection(tableName) {
|
|
|
1150
1999
|
(OMX_FIRST_PARTY_MCP_SERVER_NAMES.includes(name) ||
|
|
1151
2000
|
name === "omx_team_run"));
|
|
1152
2001
|
}
|
|
1153
|
-
function isLegacyOmxAgentSection(tableName) {
|
|
1154
|
-
const m = tableName.match(/^agents\.(?:"([^"]+)"|(\w[\w-]*))$/);
|
|
1155
|
-
if (!m)
|
|
1156
|
-
return false;
|
|
1157
|
-
const name = m[1] || m[2] || "";
|
|
1158
|
-
return Object.prototype.hasOwnProperty.call(AGENT_DEFINITIONS, name);
|
|
1159
|
-
}
|
|
1160
2002
|
/**
|
|
1161
|
-
* Strip
|
|
2003
|
+
* Strip first-party OMX MCP table sections that exist outside the marker block.
|
|
1162
2004
|
* This covers legacy configs that were written before markers were added,
|
|
1163
2005
|
* or configs where the marker was accidentally removed.
|
|
1164
|
-
*
|
|
1165
|
-
* Targets: exact first-party [mcp_servers.<name>] entries, retired
|
|
1166
|
-
* [mcp_servers.omx_team_run], and legacy [agents.<name>] entries.
|
|
1167
2006
|
*/
|
|
1168
2007
|
function stripOrphanedOmxSections(config) {
|
|
1169
2008
|
const lines = config.split(/\r?\n/);
|
|
@@ -1177,8 +2016,7 @@ function stripOrphanedOmxSections(config) {
|
|
|
1177
2016
|
// Note: [tui] is NOT stripped here because it could be user-owned.
|
|
1178
2017
|
// The marker-based stripExistingOmxBlocks already handles [tui]
|
|
1179
2018
|
// when it lives inside the OMX marker block.
|
|
1180
|
-
const isOmxSection = isOmxFirstPartyMcpSection(tableName)
|
|
1181
|
-
isLegacyOmxAgentSection(tableName);
|
|
2019
|
+
const isOmxSection = isOmxFirstPartyMcpSection(tableName);
|
|
1182
2020
|
if (isOmxSection) {
|
|
1183
2021
|
// Remove preceding OMX comment lines and blank lines
|
|
1184
2022
|
while (result.length > 0) {
|
|
@@ -1408,35 +2246,45 @@ function upsertTuiStatusLine(config, preset = DEFAULT_STATUS_LINE_PRESET, option
|
|
|
1408
2246
|
// ---------------------------------------------------------------------------
|
|
1409
2247
|
// OMX [table] sections block (appended at end of file)
|
|
1410
2248
|
// ---------------------------------------------------------------------------
|
|
1411
|
-
export function stripExistingOmxBlocks(config) {
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
const
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
2249
|
+
export function stripExistingOmxBlocks(config, options = {}) {
|
|
2250
|
+
const inventory = collectManagedHookTrustStateSourceRepresentations(config);
|
|
2251
|
+
const { source } = inventory;
|
|
2252
|
+
const markerRanges = collectMarkerRanges(source, OMX_CONFIG_START_MARKER, OMX_CONFIG_END_MARKER, false, inventory.parsedAssignmentSpans);
|
|
2253
|
+
if (markerRanges.length === 0)
|
|
2254
|
+
return { cleaned: config, removed: 0 };
|
|
2255
|
+
const conflicts = managedMarkerTrustStateConflicts(source, inventory.representations, markerRanges, inventory.markerContainedHooksStateSpans, inventory.invalidMarkerContainedHooksStateSpans, inventory.parsedStatementSpans, inventory.parsedAssignmentSpans, managedHookTrustStateExpectations(options.priorManagedHookTrustState, options.managedTrustState));
|
|
2256
|
+
rejectManagedCodexHookTrustStateConflicts(conflicts);
|
|
2257
|
+
if (!source.isUnambiguous)
|
|
2258
|
+
return { cleaned: config, removed: 0 };
|
|
2259
|
+
const lines = sourceLines(config);
|
|
2260
|
+
if (markerRanges.some((range) => !lines[range.start] || !lines[range.end])) {
|
|
2261
|
+
return { cleaned: config, removed: 0 };
|
|
2262
|
+
}
|
|
2263
|
+
const removalRanges = markerRanges.map((range) => {
|
|
2264
|
+
const startLine = lines[range.start];
|
|
2265
|
+
const endLine = lines[range.end];
|
|
2266
|
+
const previousLine = lines[range.start - 1];
|
|
2267
|
+
const start = previousLine && /^# =+$/.test(previousLine.content.trim())
|
|
2268
|
+
? previousLine.start
|
|
2269
|
+
: startLine.start;
|
|
2270
|
+
return { start, end: endLine.end };
|
|
2271
|
+
});
|
|
2272
|
+
const segments = [];
|
|
2273
|
+
let cursor = 0;
|
|
2274
|
+
for (const range of removalRanges) {
|
|
2275
|
+
segments.push(config.slice(cursor, range.start));
|
|
2276
|
+
cursor = range.end;
|
|
2277
|
+
}
|
|
2278
|
+
segments.push(config.slice(cursor));
|
|
2279
|
+
const cleaned = segments
|
|
2280
|
+
.map((segment, index) => index === 0
|
|
2281
|
+
? segment.trimEnd()
|
|
2282
|
+
: index === segments.length - 1
|
|
2283
|
+
? segment.trimStart()
|
|
2284
|
+
: segment.trim())
|
|
2285
|
+
.filter(Boolean)
|
|
2286
|
+
.join("\n\n");
|
|
2287
|
+
return { cleaned, removed: markerRanges.length };
|
|
1440
2288
|
}
|
|
1441
2289
|
export function stripExistingSharedMcpRegistryBlock(config) {
|
|
1442
2290
|
let cleaned = config;
|
|
@@ -1671,7 +2519,7 @@ export function mergeSharedMcpRegistryBlock(config, servers, sourcePath) {
|
|
|
1671
2519
|
* OMX table-section block (MCP servers, TUI).
|
|
1672
2520
|
* Contains ONLY [table] sections — no bare keys.
|
|
1673
2521
|
*/
|
|
1674
|
-
function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAULT_STATUS_LINE_PRESET, codexHooksFile, hookOptions = {}, includeFirstPartyMcp = false
|
|
2522
|
+
function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAULT_STATUS_LINE_PRESET, codexHooksFile, hookOptions = {}, managedHookTrustState, includeFirstPartyMcp = false) {
|
|
1675
2523
|
const lines = [
|
|
1676
2524
|
"",
|
|
1677
2525
|
"# ============================================================",
|
|
@@ -1694,7 +2542,7 @@ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAUL
|
|
|
1694
2542
|
}
|
|
1695
2543
|
}
|
|
1696
2544
|
}
|
|
1697
|
-
const hookTrustToml = renderManagedCodexHookTrustToml(buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, hookOptions
|
|
2545
|
+
const hookTrustToml = renderManagedCodexHookTrustToml(buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, hookOptions, managedHookTrustState));
|
|
1698
2546
|
if (hookTrustToml) {
|
|
1699
2547
|
lines.push("");
|
|
1700
2548
|
lines.push("# OMX-owned Codex hook trust state");
|
|
@@ -1726,13 +2574,17 @@ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAUL
|
|
|
1726
2574
|
*
|
|
1727
2575
|
* Layout:
|
|
1728
2576
|
* 1. OMX top-level keys (notify, model_reasoning_effort, developer_instructions)
|
|
1729
|
-
* 2. [features] with
|
|
2577
|
+
* 2. [features] with child_agents_md + hooks + goals
|
|
1730
2578
|
* 3. [shell_environment_policy.set] with defaulted deprecated explore-routing opt-out
|
|
1731
2579
|
* 4. … user sections …
|
|
1732
2580
|
* 5. OMX [table] sections (mcp_servers, tui)
|
|
1733
2581
|
*/
|
|
1734
2582
|
export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
1735
|
-
let existing = existingConfig;
|
|
2583
|
+
let existing = stripOmxSeededBehavioralDefaults(existingConfig);
|
|
2584
|
+
const hookOptions = managedCodexHookOptionsFromMergeOptions(options);
|
|
2585
|
+
const managedTrustState = buildManagedCodexHookTrustStateForConfig(options.codexHooksFile, pkgRoot, hookOptions, options.managedHookTrustState);
|
|
2586
|
+
const preflightHookTrustStrip = stripManagedCodexHookTrustStateForRefresh(existing, options.priorManagedHookTrustState, managedTrustState);
|
|
2587
|
+
rejectManagedCodexHookTrustStateConflicts(preflightHookTrustStrip.preservedConflictKeys);
|
|
1736
2588
|
const preservedFirstPartyMcpSections = options.preserveExistingFirstPartyMcp === true &&
|
|
1737
2589
|
options.includeFirstPartyMcp !== true
|
|
1738
2590
|
? extractFirstPartyOmxMcpSections(existing)
|
|
@@ -1741,7 +2593,10 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1741
2593
|
const statusLinePreset = options.statusLinePreset ?? DEFAULT_STATUS_LINE_PRESET;
|
|
1742
2594
|
const customizedManagedTuiSections = extractCustomizedTuiSectionsFromOmxBlocks(existing);
|
|
1743
2595
|
if (existing.includes(OMX_CONFIG_MARKER)) {
|
|
1744
|
-
const stripped = stripExistingOmxBlocks(existing
|
|
2596
|
+
const stripped = stripExistingOmxBlocks(existing, {
|
|
2597
|
+
managedTrustState,
|
|
2598
|
+
priorManagedHookTrustState: options.priorManagedHookTrustState,
|
|
2599
|
+
});
|
|
1745
2600
|
existing = stripped.cleaned;
|
|
1746
2601
|
if (customizedManagedTuiSections.length > 0) {
|
|
1747
2602
|
existing = `${existing.trimEnd()}\n\n${customizedManagedTuiSections.join("\n\n")}\n`;
|
|
@@ -1755,18 +2610,13 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1755
2610
|
!isOmxManagedNotifyCommand(getRootTomlArray(existing, "notify"), pkgRoot)
|
|
1756
2611
|
? getRootTomlArray(existing, "notify")
|
|
1757
2612
|
: null;
|
|
1758
|
-
existing = stripOmxTopLevelKeys(existing);
|
|
2613
|
+
existing = stripOmxTopLevelKeys(existing).trimStart();
|
|
1759
2614
|
if (userNotifyToPreserve) {
|
|
1760
2615
|
existing = `${`notify = ${formatTomlStringArray(userNotifyToPreserve)}`}\n${existing.trimStart()}`;
|
|
1761
2616
|
}
|
|
1762
|
-
existing = stripOrphanedManagedNotify(existing, pkgRoot);
|
|
1763
|
-
const
|
|
1764
|
-
|
|
1765
|
-
platform: options.hookCommandPlatform,
|
|
1766
|
-
});
|
|
1767
|
-
const hookTrustStrip = stripManagedCodexHookTrustStateWithResult(existing, {
|
|
1768
|
-
managedTrustState,
|
|
1769
|
-
});
|
|
2617
|
+
existing = stripOrphanedManagedNotify(existing, pkgRoot).trimStart();
|
|
2618
|
+
const hookTrustStrip = stripManagedCodexHookTrustStateForRefresh(existing, options.priorManagedHookTrustState, managedTrustState);
|
|
2619
|
+
rejectManagedCodexHookTrustStateConflicts(hookTrustStrip.preservedConflictKeys);
|
|
1770
2620
|
existing = hookTrustStrip.config;
|
|
1771
2621
|
if (options.modelOverride) {
|
|
1772
2622
|
existing = stripRootLevelKeys(existing, ["model"]);
|
|
@@ -1777,7 +2627,6 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1777
2627
|
}
|
|
1778
2628
|
existing = upsertFeatureFlags(existing, options.codexHookFeatureFlag);
|
|
1779
2629
|
existing = upsertEnvSettings(existing);
|
|
1780
|
-
existing = upsertAgentsSettings(existing);
|
|
1781
2630
|
const tuiUpsert = includeTui
|
|
1782
2631
|
? upsertTuiStatusLine(existing, statusLinePreset, {
|
|
1783
2632
|
forceStatusLinePreset: options.forceStatusLinePreset,
|
|
@@ -1787,16 +2636,15 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1787
2636
|
const topLines = getOmxTopLevelLines(pkgRoot, existing, options.modelOverride, options.notifyCommand === undefined
|
|
1788
2637
|
? getDefaultNotifyCommand(pkgRoot)
|
|
1789
2638
|
: options.notifyCommand);
|
|
1790
|
-
const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile,
|
|
1791
|
-
codexHomeDir: options.codexHomeDir,
|
|
1792
|
-
platform: options.hookCommandPlatform,
|
|
1793
|
-
}, options.includeFirstPartyMcp === true, hookTrustStrip.preservedConflictKeys);
|
|
2639
|
+
const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile, hookOptions, managedTrustState, options.includeFirstPartyMcp === true);
|
|
1794
2640
|
const sharedRegistryBlock = getSharedMcpRegistryBlock(options.sharedMcpServers ?? [], options.sharedMcpRegistrySource, existing);
|
|
1795
|
-
let body = existing.
|
|
2641
|
+
let body = existing.trim();
|
|
1796
2642
|
if (sharedRegistryBlock) {
|
|
1797
2643
|
body = body ? `${body}\n\n${sharedRegistryBlock}` : sharedRegistryBlock;
|
|
1798
2644
|
}
|
|
1799
|
-
|
|
2645
|
+
const bodySeparator = body.length > 0 && !/^\s*\[/.test(body) ? "\n" : "\n\n";
|
|
2646
|
+
const merged = addDefaultLauncherMcpStartupTimeouts(topLines.join("\n") + bodySeparator + body + "\n" + tablesBlock);
|
|
2647
|
+
return appendLegacyHookTrustState(merged, options.legacyHookTrustState);
|
|
1800
2648
|
}
|
|
1801
2649
|
/**
|
|
1802
2650
|
* Detect and repair upgrade-era managed config incompatibilities in config.toml.
|
|
@@ -1809,6 +2657,33 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1809
2657
|
*
|
|
1810
2658
|
* Returns `true` if a repair was performed.
|
|
1811
2659
|
*/
|
|
2660
|
+
function managedHookTrustProofRequiredForRepair(config) {
|
|
2661
|
+
const inventory = collectManagedHookTrustStateSourceRepresentations(config);
|
|
2662
|
+
return managedMarkerTrustStateConflicts(inventory.source, inventory.representations, inventory.managedMarkerRanges, inventory.markerContainedHooksStateSpans, inventory.invalidMarkerContainedHooksStateSpans, inventory.parsedStatementSpans, inventory.parsedAssignmentSpans, managedHookTrustStateExpectations()).size > 0;
|
|
2663
|
+
}
|
|
2664
|
+
async function launchRepairOptionsWithManagedHookTrustProof(configPath, config, options) {
|
|
2665
|
+
if (!managedHookTrustProofRequiredForRepair(config)) {
|
|
2666
|
+
return options;
|
|
2667
|
+
}
|
|
2668
|
+
const hooksPath = options.codexHooksFile ?? resolve(configPath, "..", "hooks.json");
|
|
2669
|
+
let hooksContent;
|
|
2670
|
+
try {
|
|
2671
|
+
hooksContent = await readFile(hooksPath, "utf-8");
|
|
2672
|
+
}
|
|
2673
|
+
catch (error) {
|
|
2674
|
+
throw new ManagedCodexHooksPlanError("invalid_document", `Cannot safely repair config.toml because the current hooks artifact at ${hooksPath} could not be read.`, { cause: String(error), hooksPath });
|
|
2675
|
+
}
|
|
2676
|
+
const trustScan = scanManagedCodexHookTrustStateFromContent(hooksContent, hooksPath, managedCodexHookOptionsFromMergeOptions(options));
|
|
2677
|
+
if (!trustScan.ok)
|
|
2678
|
+
throw trustScan.error;
|
|
2679
|
+
return {
|
|
2680
|
+
...options,
|
|
2681
|
+
codexHooksFile: hooksPath,
|
|
2682
|
+
codexHooksContent: hooksContent,
|
|
2683
|
+
managedHookTrustState: trustScan.trustState,
|
|
2684
|
+
priorManagedHookTrustState: trustScan.trustState,
|
|
2685
|
+
};
|
|
2686
|
+
}
|
|
1812
2687
|
export async function repairConfigIfNeeded(configPath, pkgRoot, options = {}) {
|
|
1813
2688
|
if (!existsSync(configPath))
|
|
1814
2689
|
return false;
|
|
@@ -1818,8 +2693,10 @@ export async function repairConfigIfNeeded(configPath, pkgRoot, options = {}) {
|
|
|
1818
2693
|
const hasLauncherTimeoutGap = findLauncherTimeoutRepairTargets(content).length > 0;
|
|
1819
2694
|
if (tuiCount <= 1 && !hasLegacyTeamRunTable && !hasLauncherTimeoutGap)
|
|
1820
2695
|
return false;
|
|
1821
|
-
// Managed config compatibility issue detected —
|
|
1822
|
-
|
|
2696
|
+
// Managed config compatibility issue detected — derive proof from the current
|
|
2697
|
+
// hooks artifact before any marker stripping can replace managed trust state.
|
|
2698
|
+
const repairOptions = await launchRepairOptionsWithManagedHookTrustProof(configPath, content, options);
|
|
2699
|
+
const repaired = buildMergedConfig(content, pkgRoot, repairOptions);
|
|
1823
2700
|
if (repaired === content)
|
|
1824
2701
|
return false;
|
|
1825
2702
|
await writeFile(configPath, repaired);
|
|
@@ -1830,12 +2707,6 @@ export async function mergeConfig(configPath, pkgRoot, options = {}) {
|
|
|
1830
2707
|
if (existsSync(configPath)) {
|
|
1831
2708
|
existing = await readFile(configPath, "utf-8");
|
|
1832
2709
|
}
|
|
1833
|
-
if (existing.includes("oh-my-codex (OMX) Configuration")) {
|
|
1834
|
-
const stripped = stripExistingOmxBlocks(existing);
|
|
1835
|
-
if (options.verbose && stripped.removed > 0) {
|
|
1836
|
-
console.log(" Updating existing OMX config block.");
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
2710
|
const finalConfig = buildMergedConfig(existing, pkgRoot, options);
|
|
1840
2711
|
await writeFile(configPath, finalConfig);
|
|
1841
2712
|
if (options.verbose) {
|