oh-my-codex 0.20.2 → 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 +26 -0
- 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/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/hotswap.d.ts +6 -0
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +85 -15
- package/dist/auth/hotswap.js.map +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.test.js +1 -1
- package/dist/autopilot/__tests__/ralplan-gate.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__/codex-plugin-layout.test.js +80 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +103 -1
- 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__/index.test.js +258 -4
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +287 -1
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +4 -1
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/native-hook-claim-journal.test.js +84 -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 +56 -171
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan.test.js +37 -111
- 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-search-help.test.js +25 -1
- package/dist/cli/__tests__/session-search-help.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +42 -4
- package/dist/cli/__tests__/setup-install-mode.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__/uninstall.test.js +46 -0
- package/dist/cli/__tests__/uninstall.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/doctor.d.ts +3 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +15 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +4 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +138 -38
- 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-hook-claim-journal.d.ts +16 -5
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -1
- package/dist/cli/native-hook-claim-journal.js +42 -29
- package/dist/cli/native-hook-claim-journal.js.map +1 -1
- package/dist/cli/ralph.js +2 -2
- package/dist/cli/ralph.js.map +1 -1
- package/dist/cli/ralplan.d.ts +4 -8
- package/dist/cli/ralplan.d.ts.map +1 -1
- package/dist/cli/ralplan.js +19 -112
- 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.d.ts +5 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +80 -31
- package/dist/cli/setup.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 +61 -19
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/compat/__tests__/rust-runtime-compat.test.js +1 -1
- package/dist/config/__tests__/generator-idempotent.test.js +330 -1
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +2 -2
- 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 +4 -20
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +499 -119
- 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/hooks/__tests__/agents-overlay.test.js +2 -2
- package/dist/hooks/__tests__/agents-overlay.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +4 -4
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +238 -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 +96 -9
- package/dist/hooks/__tests__/notify-hook-auto-nudge.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 +155 -23
- 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-worker-idle.test.js +43 -4
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/session.test.js +348 -2
- package/dist/hooks/__tests__/session.test.js.map +1 -1
- package/dist/hooks/agents-overlay.js +1 -1
- package/dist/hooks/session.d.ts +26 -2
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +169 -13
- package/dist/hooks/session.js.map +1 -1
- package/dist/leader/__tests__/contract.test.js +57 -7
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +16 -0
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +79 -4
- 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__/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/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-tmux-pane.test.js +4 -4
- package/dist/modes/__tests__/base-tmux-pane.test.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/pipeline/__tests__/orchestrator.test.js +4 -4
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +8 -8
- package/dist/pipeline/__tests__/stages.test.js.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +134 -10
- 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 +8 -4
- package/dist/ralplan/__tests__/runtime.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +58 -50
- 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 +1 -0
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +11 -7
- 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/scripts/__tests__/codex-native-hook.test.js +2620 -487
- package/dist/scripts/__tests__/codex-native-hook.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 +46 -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 +39 -159
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +254 -2
- package/dist/scripts/__tests__/smoke-packed-install.test.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 +11013 -1153
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-fallback-watcher.js +82 -108
- 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/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 +39 -13
- 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 +19 -18
- 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 +37 -28
- package/dist/scripts/notify-hook/team-worker.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +28 -2
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +1 -0
- package/dist/scripts/notify-hook.js.map +1 -1
- package/dist/scripts/smoke-packed-install.d.ts +48 -3
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +2796 -13
- package/dist/scripts/smoke-packed-install.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 +2 -0
- package/dist/state/__tests__/operations.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/subagents/__tests__/leader-bootstrap-3181.test.js +24 -245
- package/dist/subagents/__tests__/leader-bootstrap-3181.test.js.map +1 -1
- package/dist/subagents/tracker.d.ts +1 -82
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +3 -275
- 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 +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 +110 -3
- package/dist/team/__tests__/model-contract.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 +3204 -335
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +2359 -142
- package/dist/team/__tests__/scaling.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 +3049 -784
- package/dist/team/__tests__/tmux-session.test.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.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/runtime.d.ts +1 -0
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +1244 -180
- 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 +1430 -384
- 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/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.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-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 +123 -23
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +1250 -291
- 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/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/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/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/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 +1 -1
- 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/ralph/SKILL.md +6 -4
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +3 -2
- package/plugins/oh-my-codex/skills/team/SKILL.md +13 -9
- package/skills/ralph/SKILL.md +6 -4
- package/skills/ralplan/SKILL.md +3 -2
- package/skills/team/SKILL.md +13 -9
- package/src/scripts/__tests__/codex-native-hook.test.ts +2826 -497
- package/src/scripts/__tests__/reasoning-artifact-contract.test.ts +129 -0
- package/src/scripts/__tests__/role-intent-bootstrap-e2e-3181.test.ts +48 -185
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +44 -177
- package/src/scripts/__tests__/smoke-packed-install.test.ts +320 -2
- package/src/scripts/codex-native-hook.ts +10715 -1069
- package/src/scripts/notify-fallback-watcher.ts +84 -115
- package/src/scripts/notify-hook/auto-nudge.ts +71 -3
- 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 +28 -2
- package/src/scripts/notify-hook.ts +1 -0
- package/src/scripts/smoke-packed-install.ts +3196 -14
- 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
|
@@ -1,174 +1,54 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
5
|
import { describe, it } from 'node:test';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
async function
|
|
10
|
-
const
|
|
11
|
-
const stderr = [];
|
|
12
|
-
const previous = process.exitCode;
|
|
6
|
+
import { bindPendingRoleIntentUnderLock, readSubagentTrackingState, readSubagentTrackingStateStrict, recordPendingRoleIntent, subagentTrackingPath, } from '../../subagents/tracker.js';
|
|
7
|
+
const ARCHITECT_TOKEN = 'abcdef0123456789abcdef0123456789';
|
|
8
|
+
const CRITIC_TOKEN = '00112233445566778899aabbccddeeff';
|
|
9
|
+
async function withCwd(fn) {
|
|
10
|
+
const cwd = await mkdtemp(join(tmpdir(), 'omx-3194-'));
|
|
13
11
|
try {
|
|
14
|
-
|
|
15
|
-
await ralplanCommand(args, { cwd: () => cwd, stdout: (l) => stdout.push(l), stderr: (l) => stderr.push(l) });
|
|
16
|
-
return { json: JSON.parse(stdout.join('\n')), exitCode: process.exitCode };
|
|
12
|
+
await fn(cwd);
|
|
17
13
|
}
|
|
18
14
|
finally {
|
|
19
|
-
|
|
15
|
+
await rm(cwd, { recursive: true, force: true });
|
|
20
16
|
}
|
|
21
17
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
delete process.env.OMX_SESSION_ID;
|
|
28
|
-
delete process.env.CODEX_SESSION_ID;
|
|
29
|
-
delete process.env.SESSION_ID;
|
|
30
|
-
try {
|
|
31
|
-
await fn();
|
|
32
|
-
}
|
|
33
|
-
finally {
|
|
34
|
-
for (const key of ['OMX_SESSION_ID', 'CODEX_SESSION_ID', 'SESSION_ID']) {
|
|
35
|
-
if (prior[key] === undefined)
|
|
36
|
-
delete process.env[key];
|
|
37
|
-
else
|
|
38
|
-
process.env[key] = prior[key];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
// Both plugin and legacy delivery drive the same native hook + CLI + tracker recovery path.
|
|
43
|
-
// Leader attestation is established only on the strictly-gated fresh leader PreToolUse
|
|
44
|
-
// entry point (the role-intent command's own PreToolUse fires before it executes); both
|
|
45
|
-
// deliveries route through it, so durable recovery is proven identically for each.
|
|
46
|
-
const DELIVERIES = [
|
|
47
|
-
{ label: 'plugin (PreToolUse-seeded)', event: 'PreToolUse' },
|
|
48
|
-
{ label: 'legacy (PreToolUse-seeded)', event: 'PreToolUse' },
|
|
49
|
-
];
|
|
50
|
-
async function seedAuthenticatedLeader(cwd, sessionId, event) {
|
|
51
|
-
if (event === 'SessionStart') {
|
|
52
|
-
await dispatchCodexNativeHook({ hook_event_name: 'SessionStart', cwd, session_id: sessionId }, { cwd, sessionOwnerPid: process.pid });
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
await dispatchCodexNativeHook({
|
|
56
|
-
hook_event_name: 'PreToolUse',
|
|
57
|
-
cwd,
|
|
58
|
-
session_id: sessionId,
|
|
59
|
-
thread_id: sessionId,
|
|
60
|
-
tool_name: 'Bash',
|
|
61
|
-
tool_use_id: 'tool-first',
|
|
62
|
-
tool_input: { command: 'omx ralplan role-intent write --role architect --parent-thread "$CODEX_THREAD_ID" --json' },
|
|
63
|
-
}, { cwd, sessionOwnerPid: process.pid });
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
describe('#3181 durable bootstrap-order recovery', () => {
|
|
67
|
-
for (const { label, event } of DELIVERIES) {
|
|
68
|
-
it(`${label}: same-session resume recovers the exact adapted Architect intent/receipt/spawn_task_name before any spawn`, async () => {
|
|
69
|
-
const cwd = await mkdtemp(join(tmpdir(), 'omx-3181-recover-'));
|
|
70
|
-
await withFreshEnv(async () => {
|
|
71
|
-
try {
|
|
72
|
-
const sessionId = `codex-native-${event}`;
|
|
73
|
-
await seedAuthenticatedLeader(cwd, sessionId, event);
|
|
74
|
-
// Durably record the Architect intent (before any worker spawn).
|
|
75
|
-
const first = (await invoke(cwd, roleIntentArgs('architect', sessionId))).json;
|
|
76
|
-
assert.equal(first.ok, true);
|
|
77
|
-
assert.equal(first.intent.role, 'architect');
|
|
78
|
-
const token = first.intent.correlation_token;
|
|
79
|
-
const spawnTaskName = first.spawn_task_name;
|
|
80
|
-
// Crash/restart-before-first-spawn: durable state persists on disk. On the SAME
|
|
81
|
-
// canonical session, the resumed leader re-runs role-intent and MUST recover the
|
|
82
|
-
// exact intent/receipt/spawn_task_name — never a fresh unrelated intent.
|
|
83
|
-
const resumed = (await invoke(cwd, roleIntentArgs('architect', sessionId))).json;
|
|
84
|
-
assert.equal(resumed.intent.correlation_token, token, 'exact correlation token must be recovered');
|
|
85
|
-
assert.equal(resumed.spawn_task_name, spawnTaskName, 'exact spawn_task_name must be recovered');
|
|
86
|
-
const state = await readSubagentTrackingState(cwd);
|
|
87
|
-
assert.equal(state.pending_role_intents.length, 1, 'no unrelated replacement intent may be created');
|
|
88
|
-
assert.equal(state.pending_role_intents[0]?.role, 'architect');
|
|
89
|
-
// Ordering invariant: while the Architect intent is still live (pre-spawn), a Critic
|
|
90
|
-
// request for the same leader must NOT reorder/replace it — single_flight_conflict.
|
|
91
|
-
const critic = (await invoke(cwd, roleIntentArgs('critic', sessionId))).json;
|
|
92
|
-
assert.deepEqual(critic, { ok: false, reason: 'single_flight_conflict' });
|
|
93
|
-
assert.equal((await readSubagentTrackingState(cwd)).pending_role_intents.length, 1);
|
|
94
|
-
}
|
|
95
|
-
finally {
|
|
96
|
-
await rm(cwd, { recursive: true, force: true });
|
|
97
|
-
}
|
|
18
|
+
describe('#3194 pending role-intent durability', () => {
|
|
19
|
+
it('keeps Architect before Critic as distinct single-flight intents and preserves binding integrity', async () => {
|
|
20
|
+
await withCwd(async (cwd) => {
|
|
21
|
+
const architect = recordPendingRoleIntent(cwd, {
|
|
22
|
+
role: 'architect', sessionId: 'synthetic-session', parentThreadId: 'synthetic-parent', correlationToken: ARCHITECT_TOKEN, nowMs: 0,
|
|
98
23
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const cwd = await mkdtemp(join(tmpdir(), 'omx-3181-recover-retry-'));
|
|
103
|
-
await withFreshEnv(async () => {
|
|
104
|
-
try {
|
|
105
|
-
const sessionId = 'codex-native-retry';
|
|
106
|
-
await seedAuthenticatedLeader(cwd, sessionId, 'PreToolUse');
|
|
107
|
-
const receipts = [];
|
|
108
|
-
for (let i = 0; i < 3; i += 1) {
|
|
109
|
-
const r = (await invoke(cwd, roleIntentArgs('architect', sessionId))).json;
|
|
110
|
-
receipts.push(r.intent.correlation_token);
|
|
111
|
-
}
|
|
112
|
-
assert.equal(new Set(receipts).size, 1, 'every retry recovers the same receipt');
|
|
113
|
-
assert.equal((await readSubagentTrackingState(cwd)).pending_role_intents.length, 1);
|
|
114
|
-
}
|
|
115
|
-
finally {
|
|
116
|
-
await rm(cwd, { recursive: true, force: true });
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
it('foreign-session resume fails closed and never adopts the foreign leader', async () => {
|
|
121
|
-
const cwd = await mkdtemp(join(tmpdir(), 'omx-3181-recover-foreign-'));
|
|
122
|
-
const prior = process.env.OMX_SESSION_ID;
|
|
123
|
-
try {
|
|
124
|
-
delete process.env.CODEX_SESSION_ID;
|
|
125
|
-
delete process.env.SESSION_ID;
|
|
126
|
-
// Real leader session A is authenticated and has a durable intent.
|
|
127
|
-
await withFreshEnv(async () => {
|
|
128
|
-
await seedAuthenticatedLeader(cwd, 'codex-native-A', 'PreToolUse');
|
|
129
|
-
const r = (await invoke(cwd, roleIntentArgs('architect', 'codex-native-A'))).json;
|
|
130
|
-
assert.equal(r.ok, true);
|
|
24
|
+
assert.equal(architect.ok, true);
|
|
25
|
+
const critic = recordPendingRoleIntent(cwd, {
|
|
26
|
+
role: 'critic', sessionId: 'synthetic-session', parentThreadId: 'synthetic-parent', correlationToken: CRITIC_TOKEN, nowMs: 0,
|
|
131
27
|
});
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
assert.equal(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
28
|
+
assert.deepEqual(critic, { ok: false, reason: 'single_flight_conflict' });
|
|
29
|
+
const binding = bindPendingRoleIntentUnderLock(cwd, {
|
|
30
|
+
sessionId: 'synthetic-session', parentThreadId: 'synthetic-parent', correlationToken: ARCHITECT_TOKEN, nowMs: 1,
|
|
31
|
+
}, (state) => state);
|
|
32
|
+
assert.equal(binding?.role, 'architect');
|
|
33
|
+
assert.equal(binding?.alreadyBound, false);
|
|
34
|
+
const retry = bindPendingRoleIntentUnderLock(cwd, {
|
|
35
|
+
sessionId: 'synthetic-session', parentThreadId: 'synthetic-parent', correlationToken: ARCHITECT_TOKEN, nowMs: 2,
|
|
36
|
+
}, () => { throw new Error('an existing binding must not invoke the callback'); });
|
|
37
|
+
assert.equal(retry?.alreadyBound, true);
|
|
38
|
+
const state = await readSubagentTrackingState(cwd);
|
|
39
|
+
assert.equal(state.pending_role_intents.length, 1);
|
|
40
|
+
assert.equal(state.pending_role_intents[0]?.binding_state, 'bound');
|
|
41
|
+
assert.equal(state.pending_role_intents[0]?.correlation_token, ARCHITECT_TOKEN);
|
|
42
|
+
});
|
|
147
43
|
});
|
|
148
|
-
it('
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
// the CLI strict-reads it and fails closed rather than reading it as empty and
|
|
157
|
-
// overwriting it via the legacy path (which would erase leader/subagent evidence).
|
|
158
|
-
const corrupt = '{ corrupt tracker not valid json';
|
|
159
|
-
await mkdir(join(cwd, '.omx', 'state'), { recursive: true });
|
|
160
|
-
await writeFile(subagentTrackingPath(cwd), corrupt);
|
|
161
|
-
// A spoofed parent AND the real native leader both fail closed on a corrupt tracker.
|
|
162
|
-
const spoofed = (await invoke(cwd, roleIntentArgs('architect', 'attacker-thread'))).json;
|
|
163
|
-
assert.deepEqual(spoofed, { ok: false, reason: 'native_anchor_unavailable' }, 'spoof on a corrupt tracker fails closed');
|
|
164
|
-
const nativeLeader = (await invoke(cwd, roleIntentArgs('architect', sessionId))).json;
|
|
165
|
-
assert.deepEqual(nativeLeader, { ok: false, reason: 'native_anchor_unavailable' }, 'even the native leader fails closed on a corrupt tracker');
|
|
166
|
-
// The corrupt tracker is never overwritten (evidence preserved, not silently reset).
|
|
167
|
-
assert.equal(await readFile(subagentTrackingPath(cwd), 'utf-8'), corrupt, 'corrupt tracker must not be overwritten');
|
|
168
|
-
}
|
|
169
|
-
finally {
|
|
170
|
-
await rm(cwd, { recursive: true, force: true });
|
|
171
|
-
}
|
|
44
|
+
it('strictly rejects corrupt durable tracker bytes without mutation', async () => {
|
|
45
|
+
await withCwd(async (cwd) => {
|
|
46
|
+
const path = subagentTrackingPath(cwd);
|
|
47
|
+
const corrupt = '{ synthetic corrupt tracker';
|
|
48
|
+
await mkdir(dirname(path), { recursive: true });
|
|
49
|
+
await writeFile(path, corrupt);
|
|
50
|
+
assert.deepEqual(await readSubagentTrackingStateStrict(cwd), { ok: false });
|
|
51
|
+
assert.equal(await readFile(path, 'utf8'), corrupt);
|
|
172
52
|
});
|
|
173
53
|
});
|
|
174
54
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-intent-durable-recovery-3181.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"role-intent-durable-recovery-3181.test.js","sourceRoot":"","sources":["../../../src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { access, chmod, mkdtemp, mkdir, rm, symlink, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { access, chmod, mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises';
|
|
4
4
|
import { EventEmitter } from 'node:events';
|
|
5
5
|
import { tmpdir } from 'node:os';
|
|
6
6
|
import { delimiter, join } from 'node:path';
|
|
7
7
|
import { PassThrough } from 'node:stream';
|
|
8
8
|
import { test } from 'node:test';
|
|
9
|
-
import { ensureRepoDependencies, hasUsableNodeModules, buildPackedRegressionEnvironment, CODEX_APP_SERVER_TIMEOUTS, CodexAppServer, CodexExecutableNotFoundError, MANAGED_CODEX_HOOK_EVENTS, PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS, PACKED_INSTALL_NATIVE_HOOK_REGRESSION_PROMPTS, PACKED_INSTALL_SMOKE_CORE_COMMANDS, appendForeignHookGroups, appendDisplayOrderStableForeignHookGroups,
|
|
9
|
+
import { assertInstalledPluginSurface, assertInstalledReasoningDeclarationContract, assertInstalledReasoningRuntimeContract, assertInstalledRootReasoningHelp, assertInstalledRootReasoningRejection, assertInstalledTeamSkillContract, assertPackedInstallFileMetadata, buildNativeHookSmokePayload, ensureRepoDependencies, hasUsableNodeModules, buildPackedRegressionEnvironment, CODEX_APP_SERVER_TIMEOUTS, CodexAppServer, CodexExecutableNotFoundError, MANAGED_CODEX_HOOK_EVENTS, PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS, PACKED_INSTALL_NATIVE_HOOK_REGRESSION_PROMPTS, PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, PACKED_INSTALL_SMOKE_CORE_COMMANDS, appendForeignHookGroups, appendDisplayOrderStableForeignHookGroups, createCodexBatchWriteEnvelope, createCodexHooksListEnvelope, createCodexInitializeEnvelope, foreignHookGroupSnapshot, generatedHookTrustState, isForbiddenPackedInstallArtifact, PACKED_INSTALL_FORBIDDEN_ARTIFACT_PATHS, PACKED_INSTALL_REQUIRED_ARTIFACT_PATHS, PACKED_INSTALL_PLUGIN_MCP_TARGETS, parseFakeCodexLaunches, parseNpmPackJsonOutput, parseCodexHooksListResult, probeCodexVersion, resolveGitCommonDir, resolveReusableNodeModulesSource, validateHookStdout, assertCodexBatchWriteResult, assertGeneratedTrustMatchesCodex, managedCodexHooksByEvent, } from '../smoke-packed-install.js';
|
|
10
|
+
import { parseNativeSubagentResultDisposition } from '../../leader/contract.js';
|
|
10
11
|
function createFakeCodexAppServer(onRequest) {
|
|
11
12
|
const child = Object.assign(new EventEmitter(), {
|
|
12
13
|
stdin: new PassThrough(),
|
|
@@ -28,6 +29,36 @@ test('packed install smoke retains narrow boot commands and adds the isolated li
|
|
|
28
29
|
assert.equal(PACKED_INSTALL_SMOKE_CORE_COMMANDS.some((argv) => argv.includes('api')), true);
|
|
29
30
|
assert.equal(PACKED_INSTALL_SMOKE_CORE_COMMANDS.some((argv) => argv.includes('sparkshell')), true);
|
|
30
31
|
});
|
|
32
|
+
test('packed 0.144.5 fixture is sanitized, pointer-free, and kept separate from the 0.142.5 lifecycle pin', () => {
|
|
33
|
+
assert.deepEqual(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, {
|
|
34
|
+
hook_event_name: 'PreToolUse',
|
|
35
|
+
session_id: 'packed-01445-session',
|
|
36
|
+
turn_id: 'packed-01445-turn',
|
|
37
|
+
tool_name: 'Bash',
|
|
38
|
+
tool_use_id: 'packed-01445-tool',
|
|
39
|
+
tool_input: { command: 'omx ralplan role-intent write --role architect --parent-thread "$CODEX_THREAD_ID" --json' },
|
|
40
|
+
});
|
|
41
|
+
assert.equal(Object.hasOwn(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, 'tracker'), false);
|
|
42
|
+
assert.equal(Object.hasOwn(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, 'session_pointer'), false);
|
|
43
|
+
assert.equal(Object.hasOwn(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, 'cwd'), false);
|
|
44
|
+
assert.equal(Object.hasOwn(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE, 'thread_id'), false);
|
|
45
|
+
assert.equal(PACKED_CODEX_01445_NO_POINTER_NO_TRACKER_FIXTURE.session_id.includes('-'), true);
|
|
46
|
+
});
|
|
47
|
+
test('packed plugin collaboration success stays authoritative over unrelated child prose', () => {
|
|
48
|
+
const packedResponse = JSON.stringify({
|
|
49
|
+
success: true,
|
|
50
|
+
status: 'completed',
|
|
51
|
+
output: 'Packed/plugin child succeeded; an optional adapter was unavailable, unsupported, and not found.',
|
|
52
|
+
});
|
|
53
|
+
for (const toolName of [
|
|
54
|
+
'collaboration.spawn_agent',
|
|
55
|
+
'collaboration.list_agents',
|
|
56
|
+
'collaboration.followup_task',
|
|
57
|
+
'collaboration.wait_agent',
|
|
58
|
+
]) {
|
|
59
|
+
assert.equal(parseNativeSubagentResultDisposition(toolName, packedResponse).kind, 'success', toolName);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
31
62
|
test('packed lifecycle keeps the pinned newline-delimited Codex app-server envelopes literal', () => {
|
|
32
63
|
assert.deepEqual(createCodexInitializeEnvelope('omx-hook-trust-regression'), {
|
|
33
64
|
id: 1,
|
|
@@ -662,6 +693,16 @@ test('display-order-stable foreign fixture preserves pre-approved group and hand
|
|
|
662
693
|
{ event: 'PreToolUse', groupIndex: 1, handlerIndex: 2 },
|
|
663
694
|
]);
|
|
664
695
|
});
|
|
696
|
+
test('packed install smoke probes every advertised plugin MCP target', () => {
|
|
697
|
+
assert.deepEqual(PACKED_INSTALL_PLUGIN_MCP_TARGETS, [
|
|
698
|
+
['omx_state', 'state', 'omx-state'],
|
|
699
|
+
['omx_memory', 'memory', 'omx-memory'],
|
|
700
|
+
['omx_code_intel', 'code-intel', 'omx-code-intel'],
|
|
701
|
+
['omx_trace', 'trace', 'omx-trace'],
|
|
702
|
+
['omx_wiki', 'wiki', 'omx-wiki'],
|
|
703
|
+
['omx_hermes', 'hermes', 'omx-hermes'],
|
|
704
|
+
]);
|
|
705
|
+
});
|
|
665
706
|
test('packed install smoke covers every installed native hook event with minimal payloads', () => {
|
|
666
707
|
assert.deepEqual(PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS, [
|
|
667
708
|
'SessionStart',
|
|
@@ -881,6 +922,27 @@ test('packed install native hook stdout validation enforces event output contrac
|
|
|
881
922
|
}
|
|
882
923
|
assert.throws(() => validateHookStdout('UserPromptSubmit', '{not json'), /native hook UserPromptSubmit emitted invalid JSON stdout/);
|
|
883
924
|
});
|
|
925
|
+
test('fake Codex launch capture preserves argv and runtime side-effect evidence', () => {
|
|
926
|
+
const capture = `${JSON.stringify({
|
|
927
|
+
argv: ['--', '--spark'],
|
|
928
|
+
cwd: '/tmp/omx-packed-launch',
|
|
929
|
+
hasResumeSqlite: true,
|
|
930
|
+
OMX_NOTIFY_TEMP_CONTRACT: null,
|
|
931
|
+
OMX_TEAM_WORKER_LAUNCH_ARGS: null,
|
|
932
|
+
})}\n`;
|
|
933
|
+
assert.deepEqual(parseFakeCodexLaunches(capture), [{
|
|
934
|
+
argv: ['--', '--spark'],
|
|
935
|
+
cwd: '/tmp/omx-packed-launch',
|
|
936
|
+
hasResumeSqlite: true,
|
|
937
|
+
OMX_NOTIFY_TEMP_CONTRACT: null,
|
|
938
|
+
OMX_TEAM_WORKER_LAUNCH_ARGS: null,
|
|
939
|
+
}]);
|
|
940
|
+
assert.throws(() => parseFakeCodexLaunches(`${JSON.stringify({
|
|
941
|
+
argv: ['--spark'],
|
|
942
|
+
cwd: '/tmp/omx-packed-launch',
|
|
943
|
+
OMX_NOTIFY_TEMP_CONTRACT: null,
|
|
944
|
+
})}\n`), /fake Codex capture did not contain a valid launch record/);
|
|
945
|
+
});
|
|
884
946
|
test('parseNpmPackJsonOutput ignores prepack logs before npm pack JSON', () => {
|
|
885
947
|
const parsed = parseNpmPackJsonOutput([
|
|
886
948
|
'[sync-plugin-mirror] synced 29 canonical skill directories and plugin metadata',
|
|
@@ -893,6 +955,196 @@ test('parseNpmPackJsonOutput ignores prepack logs before npm pack JSON', () => {
|
|
|
893
955
|
].join('\n'));
|
|
894
956
|
assert.deepEqual(parsed, [{ filename: 'oh-my-codex-0.15.0.tgz' }]);
|
|
895
957
|
});
|
|
958
|
+
test('packed install metadata requires runtime, declarations, Team skills, and plugin assets only', () => {
|
|
959
|
+
const files = PACKED_INSTALL_REQUIRED_ARTIFACT_PATHS.map((path) => ({ path }));
|
|
960
|
+
assert.doesNotThrow(() => assertPackedInstallFileMetadata(files));
|
|
961
|
+
assert.equal(PACKED_INSTALL_REQUIRED_ARTIFACT_PATHS.some((path) => path.startsWith('docs/')), false, 'repository documentation must not become an npm package requirement');
|
|
962
|
+
assert.throws(() => assertPackedInstallFileMetadata(files.slice(1)), /npm pack is missing required artifact: dist\/config\/models\.js/);
|
|
963
|
+
assert.throws(() => assertPackedInstallFileMetadata([...files, { path: 'docs/reference/omx-config-schema-routing.md' }]), /npm pack includes forbidden workspace artifact: docs\/reference\/omx-config-schema-routing\.md/);
|
|
964
|
+
for (const path of [
|
|
965
|
+
'.gjc/session/plan.md',
|
|
966
|
+
'docs/reference/page.md',
|
|
967
|
+
'.omx/state/team.json',
|
|
968
|
+
'artifact.tgz',
|
|
969
|
+
'tmp/smoke-output.txt',
|
|
970
|
+
'temp/smoke-output.json',
|
|
971
|
+
'scratch.tmp',
|
|
972
|
+
]) {
|
|
973
|
+
assert.equal(isForbiddenPackedInstallArtifact(path), true, `expected ${path} to be rejected`);
|
|
974
|
+
}
|
|
975
|
+
for (const prefix of PACKED_INSTALL_FORBIDDEN_ARTIFACT_PATHS) {
|
|
976
|
+
assert.equal(isForbiddenPackedInstallArtifact(`${prefix}probe`), true);
|
|
977
|
+
}
|
|
978
|
+
assert.equal(isForbiddenPackedInstallArtifact('templates/AGENTS.md'), false);
|
|
979
|
+
assert.equal(isForbiddenPackedInstallArtifact('dist/notifications/__tests__/temp-mode.test.d.ts'), false);
|
|
980
|
+
});
|
|
981
|
+
test('packed install helpers enforce root rejection and no config mutation', () => {
|
|
982
|
+
const help = 'Usage: omx reasoning <low|medium|high|xhigh>\n --xhigh\n';
|
|
983
|
+
assert.doesNotThrow(() => assertInstalledRootReasoningHelp(help));
|
|
984
|
+
assert.throws(() => assertInstalledRootReasoningHelp(`${help} --max\n`), /must not advertise --max/);
|
|
985
|
+
const maxStderr = [
|
|
986
|
+
'Reasoning mode "max" is not supported by "omx reasoning".',
|
|
987
|
+
'Per-agent "max" is configured with agentReasoning; direct -c model_reasoning_effort=... is passed to Codex and remains capability-dependent.',
|
|
988
|
+
'Invalid reasoning mode "max". Expected one of: low, medium, high, xhigh.',
|
|
989
|
+
'Usage: omx reasoning <low|medium|high|xhigh>',
|
|
990
|
+
].join('\n');
|
|
991
|
+
assert.doesNotThrow(() => assertInstalledRootReasoningRejection('max', { status: 1, stdout: '', stderr: maxStderr }, undefined, undefined));
|
|
992
|
+
assert.throws(() => assertInstalledRootReasoningRejection('max', { status: 1, stdout: '', stderr: maxStderr }, undefined, 'created'), /must not create or mutate config\.toml/);
|
|
993
|
+
const ultraStderr = [
|
|
994
|
+
'Reasoning mode "ultra" is not supported by OMX root or per-agent reasoning and is not an alias for "max".',
|
|
995
|
+
'Direct -c model_reasoning_effort=... remains opaque Codex passthrough.',
|
|
996
|
+
'Invalid reasoning mode "ultra". Expected one of: low, medium, high, xhigh.',
|
|
997
|
+
'Usage: omx reasoning <low|medium|high|xhigh>',
|
|
998
|
+
].join('\n');
|
|
999
|
+
assert.doesNotThrow(() => assertInstalledRootReasoningRejection('ultra', { status: 1, stdout: '', stderr: ultraStderr }, 'model = "preserve"\n', 'model = "preserve"\n'));
|
|
1000
|
+
});
|
|
1001
|
+
test('packed install helpers freeze installed runtime and declaration reasoning contracts', () => {
|
|
1002
|
+
const models = {
|
|
1003
|
+
CANONICAL_REASONING_EFFORTS: ['low', 'medium', 'high', 'xhigh'],
|
|
1004
|
+
AMBIGUOUS_UNSUPPORTED_REASONING_EFFORTS: ['max', 'ultra'],
|
|
1005
|
+
PER_AGENT_REASONING_EFFORTS: ['low', 'medium', 'high', 'xhigh', 'max'],
|
|
1006
|
+
ROOT_REASONING_EFFORTS: ['low', 'medium', 'high', 'xhigh'],
|
|
1007
|
+
ROOT_UNSUPPORTED_REASONING_EFFORTS: ['max', 'ultra'],
|
|
1008
|
+
isAmbiguousUnsupportedReasoningEffort: (value) => value.toLowerCase() === 'max' || value.toLowerCase() === 'ultra',
|
|
1009
|
+
isUnsupportedRootReasoningEffort: (value) => value.toLowerCase() === 'max' || value.toLowerCase() === 'ultra',
|
|
1010
|
+
normalizeUnsupportedRootReasoningEffort: (value) => {
|
|
1011
|
+
const normalized = value.trim().toLowerCase();
|
|
1012
|
+
return normalized === 'max' || normalized === 'ultra' ? normalized : undefined;
|
|
1013
|
+
},
|
|
1014
|
+
};
|
|
1015
|
+
assert.doesNotThrow(() => assertInstalledReasoningRuntimeContract(models));
|
|
1016
|
+
const modelsDeclaration = [
|
|
1017
|
+
'export declare const CANONICAL_REASONING_EFFORTS: readonly ["low", "medium", "high", "xhigh"];',
|
|
1018
|
+
'export type ConfiguredAgentReasoningEffort = (typeof CANONICAL_REASONING_EFFORTS)[number];',
|
|
1019
|
+
'export declare const AMBIGUOUS_UNSUPPORTED_REASONING_EFFORTS: readonly ["max", "ultra"];',
|
|
1020
|
+
'export declare const PER_AGENT_REASONING_EFFORTS: readonly ["low", "medium", "high", "xhigh", "max"];',
|
|
1021
|
+
'export type PerAgentReasoningEffort = (typeof PER_AGENT_REASONING_EFFORTS)[number];',
|
|
1022
|
+
'export declare const ROOT_REASONING_EFFORTS: readonly ["low", "medium", "high", "xhigh"];',
|
|
1023
|
+
'export type RootReasoningEffort = (typeof ROOT_REASONING_EFFORTS)[number];',
|
|
1024
|
+
'export declare const ROOT_UNSUPPORTED_REASONING_EFFORTS: readonly ["max", "ultra"];',
|
|
1025
|
+
'export declare function isUnsupportedRootReasoningEffort(value: string): boolean;',
|
|
1026
|
+
'export declare function normalizeUnsupportedRootReasoningEffort(value: string): RootUnsupportedReasoningEffort | undefined;',
|
|
1027
|
+
].join('\n');
|
|
1028
|
+
const definitionsDeclaration = [
|
|
1029
|
+
'export interface AgentDefinition {',
|
|
1030
|
+
" reasoningEffort: 'low' | 'medium' | 'high' | 'xhigh';",
|
|
1031
|
+
'}',
|
|
1032
|
+
].join('\n');
|
|
1033
|
+
assert.doesNotThrow(() => assertInstalledReasoningDeclarationContract({
|
|
1034
|
+
models: modelsDeclaration,
|
|
1035
|
+
definitions: definitionsDeclaration,
|
|
1036
|
+
nativeConfig: 'export interface GeneratedNativeAgentConfig {\n reasoningEffort?: PerAgentReasoningEffort;\n}',
|
|
1037
|
+
team: 'export type TeamReasoningEffort = PerAgentReasoningEffort;',
|
|
1038
|
+
}));
|
|
1039
|
+
assert.throws(() => assertInstalledReasoningDeclarationContract({
|
|
1040
|
+
models: modelsDeclaration.replace(': boolean;', ': value is RootUnsupportedReasoningEffort;'),
|
|
1041
|
+
definitions: definitionsDeclaration,
|
|
1042
|
+
nativeConfig: 'reasoningEffort?: PerAgentReasoningEffort;',
|
|
1043
|
+
team: 'export type TeamReasoningEffort = PerAgentReasoningEffort;',
|
|
1044
|
+
}), /plain boolean, not a type predicate/);
|
|
1045
|
+
});
|
|
1046
|
+
test('packed install contract requires canonical/plugin Team skill parity and text', async () => {
|
|
1047
|
+
const canonical = await readFile(join(process.cwd(), 'skills/team/SKILL.md'));
|
|
1048
|
+
const pluginMirror = await readFile(join(process.cwd(), 'plugins/oh-my-codex/skills/team/SKILL.md'));
|
|
1049
|
+
assert.doesNotThrow(() => assertInstalledTeamSkillContract(canonical, pluginMirror));
|
|
1050
|
+
});
|
|
1051
|
+
test('packed install plugin assertions enforce the packaged plugin contract', async () => {
|
|
1052
|
+
const root = await mkdtemp(join(tmpdir(), 'omx-packed-plugin-surface-'));
|
|
1053
|
+
try {
|
|
1054
|
+
const pluginRoot = join(root, 'plugins/oh-my-codex');
|
|
1055
|
+
const pluginManifestPath = join(pluginRoot, '.codex-plugin/plugin.json');
|
|
1056
|
+
const mcpManifestPath = join(pluginRoot, '.mcp.json');
|
|
1057
|
+
const appManifestPath = join(pluginRoot, '.app.json');
|
|
1058
|
+
const hooksManifestPath = join(pluginRoot, 'hooks/hooks.json');
|
|
1059
|
+
const hookLauncherPath = join(pluginRoot, 'hooks/codex-native-hook.mjs');
|
|
1060
|
+
const hookCommand = 'node "${PLUGIN_ROOT}/hooks/codex-native-hook.mjs"';
|
|
1061
|
+
await mkdir(join(pluginRoot, '.codex-plugin'), { recursive: true });
|
|
1062
|
+
await mkdir(join(pluginRoot, 'hooks'), { recursive: true });
|
|
1063
|
+
const writeValidPluginSurface = async () => {
|
|
1064
|
+
await writeFile(pluginManifestPath, JSON.stringify({
|
|
1065
|
+
name: 'oh-my-codex',
|
|
1066
|
+
version: '0.0.0-test',
|
|
1067
|
+
skills: './skills/',
|
|
1068
|
+
mcpServers: './.mcp.json',
|
|
1069
|
+
apps: './.app.json',
|
|
1070
|
+
hooks: './hooks/hooks.json',
|
|
1071
|
+
interface: {
|
|
1072
|
+
displayName: 'OMX',
|
|
1073
|
+
shortDescription: 'Test plugin',
|
|
1074
|
+
longDescription: 'Structurally valid plugin test fixture.',
|
|
1075
|
+
developerName: 'Test',
|
|
1076
|
+
category: 'Developer Tools',
|
|
1077
|
+
},
|
|
1078
|
+
}));
|
|
1079
|
+
await writeFile(mcpManifestPath, JSON.stringify({
|
|
1080
|
+
mcpServers: Object.fromEntries([
|
|
1081
|
+
['omx_state', 'state'],
|
|
1082
|
+
['omx_memory', 'memory'],
|
|
1083
|
+
['omx_code_intel', 'code-intel'],
|
|
1084
|
+
['omx_trace', 'trace'],
|
|
1085
|
+
['omx_wiki', 'wiki'],
|
|
1086
|
+
['omx_hermes', 'hermes'],
|
|
1087
|
+
].map(([name, service]) => [name, {
|
|
1088
|
+
command: 'omx',
|
|
1089
|
+
args: ['mcp-serve', service],
|
|
1090
|
+
enabled: false,
|
|
1091
|
+
}])),
|
|
1092
|
+
}));
|
|
1093
|
+
await writeFile(appManifestPath, JSON.stringify({ apps: {} }));
|
|
1094
|
+
await writeFile(hooksManifestPath, JSON.stringify({
|
|
1095
|
+
hooks: Object.fromEntries(PACKED_INSTALL_NATIVE_HOOK_SMOKE_EVENTS.map((eventName) => [eventName, [{
|
|
1096
|
+
hooks: [{ type: 'command', command: hookCommand }],
|
|
1097
|
+
}]])),
|
|
1098
|
+
}));
|
|
1099
|
+
await writeFile(hookLauncherPath, [
|
|
1100
|
+
'#!/usr/bin/env node',
|
|
1101
|
+
"import { spawn } from 'node:child_process';",
|
|
1102
|
+
"import { join } from 'node:path';",
|
|
1103
|
+
"const OMX_PLUGIN_HOOK_LAUNCHER_CONTRACT_MARKER = 'omx-plugin-hook-launcher:v1';",
|
|
1104
|
+
"const hookDir = new URL('.', import.meta.url).pathname;",
|
|
1105
|
+
'function readPinnedLauncher() {',
|
|
1106
|
+
" const launcherPath = join(hookDir, 'omx-command.json');",
|
|
1107
|
+
' return { command: process.execPath, argsPrefix: [], launcherPath };',
|
|
1108
|
+
'}',
|
|
1109
|
+
'const input = Buffer.from(\'\');',
|
|
1110
|
+
'const { command, argsPrefix } = readPinnedLauncher();',
|
|
1111
|
+
"const child = spawn(command, [...argsPrefix, 'codex-native-hook']);",
|
|
1112
|
+
'child.stdin.end(input);',
|
|
1113
|
+
'',
|
|
1114
|
+
].join('\n'));
|
|
1115
|
+
};
|
|
1116
|
+
await writeValidPluginSurface();
|
|
1117
|
+
assert.doesNotThrow(() => assertInstalledPluginSurface(root));
|
|
1118
|
+
await writeValidPluginSurface();
|
|
1119
|
+
await writeFile(hookLauncherPath, [
|
|
1120
|
+
'#!/usr/bin/env node',
|
|
1121
|
+
"const OMX_PLUGIN_HOOK_LAUNCHER_CONTRACT_MARKER = 'omx-plugin-hook-launcher:v1';",
|
|
1122
|
+
'process.stdout.write(OMX_PLUGIN_HOOK_LAUNCHER_CONTRACT_MARKER);',
|
|
1123
|
+
'',
|
|
1124
|
+
].join('\n'));
|
|
1125
|
+
assert.throws(() => assertInstalledPluginSurface(root), /must read its pinned omx-command\.json delegate configuration/);
|
|
1126
|
+
await writeFile(pluginManifestPath, '{}');
|
|
1127
|
+
assert.throws(() => assertInstalledPluginSurface(root), /plugin\.json\.name/);
|
|
1128
|
+
await writeValidPluginSurface();
|
|
1129
|
+
await writeFile(mcpManifestPath, JSON.stringify({ mcpServers: {} }));
|
|
1130
|
+
assert.throws(() => assertInstalledPluginSurface(root), /omx_state/);
|
|
1131
|
+
await writeValidPluginSurface();
|
|
1132
|
+
await writeFile(appManifestPath, JSON.stringify({ apps: [] }));
|
|
1133
|
+
assert.throws(() => assertInstalledPluginSurface(root), /\.app\.json\.apps/);
|
|
1134
|
+
await writeValidPluginSurface();
|
|
1135
|
+
await writeFile(hooksManifestPath, JSON.stringify({ hooks: {} }));
|
|
1136
|
+
assert.throws(() => assertInstalledPluginSurface(root), /hook event is missing: SessionStart/);
|
|
1137
|
+
await writeValidPluginSurface();
|
|
1138
|
+
await writeFile(hookLauncherPath, 'export {};\n');
|
|
1139
|
+
assert.throws(() => assertInstalledPluginSurface(root), /must start with a Node shebang/);
|
|
1140
|
+
await writeValidPluginSurface();
|
|
1141
|
+
await writeFile(mcpManifestPath, '{not-json');
|
|
1142
|
+
assert.throws(() => assertInstalledPluginSurface(root), /plugin manifest is not parseable JSON/);
|
|
1143
|
+
}
|
|
1144
|
+
finally {
|
|
1145
|
+
await rm(root, { recursive: true, force: true });
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
896
1148
|
test('resolveGitCommonDir resolves relative git common dir output against the repo root', () => {
|
|
897
1149
|
const commonDir = resolveGitCommonDir('/tmp/worktree', () => ({
|
|
898
1150
|
status: 0,
|