oh-my-codex 0.20.1 → 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.map +1 -1
- package/dist/cli/__tests__/doctor-context-window-warning.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-invalid-config.test.js +47 -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 +650 -15
- 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 +77 -3
- 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 +2261 -14
- 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 +33 -2
- package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
- package/dist/cli/__tests__/setup-scope.test.js +46 -3
- 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 +1771 -24
- 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 +18 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +594 -130
- 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 +1401 -398
- 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 +944 -95
- 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 +850 -32
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +6 -1
- 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 +21 -16
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +991 -137
- 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 +103 -1
- 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 +109 -3
- 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 +4121 -592
- 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 +689 -156
- 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/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 +17522 -10630
- 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 +779 -159
- 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
|
@@ -16,7 +16,7 @@ import TOML from "@iarna/toml";
|
|
|
16
16
|
import { DEFAULT_FRONTIER_MODEL } from "./models.js";
|
|
17
17
|
import { DEFAULT_CODEX_HOOK_FEATURE_FLAG, CODEX_HOOK_FEATURE_FLAGS, CODEX_PLUGIN_SCOPED_HOOKS_FEATURE_FLAG, formatCodexHookFeatureFlagLine, normalizeCodexHookFeatureFlag, } from "./codex-feature-flags.js";
|
|
18
18
|
import { OMX_FIRST_PARTY_MCP_SERVER_NAMES, getOmxFirstPartySetupMcpServers, } from "./omx-first-party-mcp.js";
|
|
19
|
-
import { buildManagedCodexHookTrustState, escapeTomlBasicString, } from "./codex-hooks.js";
|
|
19
|
+
import { buildManagedCodexHookTrustState, escapeTomlBasicString, ManagedCodexHooksPlanError, scanManagedCodexHookTrustStateFromContent, } from "./codex-hooks.js";
|
|
20
20
|
function escapeTomlString(value) {
|
|
21
21
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
22
22
|
}
|
|
@@ -37,8 +37,8 @@ const LEGACY_SEEDED_MODEL_CONTEXT_WINDOW = 250000;
|
|
|
37
37
|
const LEGACY_SEEDED_MODEL_AUTO_COMPACT_TOKEN_LIMIT = 200000;
|
|
38
38
|
const OMX_SEEDED_BEHAVIORAL_DEFAULTS_START_MARKER = "# oh-my-codex seeded behavioral defaults (uninstall removes unchanged defaults)";
|
|
39
39
|
const OMX_SEEDED_BEHAVIORAL_DEFAULTS_END_MARKER = "# End oh-my-codex seeded behavioral defaults";
|
|
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
|
|
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
|
|
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>';
|
|
42
42
|
const SHARED_MCP_REGISTRY_MARKER = "oh-my-codex (OMX) Shared MCP Registry Sync";
|
|
43
43
|
const SHARED_MCP_REGISTRY_END_MARKER = "# End oh-my-codex shared MCP registry sync";
|
|
44
44
|
const LEGACY_MULTI_AGENT_KEYS = [
|
|
@@ -136,6 +136,7 @@ const LEGACY_OMX_STATUS_LINE = statusLineForPreset(DEFAULT_STATUS_LINE_PRESET);
|
|
|
136
136
|
const OMX_PRESET_STATUS_LINE_VALUES = new Set(Object.keys(STATUS_LINE_PRESETS).map((preset) => statusLineForPreset(preset)));
|
|
137
137
|
const LEGACY_OMX_TEAM_RUN_TABLE_PATTERN = /^\s*\[mcp_servers\.(?:"omx_team_run"|omx_team_run)\]\s*$/m;
|
|
138
138
|
const OMX_CONFIG_MARKER = "oh-my-codex (OMX) Configuration";
|
|
139
|
+
const OMX_CONFIG_START_MARKER = `# ${OMX_CONFIG_MARKER}`;
|
|
139
140
|
const OMX_CONFIG_END_MARKER = "# End oh-my-codex";
|
|
140
141
|
const CODEX_MODEL_AVAILABILITY_NUX_TABLE_PATTERN = /^\s*\[tui\.model_availability_nux\]\s*(?:#.*)?$/;
|
|
141
142
|
const TOML_TABLE_HEADER_PATTERN = /^\s*\[\[?[^\]]+\]?\]\s*(?:#.*)?$/;
|
|
@@ -793,105 +794,845 @@ export function syncProjectScopeTrustStateFromRuntime(projectConfig, runtimeConf
|
|
|
793
794
|
return block;
|
|
794
795
|
return `${stripped}\n\n${block}`;
|
|
795
796
|
}
|
|
796
|
-
function
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
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;
|
|
800
867
|
}
|
|
801
|
-
|
|
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)
|
|
802
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
|
+
};
|
|
803
912
|
}
|
|
913
|
+
return { end: line.length, incomplete: true };
|
|
804
914
|
}
|
|
805
|
-
function
|
|
806
|
-
|
|
807
|
-
|
|
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)
|
|
808
921
|
return undefined;
|
|
809
|
-
|
|
810
|
-
|
|
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] !== "[")
|
|
811
1041
|
return undefined;
|
|
812
|
-
|
|
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);
|
|
1055
|
+
}
|
|
1056
|
+
const firstKey = parseTomlSourceKeySegment(line, cursor);
|
|
1057
|
+
return {
|
|
1058
|
+
firstKey,
|
|
1059
|
+
openerOnly: firstKey === undefined &&
|
|
1060
|
+
(cursor >= line.length || line[cursor] === "#"),
|
|
1061
|
+
};
|
|
813
1062
|
}
|
|
814
|
-
function
|
|
815
|
-
|
|
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] === "[";
|
|
816
1092
|
}
|
|
817
|
-
function
|
|
818
|
-
|
|
819
|
-
|
|
1093
|
+
function isTomlSourceBlankOrComment(line) {
|
|
1094
|
+
return /^\s*(?:#.*)?$/.test(line);
|
|
1095
|
+
}
|
|
1096
|
+
function isTomlSourceStandaloneOpeningBracket(line) {
|
|
1097
|
+
const cursor = skipTomlSourceWhitespace(line, 0);
|
|
1098
|
+
if (line[cursor] !== "[")
|
|
820
1099
|
return false;
|
|
821
|
-
const
|
|
822
|
-
return
|
|
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;
|
|
823
1207
|
}
|
|
824
|
-
function
|
|
825
|
-
|
|
826
|
-
|
|
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
|
+
}
|
|
827
1218
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
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)
|
|
1231
|
+
return undefined;
|
|
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)
|
|
1243
|
+
return undefined;
|
|
1244
|
+
const hooks = parsed.hooks;
|
|
1245
|
+
if (!isPlainTomlRecord(hooks) || !Object.hasOwn(hooks, "state")) {
|
|
1246
|
+
return undefined;
|
|
1247
|
+
}
|
|
1248
|
+
return hooks.state;
|
|
1249
|
+
}
|
|
1250
|
+
function tomlHooksStateEntries(parsed) {
|
|
1251
|
+
const state = tomlHooksStateValue(parsed);
|
|
1252
|
+
return isPlainTomlRecord(state) ? state : undefined;
|
|
1253
|
+
}
|
|
1254
|
+
function hasOnlyManagedHookTrustStateField(parsed, key) {
|
|
1255
|
+
if (!parsed || Object.keys(parsed).length !== 1 || !Object.hasOwn(parsed, "hooks")) {
|
|
1256
|
+
return false;
|
|
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);
|
|
1266
|
+
}
|
|
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
|
+
}
|
|
836
1286
|
continue;
|
|
837
1287
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
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)) };
|
|
1306
|
+
}
|
|
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 });
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
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;
|
|
843
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;
|
|
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;
|
|
844
1464
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
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);
|
|
851
1485
|
continue;
|
|
852
1486
|
}
|
|
853
|
-
|
|
854
|
-
|
|
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);
|
|
855
1525
|
}
|
|
856
|
-
kept.push(...lines.slice(i, tableEnd));
|
|
857
|
-
i = tableEnd;
|
|
858
1526
|
}
|
|
859
|
-
return
|
|
1527
|
+
return conflicts;
|
|
860
1528
|
}
|
|
861
|
-
function
|
|
862
|
-
const lines =
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
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)
|
|
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))
|
|
869
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;
|
|
870
1552
|
}
|
|
871
|
-
|
|
872
|
-
const nextStartIdx = lines.findIndex((line, index) => index > i && line.trim() === OMX_HOOK_TRUST_START_MARKER);
|
|
873
|
-
if (nextEndIdx === -1 || (nextStartIdx !== -1 && nextStartIdx < nextEndIdx)) {
|
|
874
|
-
kept.push(lines[i]);
|
|
875
|
-
i += 1;
|
|
1553
|
+
if (!onlyOwnedMarkerContent)
|
|
876
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
|
+
}
|
|
877
1561
|
}
|
|
878
|
-
|
|
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 };
|
|
879
1570
|
}
|
|
880
|
-
const
|
|
881
|
-
const
|
|
882
|
-
|
|
883
|
-
|
|
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);
|
|
1596
|
+
continue;
|
|
1597
|
+
}
|
|
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
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
removeEmptyManagedHookTrustStateMarkerBlocks(source, removed);
|
|
884
1615
|
return {
|
|
885
|
-
config:
|
|
886
|
-
preservedConflictKeys
|
|
1616
|
+
config: lines.filter((_, index) => !removed.has(index)).join("\n").trimEnd(),
|
|
1617
|
+
preservedConflictKeys,
|
|
887
1618
|
};
|
|
888
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
|
+
}
|
|
889
1629
|
export function stripManagedCodexHookTrustState(config, options = {}) {
|
|
890
|
-
|
|
1630
|
+
const stripped = stripManagedCodexHookTrustStateForRefresh(config, options.priorManagedHookTrustState, options.managedTrustState ?? {});
|
|
1631
|
+
rejectManagedCodexHookTrustStateConflicts(stripped.preservedConflictKeys);
|
|
1632
|
+
return stripped.config;
|
|
891
1633
|
}
|
|
892
|
-
function renderManagedCodexHookTrustToml(managedTrustState
|
|
1634
|
+
function renderManagedCodexHookTrustToml(managedTrustState) {
|
|
893
1635
|
return Object.entries(managedTrustState)
|
|
894
|
-
.filter(([key]) => !excludedKeys.has(key))
|
|
895
1636
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
896
1637
|
.flatMap(([key, hookState]) => [
|
|
897
1638
|
`[hooks.state."${escapeTomlBasicString(key)}"]`,
|
|
@@ -901,21 +1642,92 @@ function renderManagedCodexHookTrustToml(managedTrustState, excludedKeys = new S
|
|
|
901
1642
|
.join("\n")
|
|
902
1643
|
.trimEnd();
|
|
903
1644
|
}
|
|
904
|
-
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;
|
|
905
1717
|
if (!codexHooksFile)
|
|
906
1718
|
return {};
|
|
907
1719
|
return buildManagedCodexHookTrustState(codexHooksFile, pkgRoot, options);
|
|
908
1720
|
}
|
|
909
1721
|
export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile, options = {}) {
|
|
910
|
-
const managedTrustState = buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, options);
|
|
911
|
-
const strippedResult =
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
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([
|
|
919
1731
|
stripped,
|
|
920
1732
|
"",
|
|
921
1733
|
OMX_HOOK_TRUST_START_MARKER,
|
|
@@ -923,7 +1735,7 @@ export function upsertManagedCodexHookTrustState(config, pkgRoot, codexHooksFile
|
|
|
923
1735
|
hookTrustToml,
|
|
924
1736
|
OMX_HOOK_TRUST_END_MARKER,
|
|
925
1737
|
"",
|
|
926
|
-
].filter((line, index) => index !== 0 || line.length > 0).join("\n");
|
|
1738
|
+
].filter((line, index) => index !== 0 || line.length > 0).join("\n"), options.legacyHookTrustState);
|
|
927
1739
|
}
|
|
928
1740
|
export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag = DEFAULT_CODEX_HOOK_FEATURE_FLAG, options = {}) {
|
|
929
1741
|
const lines = config.split(/\r?\n/);
|
|
@@ -936,6 +1748,9 @@ export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag
|
|
|
936
1748
|
const featureBlock = [
|
|
937
1749
|
"[features]",
|
|
938
1750
|
hookFeatureFlagLine,
|
|
1751
|
+
...(options.pluginScopedHooks && options.preserveNativeHooks
|
|
1752
|
+
? [formatCodexHookFeatureFlagLine(codexHookFeatureFlag)]
|
|
1753
|
+
: []),
|
|
939
1754
|
"goals = true",
|
|
940
1755
|
"",
|
|
941
1756
|
].join("\n");
|
|
@@ -959,9 +1774,15 @@ export function upsertPluginModeRuntimeFeatureFlags(config, codexHookFeatureFlag
|
|
|
959
1774
|
sectionEnd -= 1;
|
|
960
1775
|
}
|
|
961
1776
|
}
|
|
962
|
-
(
|
|
963
|
-
|
|
964
|
-
|
|
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
|
+
}
|
|
965
1786
|
let goalsIdx = -1;
|
|
966
1787
|
for (let i = featuresStart + 1; i < sectionEnd; i++) {
|
|
967
1788
|
if (/^\s*goals\s*=/.test(lines[i])) {
|
|
@@ -1425,35 +2246,45 @@ function upsertTuiStatusLine(config, preset = DEFAULT_STATUS_LINE_PRESET, option
|
|
|
1425
2246
|
// ---------------------------------------------------------------------------
|
|
1426
2247
|
// OMX [table] sections block (appended at end of file)
|
|
1427
2248
|
// ---------------------------------------------------------------------------
|
|
1428
|
-
export function stripExistingOmxBlocks(config) {
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
const
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
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 };
|
|
1457
2288
|
}
|
|
1458
2289
|
export function stripExistingSharedMcpRegistryBlock(config) {
|
|
1459
2290
|
let cleaned = config;
|
|
@@ -1688,7 +2519,7 @@ export function mergeSharedMcpRegistryBlock(config, servers, sourcePath) {
|
|
|
1688
2519
|
* OMX table-section block (MCP servers, TUI).
|
|
1689
2520
|
* Contains ONLY [table] sections — no bare keys.
|
|
1690
2521
|
*/
|
|
1691
|
-
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) {
|
|
1692
2523
|
const lines = [
|
|
1693
2524
|
"",
|
|
1694
2525
|
"# ============================================================",
|
|
@@ -1711,7 +2542,7 @@ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAUL
|
|
|
1711
2542
|
}
|
|
1712
2543
|
}
|
|
1713
2544
|
}
|
|
1714
|
-
const hookTrustToml = renderManagedCodexHookTrustToml(buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, hookOptions
|
|
2545
|
+
const hookTrustToml = renderManagedCodexHookTrustToml(buildManagedCodexHookTrustStateForConfig(codexHooksFile, pkgRoot, hookOptions, managedHookTrustState));
|
|
1715
2546
|
if (hookTrustToml) {
|
|
1716
2547
|
lines.push("");
|
|
1717
2548
|
lines.push("# OMX-owned Codex hook trust state");
|
|
@@ -1750,6 +2581,10 @@ function getOmxTablesBlock(pkgRoot, includeTui = true, statusLinePreset = DEFAUL
|
|
|
1750
2581
|
*/
|
|
1751
2582
|
export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
1752
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);
|
|
1753
2588
|
const preservedFirstPartyMcpSections = options.preserveExistingFirstPartyMcp === true &&
|
|
1754
2589
|
options.includeFirstPartyMcp !== true
|
|
1755
2590
|
? extractFirstPartyOmxMcpSections(existing)
|
|
@@ -1758,7 +2593,10 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1758
2593
|
const statusLinePreset = options.statusLinePreset ?? DEFAULT_STATUS_LINE_PRESET;
|
|
1759
2594
|
const customizedManagedTuiSections = extractCustomizedTuiSectionsFromOmxBlocks(existing);
|
|
1760
2595
|
if (existing.includes(OMX_CONFIG_MARKER)) {
|
|
1761
|
-
const stripped = stripExistingOmxBlocks(existing
|
|
2596
|
+
const stripped = stripExistingOmxBlocks(existing, {
|
|
2597
|
+
managedTrustState,
|
|
2598
|
+
priorManagedHookTrustState: options.priorManagedHookTrustState,
|
|
2599
|
+
});
|
|
1762
2600
|
existing = stripped.cleaned;
|
|
1763
2601
|
if (customizedManagedTuiSections.length > 0) {
|
|
1764
2602
|
existing = `${existing.trimEnd()}\n\n${customizedManagedTuiSections.join("\n\n")}\n`;
|
|
@@ -1777,13 +2615,8 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1777
2615
|
existing = `${`notify = ${formatTomlStringArray(userNotifyToPreserve)}`}\n${existing.trimStart()}`;
|
|
1778
2616
|
}
|
|
1779
2617
|
existing = stripOrphanedManagedNotify(existing, pkgRoot).trimStart();
|
|
1780
|
-
const
|
|
1781
|
-
|
|
1782
|
-
platform: options.hookCommandPlatform,
|
|
1783
|
-
});
|
|
1784
|
-
const hookTrustStrip = stripManagedCodexHookTrustStateWithResult(existing, {
|
|
1785
|
-
managedTrustState,
|
|
1786
|
-
});
|
|
2618
|
+
const hookTrustStrip = stripManagedCodexHookTrustStateForRefresh(existing, options.priorManagedHookTrustState, managedTrustState);
|
|
2619
|
+
rejectManagedCodexHookTrustStateConflicts(hookTrustStrip.preservedConflictKeys);
|
|
1787
2620
|
existing = hookTrustStrip.config;
|
|
1788
2621
|
if (options.modelOverride) {
|
|
1789
2622
|
existing = stripRootLevelKeys(existing, ["model"]);
|
|
@@ -1803,17 +2636,15 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1803
2636
|
const topLines = getOmxTopLevelLines(pkgRoot, existing, options.modelOverride, options.notifyCommand === undefined
|
|
1804
2637
|
? getDefaultNotifyCommand(pkgRoot)
|
|
1805
2638
|
: options.notifyCommand);
|
|
1806
|
-
const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile,
|
|
1807
|
-
codexHomeDir: options.codexHomeDir,
|
|
1808
|
-
platform: options.hookCommandPlatform,
|
|
1809
|
-
}, options.includeFirstPartyMcp === true, hookTrustStrip.preservedConflictKeys);
|
|
2639
|
+
const tablesBlock = getOmxTablesBlock(pkgRoot, includeTui && !tuiUpsert.hadExistingTui, statusLinePreset, options.codexHooksFile, hookOptions, managedTrustState, options.includeFirstPartyMcp === true);
|
|
1810
2640
|
const sharedRegistryBlock = getSharedMcpRegistryBlock(options.sharedMcpServers ?? [], options.sharedMcpRegistrySource, existing);
|
|
1811
2641
|
let body = existing.trim();
|
|
1812
2642
|
if (sharedRegistryBlock) {
|
|
1813
2643
|
body = body ? `${body}\n\n${sharedRegistryBlock}` : sharedRegistryBlock;
|
|
1814
2644
|
}
|
|
1815
2645
|
const bodySeparator = body.length > 0 && !/^\s*\[/.test(body) ? "\n" : "\n\n";
|
|
1816
|
-
|
|
2646
|
+
const merged = addDefaultLauncherMcpStartupTimeouts(topLines.join("\n") + bodySeparator + body + "\n" + tablesBlock);
|
|
2647
|
+
return appendLegacyHookTrustState(merged, options.legacyHookTrustState);
|
|
1817
2648
|
}
|
|
1818
2649
|
/**
|
|
1819
2650
|
* Detect and repair upgrade-era managed config incompatibilities in config.toml.
|
|
@@ -1826,6 +2657,33 @@ export function buildMergedConfig(existingConfig, pkgRoot, options = {}) {
|
|
|
1826
2657
|
*
|
|
1827
2658
|
* Returns `true` if a repair was performed.
|
|
1828
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
|
+
}
|
|
1829
2687
|
export async function repairConfigIfNeeded(configPath, pkgRoot, options = {}) {
|
|
1830
2688
|
if (!existsSync(configPath))
|
|
1831
2689
|
return false;
|
|
@@ -1835,8 +2693,10 @@ export async function repairConfigIfNeeded(configPath, pkgRoot, options = {}) {
|
|
|
1835
2693
|
const hasLauncherTimeoutGap = findLauncherTimeoutRepairTargets(content).length > 0;
|
|
1836
2694
|
if (tuiCount <= 1 && !hasLegacyTeamRunTable && !hasLauncherTimeoutGap)
|
|
1837
2695
|
return false;
|
|
1838
|
-
// Managed config compatibility issue detected —
|
|
1839
|
-
|
|
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);
|
|
1840
2700
|
if (repaired === content)
|
|
1841
2701
|
return false;
|
|
1842
2702
|
await writeFile(configPath, repaired);
|
|
@@ -1847,12 +2707,6 @@ export async function mergeConfig(configPath, pkgRoot, options = {}) {
|
|
|
1847
2707
|
if (existsSync(configPath)) {
|
|
1848
2708
|
existing = await readFile(configPath, "utf-8");
|
|
1849
2709
|
}
|
|
1850
|
-
if (existing.includes("oh-my-codex (OMX) Configuration")) {
|
|
1851
|
-
const stripped = stripExistingOmxBlocks(existing);
|
|
1852
|
-
if (options.verbose && stripped.removed > 0) {
|
|
1853
|
-
console.log(" Updating existing OMX config block.");
|
|
1854
|
-
}
|
|
1855
|
-
}
|
|
1856
2710
|
const finalConfig = buildMergedConfig(existing, pkgRoot, options);
|
|
1857
2711
|
await writeFile(configPath, finalConfig);
|
|
1858
2712
|
if (options.verbose) {
|