oh-my-codex 0.20.2 → 0.20.5
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 +36 -18
- package/Cargo.toml +1 -1
- package/README.md +28 -2
- package/crates/omx-runtime/Cargo.toml +4 -0
- package/crates/omx-runtime/src/main.rs +415 -2
- package/crates/omx-runtime/tests/execution.rs +483 -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__/herdr-target.test.d.ts +2 -0
- package/dist/adapt/__tests__/herdr-target.test.d.ts.map +1 -0
- package/dist/adapt/__tests__/herdr-target.test.js +72 -0
- package/dist/adapt/__tests__/herdr-target.test.js.map +1 -0
- package/dist/adapt/contracts.d.ts +1 -1
- package/dist/adapt/contracts.d.ts.map +1 -1
- package/dist/adapt/contracts.js +1 -1
- package/dist/adapt/contracts.js.map +1 -1
- package/dist/adapt/herdr/__tests__/authority.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/authority.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/authority.test.js +49 -0
- package/dist/adapt/herdr/__tests__/authority.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/bridge.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/bridge.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/bridge.test.js +176 -0
- package/dist/adapt/herdr/__tests__/bridge.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.js +45 -0
- package/dist/adapt/herdr/__tests__/sanitize.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/semantic.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/semantic.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/semantic.test.js +130 -0
- package/dist/adapt/herdr/__tests__/semantic.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.js +54 -0
- package/dist/adapt/herdr/__tests__/seq-store.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.js +104 -0
- package/dist/adapt/herdr/__tests__/socket-live.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/team-map.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/team-map.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/team-map.test.js +46 -0
- package/dist/adapt/herdr/__tests__/team-map.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/transport.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/transport.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/transport.test.js +160 -0
- package/dist/adapt/herdr/__tests__/transport.test.js.map +1 -0
- package/dist/adapt/herdr/__tests__/wiring.test.d.ts +2 -0
- package/dist/adapt/herdr/__tests__/wiring.test.d.ts.map +1 -0
- package/dist/adapt/herdr/__tests__/wiring.test.js +118 -0
- package/dist/adapt/herdr/__tests__/wiring.test.js.map +1 -0
- package/dist/adapt/herdr/authority.d.ts +34 -0
- package/dist/adapt/herdr/authority.d.ts.map +1 -0
- package/dist/adapt/herdr/authority.js +71 -0
- package/dist/adapt/herdr/authority.js.map +1 -0
- package/dist/adapt/herdr/bridge.d.ts +84 -0
- package/dist/adapt/herdr/bridge.d.ts.map +1 -0
- package/dist/adapt/herdr/bridge.js +222 -0
- package/dist/adapt/herdr/bridge.js.map +1 -0
- package/dist/adapt/herdr/sanitize.d.ts +20 -0
- package/dist/adapt/herdr/sanitize.d.ts.map +1 -0
- package/dist/adapt/herdr/sanitize.js +70 -0
- package/dist/adapt/herdr/sanitize.js.map +1 -0
- package/dist/adapt/herdr/semantic.d.ts +67 -0
- package/dist/adapt/herdr/semantic.d.ts.map +1 -0
- package/dist/adapt/herdr/semantic.js +170 -0
- package/dist/adapt/herdr/semantic.js.map +1 -0
- package/dist/adapt/herdr/seq-store.d.ts +32 -0
- package/dist/adapt/herdr/seq-store.d.ts.map +1 -0
- package/dist/adapt/herdr/seq-store.js +126 -0
- package/dist/adapt/herdr/seq-store.js.map +1 -0
- package/dist/adapt/herdr/team-map.d.ts +30 -0
- package/dist/adapt/herdr/team-map.d.ts.map +1 -0
- package/dist/adapt/herdr/team-map.js +37 -0
- package/dist/adapt/herdr/team-map.js.map +1 -0
- package/dist/adapt/herdr/transport.d.ts +115 -0
- package/dist/adapt/herdr/transport.d.ts.map +1 -0
- package/dist/adapt/herdr/transport.js +260 -0
- package/dist/adapt/herdr/transport.js.map +1 -0
- package/dist/adapt/herdr/wiring.d.ts +24 -0
- package/dist/adapt/herdr/wiring.d.ts.map +1 -0
- package/dist/adapt/herdr/wiring.js +62 -0
- package/dist/adapt/herdr/wiring.js.map +1 -0
- package/dist/adapt/herdr.d.ts +19 -0
- package/dist/adapt/herdr.d.ts.map +1 -0
- package/dist/adapt/herdr.js +115 -0
- package/dist/adapt/herdr.js.map +1 -0
- package/dist/adapt/index.d.ts +4 -0
- package/dist/adapt/index.d.ts.map +1 -1
- package/dist/adapt/index.js +48 -0
- package/dist/adapt/index.js.map +1 -1
- package/dist/adapt/registry.d.ts.map +1 -1
- package/dist/adapt/registry.js +11 -0
- package/dist/adapt/registry.js.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.js +60 -1
- package/dist/auth/__tests__/hotswap.test.js.map +1 -1
- package/dist/auth/__tests__/storage.test.js +33 -1
- package/dist/auth/__tests__/storage.test.js.map +1 -1
- package/dist/auth/hotswap.d.ts +22 -2
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +107 -22
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/auth/storage.js +1 -1
- package/dist/auth/storage.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +86 -1333
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
- package/dist/autopilot/ralplan-gate.js +7 -6
- package/dist/autopilot/ralplan-gate.js.map +1 -1
- package/dist/cli/__tests__/agents-init.test.js +4 -23
- package/dist/cli/__tests__/agents-init.test.js.map +1 -1
- package/dist/cli/__tests__/api.test.js +61 -24
- package/dist/cli/__tests__/api.test.js.map +1 -1
- package/dist/cli/__tests__/auth.test.js +63 -7
- package/dist/cli/__tests__/auth.test.js.map +1 -1
- package/dist/cli/__tests__/codex-feature-probe.test.js +66 -1
- package/dist/cli/__tests__/codex-feature-probe.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +150 -2
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/detached-leader-teardown.test.d.ts +2 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.d.ts.map +1 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.js +473 -0
- package/dist/cli/__tests__/detached-leader-teardown.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.js +103 -0
- package/dist/cli/__tests__/doctor-process-identity-readiness.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.js +139 -0
- package/dist/cli/__tests__/doctor-state-root-binding.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-warning-copy.test.js +135 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +211 -0
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +878 -463
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +1290 -127
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +8 -4
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-assets.test.js +398 -16
- package/dist/cli/__tests__/native-assets.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +132 -6
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -1
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +3 -3
- package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +3 -3
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +49 -164
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.d.ts +2 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.d.ts.map +1 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.js +56 -0
- package/dist/cli/__tests__/ralplan-child-binding-3212.test.js.map +1 -0
- package/dist/cli/__tests__/ralplan.test.js +107 -109
- package/dist/cli/__tests__/ralplan.test.js.map +1 -1
- package/dist/cli/__tests__/resume.test.js +11 -10
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +1118 -43
- 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__/setup-agents-overwrite.test.js +8 -55
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +224 -7
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/sparkshell-cli.test.js +93 -41
- package/dist/cli/__tests__/sparkshell-cli.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +150 -8
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +117 -2
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/uninstall.test.js +95 -4
- package/dist/cli/__tests__/uninstall.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +669 -177
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js +33 -2
- package/dist/cli/__tests__/windows-popup-loop-contract.test.js.map +1 -1
- package/dist/cli/api.d.ts.map +1 -1
- package/dist/cli/api.js +9 -10
- package/dist/cli/api.js.map +1 -1
- package/dist/cli/codex-feature-probe.d.ts +16 -0
- package/dist/cli/codex-feature-probe.d.ts.map +1 -1
- package/dist/cli/codex-feature-probe.js +44 -0
- package/dist/cli/codex-feature-probe.js.map +1 -1
- package/dist/cli/codex-home.d.ts.map +1 -1
- package/dist/cli/codex-home.js +7 -4
- package/dist/cli/codex-home.js.map +1 -1
- package/dist/cli/doctor.d.ts +20 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +290 -3
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +234 -12
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2409 -746
- 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/native-assets.d.ts +25 -0
- package/dist/cli/native-assets.d.ts.map +1 -1
- package/dist/cli/native-assets.js +448 -51
- package/dist/cli/native-assets.js.map +1 -1
- package/dist/cli/native-hook-claim-journal.d.ts +20 -5
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -1
- package/dist/cli/native-hook-claim-journal.js +67 -32
- package/dist/cli/native-hook-claim-journal.js.map +1 -1
- package/dist/cli/package-manager-ownership.d.ts +63 -0
- package/dist/cli/package-manager-ownership.d.ts.map +1 -0
- package/dist/cli/package-manager-ownership.js +323 -0
- package/dist/cli/package-manager-ownership.js.map +1 -0
- package/dist/cli/ralph.js +2 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +5 -7
- package/dist/cli/ralplan.d.ts.map +1 -1
- package/dist/cli/ralplan.js +83 -134
- package/dist/cli/ralplan.js.map +1 -1
- 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 +15 -0
- package/dist/cli/setup-preferences.d.ts.map +1 -1
- package/dist/cli/setup-preferences.js +27 -1
- package/dist/cli/setup-preferences.js.map +1 -1
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +119 -47
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/sparkshell.d.ts.map +1 -1
- package/dist/cli/sparkshell.js +52 -9
- package/dist/cli/sparkshell.js.map +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +2 -2
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/uninstall.d.ts +9 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +71 -30
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/cli/update-worker.d.ts +2 -0
- package/dist/cli/update-worker.d.ts.map +1 -0
- package/dist/cli/update-worker.js +142 -0
- package/dist/cli/update-worker.js.map +1 -0
- package/dist/cli/update.d.ts +14 -22
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +192 -241
- package/dist/cli/update.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +503 -30
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +5 -3
- 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/generator.d.ts +27 -21
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +610 -152
- package/dist/config/generator.js.map +1 -1
- package/dist/config/models.d.ts +12 -2
- 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/goal-workflows/__tests__/codex-goal-snapshot.test.js +25 -0
- package/dist/goal-workflows/__tests__/codex-goal-snapshot.test.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +2 -0
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/agents-overlay.test.js +5 -3
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +27 -4
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.d.ts +2 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.js +172 -0
- package/dist/hooks/__tests__/issue-3293-autopilot-handoff.test.js.map +1 -0
- package/dist/hooks/__tests__/keyword-detector.test.js +176 -37
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +402 -545
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +39 -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 +161 -26
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-cross-worktree-heartbeat.test.js +27 -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 +10 -118
- package/dist/hooks/__tests__/notify-hook-managed-tmux.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js +7 -0
- package/dist/hooks/__tests__/notify-hook-regression-205.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +533 -14
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +159 -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-team-worker-fail-closed.test.js +2 -1
- package/dist/hooks/__tests__/notify-hook-team-worker-fail-closed.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-worker-idle.test.js +44 -4
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js +9 -0
- package/dist/hooks/__tests__/prompt-guidance-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/session.test.js +3130 -365
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +1 -1
- package/dist/hooks/agents-overlay.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js +108 -2
- package/dist/hooks/extensibility/__tests__/dispatcher.test.js.map +1 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.js +151 -1
- package/dist/hooks/extensibility/__tests__/sdk.test.js.map +1 -1
- package/dist/hooks/extensibility/dispatcher.d.ts.map +1 -1
- package/dist/hooks/extensibility/dispatcher.js +20 -3
- package/dist/hooks/extensibility/dispatcher.js.map +1 -1
- package/dist/hooks/extensibility/plugin-runner.js +1 -0
- package/dist/hooks/extensibility/plugin-runner.js.map +1 -1
- package/dist/hooks/extensibility/runtime.d.ts.map +1 -1
- package/dist/hooks/extensibility/runtime.js.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.d.ts +1 -1
- package/dist/hooks/extensibility/sdk/paths.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/paths.js +2 -2
- package/dist/hooks/extensibility/sdk/paths.js.map +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.d.ts +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk/runtime-state.js +55 -15
- package/dist/hooks/extensibility/sdk/runtime-state.js.map +1 -1
- package/dist/hooks/extensibility/sdk.d.ts +1 -0
- package/dist/hooks/extensibility/sdk.d.ts.map +1 -1
- package/dist/hooks/extensibility/sdk.js +1 -1
- package/dist/hooks/extensibility/sdk.js.map +1 -1
- package/dist/hooks/extensibility/types.d.ts +7 -0
- package/dist/hooks/extensibility/types.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.d.ts +10 -3
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +116 -20
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hooks/session.d.ts +204 -14
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1500 -223
- package/dist/hooks/session.js.map +1 -1
- package/dist/hud/__tests__/hud-tmux-injection.test.js +6 -6
- package/dist/hud/__tests__/hud-tmux-injection.test.js.map +1 -1
- package/dist/hud/__tests__/index.test.js +26 -16
- package/dist/hud/__tests__/index.test.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +83 -78
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +36 -31
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +155 -198
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/tmux.d.ts +42 -4
- package/dist/hud/tmux.d.ts.map +1 -1
- package/dist/hud/tmux.js +1017 -139
- package/dist/hud/tmux.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +124 -37
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +17 -6
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +102 -26
- package/dist/leader/contract.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__/hermes-bridge.test.js +17 -0
- package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -1
- package/dist/mcp/__tests__/server-lifecycle.test.js +4 -4
- package/dist/mcp/__tests__/state-paths.test.js +735 -4
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/__tests__/state-server.test.js +1 -1
- package/dist/mcp/__tests__/state-server.test.js.map +1 -1
- package/dist/mcp/__tests__/trace-server.test.js +2 -2
- package/dist/mcp/__tests__/trace-server.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/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.d.ts.map +1 -1
- package/dist/mcp/hermes-bridge.js +2 -2
- package/dist/mcp/hermes-bridge.js.map +1 -1
- package/dist/mcp/state-paths.d.ts +78 -4
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +543 -40
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/mcp/state-server.d.ts +4 -4
- package/dist/mcp/state-server.d.ts.map +1 -1
- package/dist/mcp/wiki-server.d.ts +11 -0
- 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-autopilot-gates.test.js +36 -7
- package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -1
- package/dist/modes/__tests__/base-multi-state-compat.test.js +1 -1
- package/dist/modes/__tests__/base-multi-state-compat.test.js.map +1 -1
- package/dist/modes/__tests__/base-session-scope.test.js +17 -8
- 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 +5 -5
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +76 -21
- package/dist/modes/base.js.map +1 -1
- package/dist/native-assets/archive.d.ts +17 -0
- package/dist/native-assets/archive.d.ts.map +1 -0
- package/dist/native-assets/archive.js +238 -0
- package/dist/native-assets/archive.js.map +1 -0
- package/dist/native-assets/policy.d.ts +42 -0
- package/dist/native-assets/policy.d.ts.map +1 -0
- package/dist/native-assets/policy.js +155 -0
- package/dist/native-assets/policy.js.map +1 -0
- 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/pipeline/__tests__/orchestrator.test.js +164 -42
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +72 -155
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +124 -18
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/stages/ralplan.d.ts.map +1 -1
- package/dist/pipeline/stages/ralplan.js +36 -8
- package/dist/pipeline/stages/ralplan.js.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +73 -1316
- 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 +335 -0
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -0
- package/dist/ralplan/__tests__/runtime.test.js +85 -101
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +9 -1
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +82 -338
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/documented-leader-preflight.d.ts +41 -0
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -0
- package/dist/ralplan/documented-leader-preflight.js +360 -0
- package/dist/ralplan/documented-leader-preflight.js.map +1 -0
- package/dist/ralplan/runtime.d.ts +2 -1
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +67 -168
- 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/run-state.d.ts +5 -1
- package/dist/runtime/run-state.d.ts.map +1 -1
- package/dist/runtime/run-state.js +15 -8
- package/dist/runtime/run-state.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +16323 -8978
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.js +225 -0
- package/dist/scripts/__tests__/issue-3293-callsite-parity.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.js +188 -0
- package/dist/scripts/__tests__/issue-3293-cancel-transaction.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.js +259 -0
- package/dist/scripts/__tests__/issue-3293-hook-owned-cancel.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.js +491 -0
- package/dist/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.js +708 -0
- package/dist/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.js.map +1 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.d.ts +2 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.js +208 -0
- package/dist/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.js.map +1 -0
- package/dist/scripts/__tests__/notify-state-io.test.js +26 -0
- package/dist/scripts/__tests__/notify-state-io.test.js.map +1 -1
- package/dist/scripts/__tests__/notify-tmux-injection.test.js +23 -1
- package/dist/scripts/__tests__/notify-tmux-injection.test.js.map +1 -1
- package/dist/scripts/__tests__/postinstall.test.js +19 -1
- package/dist/scripts/__tests__/postinstall.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.js +63 -173
- package/dist/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js +74 -159
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +404 -13
- package/dist/scripts/__tests__/smoke-packed-install.test.js.map +1 -1
- package/dist/scripts/__tests__/verify-native-release-assets.test.d.ts +2 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.d.ts.map +1 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.js +235 -0
- package/dist/scripts/__tests__/verify-native-release-assets.test.js.map +1 -0
- package/dist/scripts/codex-native-hook.d.ts +53 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +14448 -1480
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/codex-native-pre-post.d.ts +9 -0
- package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
- package/dist/scripts/codex-native-pre-post.js +35 -12
- package/dist/scripts/codex-native-pre-post.js.map +1 -1
- package/dist/scripts/generate-native-release-manifest.js +80 -51
- package/dist/scripts/generate-native-release-manifest.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +78 -115
- package/dist/scripts/notify-fallback-watcher.js.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/auto-nudge.js +74 -3
- package/dist/scripts/notify-hook/auto-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/state-io.d.ts.map +1 -1
- package/dist/scripts/notify-hook/state-io.js +5 -0
- package/dist/scripts/notify-hook/state-io.js.map +1 -1
- package/dist/scripts/notify-hook/team-dispatch.d.ts +9 -0
- 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.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +71 -16
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts +12 -4
- 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-stop.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker-stop.js +42 -21
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts +3 -0
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +82 -33
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts +1 -0
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +32 -3
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +79 -82
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/postinstall-advisory.d.ts +14 -0
- package/dist/scripts/postinstall-advisory.d.ts.map +1 -0
- package/dist/scripts/postinstall-advisory.js +49 -0
- package/dist/scripts/postinstall-advisory.js.map +1 -0
- package/dist/scripts/postinstall.d.ts +1 -1
- package/dist/scripts/postinstall.d.ts.map +1 -1
- package/dist/scripts/postinstall.js +1 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +80 -4
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +3162 -26
- package/dist/scripts/smoke-packed-install.js.map +1 -1
- package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js +16 -1
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/scripts/verify-native-release-assets.js +37 -23
- package/dist/scripts/verify-native-release-assets.js.map +1 -1
- package/dist/state/__tests__/mode-state-context.test.js +61 -0
- package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +462 -850
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/__tests__/skill-active.test.js +400 -2
- package/dist/state/__tests__/skill-active.test.js.map +1 -1
- package/dist/state/mode-state-context.d.ts +8 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +73 -0
- package/dist/state/mode-state-context.js.map +1 -1
- package/dist/state/operations.d.ts +3 -0
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +144 -40
- package/dist/state/operations.js.map +1 -1
- package/dist/state/skill-active.d.ts +18 -1
- package/dist/state/skill-active.d.ts.map +1 -1
- package/dist/state/skill-active.js +420 -23
- package/dist/state/skill-active.js.map +1 -1
- package/dist/state/workflow-transition-reconcile.d.ts +3 -0
- package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
- package/dist/state/workflow-transition-reconcile.js +10 -4
- package/dist/state/workflow-transition-reconcile.js.map +1 -1
- package/dist/state/workflow-transition.d.ts.map +1 -1
- package/dist/state/workflow-transition.js +3 -1
- package/dist/state/workflow-transition.js.map +1 -1
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js +53 -247
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -1
- package/dist/subagents/__tests__/tracker.test.js +837 -1048
- package/dist/subagents/__tests__/tracker.test.js.map +1 -1
- package/dist/subagents/tracker.d.ts +58 -135
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +811 -632
- 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__/delivery-e2e-smoke.test.js +58 -17
- 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 +197 -30
- package/dist/team/__tests__/mcp-comm.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +110 -3
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/notice-ledger.test.d.ts +2 -0
- package/dist/team/__tests__/notice-ledger.test.d.ts.map +1 -0
- package/dist/team/__tests__/notice-ledger.test.js +131 -0
- package/dist/team/__tests__/notice-ledger.test.js.map +1 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.d.ts +2 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.d.ts.map +1 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.js +410 -0
- package/dist/team/__tests__/pane-teardown-residue-e2e.test.js.map +1 -0
- package/dist/team/__tests__/phase-controller.test.js +20 -0
- package/dist/team/__tests__/phase-controller.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 +3963 -428
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +2405 -203
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state-root.test.js +117 -2
- 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 +4099 -1039
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.d.ts +2 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.d.ts.map +1 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.js +149 -0
- package/dist/team/__tests__/tmux-source-authority-realtmux.test.js.map +1 -0
- package/dist/team/__tests__/tmux-test-fixture.d.ts +69 -0
- package/dist/team/__tests__/tmux-test-fixture.d.ts.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.js +242 -15
- package/dist/team/__tests__/tmux-test-fixture.js.map +1 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js +177 -1
- package/dist/team/__tests__/tmux-test-fixture.test.js.map +1 -1
- package/dist/team/__tests__/worker-runtime-identity.test.js +53 -44
- 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.map +1 -1
- package/dist/team/api-interop.js +15 -9
- package/dist/team/api-interop.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/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 +2 -5
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +59 -17
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/notice-ledger.d.ts +54 -0
- package/dist/team/notice-ledger.d.ts.map +1 -0
- package/dist/team/notice-ledger.js +259 -0
- package/dist/team/notice-ledger.js.map +1 -0
- package/dist/team/phase-controller.d.ts.map +1 -1
- package/dist/team/phase-controller.js +2 -0
- package/dist/team/phase-controller.js.map +1 -1
- package/dist/team/runtime.d.ts +4 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +1527 -291
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts +13 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +1503 -387
- package/dist/team/scaling.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/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/monitor.d.ts +10 -0
- package/dist/team/state/monitor.d.ts.map +1 -1
- package/dist/team/state/monitor.js +13 -0
- package/dist/team/state/monitor.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/types.d.ts +15 -0
- package/dist/team/state/types.d.ts.map +1 -1
- package/dist/team/state/types.js.map +1 -1
- package/dist/team/state-root.d.ts +12 -0
- package/dist/team/state-root.d.ts.map +1 -1
- package/dist/team/state-root.js +177 -0
- package/dist/team/state-root.js.map +1 -1
- package/dist/team/state.d.ts +85 -1
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +672 -129
- package/dist/team/state.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 +163 -27
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +1682 -376
- package/dist/team/tmux-session.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 +950 -2
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +1 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +35 -1
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +232 -46
- package/dist/ultragoal/artifacts.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 +114 -0
- package/dist/utils/__tests__/file-durability.test.js.map +1 -0
- package/dist/utils/__tests__/paths.test.js +21 -1
- package/dist/utils/__tests__/paths.test.js.map +1 -1
- package/dist/utils/file-durability.d.ts +25 -0
- package/dist/utils/file-durability.d.ts.map +1 -0
- package/dist/utils/file-durability.js +67 -0
- package/dist/utils/file-durability.js.map +1 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -6
- package/dist/utils/paths.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +49 -4
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +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/__tests__/explore-harness-release-workflow.test.js +60 -0
- package/dist/verification/__tests__/explore-harness-release-workflow.test.js.map +1 -1
- package/dist/verification/__tests__/native-release-manifest.test.js +157 -4
- package/dist/verification/__tests__/native-release-manifest.test.js.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/package.json +13 -5
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +105 -17
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +13 -5
- package/plugins/oh-my-codex/skills/cancel/SKILL.md +30 -85
- package/plugins/oh-my-codex/skills/ralph/SKILL.md +6 -4
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +16 -17
- package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +3 -2
- package/skills/autopilot/SKILL.md +13 -5
- package/skills/cancel/SKILL.md +30 -85
- package/skills/ralph/SKILL.md +6 -4
- package/skills/ralplan/SKILL.md +16 -17
- package/skills/team/SKILL.md +13 -9
- package/skills/ultragoal/SKILL.md +3 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +8831 -951
- package/src/scripts/__tests__/issue-3293-callsite-parity.test.ts +187 -0
- package/src/scripts/__tests__/issue-3293-cancel-transaction.test.ts +189 -0
- package/src/scripts/__tests__/issue-3293-hook-owned-cancel.test.ts +187 -0
- package/src/scripts/__tests__/issue-3311-ultragoal-native-outside-tmux.test.ts +591 -0
- package/src/scripts/__tests__/issue-3358-ultragoal-cancel-lifecycle.test.ts +701 -0
- package/src/scripts/__tests__/issue-3369-autopilot-ralplan-state-machine.test.ts +211 -0
- package/src/scripts/__tests__/notify-state-io.test.ts +29 -0
- package/src/scripts/__tests__/notify-tmux-injection.test.ts +26 -1
- package/src/scripts/__tests__/postinstall.test.ts +23 -1
- package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +67 -185
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +79 -178
- package/src/scripts/__tests__/smoke-packed-install.test.ts +525 -16
- package/src/scripts/__tests__/verify-native-release-assets.test.ts +240 -0
- package/src/scripts/codex-native-hook.ts +14238 -1429
- package/src/scripts/codex-native-pre-post.ts +43 -12
- package/src/scripts/generate-native-release-manifest.ts +83 -79
- package/src/scripts/notify-fallback-watcher.ts +91 -122
- package/src/scripts/notify-hook/auto-nudge.ts +71 -3
- package/src/scripts/notify-hook/state-io.ts +11 -0
- package/src/scripts/notify-hook/team-dispatch.ts +242 -75
- package/src/scripts/notify-hook/team-leader-nudge.ts +72 -22
- package/src/scripts/notify-hook/team-tmux-guard.ts +366 -39
- package/src/scripts/notify-hook/team-worker-stop.ts +43 -20
- package/src/scripts/notify-hook/team-worker.ts +82 -31
- package/src/scripts/notify-hook/tmux-injection.ts +33 -3
- package/src/scripts/notify-hook.ts +84 -82
- package/src/scripts/postinstall-advisory.ts +67 -0
- package/src/scripts/postinstall.ts +1 -1
- package/src/scripts/smoke-packed-install.ts +3608 -39
- package/src/scripts/sync-plugin-mirror.ts +17 -1
- package/src/scripts/verify-native-release-assets.ts +39 -31
- package/templates/AGENTS.md +1 -0
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts +0 -2
- package/dist/subagents/__tests__/adapted-role-binding.test.d.ts.map +0 -1
- package/dist/subagents/__tests__/adapted-role-binding.test.js +0 -988
- package/dist/subagents/__tests__/adapted-role-binding.test.js.map +0 -1
- package/dist/subagents/adapted-role-binding.d.ts +0 -17
- package/dist/subagents/adapted-role-binding.d.ts.map +0 -1
- package/dist/subagents/adapted-role-binding.js +0 -75
- package/dist/subagents/adapted-role-binding.js.map +0 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Characterization baseline for issue #3293 direct-cancel callsite parity.
|
|
2
|
+
// Issue #3358 extends hook-owned exact-session cancellation to Ultragoal only.
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
import { mkdtemp, mkdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { dirname, join, resolve } from "node:path";
|
|
7
|
+
import { describe, it } from "node:test";
|
|
8
|
+
import { dispatchCodexNativeHook } from "../codex-native-hook.js";
|
|
9
|
+
|
|
10
|
+
async function writeJson(path: string, value: unknown): Promise<void> {
|
|
11
|
+
await mkdir(dirname(path), { recursive: true });
|
|
12
|
+
await writeFile(path, JSON.stringify(value, null, 2));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type Mode = "deep-interview" | "ralplan" | "conductor";
|
|
16
|
+
|
|
17
|
+
async function fixture(mode: Mode, suffix: string) {
|
|
18
|
+
const cwd = await mkdtemp(join(tmpdir(), `omx-3293-parity-${suffix}-`));
|
|
19
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
20
|
+
const sessionId = `session-${suffix}`;
|
|
21
|
+
const threadId = `thread-${suffix}`;
|
|
22
|
+
const sessionDir = join(stateDir, "sessions", sessionId);
|
|
23
|
+
const skill = mode === "conductor" ? "ultragoal" : mode === "deep-interview" ? "autopilot" : "ralplan";
|
|
24
|
+
const phase = mode === "deep-interview" ? "deep-interview" : "planning";
|
|
25
|
+
await writeJson(join(stateDir, "session.json"), { session_id: sessionId, cwd, leader_thread_id: threadId });
|
|
26
|
+
await writeJson(join(stateDir, "subagent-tracking.json"), {
|
|
27
|
+
schemaVersion: 1,
|
|
28
|
+
sessions: { [sessionId]: { session_id: sessionId, leader_thread_id: threadId, threads: { [threadId]: { thread_id: threadId, kind: "leader" } } } },
|
|
29
|
+
});
|
|
30
|
+
await writeJson(join(sessionDir, "skill-active-state.json"), {
|
|
31
|
+
active: true, skill, phase, session_id: sessionId, thread_id: threadId,
|
|
32
|
+
active_skills: [{ active: true, skill, phase, session_id: sessionId, thread_id: threadId }],
|
|
33
|
+
});
|
|
34
|
+
if (mode === "deep-interview") {
|
|
35
|
+
await writeJson(join(sessionDir, "autopilot-state.json"), { active: true, mode: "autopilot", current_phase: phase, session_id: sessionId, thread_id: threadId, workingDirectory: cwd });
|
|
36
|
+
} else if (mode === "ralplan") {
|
|
37
|
+
await writeJson(join(sessionDir, "ralplan-state.json"), { active: true, mode: "ralplan", current_phase: phase, session_id: sessionId, thread_id: threadId, workingDirectory: cwd });
|
|
38
|
+
} else {
|
|
39
|
+
await writeJson(join(sessionDir, "ultragoal-state.json"), { active: true, mode: "ultragoal", current_phase: phase, session_id: sessionId, thread_id: threadId, workingDirectory: cwd });
|
|
40
|
+
}
|
|
41
|
+
return { cwd, stateDir, sessionId, threadId };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function preToolUse(f: Awaited<ReturnType<typeof fixture>>, command: string, toolInput: Record<string, unknown> = { command }) {
|
|
45
|
+
return dispatchCodexNativeHook({
|
|
46
|
+
hook_event_name: "PreToolUse", cwd: f.cwd, session_id: f.sessionId, thread_id: f.threadId,
|
|
47
|
+
agent_id: f.threadId, tool_name: "Bash", tool_use_id: `tool-${Math.random()}`, tool_input: toolInput,
|
|
48
|
+
}, { cwd: f.cwd });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function assertBlocked(result: Awaited<ReturnType<typeof dispatchCodexNativeHook>>, pattern?: RegExp): void {
|
|
52
|
+
assert.equal(result.omxEventName, "pre-tool-use");
|
|
53
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
54
|
+
if (pattern) assert.match(JSON.stringify(result.outputJson), pattern);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function withTrustedOmx<T>(cwd: string, action: () => Promise<T>): Promise<T> {
|
|
58
|
+
const binDir = join(cwd, "trusted-bin");
|
|
59
|
+
const priorPath = process.env.PATH;
|
|
60
|
+
const unsafeRuntimeEnvNames = [
|
|
61
|
+
"NODE_OPTIONS",
|
|
62
|
+
"OPENSSL_CONF",
|
|
63
|
+
"NODE_V8_COVERAGE",
|
|
64
|
+
"NODE_COMPILE_CACHE",
|
|
65
|
+
"NODE_REDIRECT_WARNINGS",
|
|
66
|
+
"NODE_REPORT_DIRECTORY",
|
|
67
|
+
"NODE_REPORT_FILENAME",
|
|
68
|
+
] as const;
|
|
69
|
+
const priorRuntimeEnv = Object.fromEntries(unsafeRuntimeEnvNames.map((name) => [name, process.env[name]]));
|
|
70
|
+
await mkdir(binDir, { recursive: true });
|
|
71
|
+
await symlink(resolve(process.cwd(), "dist", "cli", "omx.js"), join(binDir, "omx"));
|
|
72
|
+
process.env.PATH = `${binDir}:${dirname(process.execPath)}`;
|
|
73
|
+
for (const name of unsafeRuntimeEnvNames) delete process.env[name];
|
|
74
|
+
try { return await action(); }
|
|
75
|
+
finally {
|
|
76
|
+
if (priorPath === undefined) delete process.env.PATH;
|
|
77
|
+
else process.env.PATH = priorPath;
|
|
78
|
+
for (const name of unsafeRuntimeEnvNames) {
|
|
79
|
+
if (priorRuntimeEnv[name] === undefined) delete process.env[name];
|
|
80
|
+
else process.env[name] = priorRuntimeEnv[name];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
describe("issue #3293 callsite parity baseline", () => {
|
|
87
|
+
it("deep-interview ~9541: payload-absent implementation-write path remains fail-closed by provenance", async () => {
|
|
88
|
+
const f = await fixture("deep-interview", "payload-absent");
|
|
89
|
+
try {
|
|
90
|
+
// blocksDeepInterviewImplementationWrite is private; this public root-conflict
|
|
91
|
+
// boundary reaches its payload-absent invocation with a cancel-shaped Bash command.
|
|
92
|
+
const result = await dispatchCodexNativeHook({
|
|
93
|
+
hook_event_name: "PreToolUse", cwd: f.cwd, session_id: "foreign-native", tool_name: "Bash",
|
|
94
|
+
tool_input: { command: "omx cancel" },
|
|
95
|
+
}, { cwd: f.cwd });
|
|
96
|
+
assertBlocked(result, /payload session identity is foreign or cannot be mapped to the active session/);
|
|
97
|
+
|
|
98
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("deep-interview ~9498: non-cancel read-only OMX command is allowed", async () => {
|
|
102
|
+
const f = await fixture("deep-interview", "readonly");
|
|
103
|
+
try { await withTrustedOmx(f.cwd, async () => assert.equal((await preToolUse(f, "omx state read --json")).outputJson, null)); }
|
|
104
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("deep-interview ~9498: permitted planning artifact write is allowed", async () => {
|
|
108
|
+
const f = await fixture("deep-interview", "artifact");
|
|
109
|
+
try { assert.equal((await preToolUse(f, "printf spec > .omx/specs/issue.md")).outputJson, null); }
|
|
110
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("deep-interview ~9498: forbidden implementation write is blocked", async () => {
|
|
114
|
+
const f = await fixture("deep-interview", "implementation");
|
|
115
|
+
try { assertBlocked(await preToolUse(f, "printf code > src/product.ts"), /src\/product\.ts/); }
|
|
116
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("deep-interview ~8863: bare omx cancel is handled by the hook", async () => {
|
|
120
|
+
const f = await fixture("deep-interview", "deep-bare");
|
|
121
|
+
try { await withTrustedOmx(f.cwd, async () => assertBlocked(await preToolUse(f, "omx cancel"), /cancelled_exact_session/)); }
|
|
122
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("deep-interview ~8863: omx cancel --force remains blocked by bare-only grammar", async () => {
|
|
126
|
+
const f = await fixture("deep-interview", "deep-force");
|
|
127
|
+
try { assertBlocked(await preToolUse(f, "omx cancel --force"), /invalid_command/); }
|
|
128
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
for (const mode of ["deep-interview", "ralplan", "conductor"] as const) {
|
|
132
|
+
it(`${mode} direct-cancel callsite: raw/analyzed command mismatch remains blocked`, async () => {
|
|
133
|
+
const f = await fixture(mode, `${mode}-raw-mismatch`);
|
|
134
|
+
try { assertBlocked(await preToolUse(f, " omx cancel ")); }
|
|
135
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (const command of ["omx cancel", "omx cancel --force"]) {
|
|
140
|
+
it(`ralplan ~9114: ${command} falls through to the pre-#3293 executable-trust path`, async () => {
|
|
141
|
+
const f = await fixture("ralplan", `ralplan-${command.endsWith("force") ? "force" : "bare"}`);
|
|
142
|
+
try { await withTrustedOmx(f.cwd, async () => assert.equal((await preToolUse(f, command)).outputJson, null)); }
|
|
143
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
144
|
+
});
|
|
145
|
+
it(`conductor ~18227: ${command} is hook-owned for the exact Ultragoal session`, async () => {
|
|
146
|
+
const f = await fixture("conductor", `conductor-${command.endsWith("force") ? "force" : "bare"}`);
|
|
147
|
+
try { assertBlocked(await preToolUse(f, command), /cancelled_exact_session/); }
|
|
148
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
it("deep-interview ~9616: foreign payload remains fail-closed by provenance", async () => {
|
|
154
|
+
const f = await fixture("deep-interview", "deep-root-conflict");
|
|
155
|
+
try {
|
|
156
|
+
await writeJson(join(f.stateDir, "session.json"), { session_id: f.sessionId, cwd: f.cwd });
|
|
157
|
+
const result = await dispatchCodexNativeHook({ hook_event_name: "PreToolUse", cwd: f.cwd, session_id: "foreign-native", tool_name: "Edit", tool_input: { file_path: "src/product.ts" } }, { cwd: f.cwd });
|
|
158
|
+
assertBlocked(result, /payload session identity is foreign or cannot be mapped to the active session/);
|
|
159
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("ralplan ~9645: foreign payload remains fail-closed by provenance", async () => {
|
|
163
|
+
const f = await fixture("ralplan", "ralplan-root-conflict");
|
|
164
|
+
try {
|
|
165
|
+
const result = await dispatchCodexNativeHook({ hook_event_name: "PreToolUse", cwd: f.cwd, session_id: "foreign-native", tool_name: "Edit", tool_input: { file_path: "src/product.ts" } }, { cwd: f.cwd });
|
|
166
|
+
assertBlocked(result, /payload session identity is foreign or cannot be mapped to the active session/);
|
|
167
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
for (const command of [
|
|
171
|
+
"FOO=bar omx cancel", "PATH=/tmp omx cancel", "omx cancel; ls", "omx cancel | cat",
|
|
172
|
+
"omx cancel > /tmp/x", "omx cancel $(id)", "omx cancel `id`", "/tmp/omx cancel",
|
|
173
|
+
"omx cancel extra", "omx cancel --unknown", "omx cancel;",
|
|
174
|
+
]) {
|
|
175
|
+
it(`deep-interview ~8863: invalid direct-cancel grammar ${JSON.stringify(command)} is blocked`, async () => {
|
|
176
|
+
const f = await fixture("deep-interview", `grammar-${command.length}`);
|
|
177
|
+
try { assertBlocked(await preToolUse(f, command)); }
|
|
178
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
it("Conductor ~18419: exact cancellation remains reachable when executable trust is absent", async () => {
|
|
183
|
+
const f = await fixture("conductor", "conductor-detail");
|
|
184
|
+
try { assertBlocked(await preToolUse(f, "omx cancel"), /cancelled_exact_session/); }
|
|
185
|
+
finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdtemp, mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import {
|
|
8
|
+
readHookCancelTransactionRecoveryState,
|
|
9
|
+
terminalizeExactAutopilotSessionForHookCancel,
|
|
10
|
+
} from "../codex-native-hook.js";
|
|
11
|
+
|
|
12
|
+
const NOW = "2026-07-25T00:00:00.000Z";
|
|
13
|
+
|
|
14
|
+
type Fixture = {
|
|
15
|
+
cwd: string;
|
|
16
|
+
stateDir: string;
|
|
17
|
+
sessionId: string;
|
|
18
|
+
sessionDir: string;
|
|
19
|
+
autopilotPath: string;
|
|
20
|
+
skillPath: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
async function writeJson(path: string, value: unknown): Promise<void> {
|
|
24
|
+
await mkdir(join(path, ".."), { recursive: true });
|
|
25
|
+
await writeFile(path, JSON.stringify(value, null, 2));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function fixture(): Promise<Fixture> {
|
|
29
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-3293-cancel-"));
|
|
30
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
31
|
+
const sessionId = "session-3293";
|
|
32
|
+
const sessionDir = join(stateDir, "sessions", sessionId);
|
|
33
|
+
const autopilotPath = join(sessionDir, "autopilot-state.json");
|
|
34
|
+
const skillPath = join(sessionDir, "skill-active-state.json");
|
|
35
|
+
await writeJson(autopilotPath, {
|
|
36
|
+
active: true, mode: "autopilot", current_phase: "deep-interview", session_id: sessionId, cwd,
|
|
37
|
+
handoff_artifacts: { interview: "preserve" }, unrelated: { preserved: true },
|
|
38
|
+
});
|
|
39
|
+
await writeJson(skillPath, {
|
|
40
|
+
version: 1, active: true, skill: "autopilot", phase: "deep-interview", session_id: sessionId, cwd,
|
|
41
|
+
active_skills: [
|
|
42
|
+
{ skill: "autopilot", active: true, phase: "deep-interview", session_id: sessionId, cwd, marker: "cancel" },
|
|
43
|
+
{ skill: "ralph", active: true, phase: "execution", session_id: sessionId, cwd, marker: "keep" },
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
return { cwd, stateDir, sessionId, sessionDir, autopilotPath, skillPath };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function terminalize(f: Fixture) {
|
|
50
|
+
return terminalizeExactAutopilotSessionForHookCancel({ stateDir: f.stateDir, canonicalSessionId: f.sessionId, cwd: f.cwd, nowIso: NOW });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function withFixture(run: (f: Fixture) => Promise<void>): Promise<void> {
|
|
54
|
+
const f = await fixture();
|
|
55
|
+
try { await run(f); } finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
test("terminalizes the exact active deep-interview session while preserving handoff and unrelated skill entries", async () => {
|
|
59
|
+
await withFixture(async (f) => {
|
|
60
|
+
assert.deepEqual(await terminalize(f), { ok: true });
|
|
61
|
+
const autopilot = JSON.parse(await readFile(f.autopilotPath, "utf8"));
|
|
62
|
+
const skill = JSON.parse(await readFile(f.skillPath, "utf8"));
|
|
63
|
+
assert.deepEqual(autopilot.handoff_artifacts, { interview: "preserve" });
|
|
64
|
+
assert.deepEqual(autopilot.unrelated, { preserved: true });
|
|
65
|
+
assert.equal(autopilot.active, false); assert.equal(autopilot.current_phase, "cancelled");
|
|
66
|
+
assert.equal(autopilot.completed_at, NOW); assert.equal(autopilot.last_turn_at, NOW);
|
|
67
|
+
assert.equal(skill.active, true); assert.equal(skill.skill, "ralph"); assert.equal(skill.phase, "execution");
|
|
68
|
+
assert.deepEqual(skill.active_skills[0], { skill: "autopilot", active: false, phase: "cancelled", session_id: f.sessionId, cwd: f.cwd, marker: "cancel", updated_at: NOW });
|
|
69
|
+
assert.deepEqual(skill.active_skills[1], { skill: "ralph", active: true, phase: "execution", session_id: f.sessionId, cwd: f.cwd, marker: "keep" });
|
|
70
|
+
assert.equal(existsSync(join(f.sessionDir, ".hook-cancel-transaction.json")), false);
|
|
71
|
+
assert.equal(existsSync(join(f.sessionDir, ".hook-cancel.lock")), false);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("preserves a second session byte-for-byte", async () => {
|
|
76
|
+
await withFixture(async (f) => {
|
|
77
|
+
const other = join(f.stateDir, "sessions", "other-session", "autopilot-state.json");
|
|
78
|
+
await writeJson(other, { active: true, mode: "autopilot", current_phase: "deep-interview", sentinel: "other" });
|
|
79
|
+
const before = await readFile(other);
|
|
80
|
+
assert.equal((await terminalize(f)).ok, true);
|
|
81
|
+
assert.deepEqual(await readFile(other), before);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("denies a pre-existing exact-session lock without mutation", async () => {
|
|
86
|
+
await withFixture(async (f) => {
|
|
87
|
+
const before = await readFile(f.autopilotPath); await writeFile(join(f.sessionDir, ".hook-cancel.lock"), "held");
|
|
88
|
+
assert.deepEqual(await terminalize(f), { ok: false, reason: "lock_held" });
|
|
89
|
+
assert.deepEqual(await readFile(f.autopilotPath), before);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("denies a pre-existing prepared journal with a value-free recovery reason", async () => {
|
|
94
|
+
await withFixture(async (f) => {
|
|
95
|
+
await writeFile(join(f.sessionDir, ".hook-cancel-transaction.json"), JSON.stringify({ version: 1, phase: "prepared" }));
|
|
96
|
+
assert.deepEqual(await terminalize(f), { ok: false, reason: "recovery_required" });
|
|
97
|
+
assert.equal(await readHookCancelTransactionRecoveryState({ stateDir: f.stateDir, canonicalSessionId: f.sessionId }), "recovery_required");
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
for (const sessionId of [".", "..", "../escape"]) {
|
|
102
|
+
test(`denies unsafe session id ${JSON.stringify(sessionId)} without mutation`, async () => {
|
|
103
|
+
await withFixture(async (f) => {
|
|
104
|
+
const before = [await readFile(f.autopilotPath), await readFile(f.skillPath)];
|
|
105
|
+
assert.deepEqual(await terminalizeExactAutopilotSessionForHookCancel({ stateDir: f.stateDir, canonicalSessionId: sessionId, cwd: f.cwd, nowIso: NOW }), { ok: false, reason: "invalid_target" });
|
|
106
|
+
assert.equal(await readHookCancelTransactionRecoveryState({ stateDir: f.stateDir, canonicalSessionId: sessionId }), "invalid_target");
|
|
107
|
+
assert.deepEqual([await readFile(f.autopilotPath), await readFile(f.skillPath)], before);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
test("denies a symlinked session directory component", async () => {
|
|
113
|
+
await withFixture(async (f) => {
|
|
114
|
+
const linked = join(f.stateDir, "sessions", "linked-session"); await symlink(f.sessionDir, linked);
|
|
115
|
+
assert.deepEqual(await terminalizeExactAutopilotSessionForHookCancel({ stateDir: f.stateDir, canonicalSessionId: "linked-session", cwd: f.cwd, nowIso: NOW }), { ok: false, reason: "invalid_target" });
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("denies a symlinked or non-regular target file", async () => {
|
|
120
|
+
await withFixture(async (f) => {
|
|
121
|
+
await rm(f.autopilotPath); await symlink(f.skillPath, f.autopilotPath);
|
|
122
|
+
assert.equal((await terminalize(f)).ok, false);
|
|
123
|
+
});
|
|
124
|
+
await withFixture(async (f) => {
|
|
125
|
+
await rm(f.autopilotPath); await mkdir(f.autopilotPath);
|
|
126
|
+
assert.equal((await terminalize(f)).ok, false);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("denies state changed during preflight without mutation", async () => {
|
|
131
|
+
await withFixture(async (f) => {
|
|
132
|
+
const before = await readFile(f.autopilotPath);
|
|
133
|
+
const prior = process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER;
|
|
134
|
+
process.env.NODE_ENV = "test";
|
|
135
|
+
process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER = "preflight-instability";
|
|
136
|
+
try {
|
|
137
|
+
assert.deepEqual(await terminalize(f), { ok: false, reason: "preflight_failed" });
|
|
138
|
+
} finally {
|
|
139
|
+
if (prior === undefined) delete process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER;
|
|
140
|
+
else process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER = prior;
|
|
141
|
+
}
|
|
142
|
+
assert.deepEqual(await readFile(f.autopilotPath), before);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("denies malformed or oversized JSON without mutation", async () => {
|
|
147
|
+
await withFixture(async (f) => { await writeFile(f.autopilotPath, "{"); const before = await readFile(f.autopilotPath); assert.equal((await terminalize(f)).ok, false); assert.deepEqual(await readFile(f.autopilotPath), before); });
|
|
148
|
+
await withFixture(async (f) => { const bytes = Buffer.alloc(1024 * 1024 + 1, 0x20); await writeFile(f.autopilotPath, bytes); assert.equal((await terminalize(f)).ok, false); assert.deepEqual(await readFile(f.autopilotPath), bytes); });
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("denies contradictory owner session or cwd fields without mutation", async () => {
|
|
152
|
+
await withFixture(async (f) => { await writeJson(f.skillPath, { active: true, skill: "autopilot", phase: "deep-interview", session_id: "other", cwd: f.cwd }); assert.deepEqual(await terminalize(f), { ok: false, reason: "state_mismatch" }); });
|
|
153
|
+
await withFixture(async (f) => { await writeJson(f.autopilotPath, { active: true, mode: "autopilot", current_phase: "deep-interview", session_id: f.sessionId, cwd: join(f.cwd, "other") }); assert.deepEqual(await terminalize(f), { ok: false, reason: "state_mismatch" }); });
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("denies a missing paired skill-active state without mutation", async () => {
|
|
157
|
+
await withFixture(async (f) => { const before = await readFile(f.autopilotPath); await rm(f.skillPath); assert.deepEqual(await terminalize(f), { ok: false, reason: "preflight_failed" }); assert.deepEqual(await readFile(f.autopilotPath), before); });
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("cleans a lock whose initialization fails before the transaction starts", async () => {
|
|
161
|
+
await withFixture(async (f) => {
|
|
162
|
+
const original = [await readFile(f.autopilotPath), await readFile(f.skillPath)];
|
|
163
|
+
const prior = process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER;
|
|
164
|
+
process.env.NODE_ENV = "test";
|
|
165
|
+
process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER = "lock-acquire";
|
|
166
|
+
try {
|
|
167
|
+
assert.deepEqual(await terminalize(f), { ok: false, reason: "lock_held" });
|
|
168
|
+
} finally {
|
|
169
|
+
if (prior === undefined) delete process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER;
|
|
170
|
+
else process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER = prior;
|
|
171
|
+
}
|
|
172
|
+
assert.equal(existsSync(join(f.sessionDir, ".hook-cancel.lock")), false);
|
|
173
|
+
assert.deepEqual([await readFile(f.autopilotPath), await readFile(f.skillPath)], original);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
for (const boundary of ["journal-fsync", "partial-first-data-write", "first-data-write", "partial-second-data-write", "second-data-write", "verification", "journal-commit", "unlink", "lock-release"]) {
|
|
178
|
+
test(`fault injection after ${boundary} never leaves a torn two-file state`, async () => {
|
|
179
|
+
await withFixture(async (f) => {
|
|
180
|
+
const original = [await readFile(f.autopilotPath), await readFile(f.skillPath)];
|
|
181
|
+
const prior = process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER;
|
|
182
|
+
process.env.NODE_ENV = "test"; process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER = boundary;
|
|
183
|
+
try { await terminalize(f); } finally { if (prior === undefined) delete process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER; else process.env.OMX_NATIVE_HOOK_TEST_CANCEL_TRANSACTION_FAIL_AFTER = prior; }
|
|
184
|
+
const now = [await readFile(f.autopilotPath), await readFile(f.skillPath)];
|
|
185
|
+
const journal = existsSync(join(f.sessionDir, ".hook-cancel-transaction.json"));
|
|
186
|
+
assert.ok((now[0].equals(original[0]) && now[1].equals(original[1])) || (!now[0].equals(original[0]) && !now[1].equals(original[1])) || journal, boundary);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { chmod, mkdtemp, mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { describe, it } from "node:test";
|
|
6
|
+
import { dispatchCodexNativeHook } from "../codex-native-hook.js";
|
|
7
|
+
|
|
8
|
+
async function json(path: string, value: unknown): Promise<void> {
|
|
9
|
+
await mkdir(dirname(path), { recursive: true });
|
|
10
|
+
await writeFile(path, JSON.stringify(value, null, 2));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function fixture(sessionId = "session-hook-cancel") {
|
|
14
|
+
const cwd = await mkdtemp(join(tmpdir(), "omx-3293-hook-cancel-"));
|
|
15
|
+
const stateDir = join(cwd, ".omx", "state");
|
|
16
|
+
const threadId = `thread-${sessionId}`;
|
|
17
|
+
const sessionDir = join(stateDir, "sessions", sessionId);
|
|
18
|
+
await json(join(stateDir, "session.json"), { session_id: sessionId, cwd, leader_thread_id: threadId });
|
|
19
|
+
await json(join(stateDir, "subagent-tracking.json"), { schemaVersion: 1, sessions: { [sessionId]: { session_id: sessionId, leader_thread_id: threadId, threads: { [threadId]: { thread_id: threadId, kind: "leader" } } } } });
|
|
20
|
+
await json(join(sessionDir, "autopilot-state.json"), { active: true, mode: "autopilot", current_phase: "deep-interview", session_id: sessionId, thread_id: threadId, workingDirectory: cwd });
|
|
21
|
+
await json(join(sessionDir, "skill-active-state.json"), { active: true, skill: "autopilot", phase: "deep-interview", session_id: sessionId, thread_id: threadId, active_skills: [{ active: true, skill: "autopilot", phase: "deep-interview", session_id: sessionId, thread_id: threadId }] });
|
|
22
|
+
return { cwd, stateDir, sessionDir, sessionId, threadId };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type Fixture = Awaited<ReturnType<typeof fixture>>;
|
|
26
|
+
|
|
27
|
+
function preTool(f: Fixture, command: string, overrides: Record<string, unknown> = {}) {
|
|
28
|
+
return dispatchCodexNativeHook({ hook_event_name: "PreToolUse", cwd: f.cwd, session_id: f.sessionId, thread_id: f.threadId, agent_id: f.threadId, tool_name: "Bash", tool_input: { command }, ...overrides }, { cwd: f.cwd });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function stop(f: Fixture) {
|
|
32
|
+
return dispatchCodexNativeHook({ hook_event_name: "Stop", cwd: f.cwd, session_id: f.sessionId, thread_id: f.threadId }, { cwd: f.cwd });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function assertValueFreeDenial(result: Awaited<ReturnType<typeof preTool>>, f: Fixture, stateContent: string, label: string): void {
|
|
36
|
+
assert.equal(result.outputJson?.decision, "block", label);
|
|
37
|
+
const rendered = JSON.stringify(result.outputJson);
|
|
38
|
+
for (const secret of [f.cwd, f.sessionId, stateContent]) assert.equal(rendered.includes(secret), false, `${label}: diagnostic leaked a value`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function withEnv<T>(values: Record<string, string | undefined>, run: () => Promise<T>): Promise<T> {
|
|
42
|
+
const before = new Map(Object.keys(values).map((name) => [name, process.env[name]]));
|
|
43
|
+
try {
|
|
44
|
+
for (const [name, value] of Object.entries(values)) {
|
|
45
|
+
if (value === undefined) delete process.env[name]; else process.env[name] = value;
|
|
46
|
+
}
|
|
47
|
+
return await run();
|
|
48
|
+
} finally {
|
|
49
|
+
for (const [name, value] of before) {
|
|
50
|
+
if (value === undefined) delete process.env[name]; else process.env[name] = value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function denialFixture(command: string, mutate?: (f: Fixture) => Promise<void>, payload?: Record<string, unknown>) {
|
|
56
|
+
const f = await fixture();
|
|
57
|
+
try {
|
|
58
|
+
if (mutate) await mutate(f);
|
|
59
|
+
const stateContent = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8");
|
|
60
|
+
const result = await preTool(f, command, payload);
|
|
61
|
+
assertValueFreeDenial(result, f, stateContent, command);
|
|
62
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
describe("issue #3293 hook-owned cancellation", () => {
|
|
66
|
+
it("handles bare deep-interview cancellation, terminalizes both files, and does not execute Bash", async () => {
|
|
67
|
+
const f = await fixture();
|
|
68
|
+
try {
|
|
69
|
+
const sentinel = join(f.cwd, "plugin-sentinel");
|
|
70
|
+
await mkdir(join(f.cwd, ".omx", "hooks"), { recursive: true });
|
|
71
|
+
await writeFile(join(f.cwd, ".omx", "hooks", "sentinel.mjs"), `import { writeFile } from 'node:fs/promises'; await writeFile(${JSON.stringify(sentinel)}, 'ran');`);
|
|
72
|
+
const result = await preTool(f, "omx cancel");
|
|
73
|
+
assert.equal(result.outputJson?.decision, "block");
|
|
74
|
+
assert.match(JSON.stringify(result.outputJson), /cancelled_exact_session/);
|
|
75
|
+
assert.equal(JSON.parse(await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8")).active, false);
|
|
76
|
+
assert.equal(JSON.parse(await readFile(join(f.sessionDir, "skill-active-state.json"), "utf8")).active, false);
|
|
77
|
+
await assert.rejects(readFile(sentinel));
|
|
78
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("stops repeatedly without continuation, reactivation, or terminal-byte changes", async () => {
|
|
82
|
+
const f = await fixture();
|
|
83
|
+
try {
|
|
84
|
+
await preTool(f, "omx cancel");
|
|
85
|
+
const paths = [join(f.sessionDir, "autopilot-state.json"), join(f.sessionDir, "skill-active-state.json")];
|
|
86
|
+
const terminal = await Promise.all(paths.map((path) => readFile(path)));
|
|
87
|
+
assert.equal((await stop(f)).outputJson, null);
|
|
88
|
+
assert.equal((await stop(f)).outputJson, null);
|
|
89
|
+
assert.deepEqual(await Promise.all(paths.map((path) => readFile(path))), terminal);
|
|
90
|
+
assert.equal(JSON.parse(terminal[0].toString()).active, false);
|
|
91
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("terminalizes only the exact session", async () => {
|
|
95
|
+
const f = await fixture();
|
|
96
|
+
try {
|
|
97
|
+
const otherId = "session-other";
|
|
98
|
+
const otherDir = join(f.stateDir, "sessions", otherId);
|
|
99
|
+
const otherAutopilot = { active: true, mode: "autopilot", current_phase: "deep-interview", session_id: otherId, thread_id: "thread-other", workingDirectory: f.cwd };
|
|
100
|
+
const otherSkill = { active: true, skill: "autopilot", phase: "deep-interview", session_id: otherId, thread_id: "thread-other" };
|
|
101
|
+
await json(join(otherDir, "autopilot-state.json"), otherAutopilot);
|
|
102
|
+
await json(join(otherDir, "skill-active-state.json"), otherSkill);
|
|
103
|
+
const before = await Promise.all([readFile(join(otherDir, "autopilot-state.json")), readFile(join(otherDir, "skill-active-state.json"))]);
|
|
104
|
+
await preTool(f, "omx cancel");
|
|
105
|
+
assert.deepEqual(await Promise.all([readFile(join(otherDir, "autopilot-state.json")), readFile(join(otherDir, "skill-active-state.json"))]), before);
|
|
106
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("fails closed for cancellation and Stop when a prepared journal exists", async () => {
|
|
110
|
+
const f = await fixture();
|
|
111
|
+
try {
|
|
112
|
+
await json(join(f.sessionDir, ".hook-cancel-transaction.json"), { phase: "prepared", session_id: f.sessionId });
|
|
113
|
+
const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8");
|
|
114
|
+
assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, "prepared cancellation");
|
|
115
|
+
const stopped = await stop(f);
|
|
116
|
+
assert.equal(stopped.outputJson?.decision, "block");
|
|
117
|
+
const rendered = JSON.stringify(stopped.outputJson);
|
|
118
|
+
for (const secret of [f.cwd, f.sessionId, content]) assert.equal(rendered.includes(secret), false);
|
|
119
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("denies a fully forged public-hook caller because no executable trust can be forged", async () => {
|
|
123
|
+
const f = await fixture();
|
|
124
|
+
try {
|
|
125
|
+
const attacker = join(f.cwd, "attacker-bin");
|
|
126
|
+
await mkdir(attacker); await writeFile(join(attacker, "omx"), "#!/bin/sh\nexit 0\n"); await chmod(join(attacker, "omx"), 0o755);
|
|
127
|
+
await withEnv({ PATH: attacker }, async () => {
|
|
128
|
+
const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8");
|
|
129
|
+
const result = await preTool(f, "omx cancel", { thread_id: "unbound-attacker", agent_id: "unbound-attacker" });
|
|
130
|
+
assertValueFreeDenial(result, f, content, "fully forged public hook");
|
|
131
|
+
});
|
|
132
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("denies hostile modified shim contents", async () => {
|
|
136
|
+
const f = await fixture();
|
|
137
|
+
try {
|
|
138
|
+
const bin = join(f.cwd, "modified-bin");
|
|
139
|
+
await mkdir(bin); await writeFile(join(bin, "omx"), "#!/bin/sh\necho attacker\n"); await chmod(join(bin, "omx"), 0o755);
|
|
140
|
+
const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8");
|
|
141
|
+
await withEnv({ PATH: bin }, async () => assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, "modified shim"));
|
|
142
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("denies hostile shim symlink replacement", async () => {
|
|
146
|
+
const f = await fixture();
|
|
147
|
+
try {
|
|
148
|
+
const bin = join(f.cwd, "symlink-bin"); const target = join(f.cwd, "attacker-omx");
|
|
149
|
+
await mkdir(bin); await writeFile(target, "#!/bin/sh\necho attacker\n"); await chmod(target, 0o755); await symlink(target, join(bin, "omx"));
|
|
150
|
+
const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8");
|
|
151
|
+
await withEnv({ PATH: bin }, async () => assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, "symlink shim"));
|
|
152
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const commandCases = [
|
|
156
|
+
["wrapper with extra commands", "env omx cancel"], ["wrapper with extra args", "omx cancel --force"],
|
|
157
|
+
["unsafe leading assignment", "FOO=bar omx cancel"], ["semicolon operator", "omx cancel; true"], ["and operator", "omx cancel && true"], ["or operator", "omx cancel || true"], ["pipeline operator", "omx cancel | cat"], ["background operator", "omx cancel &"],
|
|
158
|
+
["command substitution", "$(printf omx) cancel"], ["backtick substitution", "`printf omx` cancel"], ["input redirection", "omx cancel < /dev/null"], ["output redirection", "omx cancel > /dev/null"], ["path-qualified untrusted executable", "/tmp/omx cancel"],
|
|
159
|
+
] as const;
|
|
160
|
+
for (const [name, command] of commandCases) it(`denies hostile ${name}`, async () => denialFixture(command));
|
|
161
|
+
|
|
162
|
+
const envCases = ["BASH_ENV", "BASH_FUNC_omx%%", "NODE_OPTIONS", "NODE_V8_COVERAGE", "NODE_COMPILE_CACHE", "NODE_REDIRECT_WARNINGS", "NODE_REPORT_DIRECTORY", "NODE_REPORT_FILENAME", "OPENSSL_CONF"] as const;
|
|
163
|
+
for (const name of envCases) it(`denies hostile inherited ${name}`, async () => {
|
|
164
|
+
const f = await fixture();
|
|
165
|
+
try {
|
|
166
|
+
const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8");
|
|
167
|
+
await withEnv({ [name]: name === "BASH_FUNC_omx%%" ? "() { :; }" : join(f.cwd, "injected") }, async () => assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, name));
|
|
168
|
+
} finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("denies hostile loader injection", async () => denialFixture("node --loader attacker.mjs omx cancel"));
|
|
172
|
+
it("denies hostile PATH-shadowed omx", async () => {
|
|
173
|
+
const f = await fixture(); try { const bin = join(f.cwd, "shadow"); await mkdir(bin); await writeFile(join(bin, "omx"), "#!/bin/sh\nexit 0\n"); await chmod(join(bin, "omx"), 0o755); const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8"); await withEnv({ PATH: bin }, async () => assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, "PATH shadow")); } finally { await rm(f.cwd, { recursive: true, force: true }); }
|
|
174
|
+
});
|
|
175
|
+
it("denies hostile repo-local lookalike executable", async () => denialFixture("./omx cancel", async (f) => { await writeFile(join(f.cwd, "omx"), "#!/bin/sh\nexit 0\n"); await chmod(join(f.cwd, "omx"), 0o755); }));
|
|
176
|
+
it("denies hostile cross-session selector", async () => denialFixture("omx cancel", undefined, { session_id: "other-session", sessionId: "other-session" }));
|
|
177
|
+
it("denies hostile cross-root selector", async () => denialFixture("OMX_ROOT=/tmp/other omx cancel"));
|
|
178
|
+
it("denies hostile unset PATH", async () => { const f = await fixture(); try { const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8"); await withEnv({ PATH: undefined }, async () => assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, "unset PATH")); } finally { await rm(f.cwd, { recursive: true, force: true }); } });
|
|
179
|
+
it("denies hostile unreadable PATH entry", async () => { const f = await fixture(); try { const path = join(f.cwd, "unreadable"); await mkdir(path); await chmod(path, 0o000); const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8"); await withEnv({ PATH: path }, async () => assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, "unreadable PATH")); await chmod(path, 0o755); } finally { await rm(f.cwd, { recursive: true, force: true }); } });
|
|
180
|
+
it("denies hostile non-directory PATH entry", async () => { const f = await fixture(); try { const path = join(f.cwd, "not-directory"); await writeFile(path, "x"); const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8"); await withEnv({ PATH: path }, async () => assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, "file PATH")); } finally { await rm(f.cwd, { recursive: true, force: true }); } });
|
|
181
|
+
it("denies hostile non-executable shim", async () => { const f = await fixture(); try { const bin = join(f.cwd, "bin"); await mkdir(bin); await writeFile(join(bin, "omx"), "#!/bin/sh\nexit 0\n"); const content = await readFile(join(f.sessionDir, "autopilot-state.json"), "utf8"); await withEnv({ PATH: bin }, async () => assertValueFreeDenial(await preTool(f, "omx cancel"), f, content, "non-executable shim")); } finally { await rm(f.cwd, { recursive: true, force: true }); } });
|
|
182
|
+
|
|
183
|
+
it("R-4 documents payload-bound identity and ambient same-euid target-root selection", async () => {
|
|
184
|
+
const source = await readFile(resolve(process.cwd(), "src/scripts/codex-native-hook.ts"), "utf8");
|
|
185
|
+
assert.match(source, /identity matching is payload-bound while target-root\s+\/\/ selection remains ambient and same-euid trusted/);
|
|
186
|
+
});
|
|
187
|
+
});
|