oh-my-codex 0.20.1 → 0.20.3
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 +7 -6
- package/Cargo.toml +1 -1
- package/README.md +36 -1
- package/crates/omx-runtime/Cargo.toml +1 -0
- package/crates/omx-runtime/src/main.rs +25 -2
- package/crates/omx-runtime/tests/execution.rs +219 -0
- package/crates/omx-runtime-core/src/dispatch.rs +96 -10
- package/crates/omx-runtime-core/src/engine.rs +839 -29
- package/crates/omx-runtime-core/src/lib.rs +8 -0
- package/dist/adapt/__tests__/hermes.test.js.map +1 -1
- package/dist/adapt/contracts.d.ts.map +1 -1
- package/dist/agents/__tests__/definitions.test.js +81 -0
- package/dist/agents/__tests__/definitions.test.js.map +1 -1
- package/dist/agents/__tests__/native-config.test.js +25 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts +2 -1
- package/dist/agents/native-config.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 +6 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +102 -19
- 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 +5 -5
- 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 +60 -6
- 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 +80 -0
- 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 +752 -15
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +136 -0
- 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 +473 -14
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +336 -4
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +87 -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 +206 -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 +72 -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 +55 -0
- package/dist/cli/__tests__/ralplan.test.js.map +1 -0
- package/dist/cli/__tests__/resume.test.js +17 -11
- 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 +25 -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 +2579 -294
- 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 +105 -7
- 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 +1817 -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 +2 -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 +21 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +607 -130
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/explore.js.map +1 -1
- package/dist/cli/index.d.ts +14 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +245 -57
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-parity.js +2 -2
- package/dist/cli/mcp-parity.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 +29 -0
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -0
- package/dist/cli/native-hook-claim-journal.js +252 -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 +10 -0
- package/dist/cli/ralplan.d.ts.map +1 -0
- package/dist/cli/ralplan.js +110 -0
- package/dist/cli/ralplan.js.map +1 -0
- package/dist/cli/session-search.d.ts +5 -0
- package/dist/cli/session-search.d.ts.map +1 -1
- package/dist/cli/session-search.js +87 -0
- package/dist/cli/session-search.js.map +1 -1
- 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 +58 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1450 -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 +17 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +986 -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 +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 +1179 -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/__tests__/models.test.js +67 -3
- package/dist/config/__tests__/models.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 +23 -34
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +1480 -246
- package/dist/config/generator.js.map +1 -1
- package/dist/config/mcp-registry.js.map +1 -1
- package/dist/config/models.d.ts +14 -4
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +15 -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 +1376 -6
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +252 -543
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +38 -4
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +765 -10
- 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 +531 -12
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +163 -24
- 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 +482 -32
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +68 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +7 -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 +43 -4
- 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 +878 -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 +163 -34
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1395 -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 +153 -1
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +42 -5
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +184 -3
- package/dist/leader/contract.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/code-intel-server.test.js +31 -3
- package/dist/mcp/__tests__/code-intel-server.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/__tests__/wiki-server.test.js +18 -0
- package/dist/mcp/__tests__/wiki-server.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 +13 -3
- 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 +34 -23
- package/dist/mcp/wiki-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.js +9 -2
- 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/__tests__/base-tmux-pane.test.js +4 -4
- package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +5 -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.d.ts.map +1 -1
- package/dist/notifications/temp-contract.js +4 -0
- 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 +4 -4
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +16 -13
- 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 +527 -8
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts +2 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.d.ts.map +1 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js +46 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
- package/dist/ralplan/__tests__/runtime.test.js +116 -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 +173 -70
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/documented-leader-preflight.d.ts +34 -0
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
- package/dist/ralplan/documented-leader-preflight.js +58 -0
- package/dist/ralplan/documented-leader-preflight.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +3 -2
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +12 -9
- package/dist/ralplan/runtime.js.map +1 -1
- package/dist/runtime/__tests__/bridge.test.js +42 -1
- package/dist/runtime/__tests__/bridge.test.js.map +1 -1
- package/dist/runtime/bridge.d.ts +12 -0
- package/dist/runtime/bridge.d.ts.map +1 -1
- package/dist/runtime/bridge.js +52 -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 +6657 -995
- 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__/reasoning-artifact-contract.test.d.ts +2 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js +108 -0
- package/dist/scripts/__tests__/reasoning-artifact-contract.test.js.map +1 -0
- 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 +78 -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 +55 -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 +1100 -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 +4 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +11577 -1184
- 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 +218 -138
- 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 +112 -15
- 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 +10 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.js +234 -79
- 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-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +39 -13
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +16 -8
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +365 -44
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- 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-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +19 -18
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +5 -2
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +37 -28
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- 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 +53 -18
- 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 +267 -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 +927 -5
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +4317 -13
- 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__/mode-state-context.test.js +54 -0
- package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +66 -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.d.ts +5 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +59 -0
- 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__/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 +52 -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/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 +91 -0
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +806 -62
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/api-interop.test.js +91 -1
- package/dist/team/__tests__/api-interop.test.js.map +1 -1
- package/dist/team/__tests__/approved-execution.test.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +52 -10
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/idle-nudge.test.js +45 -15
- package/dist/team/__tests__/idle-nudge.test.js.map +1 -1
- package/dist/team/__tests__/mcp-comm.test.js +93 -27
- package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +341 -4
- 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-cli.test.js +9 -0
- package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +3624 -355
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +2516 -118
- 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__/state.test.js +804 -36
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/team-ops-contract.test.js +6 -0
- package/dist/team/__tests__/team-ops-contract.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +3664 -969
- 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/__tests__/worker-runtime-identity.test.js +38 -2
- package/dist/team/__tests__/worker-runtime-identity.test.js.map +1 -1
- package/dist/team/__tests__/worktree.test.js +6 -0
- package/dist/team/__tests__/worktree.test.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 +15 -9
- 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/exact-pane.d.ts +23 -0
- package/dist/team/exact-pane.d.ts.map +1 -0
- package/dist/team/exact-pane.js +133 -0
- package/dist/team/exact-pane.js.map +1 -0
- 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 +12 -1
- package/dist/team/idle-nudge.d.ts.map +1 -1
- package/dist/team/idle-nudge.js +41 -14
- package/dist/team/idle-nudge.js.map +1 -1
- package/dist/team/model-contract.d.ts +18 -2
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +314 -35
- 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 +1 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +1326 -231
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +22 -8
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +1463 -376
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/dispatch-lock.js.map +1 -1
- package/dist/team/state/dispatch.d.ts.map +1 -1
- package/dist/team/state/dispatch.js +26 -8
- package/dist/team/state/dispatch.js.map +1 -1
- package/dist/team/state/events.js.map +1 -1
- package/dist/team/state/locks.d.ts.map +1 -1
- package/dist/team/state/locks.js +61 -13
- package/dist/team/state/locks.js.map +1 -1
- package/dist/team/state/tasks.d.ts.map +1 -1
- package/dist/team/state/tasks.js +4 -3
- package/dist/team/state/tasks.js.map +1 -1
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts +67 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +636 -129
- 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/team-ops.d.ts +5 -0
- package/dist/team/team-ops.d.ts.map +1 -1
- package/dist/team/team-ops.js +4 -0
- package/dist/team/team-ops.js.map +1 -1
- package/dist/team/tmux-session.d.ts +125 -23
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +1340 -333
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/team/worktree.d.ts.map +1 -1
- package/dist/team/worktree.js +4 -0
- package/dist/team/worktree.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +4 -1
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/index.js.map +1 -1
- package/dist/utils/__tests__/file-durability.test.d.ts +2 -0
- package/dist/utils/__tests__/file-durability.test.d.ts.map +1 -0
- package/dist/utils/__tests__/file-durability.test.js +57 -0
- package/dist/utils/__tests__/file-durability.test.js.map +1 -0
- package/dist/utils/agents-model-table.js.map +1 -1
- package/dist/utils/file-durability.d.ts +15 -0
- package/dist/utils/file-durability.d.ts.map +1 -0
- package/dist/utils/file-durability.js +37 -0
- package/dist/utils/file-durability.js.map +1 -0
- 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 +3 -0
- 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.d.ts +4 -1
- package/dist/wiki/lint.d.ts.map +1 -1
- package/dist/wiki/lint.js +3 -2
- 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/hooks/codex-native-hook.mjs +24 -0
- package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +10 -5
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -2
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +6 -2
- package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
- package/skills/omx-setup/SKILL.md +10 -5
- package/skills/ralph/SKILL.md +6 -2
- package/skills/ralplan/SKILL.md +6 -2
- package/skills/team/SKILL.md +13 -9
- package/src/scripts/__tests__/codex-native-hook.test.ts +20048 -10827
- 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__/reasoning-artifact-contract.test.ts +129 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +78 -0
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +60 -0
- package/src/scripts/__tests__/smoke-packed-install.test.ts +1309 -4
- package/src/scripts/codex-native-hook.ts +11429 -1163
- package/src/scripts/notify-fallback-delivery.ts +416 -0
- package/src/scripts/notify-fallback-watcher.ts +216 -155
- package/src/scripts/notify-hook/auto-nudge.ts +113 -14
- 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/team-dispatch.ts +242 -75
- package/src/scripts/notify-hook/team-leader-nudge.ts +40 -18
- package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
- package/src/scripts/notify-hook/team-worker-stop.ts +20 -16
- package/src/scripts/notify-hook/team-worker.ts +39 -26
- package/src/scripts/notify-hook/tmux-injection.ts +66 -23
- package/src/scripts/notify-hook/visual-verdict.ts +22 -12
- package/src/scripts/notify-hook.ts +336 -90
- package/src/scripts/smoke-packed-install.ts +5154 -149
package/dist/cli/uninstall.js
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* omx uninstall - Remove oh-my-codex configuration and installed artifacts
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import { existsSync } from "fs";
|
|
6
|
-
import { join, basename, dirname } from "path";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
4
|
+
import { chmod, copyFile, lstat, open, readFile, readdir, rename, rm, writeFile } from "fs/promises";
|
|
5
|
+
import { constants, existsSync } from "fs";
|
|
6
|
+
import { join, basename, dirname, isAbsolute, relative } from "path";
|
|
7
|
+
import { randomUUID } from "crypto";
|
|
8
|
+
import { clearNativeHookClaimJournal as clearNativeHookClaimJournalWithDurability, createNativeHookClaimJournalDurability, persistNativeHookClaimJournal as persistNativeHookClaimJournalWithDurability, recoverNativeHookClaimJournal, syncNativeHookClaimParent as syncNativeHookClaimParentWithDurability, restoreNativeHookClaimNoClobber as restoreNativeHookClaimNoClobberWithDurability, } from "./native-hook-claim-journal.js";
|
|
9
|
+
import { formatTomlStringArray, getRootTomlArray, isOmxManagedNotifyCommand, sanitizePreviousNotifyCommand, stripExistingOmxBlocks, stripManagedCodexHookTrustState, stripOmxEnvSettings, stripOmxTopLevelKeys, stripOmxFeatureFlags, upsertCodexHooksFeatureFlag, stripOmxSeededBehavioralDefaults, } from "../config/generator.js";
|
|
10
|
+
import { buildManagedCodexNativeHookWindowsShimContent, buildManagedCodexNativeHookWindowsShimPath, classifyManagedCodexNativeHookWindowsShimOwnership, planManagedCodexHooksRemoval, ManagedCodexHooksPlanError, } from "../config/codex-hooks.js";
|
|
9
11
|
import { getPackageRoot } from "../utils/package.js";
|
|
10
12
|
import { AGENT_DEFINITIONS } from "../agents/definitions.js";
|
|
11
13
|
import { detectLegacySkillRootOverlap } from "../utils/paths.js";
|
|
12
|
-
import { resolveScopeDirectories } from "./setup.js";
|
|
14
|
+
import { decideWindowsNativeHookShimReference, resolveScopeDirectories, } from "./setup.js";
|
|
13
15
|
import { resolveCodexHookFeatureFlagForCli } from "./codex-feature-probe.js";
|
|
14
16
|
import { readPersistedSetupScope } from "./index.js";
|
|
15
|
-
import { isOmxGeneratedAgentsMd } from "../utils/agents-md.js";
|
|
17
|
+
import { isOmxGeneratedAgentsMd, OMX_MANAGED_AGENTS_END_MARKER, OMX_MANAGED_AGENTS_START_MARKER, } from "../utils/agents-md.js";
|
|
16
18
|
import { OMX_FIRST_PARTY_MCP_SERVER_NAMES } from "../config/omx-first-party-mcp.js";
|
|
19
|
+
import TOML from "@iarna/toml";
|
|
20
|
+
import { emitDegradedDurabilityWarning, recordRegularFileSyncOutcome, syncRegularFile, } from "../utils/file-durability.js";
|
|
21
|
+
let uninstallClaimJournalDurabilityOverride;
|
|
22
|
+
/** @internal Test seam for deterministic claim-journal durability coverage. */
|
|
23
|
+
export function setUninstallClaimJournalDurabilityForTest(durability) {
|
|
24
|
+
const previous = uninstallClaimJournalDurabilityOverride;
|
|
25
|
+
uninstallClaimJournalDurabilityOverride = durability;
|
|
26
|
+
return () => {
|
|
27
|
+
uninstallClaimJournalDurabilityOverride = previous;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
17
30
|
function detectOmxConfigArtifacts(config) {
|
|
18
31
|
const hasMcpServers = OMX_FIRST_PARTY_MCP_SERVER_NAMES.filter((name) => new RegExp(`\\[mcp_servers\\.${name}\\]`).test(config));
|
|
19
32
|
const agentNames = Object.keys(AGENT_DEFINITIONS);
|
|
@@ -34,14 +47,12 @@ function detectOmxConfigArtifacts(config) {
|
|
|
34
47
|
/^\s*codex_hooks\s*=\s*true/m.test(config) ||
|
|
35
48
|
/^\s*goals\s*=\s*true/m.test(config) ||
|
|
36
49
|
/^\s*goal\s*=\s*true/m.test(config);
|
|
37
|
-
const hasExploreRoutingEnv = /^\s*USE_OMX_EXPLORE_CMD\s*=/m.test(config);
|
|
38
50
|
return {
|
|
39
51
|
hasMcpServers,
|
|
40
52
|
hasAgentEntries,
|
|
41
53
|
hasTuiSection,
|
|
42
54
|
hasTopLevelKeys,
|
|
43
55
|
hasFeatureFlags,
|
|
44
|
-
hasExploreRoutingEnv,
|
|
45
56
|
};
|
|
46
57
|
}
|
|
47
58
|
function hasNativeHooksFeatureFlag(config) {
|
|
@@ -60,17 +71,176 @@ function hasNativeHooksFeatureFlag(config) {
|
|
|
60
71
|
.slice(featuresStart + 1, sectionEnd)
|
|
61
72
|
.some((line) => /^\s*(?:hooks|codex_hooks)\s*=\s*true/.test(line));
|
|
62
73
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
function fileIdentity(stat) {
|
|
75
|
+
return {
|
|
76
|
+
dev: stat.dev,
|
|
77
|
+
ino: stat.ino,
|
|
78
|
+
size: stat.size,
|
|
79
|
+
mode: stat.mode,
|
|
80
|
+
mtimeMs: stat.mtimeMs,
|
|
81
|
+
ctimeMs: stat.ctimeMs,
|
|
82
|
+
links: stat.nlink,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function hasSameFileIdentity(left, right) {
|
|
86
|
+
return left.dev === right.dev &&
|
|
87
|
+
left.ino === right.ino &&
|
|
88
|
+
left.size === right.size &&
|
|
89
|
+
left.mode === right.mode &&
|
|
90
|
+
left.mtimeMs === right.mtimeMs &&
|
|
91
|
+
left.ctimeMs === right.ctimeMs &&
|
|
92
|
+
left.links === right.links;
|
|
93
|
+
}
|
|
94
|
+
function isMissingPathError(error) {
|
|
95
|
+
return (typeof error === "object" &&
|
|
96
|
+
error !== null &&
|
|
97
|
+
"code" in error &&
|
|
98
|
+
error.code === "ENOENT");
|
|
99
|
+
}
|
|
100
|
+
async function captureControlledTopology(root, path) {
|
|
101
|
+
const parentPath = dirname(path);
|
|
102
|
+
const relativeParent = relative(root, parentPath);
|
|
103
|
+
if (isAbsolute(relativeParent) ||
|
|
104
|
+
relativeParent === ".." ||
|
|
105
|
+
relativeParent.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ||
|
|
106
|
+
relativeParent.startsWith("/")) {
|
|
107
|
+
throw new Error(`Refusing to process ${path}: it is outside controlled Codex scope ${root}.`);
|
|
108
|
+
}
|
|
109
|
+
const ancestors = [];
|
|
110
|
+
let currentPath = root;
|
|
111
|
+
for (const segment of ["", ...relativeParent.split(/[\\/]/).filter(Boolean)]) {
|
|
112
|
+
if (segment)
|
|
113
|
+
currentPath = join(currentPath, segment);
|
|
114
|
+
try {
|
|
115
|
+
const stat = await lstat(currentPath);
|
|
116
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
117
|
+
throw new Error(`Refusing to process ${path}: controlled ancestor ${currentPath} must be a non-symbolic-link directory.`);
|
|
118
|
+
}
|
|
119
|
+
ancestors.push({
|
|
120
|
+
path: currentPath,
|
|
121
|
+
identity: { dev: stat.dev, ino: stat.ino },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
if (!isMissingPathError(error))
|
|
126
|
+
throw error;
|
|
127
|
+
ancestors.push({ path: currentPath, identity: null });
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return { root, ancestors };
|
|
132
|
+
}
|
|
133
|
+
async function assertControlledTopologyCurrent(topology) {
|
|
134
|
+
if (!topology)
|
|
135
|
+
return;
|
|
136
|
+
for (const ancestor of topology.ancestors) {
|
|
137
|
+
try {
|
|
138
|
+
const stat = await lstat(ancestor.path);
|
|
139
|
+
if (ancestor.identity === null ||
|
|
140
|
+
stat.isSymbolicLink() ||
|
|
141
|
+
!stat.isDirectory() ||
|
|
142
|
+
stat.dev !== ancestor.identity.dev ||
|
|
143
|
+
stat.ino !== ancestor.identity.ino) {
|
|
144
|
+
throw new Error(`Refusing uninstall because controlled ancestor ${ancestor.path} changed topology after planning.`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
if (error instanceof Error && error.message.includes("changed topology")) {
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
if (isMissingPathError(error) && ancestor.identity === null)
|
|
152
|
+
continue;
|
|
153
|
+
if (isMissingPathError(error)) {
|
|
154
|
+
throw new Error(`Refusing uninstall because controlled ancestor ${ancestor.path} changed topology after planning.`);
|
|
155
|
+
}
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function decodeStrictUtf8(path, bytes) {
|
|
66
161
|
try {
|
|
67
|
-
const
|
|
68
|
-
|
|
162
|
+
const content = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
163
|
+
if (!Buffer.from(content, "utf-8").equals(bytes)) {
|
|
164
|
+
throw new Error("decoded text did not round-trip to the original bytes");
|
|
165
|
+
}
|
|
166
|
+
return content;
|
|
69
167
|
}
|
|
70
168
|
catch {
|
|
71
|
-
|
|
169
|
+
throw new ManagedCodexHooksPlanError("invalid_document", `Refusing to process ${path}: it is not valid UTF-8.`, { path });
|
|
72
170
|
}
|
|
73
171
|
}
|
|
172
|
+
async function readFileSnapshot(path, options = {}) {
|
|
173
|
+
const topology = options.controlledRoot
|
|
174
|
+
? await captureControlledTopology(options.controlledRoot, path)
|
|
175
|
+
: null;
|
|
176
|
+
let before;
|
|
177
|
+
try {
|
|
178
|
+
before = await lstat(path);
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
if (isMissingPathError(error)) {
|
|
182
|
+
await assertControlledTopologyCurrent(topology);
|
|
183
|
+
return {
|
|
184
|
+
path,
|
|
185
|
+
content: null,
|
|
186
|
+
bytes: null,
|
|
187
|
+
mode: null,
|
|
188
|
+
identity: null,
|
|
189
|
+
topology,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
if (before.isSymbolicLink() || !before.isFile() || before.nlink !== 1) {
|
|
195
|
+
throw new Error(`Refusing to process ${path}: expected a regular file, not a symbolic link or other filesystem object.`);
|
|
196
|
+
}
|
|
197
|
+
const bytes = await readFile(path);
|
|
198
|
+
const after = await lstat(path);
|
|
199
|
+
await assertControlledTopologyCurrent(topology);
|
|
200
|
+
if (after.isSymbolicLink() || !after.isFile() || after.nlink !== 1 || !hasSameFileIdentity(fileIdentity(before), fileIdentity(after))) {
|
|
201
|
+
throw new Error(`Refusing to process ${path}: it changed while uninstall was planning.`);
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
path,
|
|
205
|
+
content: options.strictUtf8 === false ? bytes.toString("utf-8") : decodeStrictUtf8(path, bytes),
|
|
206
|
+
bytes,
|
|
207
|
+
mode: after.mode & 0o7777,
|
|
208
|
+
identity: fileIdentity(after),
|
|
209
|
+
topology,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
async function planHooksRemoval(hooks, pkgRoot, platform, controlledRoot) {
|
|
213
|
+
let plan;
|
|
214
|
+
if (hooks.content !== null) {
|
|
215
|
+
const result = planManagedCodexHooksRemoval(hooks.content, hooks.path, {
|
|
216
|
+
platform,
|
|
217
|
+
codexHomeDir: dirname(hooks.path),
|
|
218
|
+
});
|
|
219
|
+
if (!result.ok)
|
|
220
|
+
throw result.error;
|
|
221
|
+
plan = result;
|
|
222
|
+
}
|
|
223
|
+
if (platform !== "win32")
|
|
224
|
+
return { hooks, plan };
|
|
225
|
+
const shimPath = buildManagedCodexNativeHookWindowsShimPath(dirname(hooks.path));
|
|
226
|
+
const shim = await readFileSnapshot(shimPath, {
|
|
227
|
+
strictUtf8: false,
|
|
228
|
+
// On non-Windows hosts the test-only platform seam intentionally produces
|
|
229
|
+
// a win32 path that the host filesystem cannot place under this root.
|
|
230
|
+
controlledRoot: platform === process.platform ? controlledRoot : undefined,
|
|
231
|
+
});
|
|
232
|
+
if (shim.bytes !== null) {
|
|
233
|
+
const expectedShim = Buffer.from(buildManagedCodexNativeHookWindowsShimContent(pkgRoot), "utf-8");
|
|
234
|
+
if (classifyManagedCodexNativeHookWindowsShimOwnership(shim.bytes, expectedShim) === "modified") {
|
|
235
|
+
throw new Error(`Refusing to remove modified native hook Windows shim at ${shim.path}.`);
|
|
236
|
+
}
|
|
237
|
+
const shimReference = decideWindowsNativeHookShimReference(plan?.finalContent ?? null, shim.path);
|
|
238
|
+
if (shimReference !== "not_referenced") {
|
|
239
|
+
return { hooks, plan, preservedShimPrecondition: shim };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return { hooks, plan, shim };
|
|
243
|
+
}
|
|
74
244
|
function insertRootTomlKey(config, line) {
|
|
75
245
|
const lines = config.split(/\r?\n/);
|
|
76
246
|
const firstTableIndex = lines.findIndex((candidate) => /^\s*\[/.test(candidate));
|
|
@@ -78,30 +248,90 @@ function insertRootTomlKey(config, line) {
|
|
|
78
248
|
lines.splice(insertAt, 0, line);
|
|
79
249
|
return lines.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
80
250
|
}
|
|
81
|
-
|
|
82
|
-
const currentNotify = getRootTomlArray(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
251
|
+
function isManagedDispatcherNotify(config) {
|
|
252
|
+
const currentNotify = getRootTomlArray(config, "notify");
|
|
253
|
+
return Boolean(isOmxManagedNotifyCommand(currentNotify, getPackageRoot()) &&
|
|
254
|
+
currentNotify?.some((part) => /(?:^|[\\/])notify-dispatcher\.js$/.test(part)));
|
|
255
|
+
}
|
|
256
|
+
function invalidNotifyMetadata(path, reason) {
|
|
257
|
+
return new ManagedCodexHooksPlanError("invalid_document", `Refusing to use notification metadata ${path}: ${reason}.`, { path });
|
|
258
|
+
}
|
|
259
|
+
function parseNotifyMetadata(snapshot, currentNotify) {
|
|
260
|
+
if (snapshot.content === null) {
|
|
261
|
+
throw invalidNotifyMetadata(snapshot.path, "the managed dispatcher metadata is missing");
|
|
262
|
+
}
|
|
263
|
+
if (!currentNotify.includes(snapshot.path)) {
|
|
264
|
+
throw invalidNotifyMetadata(snapshot.path, "the managed dispatcher does not reference the controlled metadata path");
|
|
86
265
|
}
|
|
87
|
-
|
|
266
|
+
let parsed;
|
|
88
267
|
try {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
268
|
+
parsed = JSON.parse(snapshot.content);
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
throw invalidNotifyMetadata(snapshot.path, `invalid JSON (${error instanceof Error ? error.message : String(error)})`);
|
|
272
|
+
}
|
|
273
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
274
|
+
throw invalidNotifyMetadata(snapshot.path, "expected a JSON object");
|
|
275
|
+
}
|
|
276
|
+
const metadata = parsed;
|
|
277
|
+
if (metadata.managedBy !== "oh-my-codex" || metadata.version !== 1) {
|
|
278
|
+
throw invalidNotifyMetadata(snapshot.path, "expected OMX ownership and version 1");
|
|
279
|
+
}
|
|
280
|
+
const validateStringArray = (value, name) => {
|
|
281
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
282
|
+
throw invalidNotifyMetadata(snapshot.path, `${name} must be an array of strings`);
|
|
97
283
|
}
|
|
284
|
+
return [...value];
|
|
285
|
+
};
|
|
286
|
+
const previousNotify = metadata.previousNotify;
|
|
287
|
+
if (!Object.hasOwn(metadata, "previousNotify") ||
|
|
288
|
+
(previousNotify !== null &&
|
|
289
|
+
(!Array.isArray(previousNotify) ||
|
|
290
|
+
!previousNotify.every((item) => typeof item === "string")))) {
|
|
291
|
+
throw invalidNotifyMetadata(snapshot.path, "previousNotify must be null or an array of strings");
|
|
98
292
|
}
|
|
99
|
-
|
|
100
|
-
|
|
293
|
+
validateStringArray(metadata.omxNotify, "omxNotify");
|
|
294
|
+
const dispatcherNotify = validateStringArray(metadata.dispatcherNotify, "dispatcherNotify");
|
|
295
|
+
if (dispatcherNotify.length !== currentNotify.length ||
|
|
296
|
+
dispatcherNotify.some((part, index) => part !== currentNotify[index])) {
|
|
297
|
+
throw invalidNotifyMetadata(snapshot.path, "dispatcherNotify does not match the managed dispatcher command");
|
|
101
298
|
}
|
|
102
|
-
return
|
|
299
|
+
return {
|
|
300
|
+
snapshot,
|
|
301
|
+
previousNotify: Array.isArray(previousNotify) ? [...previousNotify] : null,
|
|
302
|
+
};
|
|
103
303
|
}
|
|
104
|
-
async function
|
|
304
|
+
async function planNotifyMetadata(configSnapshot, codexHomeDir) {
|
|
305
|
+
if (configSnapshot.content === null || !isManagedDispatcherNotify(configSnapshot.content)) {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
const currentNotify = getRootTomlArray(configSnapshot.content, "notify");
|
|
309
|
+
if (!currentNotify) {
|
|
310
|
+
throw invalidNotifyMetadata(join(codexHomeDir, ".omx", "notify-dispatch.json"), "the managed dispatcher command is invalid");
|
|
311
|
+
}
|
|
312
|
+
let snapshot;
|
|
313
|
+
try {
|
|
314
|
+
snapshot = await readFileSnapshot(join(codexHomeDir, ".omx", "notify-dispatch.json"), { controlledRoot: codexHomeDir });
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
if (error instanceof ManagedCodexHooksPlanError)
|
|
318
|
+
throw error;
|
|
319
|
+
throw invalidNotifyMetadata(join(codexHomeDir, ".omx", "notify-dispatch.json"), `unreadable (${error instanceof Error ? error.message : String(error)})`);
|
|
320
|
+
}
|
|
321
|
+
return parseNotifyMetadata(snapshot, currentNotify);
|
|
322
|
+
}
|
|
323
|
+
function restorePreviousNotifyIfDispatcher(strippedConfig, originalConfig, metadataPlan) {
|
|
324
|
+
if (!isManagedDispatcherNotify(originalConfig))
|
|
325
|
+
return strippedConfig;
|
|
326
|
+
if (!metadataPlan) {
|
|
327
|
+
throw new Error("Missing planned notification metadata for a managed dispatcher.");
|
|
328
|
+
}
|
|
329
|
+
const sanitizedPreviousNotify = sanitizePreviousNotifyCommand(metadataPlan.previousNotify, getPackageRoot());
|
|
330
|
+
return sanitizedPreviousNotify
|
|
331
|
+
? insertRootTomlKey(strippedConfig, `notify = ${formatTomlStringArray(sanitizedPreviousNotify)}`)
|
|
332
|
+
: strippedConfig;
|
|
333
|
+
}
|
|
334
|
+
async function planConfigCleanup(configSnapshot, options) {
|
|
105
335
|
const result = {
|
|
106
336
|
configCleaned: false,
|
|
107
337
|
mcpServersRemoved: [],
|
|
@@ -110,12 +340,10 @@ async function cleanConfig(configPath, options) {
|
|
|
110
340
|
topLevelKeysRemoved: false,
|
|
111
341
|
featureFlagsRemoved: false,
|
|
112
342
|
};
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return result;
|
|
343
|
+
const original = configSnapshot.content;
|
|
344
|
+
if (original === null) {
|
|
345
|
+
return { config: configSnapshot, finalContent: null, result };
|
|
117
346
|
}
|
|
118
|
-
const original = await readFile(configPath, "utf-8");
|
|
119
347
|
const detected = detectOmxConfigArtifacts(original);
|
|
120
348
|
const shouldRestoreHooksFeatureFlag = options.preserveHooksFeatureFlag && hasNativeHooksFeatureFlag(original);
|
|
121
349
|
result.mcpServersRemoved = detected.hasMcpServers;
|
|
@@ -123,16 +351,31 @@ async function cleanConfig(configPath, options) {
|
|
|
123
351
|
result.tuiSectionRemoved = detected.hasTuiSection;
|
|
124
352
|
result.topLevelKeysRemoved = detected.hasTopLevelKeys;
|
|
125
353
|
result.featureFlagsRemoved = detected.hasFeatureFlags;
|
|
354
|
+
// Verify proof ownership against the untouched source before marker stripping
|
|
355
|
+
// can hide a foreign sibling in an otherwise OMX-looking trust declaration.
|
|
356
|
+
stripManagedCodexHookTrustState(original, {
|
|
357
|
+
priorManagedHookTrustState: options.priorHookTrustState,
|
|
358
|
+
managedTrustState: options.finalHookTrustState,
|
|
359
|
+
});
|
|
126
360
|
// Strip OMX tables block (MCP servers, agents, tui)
|
|
127
361
|
let config = original;
|
|
128
|
-
const { cleaned } = stripExistingOmxBlocks(config
|
|
362
|
+
const { cleaned } = stripExistingOmxBlocks(config, {
|
|
363
|
+
managedTrustState: options.finalHookTrustState,
|
|
364
|
+
priorManagedHookTrustState: options.priorHookTrustState,
|
|
365
|
+
});
|
|
129
366
|
config = cleaned;
|
|
130
367
|
// Strip OMX top-level keys, then restore a pre-existing user notify when
|
|
131
368
|
// setup had wrapped it in the OMX dispatcher.
|
|
132
369
|
config = stripOmxTopLevelKeys(config);
|
|
133
|
-
config =
|
|
370
|
+
config = restorePreviousNotifyIfDispatcher(config, original, options.notifyMetadata);
|
|
134
371
|
// Strip OMX-seeded behavioral defaults only when the seeded pair is unchanged.
|
|
135
372
|
config = stripOmxSeededBehavioralDefaults(config);
|
|
373
|
+
// Remove only trust tables whose hashes and coordinates match the planned
|
|
374
|
+
// managed hooks before their removal. User-owned conflicts remain intact.
|
|
375
|
+
config = stripManagedCodexHookTrustState(config, {
|
|
376
|
+
priorManagedHookTrustState: options.priorHookTrustState,
|
|
377
|
+
managedTrustState: options.finalHookTrustState,
|
|
378
|
+
});
|
|
136
379
|
// Strip feature flags
|
|
137
380
|
config = stripOmxFeatureFlags(config, { preserveMultiAgent: true });
|
|
138
381
|
if (shouldRestoreHooksFeatureFlag) {
|
|
@@ -145,20 +388,8 @@ async function cleanConfig(configPath, options) {
|
|
|
145
388
|
config = stripOmxEnvSettings(config);
|
|
146
389
|
// Normalize trailing whitespace
|
|
147
390
|
config = config.trimEnd() + "\n";
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (!options.dryRun) {
|
|
151
|
-
await writeFile(configPath, config);
|
|
152
|
-
}
|
|
153
|
-
if (options.verbose) {
|
|
154
|
-
console.log(` ${options.dryRun ? "Would clean" : "Cleaned"} ${configPath}`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
if (options.verbose)
|
|
159
|
-
console.log(" No OMX config entries found.");
|
|
160
|
-
}
|
|
161
|
-
return result;
|
|
391
|
+
result.configCleaned = config !== original;
|
|
392
|
+
return { config: configSnapshot, finalContent: config, result };
|
|
162
393
|
}
|
|
163
394
|
async function removeInstalledPrompts(promptsDir, pkgRoot, options) {
|
|
164
395
|
const srcPromptsDir = join(pkgRoot, "prompts");
|
|
@@ -239,6 +470,19 @@ async function removeAgentsMd(agentsMdPath, options) {
|
|
|
239
470
|
return false;
|
|
240
471
|
try {
|
|
241
472
|
const content = await readFile(agentsMdPath, "utf-8");
|
|
473
|
+
const startIndex = content.indexOf(OMX_MANAGED_AGENTS_START_MARKER);
|
|
474
|
+
const endIndex = content.indexOf(OMX_MANAGED_AGENTS_END_MARKER);
|
|
475
|
+
if (startIndex >= 0 && endIndex > startIndex) {
|
|
476
|
+
const blockEnd = endIndex + OMX_MANAGED_AGENTS_END_MARKER.length;
|
|
477
|
+
const preserved = `${content.slice(0, startIndex).trimEnd()}\n${content.slice(blockEnd).trimStart()}`.trim();
|
|
478
|
+
if (preserved) {
|
|
479
|
+
if (!options.dryRun)
|
|
480
|
+
await writeFile(agentsMdPath, `${preserved}\n`, "utf-8");
|
|
481
|
+
if (options.verbose)
|
|
482
|
+
console.log(" Removed OMX-managed AGENTS.md sections and preserved user guidance.");
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
242
486
|
if (!isOmxGeneratedAgentsMd(content)) {
|
|
243
487
|
if (options.verbose)
|
|
244
488
|
console.log(" AGENTS.md is not OMX-generated, skipping.");
|
|
@@ -255,29 +499,584 @@ async function removeAgentsMd(agentsMdPath, options) {
|
|
|
255
499
|
console.log(` ${options.dryRun ? "Would remove" : "Removed"} AGENTS.md`);
|
|
256
500
|
return true;
|
|
257
501
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
502
|
+
function assertValidHooksJson(content) {
|
|
503
|
+
JSON.parse(content);
|
|
504
|
+
}
|
|
505
|
+
function assertValidToml(content) {
|
|
506
|
+
TOML.parse(content);
|
|
507
|
+
}
|
|
508
|
+
function transactionTemporaryPath(path, purpose, options) {
|
|
509
|
+
return options.transactionTemporaryPath?.(path, purpose) ?? join(dirname(path), `.${basename(path)}.omx-uninstall-${purpose}-${process.pid}-${randomUUID()}.tmp`);
|
|
510
|
+
}
|
|
511
|
+
function uninstallClaimJournalDurability() {
|
|
512
|
+
return uninstallClaimJournalDurabilityOverride
|
|
513
|
+
?? createNativeHookClaimJournalDurability();
|
|
514
|
+
}
|
|
515
|
+
async function clearNativeHookClaimJournal(root) {
|
|
516
|
+
return clearNativeHookClaimJournalWithDurability(root, uninstallClaimJournalDurability());
|
|
517
|
+
}
|
|
518
|
+
async function persistNativeHookClaimJournal(root, entry) {
|
|
519
|
+
return persistNativeHookClaimJournalWithDurability(root, entry, uninstallClaimJournalDurability());
|
|
520
|
+
}
|
|
521
|
+
async function restoreNativeHookClaimNoClobber(claimPath, destinationPath) {
|
|
522
|
+
return restoreNativeHookClaimNoClobberWithDurability(claimPath, destinationPath, uninstallClaimJournalDurability());
|
|
523
|
+
}
|
|
524
|
+
async function syncNativeHookClaimParent(path) {
|
|
525
|
+
return syncNativeHookClaimParentWithDurability(path, uninstallClaimJournalDurability());
|
|
526
|
+
}
|
|
527
|
+
function transactionClaimPath(path) {
|
|
528
|
+
return join(dirname(path), `.${basename(path)}.omx-uninstall-claim-${process.pid}-${randomUUID()}.tmp`);
|
|
529
|
+
}
|
|
530
|
+
async function restoreUninstallClaim(claimPath, destinationPath, tracker) {
|
|
531
|
+
recordRegularFileSyncOutcome(tracker, await restoreNativeHookClaimNoClobber(claimPath, destinationPath));
|
|
532
|
+
}
|
|
533
|
+
function snapshotReadOptions(snapshot) {
|
|
534
|
+
return {
|
|
535
|
+
strictUtf8: false,
|
|
536
|
+
controlledRoot: snapshot.topology?.root,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
async function captureCurrentSnapshot(reference) {
|
|
540
|
+
return readFileSnapshot(reference.path, snapshotReadOptions(reference));
|
|
541
|
+
}
|
|
542
|
+
function renamedDestinationOwnership(snapshot, destinationPath, topology) {
|
|
543
|
+
if (snapshot.bytes === null || snapshot.mode === null || snapshot.identity === null) {
|
|
544
|
+
throw new Error(`Replacement temporary ${snapshot.path} was not fully captured before rename.`);
|
|
545
|
+
}
|
|
546
|
+
return {
|
|
547
|
+
path: destinationPath,
|
|
548
|
+
bytes: snapshot.bytes,
|
|
549
|
+
mode: snapshot.mode,
|
|
550
|
+
identity: { dev: snapshot.identity.dev, ino: snapshot.identity.ino },
|
|
551
|
+
topology,
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
async function captureRenamedDestinationOwnership(ownership) {
|
|
555
|
+
await assertControlledTopologyCurrent(ownership.topology);
|
|
556
|
+
const current = await readFileSnapshot(ownership.path, {
|
|
557
|
+
strictUtf8: false,
|
|
558
|
+
controlledRoot: ownership.topology?.root,
|
|
559
|
+
});
|
|
560
|
+
if (current.bytes === null ||
|
|
561
|
+
current.mode !== ownership.mode ||
|
|
562
|
+
!current.bytes.equals(ownership.bytes) ||
|
|
563
|
+
current.identity === null ||
|
|
564
|
+
current.identity.dev !== ownership.identity.dev ||
|
|
565
|
+
current.identity.ino !== ownership.identity.ino) {
|
|
566
|
+
throw new Error(`Uninstall replacement ownership changed for ${ownership.path}.`);
|
|
567
|
+
}
|
|
568
|
+
return current;
|
|
569
|
+
}
|
|
570
|
+
async function assertSnapshotCurrent(snapshot) {
|
|
571
|
+
await assertControlledTopologyCurrent(snapshot.topology);
|
|
572
|
+
const current = await captureCurrentSnapshot(snapshot);
|
|
573
|
+
if (snapshot.bytes === null && current.bytes === null)
|
|
574
|
+
return;
|
|
575
|
+
if (snapshot.bytes !== null &&
|
|
576
|
+
current.bytes !== null &&
|
|
577
|
+
snapshot.identity !== null &&
|
|
578
|
+
current.identity !== null &&
|
|
579
|
+
snapshot.bytes.equals(current.bytes) &&
|
|
580
|
+
hasSameFileIdentity(snapshot.identity, current.identity)) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
throw new Error(`Refusing uninstall because planned artifact ${snapshot.path} changed, was created, or was removed after planning.`);
|
|
584
|
+
}
|
|
585
|
+
async function assertSnapshotAtPath(path, expected, context) {
|
|
586
|
+
await assertControlledTopologyCurrent(expected.topology);
|
|
587
|
+
const actual = await readFileSnapshot(path, snapshotReadOptions(expected));
|
|
588
|
+
if (expected.bytes === null ||
|
|
589
|
+
actual.bytes === null ||
|
|
590
|
+
expected.identity === null ||
|
|
591
|
+
actual.identity === null ||
|
|
592
|
+
!expected.bytes.equals(actual.bytes) ||
|
|
593
|
+
actual.mode !== expected.mode ||
|
|
594
|
+
actual.identity.dev !== expected.identity.dev ||
|
|
595
|
+
actual.identity.ino !== expected.identity.ino) {
|
|
596
|
+
throw new Error(`Refusing uninstall because ${context} ${path} is not the planned artifact.`);
|
|
597
|
+
}
|
|
598
|
+
return actual;
|
|
599
|
+
}
|
|
600
|
+
async function assertSnapshotMatchesPlannedContent(actual, expected, context) {
|
|
601
|
+
await assertControlledTopologyCurrent(expected.topology);
|
|
602
|
+
if (actual.bytes === null ||
|
|
603
|
+
expected.bytes === null ||
|
|
604
|
+
actual.mode !== expected.mode ||
|
|
605
|
+
!actual.bytes.equals(expected.bytes)) {
|
|
606
|
+
throw new Error(`Uninstall ${context} mismatch for ${expected.path}.`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
async function assertSnapshotsCurrent(snapshots) {
|
|
610
|
+
for (const snapshot of snapshots)
|
|
611
|
+
await assertSnapshotCurrent(snapshot);
|
|
612
|
+
}
|
|
613
|
+
async function removeOwnedTemporary(path, snapshot, originalError, description, tracker) {
|
|
614
|
+
try {
|
|
615
|
+
if (!snapshot) {
|
|
616
|
+
throw new Error(`${description} path was not fully captured after writing.`);
|
|
272
617
|
}
|
|
273
|
-
|
|
274
|
-
|
|
618
|
+
await assertSnapshotCurrent(snapshot);
|
|
619
|
+
const claimPath = transactionClaimPath(path);
|
|
620
|
+
await rename(path, claimPath);
|
|
621
|
+
try {
|
|
622
|
+
await assertSnapshotAtPath(claimPath, snapshot, `${description} cleanup claim`);
|
|
275
623
|
}
|
|
624
|
+
catch (error) {
|
|
625
|
+
try {
|
|
626
|
+
await restoreUninstallClaim(claimPath, path, tracker);
|
|
627
|
+
}
|
|
628
|
+
catch (recoveryError) {
|
|
629
|
+
throw new Error(`${error instanceof Error ? error.message : String(error)}; preserved claim ${claimPath} for manual recovery: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`);
|
|
630
|
+
}
|
|
631
|
+
throw error;
|
|
632
|
+
}
|
|
633
|
+
await rm(claimPath);
|
|
276
634
|
}
|
|
277
|
-
|
|
278
|
-
|
|
635
|
+
catch (cleanupError) {
|
|
636
|
+
const message = originalError instanceof Error
|
|
637
|
+
? originalError.message
|
|
638
|
+
: String(originalError);
|
|
639
|
+
throw new Error(`Uninstall artifact transaction failed (${message}) and preserved ${description} ${path} for manual recovery after cleanup verification failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
async function syncUninstallRegularFile(site, handle, options) {
|
|
643
|
+
const platform = options.transactionPlatform ?? process.platform;
|
|
644
|
+
const outcome = options.regularFileSyncForTest
|
|
645
|
+
? await options.regularFileSyncForTest(site, handle, platform)
|
|
646
|
+
: await syncRegularFile(handle, platform);
|
|
647
|
+
recordRegularFileSyncOutcome(options.durabilityTracker, outcome);
|
|
648
|
+
}
|
|
649
|
+
async function atomicReplaceFile(mutation, expectedCurrent, content, options, stage, onRename, assertApplied) {
|
|
650
|
+
if (mutation.snapshot.mode === null) {
|
|
651
|
+
throw new Error(`Refusing to replace ${mutation.snapshot.path}: uninstall did not plan a regular-file mode.`);
|
|
652
|
+
}
|
|
653
|
+
const temporaryPath = transactionTemporaryPath(mutation.snapshot.path, "write", options);
|
|
654
|
+
let handle;
|
|
655
|
+
let temporaryCreated = false;
|
|
656
|
+
let temporarySnapshot;
|
|
657
|
+
let claimPath;
|
|
658
|
+
let claimCreated = false;
|
|
659
|
+
let journaledClaim = false;
|
|
660
|
+
try {
|
|
661
|
+
await options.transactionFailureInjector?.(stage === "write" ? "before-temp-write" : "before-rollback");
|
|
662
|
+
await assertApplied?.();
|
|
663
|
+
await assertSnapshotCurrent(expectedCurrent);
|
|
664
|
+
handle = await open(temporaryPath, "wx", mutation.snapshot.mode);
|
|
665
|
+
temporaryCreated = true;
|
|
666
|
+
await handle.writeFile(content);
|
|
667
|
+
await chmod(temporaryPath, mutation.snapshot.mode);
|
|
668
|
+
await syncUninstallRegularFile("replacement-temporary", handle, options);
|
|
669
|
+
await handle.close();
|
|
670
|
+
handle = undefined;
|
|
671
|
+
temporarySnapshot = await readFileSnapshot(temporaryPath, snapshotReadOptions(mutation.snapshot));
|
|
672
|
+
if (temporarySnapshot.bytes === null ||
|
|
673
|
+
temporarySnapshot.mode !== mutation.snapshot.mode ||
|
|
674
|
+
!temporarySnapshot.bytes.equals(content)) {
|
|
675
|
+
throw new Error(`Read-back verification failed for replacement temporary ${temporaryPath}.`);
|
|
676
|
+
}
|
|
677
|
+
await options.transactionFailureInjector?.(stage === "write" ? "before-rename" : "before-rollback-rename");
|
|
678
|
+
await assertApplied?.();
|
|
679
|
+
await assertControlledTopologyCurrent(mutation.snapshot.topology);
|
|
680
|
+
await assertSnapshotCurrent(expectedCurrent);
|
|
681
|
+
await assertSnapshotCurrent(temporarySnapshot);
|
|
682
|
+
await options.transactionFailureInjector?.(stage === "write"
|
|
683
|
+
? "after-final-rename-validation"
|
|
684
|
+
: "after-final-restore-validation");
|
|
685
|
+
if (!temporarySnapshot) {
|
|
686
|
+
throw new Error(`Replacement temporary ${temporaryPath} was not fully captured before install.`);
|
|
687
|
+
}
|
|
688
|
+
claimPath = transactionClaimPath(mutation.snapshot.path);
|
|
689
|
+
const controlledRoot = mutation.snapshot.topology?.root;
|
|
690
|
+
if (expectedCurrent.bytes !== null && controlledRoot) {
|
|
691
|
+
recordRegularFileSyncOutcome(options.durabilityTracker, await persistNativeHookClaimJournal(controlledRoot, {
|
|
692
|
+
canonicalPath: mutation.snapshot.path,
|
|
693
|
+
claimPath,
|
|
694
|
+
before: expectedCurrent.bytes,
|
|
695
|
+
after: content,
|
|
696
|
+
}));
|
|
697
|
+
journaledClaim = true;
|
|
698
|
+
await rename(mutation.snapshot.path, claimPath);
|
|
699
|
+
claimCreated = true;
|
|
700
|
+
await syncNativeHookClaimParent(claimPath);
|
|
701
|
+
await assertSnapshotAtPath(claimPath, expectedCurrent, "replacement claim");
|
|
702
|
+
}
|
|
703
|
+
await copyFile(temporaryPath, mutation.snapshot.path, constants.COPYFILE_EXCL);
|
|
704
|
+
await chmod(mutation.snapshot.path, mutation.snapshot.mode);
|
|
705
|
+
const installedHandle = await open(mutation.snapshot.path, "r");
|
|
706
|
+
try {
|
|
707
|
+
await syncUninstallRegularFile("installed-destination", installedHandle, options);
|
|
708
|
+
}
|
|
709
|
+
finally {
|
|
710
|
+
await installedHandle.close();
|
|
711
|
+
}
|
|
712
|
+
await syncNativeHookClaimParent(mutation.snapshot.path);
|
|
713
|
+
const actual = await captureCurrentSnapshot(mutation.snapshot);
|
|
714
|
+
if (actual.bytes === null || actual.mode !== mutation.snapshot.mode || !actual.bytes.equals(content)) {
|
|
715
|
+
throw new Error(`Read-back verification failed for replacement ${mutation.snapshot.path}.`);
|
|
716
|
+
}
|
|
717
|
+
if (claimCreated && claimPath) {
|
|
718
|
+
await rm(claimPath);
|
|
719
|
+
await syncNativeHookClaimParent(claimPath);
|
|
720
|
+
claimCreated = false;
|
|
721
|
+
}
|
|
722
|
+
if (journaledClaim && controlledRoot) {
|
|
723
|
+
await clearNativeHookClaimJournal(controlledRoot);
|
|
724
|
+
journaledClaim = false;
|
|
725
|
+
}
|
|
726
|
+
await rm(temporaryPath);
|
|
727
|
+
temporaryCreated = false;
|
|
728
|
+
const ownership = renamedDestinationOwnership(actual, mutation.snapshot.path, mutation.snapshot.topology);
|
|
729
|
+
onRename(ownership);
|
|
730
|
+
if (stage === "write") {
|
|
731
|
+
await options.transactionFailureInjector?.("after-rename");
|
|
732
|
+
}
|
|
733
|
+
const verified = await captureRenamedDestinationOwnership(ownership);
|
|
734
|
+
if (stage === "write" && mutation.validate) {
|
|
735
|
+
mutation.validate(decodeStrictUtf8(mutation.snapshot.path, verified.bytes));
|
|
736
|
+
}
|
|
737
|
+
return verified;
|
|
738
|
+
}
|
|
739
|
+
catch (error) {
|
|
740
|
+
await handle?.close().catch(() => undefined);
|
|
741
|
+
if (claimCreated && claimPath) {
|
|
742
|
+
try {
|
|
743
|
+
await restoreUninstallClaim(claimPath, mutation.snapshot.path, options.durabilityTracker);
|
|
744
|
+
await syncNativeHookClaimParent(mutation.snapshot.path);
|
|
745
|
+
claimCreated = false;
|
|
746
|
+
const controlledRoot = mutation.snapshot.topology?.root;
|
|
747
|
+
if (journaledClaim && controlledRoot) {
|
|
748
|
+
await clearNativeHookClaimJournal(controlledRoot);
|
|
749
|
+
journaledClaim = false;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
catch (recoveryError) {
|
|
753
|
+
throw new Error(`Uninstall replacement failed (${error instanceof Error ? error.message : String(error)}) and preserved ${claimPath} for manual recovery: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (temporaryCreated) {
|
|
757
|
+
await removeOwnedTemporary(temporaryPath, temporarySnapshot, error, "temporary", options.durabilityTracker);
|
|
758
|
+
}
|
|
759
|
+
throw error;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
async function stageAndRemoveFile(mutation, execution, options, assertApplied) {
|
|
763
|
+
if (mutation.snapshot.bytes === null || mutation.snapshot.mode === null) {
|
|
764
|
+
throw new Error(`Refusing to remove ${mutation.snapshot.path}: uninstall did not plan a regular-file snapshot.`);
|
|
765
|
+
}
|
|
766
|
+
const stagedPath = transactionTemporaryPath(mutation.snapshot.path, "delete", options);
|
|
767
|
+
let handle;
|
|
768
|
+
let stagedCreated = false;
|
|
769
|
+
try {
|
|
770
|
+
await options.transactionFailureInjector?.("before-temp-write");
|
|
771
|
+
await assertApplied();
|
|
772
|
+
await assertSnapshotCurrent(mutation.snapshot);
|
|
773
|
+
handle = await open(stagedPath, "wx", mutation.snapshot.mode);
|
|
774
|
+
stagedCreated = true;
|
|
775
|
+
await handle.writeFile(mutation.snapshot.bytes);
|
|
776
|
+
await chmod(stagedPath, mutation.snapshot.mode);
|
|
777
|
+
await syncUninstallRegularFile("staged-deletion", handle, options);
|
|
778
|
+
await handle.close();
|
|
779
|
+
handle = undefined;
|
|
780
|
+
const stagedDeletion = await readFileSnapshot(stagedPath, snapshotReadOptions(mutation.snapshot));
|
|
781
|
+
await assertSnapshotMatchesPlannedContent(stagedDeletion, mutation.snapshot, "staged deletion");
|
|
782
|
+
execution.stagedDeletion = stagedDeletion;
|
|
783
|
+
await options.transactionFailureInjector?.("before-remove");
|
|
784
|
+
await assertControlledTopologyCurrent(mutation.snapshot.topology);
|
|
785
|
+
await assertSnapshotCurrent(mutation.snapshot);
|
|
786
|
+
await assertSnapshotCurrent(stagedDeletion);
|
|
787
|
+
await assertApplied();
|
|
788
|
+
await options.transactionFailureInjector?.("after-final-remove-validation");
|
|
789
|
+
await assertSnapshotCurrent(stagedDeletion);
|
|
790
|
+
const claimPath = transactionClaimPath(mutation.snapshot.path);
|
|
791
|
+
const controlledRoot = mutation.snapshot.topology?.root;
|
|
792
|
+
if (controlledRoot && mutation.snapshot.bytes !== null) {
|
|
793
|
+
recordRegularFileSyncOutcome(options.durabilityTracker, await persistNativeHookClaimJournal(controlledRoot, {
|
|
794
|
+
canonicalPath: mutation.snapshot.path,
|
|
795
|
+
claimPath,
|
|
796
|
+
before: mutation.snapshot.bytes,
|
|
797
|
+
after: null,
|
|
798
|
+
}));
|
|
799
|
+
}
|
|
800
|
+
await rename(mutation.snapshot.path, claimPath);
|
|
801
|
+
if (controlledRoot)
|
|
802
|
+
await syncNativeHookClaimParent(claimPath);
|
|
803
|
+
execution.appliedSnapshot = {
|
|
804
|
+
path: mutation.snapshot.path,
|
|
805
|
+
content: null,
|
|
806
|
+
bytes: null,
|
|
807
|
+
mode: null,
|
|
808
|
+
identity: null,
|
|
809
|
+
topology: mutation.snapshot.topology,
|
|
810
|
+
};
|
|
811
|
+
execution.phase = "destructive";
|
|
812
|
+
try {
|
|
813
|
+
await assertSnapshotAtPath(claimPath, mutation.snapshot, "removal claim");
|
|
814
|
+
}
|
|
815
|
+
catch (error) {
|
|
816
|
+
try {
|
|
817
|
+
await restoreUninstallClaim(claimPath, mutation.snapshot.path, options.durabilityTracker);
|
|
818
|
+
if (controlledRoot)
|
|
819
|
+
await syncNativeHookClaimParent(mutation.snapshot.path);
|
|
820
|
+
if (controlledRoot)
|
|
821
|
+
await clearNativeHookClaimJournal(controlledRoot);
|
|
822
|
+
execution.appliedSnapshot = undefined;
|
|
823
|
+
execution.phase = "prepared";
|
|
824
|
+
}
|
|
825
|
+
catch (recoveryError) {
|
|
826
|
+
throw new Error(`Uninstall removal claim failed (${error instanceof Error ? error.message : String(error)}) and preserved ${claimPath} for manual recovery: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`);
|
|
827
|
+
}
|
|
828
|
+
throw error;
|
|
829
|
+
}
|
|
830
|
+
await rm(claimPath);
|
|
831
|
+
if (controlledRoot)
|
|
832
|
+
await syncNativeHookClaimParent(claimPath);
|
|
833
|
+
if (controlledRoot)
|
|
834
|
+
await clearNativeHookClaimJournal(controlledRoot);
|
|
835
|
+
await options.transactionFailureInjector?.("after-remove");
|
|
836
|
+
await assertControlledTopologyCurrent(mutation.snapshot.topology);
|
|
837
|
+
const absent = await captureCurrentSnapshot(mutation.snapshot);
|
|
838
|
+
if (absent.bytes !== null) {
|
|
839
|
+
throw new Error(`Read-back verification failed for ${mutation.snapshot.path}: expected absence.`);
|
|
840
|
+
}
|
|
841
|
+
execution.phase = "verified";
|
|
842
|
+
}
|
|
843
|
+
catch (error) {
|
|
844
|
+
await handle?.close().catch(() => undefined);
|
|
845
|
+
if (stagedCreated && execution.phase === "prepared") {
|
|
846
|
+
await removeOwnedTemporary(stagedPath, execution.stagedDeletion, error, "staged deletion", options.durabilityTracker);
|
|
847
|
+
}
|
|
848
|
+
throw error;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
async function applyFileMutation(execution, executions, options) {
|
|
852
|
+
const { mutation } = execution;
|
|
853
|
+
if (mutation.finalContent === null) {
|
|
854
|
+
await stageAndRemoveFile(mutation, execution, options, () => assertAppliedTransactionSnapshots(executions));
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
const appliedSnapshot = await atomicReplaceFile(mutation, mutation.snapshot, Buffer.from(mutation.finalContent, "utf-8"), options, "write", (ownership) => {
|
|
858
|
+
execution.renamedOwnership = ownership;
|
|
859
|
+
execution.phase = "destructive";
|
|
860
|
+
}, () => assertAppliedTransactionSnapshots(executions));
|
|
861
|
+
execution.appliedSnapshot = appliedSnapshot;
|
|
862
|
+
execution.renamedOwnership = undefined;
|
|
863
|
+
execution.phase = "verified";
|
|
864
|
+
}
|
|
865
|
+
function mutationStage(kind) {
|
|
866
|
+
switch (kind) {
|
|
867
|
+
case "hooks":
|
|
868
|
+
return "before-hooks-commit";
|
|
869
|
+
case "shim":
|
|
870
|
+
return "before-shim-removal";
|
|
871
|
+
case "config":
|
|
872
|
+
return "before-config-commit";
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
async function captureRollbackOwnedSnapshot(execution) {
|
|
876
|
+
if (execution.appliedSnapshot) {
|
|
877
|
+
await assertSnapshotCurrent(execution.appliedSnapshot);
|
|
878
|
+
return execution.appliedSnapshot;
|
|
879
|
+
}
|
|
880
|
+
if (execution.renamedOwnership) {
|
|
881
|
+
return captureRenamedDestinationOwnership(execution.renamedOwnership);
|
|
882
|
+
}
|
|
883
|
+
throw new Error(`Refusing stale rollback for ${execution.mutation.snapshot.path}: the mutation did not produce a verifiable state.`);
|
|
884
|
+
}
|
|
885
|
+
async function restoreFileSnapshot(execution, options, assertRollbackState) {
|
|
886
|
+
const { mutation } = execution;
|
|
887
|
+
const appliedSnapshot = await captureRollbackOwnedSnapshot(execution);
|
|
888
|
+
if (execution.stagedDeletion && !execution.stagedDeletionCleaned) {
|
|
889
|
+
await assertSnapshotCurrent(execution.stagedDeletion);
|
|
890
|
+
}
|
|
891
|
+
if (mutation.snapshot.bytes === null) {
|
|
892
|
+
await options.transactionFailureInjector?.("before-rollback");
|
|
893
|
+
await options.transactionFailureInjector?.("before-rollback-remove");
|
|
894
|
+
await assertRollbackState();
|
|
895
|
+
await assertControlledTopologyCurrent(mutation.snapshot.topology);
|
|
896
|
+
await assertSnapshotCurrent(appliedSnapshot);
|
|
897
|
+
await options.transactionFailureInjector?.("after-final-restore-validation");
|
|
898
|
+
const claimPath = transactionClaimPath(mutation.snapshot.path);
|
|
899
|
+
await rename(mutation.snapshot.path, claimPath);
|
|
900
|
+
execution.appliedSnapshot = {
|
|
901
|
+
path: mutation.snapshot.path,
|
|
902
|
+
content: null,
|
|
903
|
+
bytes: null,
|
|
904
|
+
mode: null,
|
|
905
|
+
identity: null,
|
|
906
|
+
topology: mutation.snapshot.topology,
|
|
907
|
+
};
|
|
908
|
+
execution.renamedOwnership = undefined;
|
|
909
|
+
try {
|
|
910
|
+
await assertSnapshotAtPath(claimPath, appliedSnapshot, "rollback removal claim");
|
|
911
|
+
}
|
|
912
|
+
catch (error) {
|
|
913
|
+
try {
|
|
914
|
+
await restoreUninstallClaim(claimPath, mutation.snapshot.path, options.durabilityTracker);
|
|
915
|
+
}
|
|
916
|
+
catch (recoveryError) {
|
|
917
|
+
throw new Error(`Uninstall rollback removal claim failed (${error instanceof Error ? error.message : String(error)}) and preserved ${claimPath} for manual recovery: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`);
|
|
918
|
+
}
|
|
919
|
+
throw error;
|
|
920
|
+
}
|
|
921
|
+
await rm(claimPath);
|
|
922
|
+
const absent = await captureCurrentSnapshot(mutation.snapshot);
|
|
923
|
+
if (absent.bytes !== null) {
|
|
924
|
+
throw new Error(`Uninstall rollback mismatch for ${mutation.snapshot.path}: expected absence.`);
|
|
925
|
+
}
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
const restored = await atomicReplaceFile(mutation, appliedSnapshot, mutation.snapshot.bytes, options, "rollback", (ownership) => {
|
|
929
|
+
execution.renamedOwnership = ownership;
|
|
930
|
+
}, assertRollbackState);
|
|
931
|
+
execution.appliedSnapshot = restored;
|
|
932
|
+
execution.renamedOwnership = undefined;
|
|
933
|
+
await assertSnapshotMatchesPlannedContent(restored, mutation.snapshot, "rollback");
|
|
934
|
+
}
|
|
935
|
+
async function cleanupStagedDeletions(executions, options, stage, transaction, assertRollbackState) {
|
|
936
|
+
for (const execution of executions) {
|
|
937
|
+
if (!execution.stagedDeletion || execution.stagedDeletionCleaned)
|
|
938
|
+
continue;
|
|
939
|
+
if (stage === "rollback") {
|
|
940
|
+
await options.transactionFailureInjector?.("before-rollback-remove");
|
|
941
|
+
}
|
|
942
|
+
await options.transactionFailureInjector?.("before-staged-cleanup");
|
|
943
|
+
if (transaction) {
|
|
944
|
+
await assertUnmutatedTransactionPreconditions(transaction, executions);
|
|
945
|
+
await assertAppliedTransactionSnapshots(executions);
|
|
946
|
+
}
|
|
947
|
+
await assertRollbackState?.();
|
|
948
|
+
const stagedDeletion = execution.stagedDeletion;
|
|
949
|
+
await assertSnapshotCurrent(stagedDeletion);
|
|
950
|
+
const claimPath = transactionClaimPath(stagedDeletion.path);
|
|
951
|
+
await rename(stagedDeletion.path, claimPath);
|
|
952
|
+
try {
|
|
953
|
+
await assertSnapshotAtPath(claimPath, stagedDeletion, "staged deletion cleanup claim");
|
|
954
|
+
}
|
|
955
|
+
catch (error) {
|
|
956
|
+
try {
|
|
957
|
+
await restoreUninstallClaim(claimPath, stagedDeletion.path, options.durabilityTracker);
|
|
958
|
+
}
|
|
959
|
+
catch (recoveryError) {
|
|
960
|
+
throw new Error(`Uninstall staged deletion cleanup claim failed (${error instanceof Error ? error.message : String(error)}) and preserved ${claimPath} for manual recovery: ${recoveryError instanceof Error ? recoveryError.message : String(recoveryError)}`);
|
|
961
|
+
}
|
|
962
|
+
throw error;
|
|
963
|
+
}
|
|
964
|
+
await rm(claimPath);
|
|
965
|
+
execution.stagedDeletionCleaned = true;
|
|
966
|
+
await assertRollbackState?.();
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
async function assertRollbackTransactionState(executions) {
|
|
970
|
+
for (const execution of executions) {
|
|
971
|
+
if (execution.phase === "prepared")
|
|
972
|
+
continue;
|
|
973
|
+
if (execution.stagedDeletion && !execution.stagedDeletionCleaned) {
|
|
974
|
+
await assertSnapshotCurrent(execution.stagedDeletion);
|
|
975
|
+
}
|
|
976
|
+
await captureRollbackOwnedSnapshot(execution);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
async function rollbackArtifactMutations(executions, options) {
|
|
980
|
+
const failures = [];
|
|
981
|
+
const restored = [];
|
|
982
|
+
try {
|
|
983
|
+
await assertRollbackTransactionState(executions);
|
|
984
|
+
}
|
|
985
|
+
catch (error) {
|
|
986
|
+
failures.push(`recovery preflight: ${String(error)}`);
|
|
987
|
+
}
|
|
988
|
+
if (failures.length === 0) {
|
|
989
|
+
for (const execution of [...executions].reverse()) {
|
|
990
|
+
if (execution.phase === "prepared")
|
|
991
|
+
continue;
|
|
992
|
+
try {
|
|
993
|
+
await assertRollbackTransactionState(executions);
|
|
994
|
+
await restoreFileSnapshot(execution, options, () => assertRollbackTransactionState(executions));
|
|
995
|
+
restored.push(execution);
|
|
996
|
+
await assertRollbackTransactionState(executions);
|
|
997
|
+
}
|
|
998
|
+
catch (error) {
|
|
999
|
+
failures.push(`${execution.mutation.kind}: ${String(error)}`);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
if (failures.length === 0) {
|
|
1004
|
+
try {
|
|
1005
|
+
await assertRollbackTransactionState(executions);
|
|
1006
|
+
await cleanupStagedDeletions(restored, options, "rollback", undefined, () => assertRollbackTransactionState(executions));
|
|
1007
|
+
await assertRollbackTransactionState(executions);
|
|
1008
|
+
}
|
|
1009
|
+
catch (error) {
|
|
1010
|
+
failures.push(`staged deletion cleanup: ${String(error)}`);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
if (failures.length > 0) {
|
|
1014
|
+
throw new Error(`Uninstall artifact rollback failed; manual recovery is required: ${failures.join("; ")}`);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
async function assertUnmutatedTransactionPreconditions(transaction, executions) {
|
|
1018
|
+
const mutatedPaths = new Set(executions
|
|
1019
|
+
.filter((execution) => execution.phase !== "prepared")
|
|
1020
|
+
.map((execution) => execution.mutation.snapshot.path));
|
|
1021
|
+
await assertSnapshotsCurrent(transaction.preconditions.filter((snapshot) => !mutatedPaths.has(snapshot.path)));
|
|
1022
|
+
}
|
|
1023
|
+
async function assertAppliedTransactionSnapshots(executions) {
|
|
1024
|
+
for (const execution of executions) {
|
|
1025
|
+
if (execution.phase === "prepared")
|
|
1026
|
+
continue;
|
|
1027
|
+
if (!execution.appliedSnapshot) {
|
|
1028
|
+
throw new Error(`Refusing uninstall because ${execution.mutation.snapshot.path} did not register an applied snapshot.`);
|
|
1029
|
+
}
|
|
1030
|
+
await assertSnapshotCurrent(execution.appliedSnapshot);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
async function commitUninstallArtifactTransaction(transaction, options) {
|
|
1034
|
+
const mutations = [transaction.hooks, transaction.shim, transaction.config]
|
|
1035
|
+
.filter((mutation) => mutation !== undefined);
|
|
1036
|
+
for (const mutation of mutations) {
|
|
1037
|
+
if (mutation.finalContent !== null)
|
|
1038
|
+
mutation.validate?.(mutation.finalContent);
|
|
1039
|
+
}
|
|
1040
|
+
await assertSnapshotsCurrent(transaction.preconditions);
|
|
1041
|
+
if (mutations.length === 0)
|
|
1042
|
+
return;
|
|
1043
|
+
const executions = [];
|
|
1044
|
+
let stagedCleanupStarted = false;
|
|
1045
|
+
try {
|
|
1046
|
+
for (const mutation of mutations) {
|
|
1047
|
+
await options.transactionFailureInjector?.(mutationStage(mutation.kind));
|
|
1048
|
+
await assertUnmutatedTransactionPreconditions(transaction, executions);
|
|
1049
|
+
await assertAppliedTransactionSnapshots(executions);
|
|
1050
|
+
const execution = { mutation, phase: "prepared" };
|
|
1051
|
+
executions.push(execution);
|
|
1052
|
+
await applyFileMutation(execution, executions, options);
|
|
1053
|
+
if (mutation.kind === "config") {
|
|
1054
|
+
await options.transactionFailureInjector?.("after-config-commit");
|
|
1055
|
+
}
|
|
1056
|
+
await assertUnmutatedTransactionPreconditions(transaction, executions);
|
|
1057
|
+
await assertAppliedTransactionSnapshots(executions);
|
|
1058
|
+
}
|
|
1059
|
+
await assertUnmutatedTransactionPreconditions(transaction, executions);
|
|
1060
|
+
await assertAppliedTransactionSnapshots(executions);
|
|
1061
|
+
stagedCleanupStarted = true;
|
|
1062
|
+
await cleanupStagedDeletions(executions, options, "commit", transaction);
|
|
1063
|
+
await options.transactionFailureInjector?.("after-staged-cleanup");
|
|
1064
|
+
await assertUnmutatedTransactionPreconditions(transaction, executions);
|
|
1065
|
+
await assertAppliedTransactionSnapshots(executions);
|
|
1066
|
+
}
|
|
1067
|
+
catch (error) {
|
|
1068
|
+
if (stagedCleanupStarted &&
|
|
1069
|
+
executions.some((execution) => execution.stagedDeletionCleaned)) {
|
|
1070
|
+
throw new Error(`Uninstall artifact transaction committed but staged deletion cleanup failed during finalization: ${String(error)}`);
|
|
1071
|
+
}
|
|
1072
|
+
try {
|
|
1073
|
+
await rollbackArtifactMutations(executions, options);
|
|
1074
|
+
}
|
|
1075
|
+
catch (rollbackError) {
|
|
1076
|
+
throw new Error(`Uninstall artifact transaction failed (${String(error)}); ${String(rollbackError)}`);
|
|
1077
|
+
}
|
|
1078
|
+
throw error;
|
|
279
1079
|
}
|
|
280
|
-
return true;
|
|
281
1080
|
}
|
|
282
1081
|
async function removeCacheDirectory(projectRoot, options) {
|
|
283
1082
|
const omxDir = join(projectRoot, ".omx");
|
|
@@ -331,7 +1130,7 @@ function printSummary(summary, dryRun) {
|
|
|
331
1130
|
console.log(" Feature flags (child_agents_md, goals; multi_agent and hooks are preserved when user-owned)");
|
|
332
1131
|
}
|
|
333
1132
|
}
|
|
334
|
-
else if (
|
|
1133
|
+
else if (summary.mcpServersRemoved.length === 0) {
|
|
335
1134
|
console.log(" config.toml: no OMX entries found (or --keep-config used)");
|
|
336
1135
|
}
|
|
337
1136
|
if (summary.hooksFileRemoved) {
|
|
@@ -373,6 +1172,77 @@ export async function uninstall(options = {}) {
|
|
|
373
1172
|
// Resolve scope (explicit --scope overrides persisted scope)
|
|
374
1173
|
const scope = options.scope ?? readPersistedSetupScope(projectRoot) ?? "user";
|
|
375
1174
|
const scopeDirs = resolveScopeDirectories(scope, projectRoot);
|
|
1175
|
+
if (!dryRun) {
|
|
1176
|
+
const recoveryTracker = { degraded: false };
|
|
1177
|
+
const recovery = await recoverNativeHookClaimJournal(scopeDirs.codexHomeDir, uninstallClaimJournalDurabilityOverride
|
|
1178
|
+
?? createNativeHookClaimJournalDurability(options.transactionPlatform ?? process.platform));
|
|
1179
|
+
recordRegularFileSyncOutcome(recoveryTracker, recovery.outcome);
|
|
1180
|
+
emitDegradedDurabilityWarning("native-hook claim-journal recovery", recoveryTracker);
|
|
1181
|
+
}
|
|
1182
|
+
const transactionPlatform = options.transactionPlatform ?? process.platform;
|
|
1183
|
+
// Precompute and validate every artifact before the first uninstall write.
|
|
1184
|
+
const hooksSnapshot = await readFileSnapshot(scopeDirs.codexHooksFile, {
|
|
1185
|
+
controlledRoot: scopeDirs.codexHomeDir,
|
|
1186
|
+
});
|
|
1187
|
+
const configSnapshot = await readFileSnapshot(scopeDirs.codexConfigFile, {
|
|
1188
|
+
controlledRoot: scopeDirs.codexHomeDir,
|
|
1189
|
+
});
|
|
1190
|
+
const hooksRemoval = await planHooksRemoval(hooksSnapshot, pkgRoot, transactionPlatform, scopeDirs.codexHomeDir);
|
|
1191
|
+
const notifyMetadata = keepConfig
|
|
1192
|
+
? undefined
|
|
1193
|
+
: await planNotifyMetadata(configSnapshot, scopeDirs.codexHomeDir);
|
|
1194
|
+
const preserveHooksFeatureFlag = hooksRemoval.plan?.hasForeignHooks ?? false;
|
|
1195
|
+
const configCleanup = keepConfig
|
|
1196
|
+
? undefined
|
|
1197
|
+
: await planConfigCleanup(configSnapshot, {
|
|
1198
|
+
preserveHooksFeatureFlag,
|
|
1199
|
+
priorHookTrustState: hooksRemoval.plan?.priorTrustState,
|
|
1200
|
+
finalHookTrustState: hooksRemoval.plan?.finalTrustState,
|
|
1201
|
+
notifyMetadata,
|
|
1202
|
+
codexFeaturesProbe: options.codexFeaturesProbe,
|
|
1203
|
+
codexVersionProbe: options.codexVersionProbe,
|
|
1204
|
+
});
|
|
1205
|
+
const artifactTransaction = {
|
|
1206
|
+
preconditions: [
|
|
1207
|
+
hooksRemoval.hooks,
|
|
1208
|
+
...(hooksRemoval.shim
|
|
1209
|
+
? [hooksRemoval.shim]
|
|
1210
|
+
: hooksRemoval.preservedShimPrecondition
|
|
1211
|
+
? [hooksRemoval.preservedShimPrecondition]
|
|
1212
|
+
: []),
|
|
1213
|
+
configSnapshot,
|
|
1214
|
+
...(notifyMetadata ? [notifyMetadata.snapshot] : []),
|
|
1215
|
+
],
|
|
1216
|
+
...(hooksRemoval.plan?.changed
|
|
1217
|
+
? {
|
|
1218
|
+
hooks: {
|
|
1219
|
+
kind: "hooks",
|
|
1220
|
+
snapshot: hooksRemoval.hooks,
|
|
1221
|
+
finalContent: hooksRemoval.plan.finalContent,
|
|
1222
|
+
validate: assertValidHooksJson,
|
|
1223
|
+
},
|
|
1224
|
+
}
|
|
1225
|
+
: {}),
|
|
1226
|
+
...(hooksRemoval.shim !== undefined && hooksRemoval.shim.bytes !== null
|
|
1227
|
+
? {
|
|
1228
|
+
shim: {
|
|
1229
|
+
kind: "shim",
|
|
1230
|
+
snapshot: hooksRemoval.shim,
|
|
1231
|
+
finalContent: null,
|
|
1232
|
+
},
|
|
1233
|
+
}
|
|
1234
|
+
: {}),
|
|
1235
|
+
...(configCleanup?.result.configCleaned && configCleanup.finalContent !== null
|
|
1236
|
+
? {
|
|
1237
|
+
config: {
|
|
1238
|
+
kind: "config",
|
|
1239
|
+
snapshot: configCleanup.config,
|
|
1240
|
+
finalContent: configCleanup.finalContent,
|
|
1241
|
+
validate: assertValidToml,
|
|
1242
|
+
},
|
|
1243
|
+
}
|
|
1244
|
+
: {}),
|
|
1245
|
+
};
|
|
376
1246
|
console.log("oh-my-codex uninstall");
|
|
377
1247
|
console.log("=====================\n");
|
|
378
1248
|
if (dryRun) {
|
|
@@ -395,31 +1265,52 @@ export async function uninstall(options = {}) {
|
|
|
395
1265
|
legacySkillRootWarning: null,
|
|
396
1266
|
};
|
|
397
1267
|
summary.legacySkillRootWarning = await detectLegacySkillRootWarning(scope);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
if (
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
1268
|
+
summary.hooksFileRemoved =
|
|
1269
|
+
artifactTransaction.hooks !== undefined || artifactTransaction.shim !== undefined;
|
|
1270
|
+
if (configCleanup)
|
|
1271
|
+
Object.assign(summary, configCleanup.result);
|
|
1272
|
+
// Hooks, proof-owned shim, and config are one compensating transaction. The
|
|
1273
|
+
// config mutation is intentionally last so hooks never reference unwritten trust.
|
|
1274
|
+
console.log("[1/6] Removing native hooks artifact...");
|
|
1275
|
+
if (!keepConfig)
|
|
1276
|
+
console.log("[2/6] Cleaning config.toml...");
|
|
1277
|
+
if (!dryRun) {
|
|
1278
|
+
const mutationTracker = { degraded: false };
|
|
1279
|
+
await commitUninstallArtifactTransaction(artifactTransaction, {
|
|
1280
|
+
transactionFailureInjector: options.transactionFailureInjector,
|
|
1281
|
+
transactionTemporaryPath: options.transactionTemporaryPath,
|
|
1282
|
+
transactionPlatform,
|
|
1283
|
+
regularFileSyncForTest: options.regularFileSyncForTest,
|
|
1284
|
+
durabilityTracker: mutationTracker,
|
|
411
1285
|
});
|
|
412
|
-
|
|
1286
|
+
emitDegradedDurabilityWarning("native-hook uninstall", mutationTracker);
|
|
1287
|
+
}
|
|
1288
|
+
if (verbose) {
|
|
1289
|
+
if (artifactTransaction.hooks) {
|
|
1290
|
+
console.log(` ${dryRun ? "Would clean" : artifactTransaction.hooks.finalContent === null ? "Removed" : "Cleaned"} ${basename(scopeDirs.codexHooksFile)}`);
|
|
1291
|
+
}
|
|
1292
|
+
if (artifactTransaction.shim) {
|
|
1293
|
+
console.log(` ${dryRun ? "Would remove" : "Removed"} ${basename(artifactTransaction.shim.snapshot.path)}`);
|
|
1294
|
+
}
|
|
413
1295
|
}
|
|
414
|
-
console.log();
|
|
415
|
-
// Step 2: Remove installed prompts
|
|
416
|
-
console.log("[2/6] Removing native hooks artifact...");
|
|
417
|
-
summary.hooksFileRemoved = await removeHooksFile(scopeDirs.codexHooksFile, {
|
|
418
|
-
dryRun,
|
|
419
|
-
verbose,
|
|
420
|
-
});
|
|
421
1296
|
console.log(` ${dryRun ? "Would clean" : "Cleaned"} ${summary.hooksFileRemoved ? 1 : 0} hooks artifact(s).`);
|
|
422
1297
|
console.log();
|
|
1298
|
+
// Step 2: config cleanup is calculated before Step 1 and committed last.
|
|
1299
|
+
if (keepConfig) {
|
|
1300
|
+
console.log("[2/6] Skipping config.toml cleanup (--keep-config).");
|
|
1301
|
+
}
|
|
1302
|
+
else if (verbose) {
|
|
1303
|
+
if (configCleanup?.config.content === null) {
|
|
1304
|
+
console.log(" config.toml not found, skipping.");
|
|
1305
|
+
}
|
|
1306
|
+
else if (configCleanup?.result.configCleaned) {
|
|
1307
|
+
console.log(` ${dryRun ? "Would clean" : "Cleaned"} ${scopeDirs.codexConfigFile}`);
|
|
1308
|
+
}
|
|
1309
|
+
else {
|
|
1310
|
+
console.log(" No OMX config entries found.");
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
console.log();
|
|
423
1314
|
// Step 3: Remove installed prompts
|
|
424
1315
|
console.log("[3/6] Removing agent prompts...");
|
|
425
1316
|
summary.promptsRemoved = await removeInstalledPrompts(scopeDirs.promptsDir, pkgRoot, { dryRun, verbose });
|