oh-my-codex 0.20.3 → 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 +35 -18
- package/Cargo.toml +1 -1
- package/README.md +2 -2
- package/crates/omx-runtime/Cargo.toml +3 -0
- package/crates/omx-runtime/src/main.rs +390 -0
- package/crates/omx-runtime/tests/execution.rs +264 -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/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 +16 -2
- package/dist/auth/hotswap.d.ts.map +1 -1
- package/dist/auth/hotswap.js +22 -7
- 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 +3 -1
- 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 +70 -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 +35 -3
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/exec.test.js +75 -0
- package/dist/cli/__tests__/exec.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +621 -460
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/launch-fallback.test.js +1020 -143
- package/dist/cli/__tests__/launch-fallback.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +4 -3
- 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 +53 -5
- package/dist/cli/__tests__/native-hook-claim-journal.test.js.map +1 -1
- package/dist/cli/__tests__/ralph.test.js +2 -2
- package/dist/cli/__tests__/ralph.test.js.map +1 -1
- package/dist/cli/__tests__/ralplan-bootstrap-3181.test.js +57 -57
- 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 +84 -12
- package/dist/cli/__tests__/ralplan.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__/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 +183 -4
- 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 +45 -1
- 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 +50 -5
- 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 +32 -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 +17 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +277 -3
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +231 -12
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2298 -735
- package/dist/cli/index.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 +8 -4
- package/dist/cli/native-hook-claim-journal.d.ts.map +1 -1
- package/dist/cli/native-hook-claim-journal.js +30 -8
- 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 +4 -2
- package/dist/cli/ralplan.d.ts.map +1 -1
- package/dist/cli/ralplan.js +76 -34
- package/dist/cli/ralplan.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 +3 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +55 -32
- 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.map +1 -1
- package/dist/cli/uninstall.js +27 -28
- 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/config/__tests__/generator-idempotent.test.js +173 -29
- package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
- package/dist/config/__tests__/generator-notify.test.js +3 -1
- package/dist/config/__tests__/generator-notify.test.js.map +1 -1
- package/dist/config/generator.d.ts +25 -3
- package/dist/config/generator.d.ts.map +1 -1
- package/dist/config/generator.js +113 -35
- package/dist/config/generator.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 +3 -1
- 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 +172 -33
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +173 -11
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +1 -0
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js +65 -17
- 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 +2 -2
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +4 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.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-worker-idle.test.js +1 -0
- 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 +2976 -557
- 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 +180 -14
- package/dist/hooks/session.d.ts.map +1 -1
- package/dist/hooks/session.js +1402 -281
- 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 +71 -34
- package/dist/leader/__tests__/contract.test.js.map +1 -1
- package/dist/leader/contract.d.ts +1 -6
- package/dist/leader/contract.d.ts.map +1 -1
- package/dist/leader/contract.js +25 -24
- package/dist/leader/contract.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/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/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/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/pipeline/__tests__/orchestrator.test.js +162 -40
- package/dist/pipeline/__tests__/orchestrator.test.js.map +1 -1
- package/dist/pipeline/__tests__/stages.test.js +66 -149
- 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 +70 -1437
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js +328 -39
- package/dist/ralplan/__tests__/documented-leader-preflight.test.js.map +1 -1
- package/dist/ralplan/__tests__/runtime.test.js +82 -102
- 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 +40 -304
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/ralplan/documented-leader-preflight.d.ts +15 -8
- package/dist/ralplan/documented-leader-preflight.d.ts.map +1 -1
- package/dist/ralplan/documented-leader-preflight.js +356 -54
- package/dist/ralplan/documented-leader-preflight.js.map +1 -1
- package/dist/ralplan/runtime.d.ts +1 -1
- package/dist/ralplan/runtime.d.ts.map +1 -1
- package/dist/ralplan/runtime.js +68 -173
- package/dist/ralplan/runtime.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 +14071 -8859
- 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__/role-intent-bootstrap-e2e-3181.test.js +25 -8
- 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 +60 -25
- package/dist/scripts/__tests__/role-intent-durable-recovery-3181.test.js.map +1 -1
- package/dist/scripts/__tests__/smoke-packed-install.test.js +155 -16
- 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 +50 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +3559 -451
- 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 +28 -39
- package/dist/scripts/notify-fallback-watcher.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-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +32 -3
- package/dist/scripts/notify-hook/team-leader-nudge.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 +23 -3
- package/dist/scripts/notify-hook/team-worker-stop.js.map +1 -1
- package/dist/scripts/notify-hook/team-worker.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-worker.js +45 -5
- 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 +4 -1
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/notify-hook.js +78 -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 +32 -1
- package/dist/scripts/smoke-packed-install.d.ts.map +1 -1
- package/dist/scripts/smoke-packed-install.js +413 -60
- 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 +12 -5
- package/dist/state/__tests__/mode-state-context.test.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +460 -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 +3 -0
- package/dist/state/mode-state-context.d.ts.map +1 -1
- package/dist/state/mode-state-context.js +27 -13
- 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 +27 -0
- 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 +64 -60
- package/dist/subagents/tracker.d.ts.map +1 -1
- package/dist/subagents/tracker.js +809 -358
- package/dist/subagents/tracker.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +6 -7
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/mcp-comm.test.js +104 -3
- package/dist/team/__tests__/mcp-comm.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.test.js +725 -59
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +222 -237
- 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__/tmux-session.test.js +887 -92
- 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 +45 -72
- package/dist/team/__tests__/worker-runtime-identity.test.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 +3 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +314 -142
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +161 -91
- package/dist/team/scaling.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/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 +18 -0
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +36 -0
- package/dist/team/state.js.map +1 -1
- package/dist/team/tmux-session.d.ts +40 -4
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +513 -166
- package/dist/team/tmux-session.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.js +58 -1
- package/dist/utils/__tests__/file-durability.test.js.map +1 -1
- 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 +10 -0
- package/dist/utils/file-durability.d.ts.map +1 -1
- package/dist/utils/file-durability.js +34 -4
- package/dist/utils/file-durability.js.map +1 -1
- 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__/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/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 +81 -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 +5 -5
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +15 -17
- 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 +5 -5
- package/skills/ralplan/SKILL.md +15 -17
- package/skills/ultragoal/SKILL.md +3 -2
- package/src/scripts/__tests__/codex-native-hook.test.ts +6091 -540
- 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__/role-intent-bootstrap-e2e-3181.test.ts +27 -8
- package/src/scripts/__tests__/role-intent-durable-recovery-3181.test.ts +61 -27
- package/src/scripts/__tests__/smoke-packed-install.test.ts +209 -18
- package/src/scripts/__tests__/verify-native-release-assets.test.ts +240 -0
- package/src/scripts/codex-native-hook.ts +3638 -475
- 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 +38 -38
- package/src/scripts/notify-hook/state-io.ts +11 -0
- package/src/scripts/notify-hook/team-leader-nudge.ts +32 -4
- package/src/scripts/notify-hook/team-worker-stop.ts +23 -4
- package/src/scripts/notify-hook/team-worker.ts +43 -5
- package/src/scripts/notify-hook/tmux-injection.ts +5 -1
- package/src/scripts/notify-hook.ts +83 -82
- package/src/scripts/postinstall-advisory.ts +67 -0
- package/src/scripts/postinstall.ts +1 -1
- package/src/scripts/smoke-packed-install.ts +446 -59
- 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
|
@@ -2,6 +2,7 @@ import { spawnSync, execFile } from 'child_process';
|
|
|
2
2
|
import { promisify } from 'util';
|
|
3
3
|
import { closeSync, chmodSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from 'fs';
|
|
4
4
|
import { homedir } from 'os';
|
|
5
|
+
import { randomBytes } from 'crypto';
|
|
5
6
|
import { dirname, isAbsolute, join, relative, resolve, sep } from 'path';
|
|
6
7
|
import { CODEX_BYPASS_FLAG, CLAUDE_SKIP_PERMISSIONS_FLAG, MADMAX_FLAG, CONFIG_FLAG, LONG_CONFIG_FLAG, MODEL_FLAG, } from '../cli/constants.js';
|
|
7
8
|
import { getAgent } from '../agents/definitions.js';
|
|
@@ -55,6 +56,16 @@ class ExactPaneProofUnavailableError extends Error {
|
|
|
55
56
|
this.name = 'ExactPaneProofUnavailableError';
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
class AmbiguousSplitWindowOutputError extends Error {
|
|
60
|
+
newlyObservedPaneIds;
|
|
61
|
+
reconciliationError;
|
|
62
|
+
constructor(newlyObservedPaneIds, reconciliationError = null) {
|
|
63
|
+
super('tmux_split_window_output_ambiguous');
|
|
64
|
+
this.newlyObservedPaneIds = newlyObservedPaneIds;
|
|
65
|
+
this.reconciliationError = reconciliationError;
|
|
66
|
+
this.name = 'AmbiguousSplitWindowOutputError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
58
69
|
const INJECTION_MARKER = '[OMX_TMUX_INJECT]';
|
|
59
70
|
const MODEL_INSTRUCTIONS_FILE_KEY = 'model_instructions_file';
|
|
60
71
|
const OMX_BYPASS_DEFAULT_SYSTEM_PROMPT_ENV = 'OMX_BYPASS_DEFAULT_SYSTEM_PROMPT';
|
|
@@ -101,7 +112,7 @@ const TMUX_PANE_STABILITY_POLL_MS = 60;
|
|
|
101
112
|
const TMUX_PANE_STABILITY_POLLS_REQUIRED = 2;
|
|
102
113
|
const TMUX_PANE_STABILITY_TIMEOUT_MS = 750;
|
|
103
114
|
const OMX_TEAM_STATE_ROOT_ENV = 'OMX_TEAM_STATE_ROOT';
|
|
104
|
-
function runTmux(args) {
|
|
115
|
+
function runTmux(args, preserveStdout = false) {
|
|
105
116
|
const { result } = spawnPlatformCommandSync('tmux', args, { encoding: 'utf-8' });
|
|
106
117
|
if (result.error) {
|
|
107
118
|
return { ok: false, stderr: result.error.message };
|
|
@@ -109,7 +120,16 @@ function runTmux(args) {
|
|
|
109
120
|
if (result.status !== 0) {
|
|
110
121
|
return { ok: false, stderr: (result.stderr || '').trim() || `tmux exited ${result.status}` };
|
|
111
122
|
}
|
|
112
|
-
|
|
123
|
+
const stdout = result.stdout || '';
|
|
124
|
+
return { ok: true, stdout: preserveStdout ? stdout : stdout.trim() };
|
|
125
|
+
}
|
|
126
|
+
export function parseSplitWindowPaneId(stdout, expectedReceipt) {
|
|
127
|
+
const match = expectedReceipt === undefined
|
|
128
|
+
? /^(%\d+)(?:\r?\n)?$/.exec(stdout)
|
|
129
|
+
: /^(%\d+)\t([^\r\n\t]+)(?:\r?\n)?$/.exec(stdout);
|
|
130
|
+
if (!match || (expectedReceipt !== undefined && match[2] !== expectedReceipt))
|
|
131
|
+
return null;
|
|
132
|
+
return match[1];
|
|
113
133
|
}
|
|
114
134
|
/** Preserve structured tmux fields, including an empty final field. */
|
|
115
135
|
/** Preserve structured tmux fields, including an empty final field. */
|
|
@@ -122,6 +142,115 @@ function runTmuxStructured(args) {
|
|
|
122
142
|
}
|
|
123
143
|
return { ok: true, stdout: (result.stdout || '').replace(/\r?\n$/, '') };
|
|
124
144
|
}
|
|
145
|
+
function captureSourcePaneAuthority(paneId, expectedTeamPaneOwnerId) {
|
|
146
|
+
const target = paneId.trim();
|
|
147
|
+
if (!/^%[0-9]+$/.test(target))
|
|
148
|
+
throw new Error(`invalid tmux source pane: ${paneId}`);
|
|
149
|
+
const result = runTmuxStructured([
|
|
150
|
+
'display-message', '-p', '-t', target,
|
|
151
|
+
'#{session_name}\t#{session_id}\t#{session_created}\t#{window_index}\t#{window_id}\t#{pane_id}\t#{pane_pid}',
|
|
152
|
+
]);
|
|
153
|
+
if (!result.ok)
|
|
154
|
+
throw new Error(`failed to capture tmux source authority: ${result.stderr}`);
|
|
155
|
+
const fields = result.stdout.split('\t');
|
|
156
|
+
if (fields.length !== 7)
|
|
157
|
+
throw new Error('malformed tmux source authority');
|
|
158
|
+
const [sessionName, sessionId, sessionCreated, windowIndex, windowId, capturedPaneId, panePid] = fields;
|
|
159
|
+
if (!sessionName || !/^\$[0-9]+$/.test(sessionId) || !/^[0-9]+$/.test(sessionCreated)
|
|
160
|
+
|| !/^[0-9]+$/.test(windowIndex) || !/^@[0-9]+$/.test(windowId)
|
|
161
|
+
|| capturedPaneId !== target || !/^[1-9][0-9]*$/.test(panePid)) {
|
|
162
|
+
throw new Error('malformed tmux source authority');
|
|
163
|
+
}
|
|
164
|
+
const parsedPid = Number(panePid);
|
|
165
|
+
if (!Number.isSafeInteger(parsedPid) || parsedPid <= 0)
|
|
166
|
+
throw new Error('malformed tmux source authority');
|
|
167
|
+
const proof = readExactPaneProofSync(target);
|
|
168
|
+
if (proof.status === 'unavailable')
|
|
169
|
+
throw new ExactPaneProofUnavailableError(proof);
|
|
170
|
+
if (proof.status !== 'live' || proof.pid !== parsedPid)
|
|
171
|
+
throw new Error(`tmux pane identity changed: ${target}`);
|
|
172
|
+
const ownerResult = runTmuxStructured(['show-option', '-qv', '-p', '-t', target, OMX_TEAM_PANE_OWNER_OPTION]);
|
|
173
|
+
if (!ownerResult.ok)
|
|
174
|
+
throw new Error(`failed to capture tmux pane owner: ${ownerResult.stderr}`);
|
|
175
|
+
const teamPaneOwnerId = ownerResult.stdout.trim() || null;
|
|
176
|
+
if (teamPaneOwnerId && !/^[A-Za-z0-9._:-]+$/.test(teamPaneOwnerId)) {
|
|
177
|
+
throw new Error('malformed tmux pane owner');
|
|
178
|
+
}
|
|
179
|
+
if (expectedTeamPaneOwnerId !== undefined && teamPaneOwnerId !== expectedTeamPaneOwnerId) {
|
|
180
|
+
throw new Error(`tmux pane team owner changed: ${target}`);
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
paneId: target,
|
|
184
|
+
panePid: parsedPid,
|
|
185
|
+
sessionName,
|
|
186
|
+
sessionId,
|
|
187
|
+
sessionCreated,
|
|
188
|
+
windowId,
|
|
189
|
+
windowIndex,
|
|
190
|
+
teamPaneOwnerId,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function sourceAuthorityPredicate(source) {
|
|
194
|
+
return [
|
|
195
|
+
'#{==:#{pane_dead},0}',
|
|
196
|
+
`#{==:#{pane_id},${source.paneId}}`,
|
|
197
|
+
`#{==:#{pane_pid},${source.panePid}}`,
|
|
198
|
+
`#{==:#{session_id},${source.sessionId}}`,
|
|
199
|
+
`#{==:#{session_created},${source.sessionCreated}}`,
|
|
200
|
+
`#{==:#{window_id},${source.windowId}}`,
|
|
201
|
+
...(source.teamPaneOwnerId ? [`#{==:#{${OMX_TEAM_PANE_OWNER_OPTION}},${source.teamPaneOwnerId}}`] : []),
|
|
202
|
+
].reduce((combined, condition) => `#{&&:${combined},${condition}}`);
|
|
203
|
+
}
|
|
204
|
+
function sourceTransactionReceipt() {
|
|
205
|
+
return `omx_source_${process.pid}_${Date.now()}_${randomBytes(16).toString('hex')}`;
|
|
206
|
+
}
|
|
207
|
+
function bindSplitReceiptToPaneCommand(command, receipt) {
|
|
208
|
+
return `${command} # ${receipt}`;
|
|
209
|
+
}
|
|
210
|
+
/** Queue an effect in the source pane's tmux server only when its exact pane/session/window incarnation still matches. */
|
|
211
|
+
export function runSourceAuthorizedTmux(source, effect, receipt = sourceTransactionReceipt()) {
|
|
212
|
+
const result = runTmux([
|
|
213
|
+
'if-shell', '-F', '-t', source.paneId, sourceAuthorityPredicate(source),
|
|
214
|
+
`${effect} ; display-message -p ${shellQuoteSingle(receipt)}`,
|
|
215
|
+
"display-message -p ''",
|
|
216
|
+
]);
|
|
217
|
+
if (!result.ok)
|
|
218
|
+
throw new Error(`tmux source authority transaction failed: ${result.stderr}`);
|
|
219
|
+
if (result.stdout !== receipt)
|
|
220
|
+
throw new Error('tmux source authority changed before effect');
|
|
221
|
+
return receipt;
|
|
222
|
+
}
|
|
223
|
+
function runSourceAuthorizedSplit(source, buildEffect) {
|
|
224
|
+
// Reconcile against the immutable window ID, not the mutable session:index
|
|
225
|
+
// target: a concurrent renumber between the guarded split and the after-read
|
|
226
|
+
// must never turn an unrelated window's pane into kill authority.
|
|
227
|
+
const windowTarget = source.windowId;
|
|
228
|
+
const beforeTopology = listPanesResult(windowTarget);
|
|
229
|
+
if (beforeTopology.error) {
|
|
230
|
+
throw new Error(`failed to read tmux pane topology before split: ${beforeTopology.error}`);
|
|
231
|
+
}
|
|
232
|
+
const beforePaneIds = new Set(beforeTopology.panes.map((pane) => pane.paneId));
|
|
233
|
+
const receipt = sourceTransactionReceipt();
|
|
234
|
+
const effect = buildEffect(receipt);
|
|
235
|
+
const result = runTmux([
|
|
236
|
+
'if-shell', '-F', '-t', source.paneId, sourceAuthorityPredicate(source),
|
|
237
|
+
effect.replace("-F '#{pane_id}'", `-F '#{pane_id}\\t${receipt}'`),
|
|
238
|
+
"display-message -p ''",
|
|
239
|
+
], true);
|
|
240
|
+
if (!result.ok)
|
|
241
|
+
throw new Error(`tmux source authority transaction failed: ${result.stderr}`);
|
|
242
|
+
const paneId = parseSplitWindowPaneId(result.stdout, receipt);
|
|
243
|
+
if (!paneId) {
|
|
244
|
+
const afterTopology = listPanesResult(windowTarget);
|
|
245
|
+
const newlyObservedPaneIds = afterTopology.error
|
|
246
|
+
? []
|
|
247
|
+
: afterTopology.panes
|
|
248
|
+
.filter((pane) => !beforePaneIds.has(pane.paneId) && pane.startCommand.includes(receipt))
|
|
249
|
+
.map((pane) => pane.paneId);
|
|
250
|
+
throw new AmbiguousSplitWindowOutputError(newlyObservedPaneIds, afterTopology.error);
|
|
251
|
+
}
|
|
252
|
+
return paneId;
|
|
253
|
+
}
|
|
125
254
|
function restoredHudCleanupDebtPath(cwd, stateRoot) {
|
|
126
255
|
const canonicalStateRoot = resolveCanonicalTeamStateRoot(resolve(cwd));
|
|
127
256
|
if (typeof stateRoot !== 'string' || !stateRoot.trim()) {
|
|
@@ -338,17 +467,6 @@ function sanitizeTmuxStyleOption(sessionTarget, optionName, beforeEffect) {
|
|
|
338
467
|
const result = runTmux(['set-option', '-t', sessionTarget, optionName, sanitized]);
|
|
339
468
|
return result.ok;
|
|
340
469
|
}
|
|
341
|
-
function tagPaneInstance(paneTarget, instanceId, expectedPanePid) {
|
|
342
|
-
const target = paneTarget.trim();
|
|
343
|
-
const sanitized = instanceId.trim();
|
|
344
|
-
if (!target || !sanitized)
|
|
345
|
-
return;
|
|
346
|
-
const provenTarget = requireLiveExactPaneSync(target, expectedPanePid);
|
|
347
|
-
const result = runTmux(['set-option', '-p', '-t', provenTarget, OMX_PANE_INSTANCE_OPTION, sanitized]);
|
|
348
|
-
if (!result.ok) {
|
|
349
|
-
throw new Error(`failed to tag tmux pane ${provenTarget}: ${result.stderr}`);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
470
|
export function tagPaneTeamOwner(paneTarget, teamOwnerId, expectedPanePid) {
|
|
353
471
|
const target = paneTarget.trim();
|
|
354
472
|
const sanitized = teamOwnerId.trim();
|
|
@@ -471,6 +589,13 @@ function requireLiveTeamOwnedPaneSync(paneId, expectedPanePid, expectedTeamOwner
|
|
|
471
589
|
}
|
|
472
590
|
return requireLiveExactPaneSync(target, expectedPanePid);
|
|
473
591
|
}
|
|
592
|
+
function frozenWindowTopologyError(teamTarget, expectedPaneIds, actualPaneIds) {
|
|
593
|
+
const expected = [...expectedPaneIds].sort();
|
|
594
|
+
const actual = [...actualPaneIds].sort();
|
|
595
|
+
const unexpected = actual.filter((paneId) => !expectedPaneIds.has(paneId));
|
|
596
|
+
const missing = expected.filter((paneId) => !actualPaneIds.has(paneId));
|
|
597
|
+
return new Error(`tmux window topology changed before layout mutation: target=${teamTarget}; expected=[${expected.join(',')}]; actual=[${actual.join(',')}]; unexpected=[${unexpected.join(',')}]; missing=[${missing.join(',')}]. Team requires an isolated tmux window with no host-owned foreign panes`);
|
|
598
|
+
}
|
|
474
599
|
function requireFrozenWindowTopologySync(teamTarget, expectedPanePids, expectedPaneOwners) {
|
|
475
600
|
const topology = listPanesResult(teamTarget);
|
|
476
601
|
if (topology.error)
|
|
@@ -478,7 +603,7 @@ function requireFrozenWindowTopologySync(teamTarget, expectedPanePids, expectedP
|
|
|
478
603
|
const actualPaneIds = new Set(topology.panes.map((pane) => pane.paneId));
|
|
479
604
|
if (actualPaneIds.size !== expectedPanePids.size
|
|
480
605
|
|| [...expectedPanePids.keys()].some((paneId) => !actualPaneIds.has(paneId))) {
|
|
481
|
-
throw new
|
|
606
|
+
throw frozenWindowTopologyError(teamTarget, new Set(expectedPanePids.keys()), actualPaneIds);
|
|
482
607
|
}
|
|
483
608
|
for (const [paneId, expectedPanePid] of expectedPanePids) {
|
|
484
609
|
const expectedOwner = expectedPaneOwners?.get(paneId);
|
|
@@ -511,7 +636,7 @@ function requireFrozenWindowTopologySync(teamTarget, expectedPanePids, expectedP
|
|
|
511
636
|
const finalPaneIds = new Set(finalTopology.panes.map((pane) => pane.paneId));
|
|
512
637
|
if (finalPaneIds.size !== expectedPanePids.size
|
|
513
638
|
|| [...expectedPanePids.keys()].some((paneId) => !finalPaneIds.has(paneId))) {
|
|
514
|
-
throw new
|
|
639
|
+
throw frozenWindowTopologyError(teamTarget, new Set(expectedPanePids.keys()), finalPaneIds);
|
|
515
640
|
}
|
|
516
641
|
}
|
|
517
642
|
export function listPaneIds(target) {
|
|
@@ -636,6 +761,59 @@ async function runTmuxAsync(args) {
|
|
|
636
761
|
function hasExplicitWorkerPaneId(workerPaneId) {
|
|
637
762
|
return typeof workerPaneId === 'string' && workerPaneId.trim().length > 0;
|
|
638
763
|
}
|
|
764
|
+
function readExactWorkerPaneLivenessProofSync(paneId) {
|
|
765
|
+
if (!/^%[0-9]+$/.test(paneId))
|
|
766
|
+
return { status: 'unavailable', paneId, reason: 'invalid_pane_id' };
|
|
767
|
+
const result = runTmuxStructured([
|
|
768
|
+
'display-message', '-p', '-t', paneId,
|
|
769
|
+
`#{pane_id}\t#{pane_dead}\t#{pane_pid}\t#{${OMX_TEAM_PANE_OWNER_OPTION}}`,
|
|
770
|
+
]);
|
|
771
|
+
if (!result.ok) {
|
|
772
|
+
if (/can't find pane|no such pane|unknown pane/i.test(result.stderr)) {
|
|
773
|
+
return { status: 'gone', paneId, reason: 'absent' };
|
|
774
|
+
}
|
|
775
|
+
return { status: 'unavailable', paneId, reason: `query_failed:${result.stderr || 'unknown'}` };
|
|
776
|
+
}
|
|
777
|
+
const lines = result.stdout.replace(/\r\n/g, '\n').split('\n').filter((line) => line.length > 0);
|
|
778
|
+
if (lines.length !== 1)
|
|
779
|
+
return { status: 'unavailable', paneId, reason: 'malformed_exact_pane_result' };
|
|
780
|
+
const fields = lines[0].split('\t');
|
|
781
|
+
if (fields.length !== 4)
|
|
782
|
+
return { status: 'unavailable', paneId, reason: 'malformed_exact_pane_result' };
|
|
783
|
+
const [actualPaneId, paneDead, rawPid, ownerId] = fields;
|
|
784
|
+
if (actualPaneId !== paneId) {
|
|
785
|
+
return { status: 'unavailable', paneId, reason: `pane_id_changed:expected=${paneId}:actual=${actualPaneId}` };
|
|
786
|
+
}
|
|
787
|
+
if (paneDead !== '0' && paneDead !== '1')
|
|
788
|
+
return { status: 'unavailable', paneId, reason: 'malformed_exact_pane_result' };
|
|
789
|
+
if (!/^[0-9]+$/.test(rawPid))
|
|
790
|
+
return { status: 'unavailable', paneId, reason: 'malformed_exact_pane_result' };
|
|
791
|
+
const pid = Number(rawPid);
|
|
792
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
793
|
+
return { status: 'unavailable', paneId, reason: 'malformed_exact_pane_result' };
|
|
794
|
+
if (paneDead === '1')
|
|
795
|
+
return { status: 'gone', paneId, reason: 'dead' };
|
|
796
|
+
return { status: 'live', paneId, pid, ownerId };
|
|
797
|
+
}
|
|
798
|
+
function requireExactWorkerPaneLivenessIdentity(paneId, expectedPanePid, expectedTeamOwnerId, hudPaneId) {
|
|
799
|
+
if (hudPaneId?.trim() && paneId === hudPaneId.trim()) {
|
|
800
|
+
throw new Error(`tmux worker pane is HUD target: ${paneId}`);
|
|
801
|
+
}
|
|
802
|
+
const proof = readExactWorkerPaneLivenessProofSync(paneId);
|
|
803
|
+
if (proof.status === 'unavailable' && proof.reason.startsWith('pane_id_changed:')) {
|
|
804
|
+
throw new Error(`tmux worker pane identity changed: ${paneId}: ${proof.reason}`);
|
|
805
|
+
}
|
|
806
|
+
if (proof.status !== 'live')
|
|
807
|
+
return proof;
|
|
808
|
+
if (typeof expectedPanePid === 'number' && proof.pid !== expectedPanePid) {
|
|
809
|
+
throw new Error(`tmux worker pane PID changed: ${paneId}: expected ${expectedPanePid}, got ${proof.pid}`);
|
|
810
|
+
}
|
|
811
|
+
const expectedOwner = typeof expectedTeamOwnerId === 'string' ? expectedTeamOwnerId.trim() : '';
|
|
812
|
+
if (expectedOwner && proof.ownerId !== expectedOwner) {
|
|
813
|
+
throw new Error(`tmux worker pane incarnation changed: ${paneId}: expected ${expectedOwner}, got ${proof.ownerId || 'missing'}`);
|
|
814
|
+
}
|
|
815
|
+
return proof;
|
|
816
|
+
}
|
|
639
817
|
function resolveWorkerPaneTargetSync(sessionName, workerIndex, workerPaneId) {
|
|
640
818
|
if (!hasExplicitWorkerPaneId(workerPaneId))
|
|
641
819
|
return paneTarget(sessionName, workerIndex);
|
|
@@ -883,7 +1061,7 @@ function buildBestEffortShellCommand(command) {
|
|
|
883
1061
|
}
|
|
884
1062
|
function buildAuthoritativeHudResizeShellCommand(hudPaneId, heightLines = HUD_TMUX_TEAM_HEIGHT_LINES, expectedPanePid, expectedPaneOwnerId, effectCommand = buildNestedTmuxShellCommand(buildHudResizeCommand(buildHudPaneTarget(hudPaneId), heightLines))) {
|
|
885
1063
|
const target = buildHudPaneTarget(hudPaneId);
|
|
886
|
-
const snapshot = buildNestedTmuxShellCommand("list-panes -a -F '#{pane_id}
|
|
1064
|
+
const snapshot = buildNestedTmuxShellCommand("list-panes -a -F '#{pane_id}\t#{pane_dead}\t#{pane_pid}'");
|
|
887
1065
|
const expectedPid = typeof expectedPanePid === 'number' && Number.isSafeInteger(expectedPanePid) && expectedPanePid > 0
|
|
888
1066
|
? ` && $3 == "${expectedPanePid}"`
|
|
889
1067
|
: '';
|
|
@@ -949,12 +1127,11 @@ export function buildScheduleDelayedHudResizeArgs(hudPaneId, delaySeconds = HUD_
|
|
|
949
1127
|
export function buildReconcileHudResizeArgs(hudPaneId, heightLines = HUD_TMUX_TEAM_HEIGHT_LINES, expectedPanePid, expectedPaneOwnerId) {
|
|
950
1128
|
return ['run-shell', buildBestEffortShellCommand(buildAuthoritativeHudResizeShellCommand(hudPaneId, heightLines, expectedPanePid, expectedPaneOwnerId))];
|
|
951
1129
|
}
|
|
952
|
-
function redrawLeaderPaneAfterTeamLayout(
|
|
953
|
-
const
|
|
954
|
-
if (
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
runTmux(['send-keys', '-t', provenTarget, 'C-l']);
|
|
1130
|
+
function redrawLeaderPaneAfterTeamLayout(source, expectedTeamOwnerId) {
|
|
1131
|
+
const provenTarget = requireLiveTeamOwnedPaneSync(source.paneId, source.panePid, expectedTeamOwnerId);
|
|
1132
|
+
if (provenTarget !== source.paneId)
|
|
1133
|
+
throw new Error(`tmux pane identity changed: ${source.paneId}`);
|
|
1134
|
+
runSourceAuthorizedTmux(source, `send-keys -t ${source.paneId} C-l`);
|
|
958
1135
|
}
|
|
959
1136
|
const ZSH_CANDIDATE_PATHS = ['/bin/zsh', '/usr/bin/zsh', '/usr/local/bin/zsh', '/opt/local/bin/zsh', '/opt/homebrew/bin/zsh'];
|
|
960
1137
|
const BASH_CANDIDATE_PATHS = ['/bin/bash', '/usr/bin/bash'];
|
|
@@ -1311,6 +1488,23 @@ function appendTeamWorkerMcpDisableOverrides(args, env) {
|
|
|
1311
1488
|
args.splice(endOfOptionsIndex < 0 ? args.length : endOfOptionsIndex, 0, CONFIG_FLAG, `${key}=false`);
|
|
1312
1489
|
}
|
|
1313
1490
|
}
|
|
1491
|
+
const CODEX_BYPASS_MDM_INCOMPATIBLE_REASON = 'codex_bypass_mdm_incompatible';
|
|
1492
|
+
const CODEX_BYPASS_MDM_REJECTED_MARKER = 'MDM_POLICY_REJECTED: approval_policy=never forbids --dangerously-bypass-approvals-and-sandbox';
|
|
1493
|
+
export function classifyCodexBypassMdmIncompatibility(captured, workerCli, finalArgs) {
|
|
1494
|
+
if (workerCli !== 'codex' || !finalArgs || !parseTeamWorkerLaunchArgs([...finalArgs], 'final tmux worker arguments', { directPolicyMode: 'ignore' }).wantsBypass)
|
|
1495
|
+
return null;
|
|
1496
|
+
const normalizedLines = captured.replace(/\r\n?/g, '\n').split('\n');
|
|
1497
|
+
return normalizedLines.includes(CODEX_BYPASS_MDM_REJECTED_MARKER)
|
|
1498
|
+
? CODEX_BYPASS_MDM_INCOMPATIBLE_REASON
|
|
1499
|
+
: null;
|
|
1500
|
+
}
|
|
1501
|
+
function buildAttachedTmuxWorkerStartupPlan(teamName, workerIndex, launchArgs, cwd, extraEnv, workerCliOverride, initialPrompt, workerRole) {
|
|
1502
|
+
const processSpec = buildWorkerStartupProcessLaunchSpec(teamName, workerIndex, launchArgs, cwd, extraEnv, workerCliOverride, initialPrompt, workerRole);
|
|
1503
|
+
const startupArgs = [...processSpec.args];
|
|
1504
|
+
if (processSpec.workerCli === 'codex')
|
|
1505
|
+
appendTeamWorkerMcpDisableOverrides(startupArgs, { ...process.env, ...extraEnv });
|
|
1506
|
+
return Object.freeze({ processSpec, startupArgs: Object.freeze(startupArgs) });
|
|
1507
|
+
}
|
|
1314
1508
|
function insertArgsBeforeEndOfOptions(args, insertedArgs) {
|
|
1315
1509
|
const endOfOptionsIndex = args.indexOf('--');
|
|
1316
1510
|
if (endOfOptionsIndex < 0)
|
|
@@ -1434,24 +1628,17 @@ function buildWorkerStartupScriptContent(processSpec, startupEnv, startupArgs, c
|
|
|
1434
1628
|
'',
|
|
1435
1629
|
].filter((line) => line !== '').join('\n');
|
|
1436
1630
|
}
|
|
1437
|
-
export function writeWorkerStartupScriptCommand(teamName, workerIndex, launchArgs = [], cwd = process.cwd(), extraEnv = {}, workerCliOverride, initialPrompt, workerRole) {
|
|
1631
|
+
export function writeWorkerStartupScriptCommand(teamName, workerIndex, launchArgs = [], cwd = process.cwd(), extraEnv = {}, workerCliOverride, initialPrompt, workerRole, attachedPlan) {
|
|
1438
1632
|
if (process.platform === 'win32' && !isMsysOrGitBash())
|
|
1439
1633
|
return null;
|
|
1440
1634
|
const stateRoot = extraEnv[OMX_TEAM_STATE_ROOT_ENV]?.trim();
|
|
1441
1635
|
if (!stateRoot)
|
|
1442
1636
|
return null;
|
|
1443
|
-
const
|
|
1444
|
-
const startupEnv = {
|
|
1445
|
-
...readTmuxWorkerAmbientEnv(process.env),
|
|
1446
|
-
...processSpec.env,
|
|
1447
|
-
};
|
|
1448
|
-
const startupArgs = [...processSpec.args];
|
|
1449
|
-
if (processSpec.workerCli === 'codex') {
|
|
1450
|
-
appendTeamWorkerMcpDisableOverrides(startupArgs, { ...process.env, ...extraEnv });
|
|
1451
|
-
}
|
|
1637
|
+
const startupPlan = attachedPlan ?? buildAttachedTmuxWorkerStartupPlan(teamName, workerIndex, launchArgs, cwd, extraEnv, workerCliOverride, initialPrompt, workerRole);
|
|
1638
|
+
const startupEnv = { ...readTmuxWorkerAmbientEnv(process.env), ...startupPlan.processSpec.env };
|
|
1452
1639
|
const scriptPath = join(stateRoot, 'team', teamName, 'runtime', `worker-${workerIndex}-startup.sh`);
|
|
1453
1640
|
mkdirSync(dirname(scriptPath), { recursive: true });
|
|
1454
|
-
writeFileSync(scriptPath, buildWorkerStartupScriptContent(processSpec, startupEnv, startupArgs, cwd, extraEnv), 'utf-8');
|
|
1641
|
+
writeFileSync(scriptPath, buildWorkerStartupScriptContent(startupPlan.processSpec, startupEnv, [...startupPlan.startupArgs], cwd, extraEnv), 'utf-8');
|
|
1455
1642
|
chmodSync(scriptPath, 0o700);
|
|
1456
1643
|
return `exec /bin/sh ${shellQuoteSingle(translatePathForMsys(scriptPath))}`;
|
|
1457
1644
|
}
|
|
@@ -1616,6 +1803,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1616
1803
|
const partialWorkerPaneIds = [];
|
|
1617
1804
|
const partialWorkerPaneIdsByIndex = Array.from({ length: workerCount }, () => null);
|
|
1618
1805
|
const partialWorkerPanePidsByIndex = Array.from({ length: workerCount }, () => null);
|
|
1806
|
+
const partialStartupCleanupPanePids = new Map();
|
|
1619
1807
|
let partialHudPaneId = null;
|
|
1620
1808
|
let partialHudPanePid = null;
|
|
1621
1809
|
try {
|
|
@@ -1647,7 +1835,11 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1647
1835
|
throw new ExactPaneProofUnavailableError(leaderProof);
|
|
1648
1836
|
if (leaderProof.status === 'gone')
|
|
1649
1837
|
throw new Error(`tmux pane is not proven live: ${leaderPaneId}`);
|
|
1650
|
-
|
|
1838
|
+
let leaderSource = captureSourcePaneAuthority(leaderPaneId);
|
|
1839
|
+
if (leaderSource.sessionName !== sessionName || leaderSource.windowIndex !== windowIndex || leaderSource.panePid !== leaderProof.pid) {
|
|
1840
|
+
throw new Error('tmux source authority changed during team startup');
|
|
1841
|
+
}
|
|
1842
|
+
const leaderPanePid = leaderSource.panePid;
|
|
1651
1843
|
partialLeaderPaneId = leaderPaneId;
|
|
1652
1844
|
partialLeaderPanePid = leaderPanePid;
|
|
1653
1845
|
const initialHudPaneIds = findHudWatchPaneIds(paneListResult.panes, leaderPaneId, { leaderPaneId });
|
|
@@ -1669,13 +1861,36 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1669
1861
|
// instead of making it disappear on team startup failures or broken installs.
|
|
1670
1862
|
requireFrozenWindowTopologySync(teamTarget, initialWindowPanePids);
|
|
1671
1863
|
if (ownerSessionId) {
|
|
1672
|
-
|
|
1673
|
-
if (!tagResult.ok) {
|
|
1674
|
-
throw new Error(`failed to tag tmux session ${sessionName}: ${tagResult.stderr}`);
|
|
1675
|
-
}
|
|
1864
|
+
runSourceAuthorizedTmux(leaderSource, `set-option -t ${leaderSource.sessionId} ${OMX_INSTANCE_OPTION} ${shellQuoteSingle(ownerSessionId)}`);
|
|
1676
1865
|
}
|
|
1677
|
-
|
|
1678
|
-
|
|
1866
|
+
if (ownerSessionId) {
|
|
1867
|
+
runSourceAuthorizedTmux(leaderSource, `set-option -p -t ${leaderPaneId} ${OMX_PANE_INSTANCE_OPTION} ${shellQuoteSingle(ownerSessionId)}`);
|
|
1868
|
+
}
|
|
1869
|
+
runSourceAuthorizedTmux(leaderSource, `set-option -p -t ${leaderPaneId} ${OMX_TEAM_PANE_OWNER_OPTION} ${shellQuoteSingle(teamPaneOwnerId)}`);
|
|
1870
|
+
// All subsequent Team mutations must bind the frozen leader owner in the
|
|
1871
|
+
// same tmux-server transaction as their effect. The initial tag itself is
|
|
1872
|
+
// deliberately the sole bootstrap mutation before an owner exists.
|
|
1873
|
+
leaderSource = captureSourcePaneAuthority(leaderPaneId, teamPaneOwnerId);
|
|
1874
|
+
const exactProveAndTagReconciledPane = (paneId) => {
|
|
1875
|
+
const proof = readExactPaneProofSync(paneId);
|
|
1876
|
+
if (proof.status === 'unavailable')
|
|
1877
|
+
throw new ExactPaneProofUnavailableError(proof);
|
|
1878
|
+
if (proof.status === 'gone')
|
|
1879
|
+
return null;
|
|
1880
|
+
const paneSource = captureSourcePaneAuthority(paneId);
|
|
1881
|
+
if (paneSource.panePid !== proof.pid)
|
|
1882
|
+
throw new Error(`tmux pane identity changed: ${paneId}`);
|
|
1883
|
+
if (paneSource.teamPaneOwnerId && paneSource.teamPaneOwnerId !== teamPaneOwnerId) {
|
|
1884
|
+
throw new Error(`tmux pane team owner changed: ${paneId}`);
|
|
1885
|
+
}
|
|
1886
|
+
if (ownerSessionId) {
|
|
1887
|
+
runSourceAuthorizedTmux(paneSource, `set-option -p -t ${paneId} ${OMX_PANE_INSTANCE_OPTION} ${shellQuoteSingle(ownerSessionId)}`);
|
|
1888
|
+
}
|
|
1889
|
+
rollbackTaggedPaneOwnerIds.set(paneId, teamPaneOwnerId);
|
|
1890
|
+
runSourceAuthorizedTmux(paneSource, `set-option -p -t ${paneId} ${OMX_TEAM_PANE_OWNER_OPTION} ${shellQuoteSingle(teamPaneOwnerId)}`);
|
|
1891
|
+
rollbackPanes.set(paneId, proof.pid);
|
|
1892
|
+
return proof.pid;
|
|
1893
|
+
};
|
|
1679
1894
|
if (canRecreateTeamHud) {
|
|
1680
1895
|
for (const [hudPaneId, hudPanePid] of initialWindowPanePids) {
|
|
1681
1896
|
if (hudPaneId !== leaderPaneId)
|
|
@@ -1683,6 +1898,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1683
1898
|
}
|
|
1684
1899
|
}
|
|
1685
1900
|
const workerPaneIds = [];
|
|
1901
|
+
const workerStartupArgs = Array.from({ length: workerCount }, () => Object.freeze([]));
|
|
1686
1902
|
const workerPanePidsByIndex = Array.from({ length: workerCount }, () => null);
|
|
1687
1903
|
let rightStackRootPaneId = null;
|
|
1688
1904
|
let rightStackRootPanePid = null;
|
|
@@ -1694,30 +1910,49 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1694
1910
|
const tmuxWorkerCwd = translatePathForMsys(workerCwd);
|
|
1695
1911
|
const workerEnv = startup.env || {};
|
|
1696
1912
|
const launchArgsForWorker = [...(workerLaunchPolicyPlan[i - 1] ?? workerLaunchArgs)];
|
|
1913
|
+
const attachedStartupPlan = buildAttachedTmuxWorkerStartupPlan(safeTeamName, i, launchArgsForWorker, workerCwd, workerEnv, workerCliPlan[i - 1], startup.initialPrompt, startup.workerRole);
|
|
1914
|
+
workerStartupArgs[i - 1] = attachedStartupPlan.startupArgs;
|
|
1697
1915
|
trustWorkerMiseConfigIfAvailable(workerCwd);
|
|
1698
|
-
const cmd = writeWorkerStartupScriptCommand(safeTeamName, i, launchArgsForWorker, workerCwd, workerEnv, workerCliPlan[i - 1], startup.initialPrompt, startup.workerRole) ?? buildWorkerStartupCommand(safeTeamName, i, launchArgsForWorker, workerCwd, workerEnv, workerCliPlan[i - 1], startup.initialPrompt, startup.workerRole);
|
|
1916
|
+
const cmd = writeWorkerStartupScriptCommand(safeTeamName, i, launchArgsForWorker, workerCwd, workerEnv, workerCliPlan[i - 1], startup.initialPrompt, startup.workerRole, attachedStartupPlan) ?? buildWorkerStartupCommand(safeTeamName, i, launchArgsForWorker, workerCwd, workerEnv, workerCliPlan[i - 1], startup.initialPrompt, startup.workerRole);
|
|
1699
1917
|
// First split creates the right side from leader. Remaining splits stack on the right.
|
|
1700
1918
|
const splitDirection = i === 1 ? '-h' : '-v';
|
|
1701
1919
|
const splitTarget = requireLiveTeamOwnedPaneSync(i === 1 ? leaderPaneId : (rightStackRootPaneId ?? leaderPaneId), i === 1 ? leaderPanePid : (rightStackRootPanePid ?? leaderPanePid), teamPaneOwnerId);
|
|
1702
|
-
const
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
splitTarget,
|
|
1707
|
-
'-d',
|
|
1708
|
-
'-P',
|
|
1709
|
-
'-F',
|
|
1710
|
-
'#{pane_id}',
|
|
1711
|
-
'-c',
|
|
1712
|
-
tmuxWorkerCwd,
|
|
1713
|
-
cmd,
|
|
1714
|
-
]);
|
|
1715
|
-
if (!split.ok) {
|
|
1716
|
-
throw new Error(`failed to create worker pane ${i}: ${split.stderr}`);
|
|
1920
|
+
const splitSource = captureSourcePaneAuthority(splitTarget, teamPaneOwnerId);
|
|
1921
|
+
let paneId;
|
|
1922
|
+
try {
|
|
1923
|
+
paneId = runSourceAuthorizedSplit(splitSource, (receipt) => `split-window ${splitDirection} -t ${splitTarget} -d -P -F '#{pane_id}' -c ${shellQuoteSingle(tmuxWorkerCwd)} ${shellQuoteSingle(bindSplitReceiptToPaneCommand(cmd, receipt))}`);
|
|
1717
1924
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1925
|
+
catch (error) {
|
|
1926
|
+
if (error instanceof AmbiguousSplitWindowOutputError) {
|
|
1927
|
+
const isUnassignedAmbiguity = error.newlyObservedPaneIds.length > 1;
|
|
1928
|
+
for (const candidatePaneId of error.newlyObservedPaneIds) {
|
|
1929
|
+
rollbackPanes.set(candidatePaneId, null);
|
|
1930
|
+
partialWorkerPaneIds.push(candidatePaneId);
|
|
1931
|
+
if (isUnassignedAmbiguity)
|
|
1932
|
+
partialStartupCleanupPanePids.set(candidatePaneId, null);
|
|
1933
|
+
}
|
|
1934
|
+
if (error.newlyObservedPaneIds.length === 1) {
|
|
1935
|
+
partialWorkerPaneIdsByIndex[i - 1] = error.newlyObservedPaneIds[0];
|
|
1936
|
+
}
|
|
1937
|
+
for (const candidatePaneId of error.newlyObservedPaneIds) {
|
|
1938
|
+
const reconciledPid = exactProveAndTagReconciledPane(candidatePaneId);
|
|
1939
|
+
if (reconciledPid === null) {
|
|
1940
|
+
rollbackPanes.delete(candidatePaneId);
|
|
1941
|
+
partialWorkerPaneIds.splice(partialWorkerPaneIds.lastIndexOf(candidatePaneId), 1);
|
|
1942
|
+
partialStartupCleanupPanePids.delete(candidatePaneId);
|
|
1943
|
+
if (partialWorkerPaneIdsByIndex[i - 1] === candidatePaneId) {
|
|
1944
|
+
partialWorkerPaneIdsByIndex[i - 1] = null;
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
else if (isUnassignedAmbiguity) {
|
|
1948
|
+
partialStartupCleanupPanePids.set(candidatePaneId, reconciledPid);
|
|
1949
|
+
}
|
|
1950
|
+
else {
|
|
1951
|
+
partialWorkerPanePidsByIndex[i - 1] = reconciledPid;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
throw error;
|
|
1721
1956
|
}
|
|
1722
1957
|
// The pane exists once split-window returns its concrete ID. Persist it in
|
|
1723
1958
|
// rollback/partial state before its first proof: a malformed or unavailable
|
|
@@ -1738,9 +1973,14 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1738
1973
|
if (isNativeWindows() && !waitForPaneToRemainPresent(teamTarget, paneId)) {
|
|
1739
1974
|
throw new Error(`worker pane ${i} did not remain present after tmux split-window returned ${paneId}`);
|
|
1740
1975
|
}
|
|
1741
|
-
|
|
1976
|
+
const paneSource = captureSourcePaneAuthority(paneId);
|
|
1977
|
+
if (paneSource.panePid !== panePid)
|
|
1978
|
+
throw new Error(`tmux pane identity changed: ${paneId}`);
|
|
1979
|
+
if (ownerSessionId) {
|
|
1980
|
+
runSourceAuthorizedTmux(paneSource, `set-option -p -t ${paneId} ${OMX_PANE_INSTANCE_OPTION} ${shellQuoteSingle(ownerSessionId)}`);
|
|
1981
|
+
}
|
|
1742
1982
|
rollbackTaggedPaneOwnerIds.set(paneId, teamPaneOwnerId);
|
|
1743
|
-
|
|
1983
|
+
runSourceAuthorizedTmux(paneSource, `set-option -p -t ${paneId} ${OMX_TEAM_PANE_OWNER_OPTION} ${shellQuoteSingle(teamPaneOwnerId)}`);
|
|
1744
1984
|
frozenWindowPaneOwners.set(paneId, teamPaneOwnerId);
|
|
1745
1985
|
workerPaneIds.push(paneId);
|
|
1746
1986
|
if (i === 1) {
|
|
@@ -1750,7 +1990,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1750
1990
|
}
|
|
1751
1991
|
// Keep leader as full left/main pane; workers stay stacked on the right.
|
|
1752
1992
|
requireFrozenWindowTopologySync(teamTarget, frozenWindowPanePids, frozenWindowPaneOwners);
|
|
1753
|
-
|
|
1993
|
+
runSourceAuthorizedTmux(leaderSource, `select-layout -t ${leaderSource.windowId} main-vertical`);
|
|
1754
1994
|
// Force leader pane to use half the window width.
|
|
1755
1995
|
const windowWidthResult = runTmux(['display-message', '-p', '-t', teamTarget, '#{window_width}']);
|
|
1756
1996
|
if (windowWidthResult.ok) {
|
|
@@ -1758,9 +1998,9 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1758
1998
|
if (Number.isFinite(width) && width >= 40) {
|
|
1759
1999
|
const half = String(Math.floor(width / 2));
|
|
1760
2000
|
requireFrozenWindowTopologySync(teamTarget, frozenWindowPanePids, frozenWindowPaneOwners);
|
|
1761
|
-
|
|
2001
|
+
runSourceAuthorizedTmux(leaderSource, `set-window-option -t ${leaderSource.windowId} main-pane-width ${half}`);
|
|
1762
2002
|
requireFrozenWindowTopologySync(teamTarget, frozenWindowPanePids, frozenWindowPaneOwners);
|
|
1763
|
-
|
|
2003
|
+
runSourceAuthorizedTmux(leaderSource, `select-layout -t ${leaderSource.windowId} main-vertical`);
|
|
1764
2004
|
}
|
|
1765
2005
|
}
|
|
1766
2006
|
// Re-create a single team HUD as a full-width bottom strip spanning both
|
|
@@ -1775,97 +2015,134 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1775
2015
|
const hudCwd = translatePathForMsys(cwd);
|
|
1776
2016
|
requireFrozenWindowTopologySync(teamTarget, frozenWindowPanePids, frozenWindowPaneOwners);
|
|
1777
2017
|
const hudSplitTarget = leaderPaneId;
|
|
1778
|
-
const
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
if (hudProof.status === 'unavailable')
|
|
1791
|
-
throw new ExactPaneProofUnavailableError(hudProof);
|
|
1792
|
-
if (hudProof.status === 'gone')
|
|
1793
|
-
throw new Error(`tmux pane is not proven live: ${id}`);
|
|
1794
|
-
const hudPanePid = hudProof.pid;
|
|
1795
|
-
frozenWindowPanePids.set(id, hudPanePid);
|
|
1796
|
-
rollbackPanes.set(id, hudPanePid);
|
|
1797
|
-
partialHudPanePid = hudPanePid;
|
|
1798
|
-
if (isNativeWindows() && !waitForPaneToRemainPresent(teamTarget, id)) {
|
|
1799
|
-
throw new Error(`HUD pane did not remain present after tmux split-window returned ${id}`);
|
|
2018
|
+
const hudSource = captureSourcePaneAuthority(hudSplitTarget, teamPaneOwnerId);
|
|
2019
|
+
let id;
|
|
2020
|
+
try {
|
|
2021
|
+
id = runSourceAuthorizedSplit(hudSource, (receipt) => `split-window -v -f -l ${HUD_TMUX_TEAM_HEIGHT_LINES} -t ${hudSplitTarget} -d -P -F '#{pane_id}' -c ${shellQuoteSingle(hudCwd)} ${shellQuoteSingle(bindSplitReceiptToPaneCommand(hudCmd, receipt))}`);
|
|
2022
|
+
}
|
|
2023
|
+
catch (error) {
|
|
2024
|
+
if (error instanceof AmbiguousSplitWindowOutputError) {
|
|
2025
|
+
const isUnassignedAmbiguity = error.newlyObservedPaneIds.length > 1;
|
|
2026
|
+
for (const candidatePaneId of error.newlyObservedPaneIds) {
|
|
2027
|
+
rollbackPanes.set(candidatePaneId, null);
|
|
2028
|
+
if (isUnassignedAmbiguity)
|
|
2029
|
+
partialStartupCleanupPanePids.set(candidatePaneId, null);
|
|
1800
2030
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
frozenWindowPaneOwners.set(id, teamPaneOwnerId);
|
|
1805
|
-
hudPaneId = id;
|
|
1806
|
-
if (isNativeWindows()) {
|
|
1807
|
-
const provenHudPaneId = requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
1808
|
-
const reconcile = runTmux(buildHudResizeArgs(provenHudPaneId));
|
|
1809
|
-
if (!reconcile.ok) {
|
|
1810
|
-
throw new Error(`failed to reconcile HUD resize: ${reconcile.stderr}`);
|
|
1811
|
-
}
|
|
2031
|
+
if (error.newlyObservedPaneIds.length === 1) {
|
|
2032
|
+
partialHudPaneId = error.newlyObservedPaneIds[0];
|
|
2033
|
+
partialHudPanePid = null;
|
|
1812
2034
|
}
|
|
1813
|
-
|
|
1814
|
-
const
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
resizeHookTarget = hookTarget;
|
|
1821
|
-
resizeHookName = hookName;
|
|
1822
|
-
registeredResizeHook = {
|
|
1823
|
-
name: resizeHookName,
|
|
1824
|
-
target: resizeHookTarget,
|
|
1825
|
-
leaderPaneId,
|
|
1826
|
-
leaderPanePid,
|
|
1827
|
-
hudPaneId,
|
|
1828
|
-
hudPanePid,
|
|
1829
|
-
teamPaneOwnerId,
|
|
1830
|
-
};
|
|
2035
|
+
for (const candidatePaneId of error.newlyObservedPaneIds) {
|
|
2036
|
+
const reconciledPid = exactProveAndTagReconciledPane(candidatePaneId);
|
|
2037
|
+
if (reconciledPid === null) {
|
|
2038
|
+
rollbackPanes.delete(candidatePaneId);
|
|
2039
|
+
partialStartupCleanupPanePids.delete(candidatePaneId);
|
|
2040
|
+
if (partialHudPaneId === candidatePaneId)
|
|
2041
|
+
partialHudPaneId = null;
|
|
1831
2042
|
}
|
|
1832
|
-
else {
|
|
1833
|
-
|
|
1834
|
-
+ 'continuing with best-effort HUD resize fallback.');
|
|
1835
|
-
}
|
|
1836
|
-
requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
1837
|
-
const registerClientAttachedHook = runTmux(buildRegisterClientAttachedReconcileArgs(hookTarget, clientAttachedHookName, hudPaneId, HUD_TMUX_TEAM_HEIGHT_LINES, hudPanePid, teamPaneOwnerId));
|
|
1838
|
-
if (registerClientAttachedHook.ok) {
|
|
1839
|
-
registeredClientAttachedHook = {
|
|
1840
|
-
name: clientAttachedHookName,
|
|
1841
|
-
target: hookTarget,
|
|
1842
|
-
leaderPaneId,
|
|
1843
|
-
leaderPanePid,
|
|
1844
|
-
hudPaneId,
|
|
1845
|
-
hudPanePid,
|
|
1846
|
-
teamPaneOwnerId,
|
|
1847
|
-
};
|
|
2043
|
+
else if (isUnassignedAmbiguity) {
|
|
2044
|
+
partialStartupCleanupPanePids.set(candidatePaneId, reconciledPid);
|
|
1848
2045
|
}
|
|
1849
2046
|
else {
|
|
1850
|
-
|
|
1851
|
-
+ `(${clientAttachedHookName}): ${registerClientAttachedHook.stderr}; continuing with delayed HUD resize fallback.`);
|
|
1852
|
-
}
|
|
1853
|
-
requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
1854
|
-
const delayed = runTmux(buildScheduleDelayedHudResizeArgs(hudPaneId, HUD_RESIZE_RECONCILE_DELAY_SECONDS, HUD_TMUX_TEAM_HEIGHT_LINES, hudPanePid, teamPaneOwnerId));
|
|
1855
|
-
if (!delayed.ok) {
|
|
1856
|
-
console.warn(`[omx] tmux delayed HUD resize unavailable for ${hudPaneId}: ${delayed.stderr}; continuing.`);
|
|
1857
|
-
}
|
|
1858
|
-
requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
1859
|
-
const reconcile = runTmux(buildReconcileHudResizeArgs(hudPaneId, HUD_TMUX_TEAM_HEIGHT_LINES, hudPanePid, teamPaneOwnerId));
|
|
1860
|
-
if (!reconcile.ok) {
|
|
1861
|
-
console.warn(`[omx] tmux HUD resize reconcile unavailable for ${hudPaneId}: ${reconcile.stderr}; continuing.`);
|
|
2047
|
+
partialHudPanePid = reconciledPid;
|
|
1862
2048
|
}
|
|
1863
2049
|
}
|
|
1864
2050
|
}
|
|
2051
|
+
throw error;
|
|
2052
|
+
}
|
|
2053
|
+
{
|
|
2054
|
+
// split-window has created a concrete pane even though no proof has
|
|
2055
|
+
// authorized an effect yet. Retain PID-less cleanup debt first.
|
|
2056
|
+
rollbackPanes.set(id, null);
|
|
2057
|
+
partialHudPaneId = id;
|
|
2058
|
+
partialHudPanePid = null;
|
|
2059
|
+
const hudProof = readExactPaneProofSync(id);
|
|
2060
|
+
if (hudProof.status === 'unavailable')
|
|
2061
|
+
throw new ExactPaneProofUnavailableError(hudProof);
|
|
2062
|
+
if (hudProof.status === 'gone')
|
|
2063
|
+
throw new Error(`tmux pane is not proven live: ${id}`);
|
|
2064
|
+
const hudPanePid = hudProof.pid;
|
|
2065
|
+
frozenWindowPanePids.set(id, hudPanePid);
|
|
2066
|
+
rollbackPanes.set(id, hudPanePid);
|
|
2067
|
+
partialHudPanePid = hudPanePid;
|
|
2068
|
+
if (isNativeWindows() && !waitForPaneToRemainPresent(teamTarget, id)) {
|
|
2069
|
+
throw new Error(`HUD pane did not remain present after tmux split-window returned ${id}`);
|
|
2070
|
+
}
|
|
2071
|
+
const hudSource = captureSourcePaneAuthority(id);
|
|
2072
|
+
if (hudSource.panePid !== hudPanePid)
|
|
2073
|
+
throw new Error(`tmux pane identity changed: ${id}`);
|
|
2074
|
+
if (ownerSessionId) {
|
|
2075
|
+
runSourceAuthorizedTmux(hudSource, `set-option -p -t ${id} ${OMX_PANE_INSTANCE_OPTION} ${shellQuoteSingle(ownerSessionId)}`);
|
|
2076
|
+
}
|
|
2077
|
+
rollbackTaggedPaneOwnerIds.set(id, teamPaneOwnerId);
|
|
2078
|
+
runSourceAuthorizedTmux(hudSource, `set-option -p -t ${id} ${OMX_TEAM_PANE_OWNER_OPTION} ${shellQuoteSingle(teamPaneOwnerId)}`);
|
|
2079
|
+
frozenWindowPaneOwners.set(id, teamPaneOwnerId);
|
|
2080
|
+
hudPaneId = id;
|
|
2081
|
+
if (isNativeWindows()) {
|
|
2082
|
+
const provenHudPaneId = requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
2083
|
+
const reconcile = runTmux(buildHudResizeArgs(provenHudPaneId));
|
|
2084
|
+
if (!reconcile.ok) {
|
|
2085
|
+
throw new Error(`failed to reconcile HUD resize: ${reconcile.stderr}`);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
else {
|
|
2089
|
+
const hookTarget = buildResizeHookTarget(sessionName, windowIndex);
|
|
2090
|
+
const hookName = buildResizeHookName(safeTeamName, sessionName, windowIndex, hudPaneId);
|
|
2091
|
+
requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
2092
|
+
const registerHook = runTmux(buildRegisterResizeHookArgs(hookTarget, hookName, hudPaneId, HUD_TMUX_TEAM_HEIGHT_LINES, hudPanePid, teamPaneOwnerId));
|
|
2093
|
+
const clientAttachedHookName = buildClientAttachedReconcileHookName(safeTeamName, sessionName, windowIndex, hudPaneId);
|
|
2094
|
+
if (registerHook.ok) {
|
|
2095
|
+
resizeHookTarget = hookTarget;
|
|
2096
|
+
resizeHookName = hookName;
|
|
2097
|
+
registeredResizeHook = {
|
|
2098
|
+
name: resizeHookName,
|
|
2099
|
+
target: resizeHookTarget,
|
|
2100
|
+
leaderPaneId,
|
|
2101
|
+
leaderPanePid,
|
|
2102
|
+
hudPaneId,
|
|
2103
|
+
hudPanePid,
|
|
2104
|
+
teamPaneOwnerId,
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
else {
|
|
2108
|
+
console.warn(`[omx] tmux resize hook unavailable for ${hookTarget} (${hookName}): ${registerHook.stderr}; `
|
|
2109
|
+
+ 'continuing with best-effort HUD resize fallback.');
|
|
2110
|
+
}
|
|
2111
|
+
requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
2112
|
+
const registerClientAttachedHook = runTmux(buildRegisterClientAttachedReconcileArgs(hookTarget, clientAttachedHookName, hudPaneId, HUD_TMUX_TEAM_HEIGHT_LINES, hudPanePid, teamPaneOwnerId));
|
|
2113
|
+
if (registerClientAttachedHook.ok) {
|
|
2114
|
+
registeredClientAttachedHook = {
|
|
2115
|
+
name: clientAttachedHookName,
|
|
2116
|
+
target: hookTarget,
|
|
2117
|
+
leaderPaneId,
|
|
2118
|
+
leaderPanePid,
|
|
2119
|
+
hudPaneId,
|
|
2120
|
+
hudPanePid,
|
|
2121
|
+
teamPaneOwnerId,
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
else {
|
|
2125
|
+
console.warn(`[omx] tmux client-attached resize fallback unavailable for ${hookTarget} `
|
|
2126
|
+
+ `(${clientAttachedHookName}): ${registerClientAttachedHook.stderr}; continuing with delayed HUD resize fallback.`);
|
|
2127
|
+
}
|
|
2128
|
+
requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
2129
|
+
const delayed = runTmux(buildScheduleDelayedHudResizeArgs(hudPaneId, HUD_RESIZE_RECONCILE_DELAY_SECONDS, HUD_TMUX_TEAM_HEIGHT_LINES, hudPanePid, teamPaneOwnerId));
|
|
2130
|
+
if (!delayed.ok) {
|
|
2131
|
+
console.warn(`[omx] tmux delayed HUD resize unavailable for ${hudPaneId}: ${delayed.stderr}; continuing.`);
|
|
2132
|
+
}
|
|
2133
|
+
requireLiveTeamOwnedPaneSync(hudPaneId, hudPanePid, teamPaneOwnerId);
|
|
2134
|
+
const reconcile = runTmux(buildReconcileHudResizeArgs(hudPaneId, HUD_TMUX_TEAM_HEIGHT_LINES, hudPanePid, teamPaneOwnerId));
|
|
2135
|
+
if (!reconcile.ok) {
|
|
2136
|
+
console.warn(`[omx] tmux HUD resize reconcile unavailable for ${hudPaneId}: ${reconcile.stderr}; continuing.`);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
1865
2139
|
}
|
|
1866
2140
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
2141
|
+
const focusedLeader = requireLiveTeamOwnedPaneSync(leaderPaneId, leaderPanePid, teamPaneOwnerId);
|
|
2142
|
+
if (focusedLeader !== leaderSource.paneId)
|
|
2143
|
+
throw new Error(`tmux pane identity changed: ${leaderPaneId}`);
|
|
2144
|
+
runSourceAuthorizedTmux(leaderSource, `select-pane -t ${leaderPaneId}`);
|
|
2145
|
+
redrawLeaderPaneAfterTeamLayout(leaderSource, teamPaneOwnerId);
|
|
1869
2146
|
sleepSeconds(0.5);
|
|
1870
2147
|
// Enable mouse scrolling so agent output panes can be scrolled with the
|
|
1871
2148
|
// mouse wheel without conflicting with keyboard up/down arrow-key input
|
|
@@ -1874,20 +2151,20 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1874
2151
|
if (process.env.OMX_TEAM_MOUSE !== '0') {
|
|
1875
2152
|
enableMouseScrolling(sessionName, () => { requireLiveTeamOwnedPaneSync(leaderPaneId, leaderPanePid, teamPaneOwnerId); });
|
|
1876
2153
|
}
|
|
1877
|
-
const sessionIncarnation = teamTarget.includes(':') ? null : queryDetachedTeamSession(sessionName);
|
|
1878
|
-
if (sessionIncarnation && sessionIncarnation.status !== 'exact') {
|
|
1879
|
-
throw new Error(`tmux_session_incarnation_unavailable:${sessionName}`);
|
|
1880
|
-
}
|
|
1881
2154
|
return {
|
|
1882
2155
|
name: teamTarget,
|
|
1883
|
-
tmuxSessionId:
|
|
1884
|
-
tmuxSessionCreated:
|
|
2156
|
+
tmuxSessionId: leaderSource.sessionId,
|
|
2157
|
+
tmuxSessionCreated: leaderSource.sessionCreated,
|
|
1885
2158
|
workerCount,
|
|
1886
2159
|
cwd,
|
|
1887
2160
|
workerPaneIds,
|
|
1888
2161
|
workerPaneIdsByIndex: [...workerPaneIds],
|
|
1889
2162
|
workerPanePidsByIndex,
|
|
1890
2163
|
leaderPanePid,
|
|
2164
|
+
workerStartupArgs: Object.freeze(workerStartupArgs),
|
|
2165
|
+
leaderSessionId: leaderSource.sessionId,
|
|
2166
|
+
leaderSessionCreated: leaderSource.sessionCreated,
|
|
2167
|
+
leaderWindowId: leaderSource.windowId,
|
|
1891
2168
|
hudPanePid: partialHudPanePid,
|
|
1892
2169
|
leaderPaneId,
|
|
1893
2170
|
hudPaneId,
|
|
@@ -1898,6 +2175,9 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1898
2175
|
}
|
|
1899
2176
|
catch (error) {
|
|
1900
2177
|
const cleanupErrors = [];
|
|
2178
|
+
if (error instanceof AmbiguousSplitWindowOutputError && error.reconciliationError) {
|
|
2179
|
+
cleanupErrors.push('failed to reconcile tmux pane topology after ambiguous split output');
|
|
2180
|
+
}
|
|
1901
2181
|
const unregisterAuthorizedHook = (hook, unregister, label) => {
|
|
1902
2182
|
try {
|
|
1903
2183
|
requireLiveTeamOwnedPaneSync(hook.leaderPaneId, hook.leaderPanePid, hook.teamPaneOwnerId);
|
|
@@ -1949,6 +2229,9 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1949
2229
|
.map((paneId) => paneId && unresolvedPaneIds.has(paneId) ? paneId : null);
|
|
1950
2230
|
const unresolvedWorkerPanePidsByIndex = partialWorkerPanePidsByIndex
|
|
1951
2231
|
.map((panePid, index) => partialWorkerPaneIdsByIndex[index] && unresolvedPaneIds.has(partialWorkerPaneIdsByIndex[index]) ? panePid : null);
|
|
2232
|
+
const unresolvedStartupCleanupPanes = [...partialStartupCleanupPanePids.entries()]
|
|
2233
|
+
.filter(([paneId]) => unresolvedPaneIds.has(paneId))
|
|
2234
|
+
.map(([paneId, panePid]) => ({ paneId, panePid }));
|
|
1952
2235
|
const unresolvedHudPaneId = partialHudPaneId && (unresolvedPaneIds.has(partialHudPaneId)
|
|
1953
2236
|
|| registeredResizeHook !== null
|
|
1954
2237
|
|| registeredClientAttachedHook !== null)
|
|
@@ -1956,7 +2239,8 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1956
2239
|
: null;
|
|
1957
2240
|
const hasRecoverablePartialArtifact = unresolvedPaneIds.size > 0
|
|
1958
2241
|
|| registeredResizeHook !== null
|
|
1959
|
-
|| registeredClientAttachedHook !== null
|
|
2242
|
+
|| registeredClientAttachedHook !== null
|
|
2243
|
+
|| (error instanceof AmbiguousSplitWindowOutputError && error.reconciliationError !== null);
|
|
1960
2244
|
if (hasRecoverablePartialArtifact && partialTeamTarget && partialLeaderPaneId) {
|
|
1961
2245
|
throw new CreateTeamSessionPartialError({
|
|
1962
2246
|
name: partialTeamTarget,
|
|
@@ -1965,6 +2249,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1965
2249
|
workerPaneIds: unresolvedWorkerPaneIds,
|
|
1966
2250
|
workerPaneIdsByIndex: unresolvedWorkerPaneIdsByIndex,
|
|
1967
2251
|
workerPanePidsByIndex: unresolvedWorkerPanePidsByIndex,
|
|
2252
|
+
startupCleanupPanes: unresolvedStartupCleanupPanes,
|
|
1968
2253
|
leaderPanePid: partialLeaderPanePid,
|
|
1969
2254
|
hudPanePid: unresolvedHudPaneId ? partialHudPanePid : null,
|
|
1970
2255
|
leaderPaneId: partialLeaderPaneId,
|
|
@@ -2038,7 +2323,9 @@ export function restoreStandaloneHudPane(leaderPaneId, cwd, options = {}) {
|
|
|
2038
2323
|
runTmux(['select-pane', '-t', requireAuthorizedLeaderPane()]);
|
|
2039
2324
|
return existingHudPaneId;
|
|
2040
2325
|
}
|
|
2041
|
-
const
|
|
2326
|
+
const beforeSplitPaneIds = new Set(paneListResult.panes.map((pane) => pane.paneId));
|
|
2327
|
+
const splitReceipt = sourceTransactionReceipt();
|
|
2328
|
+
const hudCmd = bindSplitReceiptToPaneCommand(`exec env ${formatHudEnvAssignments(process.env, { sessionId: options.sessionId, leaderPaneId: normalizedLeaderPaneId })} ${shellQuoteSingle(translatePathForMsys(resolveLeaderNodePath()))} ${shellQuoteSingle(translatePathForMsys(omxEntry))} hud --watch`, splitReceipt);
|
|
2042
2329
|
let hudResult = null;
|
|
2043
2330
|
for (const restoreCwd of resolveStandaloneHudRestoreCwdCandidates(normalizedLeaderPaneId, cwd, options.cwd, requireAuthorizedLeaderPane)) {
|
|
2044
2331
|
const candidateResult = runTmux([
|
|
@@ -2055,7 +2342,7 @@ export function restoreStandaloneHudPane(leaderPaneId, cwd, options = {}) {
|
|
|
2055
2342
|
'-c',
|
|
2056
2343
|
translatePathForMsys(restoreCwd.rawPath),
|
|
2057
2344
|
hudCmd,
|
|
2058
|
-
]);
|
|
2345
|
+
], true);
|
|
2059
2346
|
if (candidateResult.ok) {
|
|
2060
2347
|
hudResult = candidateResult;
|
|
2061
2348
|
break;
|
|
@@ -2063,9 +2350,45 @@ export function restoreStandaloneHudPane(leaderPaneId, cwd, options = {}) {
|
|
|
2063
2350
|
}
|
|
2064
2351
|
if (!hudResult?.ok)
|
|
2065
2352
|
return null;
|
|
2066
|
-
const paneId = hudResult.stdout
|
|
2067
|
-
if (!paneId
|
|
2068
|
-
|
|
2353
|
+
const paneId = parseSplitWindowPaneId(hudResult.stdout);
|
|
2354
|
+
if (!paneId) {
|
|
2355
|
+
const afterTopology = listPanesResult(normalizedLeaderPaneId);
|
|
2356
|
+
if (afterTopology.error) {
|
|
2357
|
+
throw new Error('restored_hud_split_topology_reconciliation_failed');
|
|
2358
|
+
}
|
|
2359
|
+
const newlyObservedPaneIds = afterTopology.panes
|
|
2360
|
+
.filter((pane) => !beforeSplitPaneIds.has(pane.paneId) && pane.startCommand.includes(splitReceipt))
|
|
2361
|
+
.map((pane) => pane.paneId);
|
|
2362
|
+
if (newlyObservedPaneIds.length === 1) {
|
|
2363
|
+
const reconciledPaneId = newlyObservedPaneIds[0];
|
|
2364
|
+
persistRestoredHudCleanupDebtSync(cwd, {
|
|
2365
|
+
schema_version: 1,
|
|
2366
|
+
operation: 'restored_hud_cleanup',
|
|
2367
|
+
pane_id: reconciledPaneId,
|
|
2368
|
+
pane_pid: null,
|
|
2369
|
+
leader_pane_id: normalizedLeaderPaneId,
|
|
2370
|
+
leader_pane_pid: options.expectedLeaderPanePid ?? leaderPanePid,
|
|
2371
|
+
leader_pane_owner_id: options.expectedLeaderPaneOwnerId?.trim() || null,
|
|
2372
|
+
hud_owner_leader_pane_id: normalizedLeaderPaneId,
|
|
2373
|
+
}, options.stateRoot);
|
|
2374
|
+
const reconciledProof = readExactPaneProofSync(reconciledPaneId);
|
|
2375
|
+
if (reconciledProof.status === 'unavailable')
|
|
2376
|
+
throw new ExactPaneProofUnavailableError(reconciledProof);
|
|
2377
|
+
if (reconciledProof.status === 'gone')
|
|
2378
|
+
throw new Error(`tmux pane is not proven live: ${reconciledPaneId}`);
|
|
2379
|
+
persistRestoredHudCleanupDebtSync(cwd, {
|
|
2380
|
+
schema_version: 1,
|
|
2381
|
+
operation: 'restored_hud_cleanup',
|
|
2382
|
+
pane_id: reconciledPaneId,
|
|
2383
|
+
pane_pid: reconciledProof.pid,
|
|
2384
|
+
leader_pane_id: normalizedLeaderPaneId,
|
|
2385
|
+
leader_pane_pid: options.expectedLeaderPanePid ?? leaderPanePid,
|
|
2386
|
+
leader_pane_owner_id: options.expectedLeaderPaneOwnerId?.trim() || null,
|
|
2387
|
+
hud_owner_leader_pane_id: normalizedLeaderPaneId,
|
|
2388
|
+
}, options.stateRoot);
|
|
2389
|
+
}
|
|
2390
|
+
throw new Error('restored_hud_split_output_ambiguous');
|
|
2391
|
+
}
|
|
2069
2392
|
persistRestoredHudCleanupDebtSync(cwd, {
|
|
2070
2393
|
schema_version: 1,
|
|
2071
2394
|
operation: 'restored_hud_cleanup',
|
|
@@ -2163,7 +2486,10 @@ function paneHasClaudeBypassPermissionsPrompt(captured) {
|
|
|
2163
2486
|
&& tail.some((line) => /Enter\s*to\s*confirm/i.test(line));
|
|
2164
2487
|
return hasWarning && hasChoices;
|
|
2165
2488
|
}
|
|
2166
|
-
export function evaluateStartupDirectTriggerSafetyCapture(captured, workerCli) {
|
|
2489
|
+
export function evaluateStartupDirectTriggerSafetyCapture(captured, workerCli, finalArgs) {
|
|
2490
|
+
const incompatibleReason = classifyCodexBypassMdmIncompatibility(captured, workerCli, finalArgs);
|
|
2491
|
+
if (incompatibleReason)
|
|
2492
|
+
return { safe: false, reason: incompatibleReason };
|
|
2167
2493
|
if (paneHasTrustPrompt(captured))
|
|
2168
2494
|
return { safe: false, reason: 'trust_prompt' };
|
|
2169
2495
|
if (paneHasClaudeBypassPermissionsPrompt(captured))
|
|
@@ -2176,7 +2502,7 @@ export function evaluateStartupDirectTriggerSafetyCapture(captured, workerCli) {
|
|
|
2176
2502
|
return { safe: true, reason: 'codex_viewport' };
|
|
2177
2503
|
return { safe: false, reason: 'not_agent_viewport' };
|
|
2178
2504
|
}
|
|
2179
|
-
export async function evaluateStartupDirectTriggerSafety(sessionName, workerIndex, workerPaneId, workerCli) {
|
|
2505
|
+
export async function evaluateStartupDirectTriggerSafety(sessionName, workerIndex, workerPaneId, workerCli, finalArgs) {
|
|
2180
2506
|
if (!isTmuxAvailable())
|
|
2181
2507
|
return { safe: false, reason: 'tmux_unavailable' };
|
|
2182
2508
|
const target = await resolveWorkerPaneTargetAsync(sessionName, workerIndex, workerPaneId);
|
|
@@ -2185,7 +2511,7 @@ export async function evaluateStartupDirectTriggerSafety(sessionName, workerInde
|
|
|
2185
2511
|
const result = await runTmuxAsync(sharedBuildVisibleCapturePaneArgv(target));
|
|
2186
2512
|
if (!result.ok)
|
|
2187
2513
|
return { safe: false, reason: 'capture_failed' };
|
|
2188
|
-
return evaluateStartupDirectTriggerSafetyCapture(result.stdout, workerCli);
|
|
2514
|
+
return evaluateStartupDirectTriggerSafetyCapture(result.stdout, workerCli, finalArgs);
|
|
2189
2515
|
}
|
|
2190
2516
|
function acceptClaudeBypassPermissionsPrompt(resolveTarget) {
|
|
2191
2517
|
const literalTarget = resolveTarget();
|
|
@@ -2455,12 +2781,13 @@ export function waitForWorkerReady(sessionName, workerIndex, timeoutMs = 30_000,
|
|
|
2455
2781
|
// Async twin of waitForWorkerReady for team startup fan-out. Keep the readiness
|
|
2456
2782
|
// semantics mirrored with the synchronous helper above, but yield between polls
|
|
2457
2783
|
// so one slow worker pane cannot block later workers' startup attempts.
|
|
2458
|
-
export async function
|
|
2784
|
+
export async function waitForWorkerReadyDetailedAsync(sessionName, workerIndex, timeoutMs = 30_000, workerPaneId, expectedPanePid, expectedTeamOwnerId, hudPaneId, incompatibility) {
|
|
2459
2785
|
const initialBackoffMs = 150;
|
|
2460
2786
|
const maxBackoffMs = 8000;
|
|
2461
2787
|
const startedAt = Date.now();
|
|
2462
2788
|
let blockedByTrustPrompt = false;
|
|
2463
2789
|
let promptDismissed = false;
|
|
2790
|
+
let startupIncompatible = false;
|
|
2464
2791
|
const resolveTarget = createPinnedWorkerPaneTargetResolver(sessionName, workerIndex, workerPaneId, expectedPanePid, expectedTeamOwnerId, hudPaneId);
|
|
2465
2792
|
const sendRobustEnter = async () => {
|
|
2466
2793
|
// Trust + follow-up splash can require two submits in Codex TUI.
|
|
@@ -2482,6 +2809,12 @@ export async function waitForWorkerReadyAsync(sessionName, workerIndex, timeoutM
|
|
|
2482
2809
|
const result = await runTmuxAsync(sharedBuildVisibleCapturePaneArgv(target));
|
|
2483
2810
|
if (!result.ok)
|
|
2484
2811
|
return false;
|
|
2812
|
+
const incompatibleReason = classifyCodexBypassMdmIncompatibility(result.stdout, incompatibility?.workerCli, incompatibility?.finalArgs);
|
|
2813
|
+
if (incompatibleReason) {
|
|
2814
|
+
startupIncompatible = true;
|
|
2815
|
+
incompatibility?.onIncompatible(incompatibleReason);
|
|
2816
|
+
return false;
|
|
2817
|
+
}
|
|
2485
2818
|
if (await dismissClaudeBypassPermissionsPromptIfPresentAsync(resolveTarget, result.stdout)) {
|
|
2486
2819
|
promptDismissed = true;
|
|
2487
2820
|
return false;
|
|
@@ -2519,6 +2852,8 @@ export async function waitForWorkerReadyAsync(sessionName, workerIndex, timeoutM
|
|
|
2519
2852
|
while (Date.now() - startedAt < timeoutMs) {
|
|
2520
2853
|
if (await check())
|
|
2521
2854
|
return true;
|
|
2855
|
+
if (startupIncompatible)
|
|
2856
|
+
return false;
|
|
2522
2857
|
if (blockedByTrustPrompt)
|
|
2523
2858
|
return false;
|
|
2524
2859
|
// After dismissing a trust prompt, reset backoff so we re-check quickly
|
|
@@ -2535,6 +2870,9 @@ export async function waitForWorkerReadyAsync(sessionName, workerIndex, timeoutM
|
|
|
2535
2870
|
}
|
|
2536
2871
|
return false;
|
|
2537
2872
|
}
|
|
2873
|
+
export async function waitForWorkerReadyAsync(sessionName, workerIndex, timeoutMs = 30_000, workerPaneId, expectedPanePid, expectedTeamOwnerId, hudPaneId) {
|
|
2874
|
+
return waitForWorkerReadyDetailedAsync(sessionName, workerIndex, timeoutMs, workerPaneId, expectedPanePid, expectedTeamOwnerId, hudPaneId);
|
|
2875
|
+
}
|
|
2538
2876
|
/**
|
|
2539
2877
|
* Detect and auto-dismiss a Codex "Trust this directory?" prompt in a worker pane.
|
|
2540
2878
|
* Returns true if a trust prompt was found and dismissed, false otherwise.
|
|
@@ -2692,8 +3030,8 @@ export function notifyLeaderStatus(sessionName, message) {
|
|
|
2692
3030
|
// Get PID of the shell process in a worker's tmux pane
|
|
2693
3031
|
export function getWorkerPanePid(sessionName, workerIndex, workerPaneId, expectedPanePid, expectedTeamOwnerId, hudPaneId) {
|
|
2694
3032
|
if (hasExplicitWorkerPaneId(workerPaneId)) {
|
|
2695
|
-
const
|
|
2696
|
-
return
|
|
3033
|
+
const proof = requireExactWorkerPaneLivenessIdentity(workerPaneId, expectedPanePid, expectedTeamOwnerId, hudPaneId);
|
|
3034
|
+
return proof.status === 'live' ? proof.pid : null;
|
|
2697
3035
|
}
|
|
2698
3036
|
const result = runTmux(['list-panes', '-t', paneTarget(sessionName, workerIndex), '-F', '#{pane_pid}']);
|
|
2699
3037
|
if (!result.ok)
|
|
@@ -2709,10 +3047,19 @@ export function getWorkerPanePid(sessionName, workerIndex, workerPaneId, expecte
|
|
|
2709
3047
|
// Check if worker's tmux pane has a running process
|
|
2710
3048
|
export function isWorkerAlive(sessionName, workerIndex, workerPaneId, expectedPanePid, expectedTeamOwnerId, hudPaneId) {
|
|
2711
3049
|
if (hasExplicitWorkerPaneId(workerPaneId)) {
|
|
2712
|
-
|
|
2713
|
-
|
|
3050
|
+
if (hudPaneId?.trim() && workerPaneId === hudPaneId.trim()) {
|
|
3051
|
+
throw new Error(`tmux worker pane is HUD target: ${workerPaneId}`);
|
|
3052
|
+
}
|
|
3053
|
+
const proof = requireExactWorkerPaneLivenessIdentity(workerPaneId, expectedPanePid, expectedTeamOwnerId, hudPaneId);
|
|
3054
|
+
if (proof.status === 'unavailable')
|
|
3055
|
+
return true;
|
|
3056
|
+
if (proof.status === 'gone')
|
|
2714
3057
|
return false;
|
|
2715
|
-
|
|
3058
|
+
if (typeof expectedPanePid !== 'number' || !Number.isSafeInteger(expectedPanePid) || expectedPanePid <= 0)
|
|
3059
|
+
return true;
|
|
3060
|
+
if (typeof expectedTeamOwnerId !== 'string' || expectedTeamOwnerId.trim() === '')
|
|
3061
|
+
return true;
|
|
3062
|
+
return probeProcessLiveness(proof.pid) !== 'gone';
|
|
2716
3063
|
}
|
|
2717
3064
|
const result = runTmux([
|
|
2718
3065
|
'list-panes',
|