oh-my-codex 0.18.13 → 0.18.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +6 -6
- package/Cargo.toml +1 -1
- package/README.md +41 -18
- package/dist/agents/__tests__/native-config.test.js +62 -0
- package/dist/agents/__tests__/native-config.test.js.map +1 -1
- package/dist/agents/native-config.d.ts.map +1 -1
- package/dist/agents/native-config.js +15 -2
- package/dist/agents/native-config.js.map +1 -1
- package/dist/autopilot/__tests__/fsm.test.js +7 -0
- package/dist/autopilot/__tests__/fsm.test.js.map +1 -1
- package/dist/autopilot/__tests__/planner-routing.test.d.ts +2 -0
- package/dist/autopilot/__tests__/planner-routing.test.d.ts.map +1 -0
- package/dist/autopilot/__tests__/planner-routing.test.js +74 -0
- package/dist/autopilot/__tests__/planner-routing.test.js.map +1 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js +315 -0
- package/dist/autopilot/__tests__/ralplan-gate.test.js.map +1 -1
- package/dist/autopilot/completion-gate.js +1 -1
- package/dist/autopilot/completion-gate.js.map +1 -1
- package/dist/autopilot/fsm.d.ts +2 -2
- package/dist/autopilot/fsm.d.ts.map +1 -1
- package/dist/autopilot/fsm.js +3 -0
- package/dist/autopilot/fsm.js.map +1 -1
- package/dist/autopilot/planner-routing.d.ts +21 -0
- package/dist/autopilot/planner-routing.d.ts.map +1 -0
- package/dist/autopilot/planner-routing.js +59 -0
- package/dist/autopilot/planner-routing.js.map +1 -0
- package/dist/autopilot/ralplan-gate.d.ts.map +1 -1
- package/dist/autopilot/ralplan-gate.js +30 -0
- package/dist/autopilot/ralplan-gate.js.map +1 -1
- package/dist/autoresearch/goal.d.ts.map +1 -1
- package/dist/autoresearch/goal.js +10 -1
- package/dist/autoresearch/goal.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-goal.test.js +33 -0
- package/dist/cli/__tests__/autoresearch-goal.test.js.map +1 -1
- package/dist/cli/__tests__/autoresearch-guided.test.js +3 -0
- package/dist/cli/__tests__/autoresearch-guided.test.js.map +1 -1
- package/dist/cli/__tests__/codex-plugin-layout.test.js +30 -0
- package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-artifact-ownership.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-artifact-ownership.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-artifact-ownership.test.js +158 -0
- package/dist/cli/__tests__/doctor-artifact-ownership.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-explore-deprecated.test.d.ts +2 -0
- package/dist/cli/__tests__/doctor-explore-deprecated.test.d.ts.map +1 -0
- package/dist/cli/__tests__/doctor-explore-deprecated.test.js +33 -0
- package/dist/cli/__tests__/doctor-explore-deprecated.test.js.map +1 -0
- package/dist/cli/__tests__/doctor-spark-routing.test.js +13 -0
- package/dist/cli/__tests__/doctor-spark-routing.test.js.map +1 -1
- package/dist/cli/__tests__/doctor-warning-copy.test.js +132 -2
- package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
- package/dist/cli/__tests__/index.test.js +5 -0
- package/dist/cli/__tests__/index.test.js.map +1 -1
- package/dist/cli/__tests__/mcp-parity.test.js +40 -0
- package/dist/cli/__tests__/mcp-parity.test.js.map +1 -1
- package/dist/cli/__tests__/nested-help-routing.test.js +4 -0
- package/dist/cli/__tests__/nested-help-routing.test.js.map +1 -1
- package/dist/cli/__tests__/package-bin-contract.test.js +7 -1
- package/dist/cli/__tests__/package-bin-contract.test.js.map +1 -1
- package/dist/cli/__tests__/performance-goal.test.js +22 -0
- package/dist/cli/__tests__/performance-goal.test.js.map +1 -1
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.d.ts +2 -0
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.d.ts.map +1 -0
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js +64 -0
- package/dist/cli/__tests__/plugin-marketplace-idempotent.test.js.map +1 -0
- package/dist/cli/__tests__/resume.test.js +96 -0
- package/dist/cli/__tests__/resume.test.js.map +1 -1
- package/dist/cli/__tests__/session-scoped-runtime.test.js +162 -0
- package/dist/cli/__tests__/session-scoped-runtime.test.js.map +1 -1
- package/dist/cli/__tests__/session-search.test.js +36 -0
- package/dist/cli/__tests__/session-search.test.js.map +1 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js +70 -1
- package/dist/cli/__tests__/setup-agents-overwrite.test.js.map +1 -1
- package/dist/cli/__tests__/setup-install-mode.test.js +33 -0
- package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
- package/dist/cli/__tests__/team.test.js +17 -3
- package/dist/cli/__tests__/team.test.js.map +1 -1
- package/dist/cli/__tests__/ultragoal.test.js +37 -0
- package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
- package/dist/cli/__tests__/update.test.js +81 -2
- package/dist/cli/__tests__/update.test.js.map +1 -1
- package/dist/cli/__tests__/url.test.d.ts +2 -0
- package/dist/cli/__tests__/url.test.d.ts.map +1 -0
- package/dist/cli/__tests__/url.test.js +82 -0
- package/dist/cli/__tests__/url.test.js.map +1 -0
- package/dist/cli/autoresearch-goal.d.ts.map +1 -1
- package/dist/cli/autoresearch-goal.js +2 -1
- package/dist/cli/autoresearch-goal.js.map +1 -1
- package/dist/cli/autoresearch-intake.d.ts.map +1 -1
- package/dist/cli/autoresearch-intake.js +2 -0
- package/dist/cli/autoresearch-intake.js.map +1 -1
- package/dist/cli/doctor.d.ts +39 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +460 -40
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +71 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/performance-goal.d.ts.map +1 -1
- package/dist/cli/performance-goal.js +4 -2
- package/dist/cli/performance-goal.js.map +1 -1
- package/dist/cli/plugin-marketplace.d.ts +1 -0
- package/dist/cli/plugin-marketplace.d.ts.map +1 -1
- package/dist/cli/plugin-marketplace.js +88 -67
- package/dist/cli/plugin-marketplace.js.map +1 -1
- package/dist/cli/project-runtime-codex-homes.d.ts +2 -0
- package/dist/cli/project-runtime-codex-homes.d.ts.map +1 -1
- package/dist/cli/project-runtime-codex-homes.js +112 -5
- package/dist/cli/project-runtime-codex-homes.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +15 -6
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/ultragoal.d.ts.map +1 -1
- package/dist/cli/ultragoal.js +5 -1
- package/dist/cli/ultragoal.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +23 -4
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/url.d.ts +8 -0
- package/dist/cli/url.d.ts.map +1 -0
- package/dist/cli/url.js +69 -0
- package/dist/cli/url.js.map +1 -0
- package/dist/config/__tests__/codex-hooks.test.js +20 -4
- package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
- package/dist/config/__tests__/models.test.js +21 -1
- package/dist/config/__tests__/models.test.js.map +1 -1
- package/dist/config/codex-hooks.d.ts.map +1 -1
- package/dist/config/codex-hooks.js +1 -4
- package/dist/config/codex-hooks.js.map +1 -1
- package/dist/config/models.d.ts +5 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +23 -0
- package/dist/config/models.js.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.d.ts +2 -0
- package/dist/goal-workflows/codex-goal-snapshot.d.ts.map +1 -1
- package/dist/goal-workflows/codex-goal-snapshot.js +10 -0
- package/dist/goal-workflows/codex-goal-snapshot.js.map +1 -1
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js +7 -0
- package/dist/hooks/__tests__/autopilot-skill-contract.test.js.map +1 -1
- package/dist/hooks/__tests__/keyword-detector.test.js +46 -0
- package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js +100 -0
- package/dist/hooks/__tests__/notify-fallback-watcher.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-all-workers-idle.test.js +75 -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 +225 -0
- package/dist/hooks/__tests__/notify-hook-auto-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js +75 -0
- package/dist/hooks/__tests__/notify-hook-team-dispatch.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js +563 -0
- package/dist/hooks/__tests__/notify-hook-team-leader-nudge.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js +187 -12
- package/dist/hooks/__tests__/notify-hook-team-tmux-guard.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +225 -0
- package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js +0 -0
- package/dist/hooks/__tests__/notify-hook-tmux-scrollback.test.js.map +1 -1
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js +75 -0
- package/dist/hooks/__tests__/notify-hook-worker-idle.test.js.map +1 -1
- package/dist/hooks/keyword-detector.d.ts.map +1 -1
- package/dist/hooks/keyword-detector.js +4 -0
- package/dist/hooks/keyword-detector.js.map +1 -1
- package/dist/hud/__tests__/reconcile.test.js +137 -2
- package/dist/hud/__tests__/reconcile.test.js.map +1 -1
- package/dist/hud/__tests__/state.test.js +107 -0
- package/dist/hud/__tests__/state.test.js.map +1 -1
- package/dist/hud/__tests__/tmux.test.js +17 -0
- package/dist/hud/__tests__/tmux.test.js.map +1 -1
- package/dist/hud/reconcile.d.ts.map +1 -1
- package/dist/hud/reconcile.js +21 -7
- package/dist/hud/reconcile.js.map +1 -1
- package/dist/hud/render.d.ts.map +1 -1
- package/dist/hud/render.js +9 -0
- package/dist/hud/render.js.map +1 -1
- package/dist/hud/state.d.ts.map +1 -1
- package/dist/hud/state.js +43 -5
- package/dist/hud/state.js.map +1 -1
- package/dist/hud/types.d.ts +6 -0
- package/dist/hud/types.d.ts.map +1 -1
- package/dist/hud/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/__tests__/bootstrap.test.js +24 -1
- package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
- package/dist/mcp/__tests__/state-paths.test.js +53 -0
- package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
- package/dist/mcp/bootstrap.d.ts +2 -0
- package/dist/mcp/bootstrap.d.ts.map +1 -1
- package/dist/mcp/bootstrap.js +32 -6
- package/dist/mcp/bootstrap.js.map +1 -1
- package/dist/mcp/state-paths.d.ts.map +1 -1
- package/dist/mcp/state-paths.js +11 -5
- package/dist/mcp/state-paths.js.map +1 -1
- package/dist/modes/__tests__/base-autopilot-gates.test.js +48 -0
- package/dist/modes/__tests__/base-autopilot-gates.test.js.map +1 -1
- package/dist/modes/base.d.ts.map +1 -1
- package/dist/modes/base.js +1 -0
- package/dist/modes/base.js.map +1 -1
- package/dist/notifications/__tests__/http-client.test.js +9 -0
- package/dist/notifications/__tests__/http-client.test.js.map +1 -1
- package/dist/notifications/http-client.js +1 -1
- package/dist/notifications/http-client.js.map +1 -1
- package/dist/performance-goal/artifacts.d.ts.map +1 -1
- package/dist/performance-goal/artifacts.js +10 -1
- package/dist/performance-goal/artifacts.js.map +1 -1
- package/dist/ralplan/__tests__/consensus-gate.test.js +112 -0
- package/dist/ralplan/__tests__/consensus-gate.test.js.map +1 -1
- package/dist/ralplan/consensus-gate.d.ts +23 -0
- package/dist/ralplan/consensus-gate.d.ts.map +1 -1
- package/dist/ralplan/consensus-gate.js +133 -21
- package/dist/ralplan/consensus-gate.js.map +1 -1
- package/dist/scripts/__tests__/codex-native-hook.test.js +1251 -13
- package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
- package/dist/scripts/codex-native-hook.d.ts.map +1 -1
- package/dist/scripts/codex-native-hook.js +601 -24
- package/dist/scripts/codex-native-hook.js.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts +1 -0
- package/dist/scripts/notify-hook/team-leader-nudge.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-leader-nudge.js +279 -86
- package/dist/scripts/notify-hook/team-leader-nudge.js.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.d.ts.map +1 -1
- package/dist/scripts/notify-hook/team-tmux-guard.js +87 -8
- package/dist/scripts/notify-hook/team-tmux-guard.js.map +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js +1 -1
- package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
- package/dist/scripts/run-compiled-ci.d.ts +2 -0
- package/dist/scripts/run-compiled-ci.d.ts.map +1 -0
- package/dist/scripts/run-compiled-ci.js +77 -0
- package/dist/scripts/run-compiled-ci.js.map +1 -0
- package/dist/scripts/sync-plugin-mirror.d.ts.map +1 -1
- package/dist/scripts/sync-plugin-mirror.js +1 -0
- package/dist/scripts/sync-plugin-mirror.js.map +1 -1
- package/dist/session-history/search.d.ts.map +1 -1
- package/dist/session-history/search.js +24 -9
- package/dist/session-history/search.js.map +1 -1
- package/dist/sidecar/__tests__/args.test.d.ts +2 -0
- package/dist/sidecar/__tests__/args.test.d.ts.map +1 -0
- package/dist/sidecar/__tests__/args.test.js +18 -0
- package/dist/sidecar/__tests__/args.test.js.map +1 -0
- package/dist/sidecar/index.d.ts.map +1 -1
- package/dist/sidecar/index.js +12 -4
- package/dist/sidecar/index.js.map +1 -1
- package/dist/state/__tests__/operations.test.js +107 -3
- package/dist/state/__tests__/operations.test.js.map +1 -1
- package/dist/state/operations.d.ts.map +1 -1
- package/dist/state/operations.js +57 -2
- package/dist/state/operations.js.map +1 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js +22 -1
- package/dist/team/__tests__/delivery-e2e-smoke.test.js.map +1 -1
- package/dist/team/__tests__/model-contract.test.js +57 -1
- package/dist/team/__tests__/model-contract.test.js.map +1 -1
- package/dist/team/__tests__/runtime.test.js +1468 -110
- package/dist/team/__tests__/runtime.test.js.map +1 -1
- package/dist/team/__tests__/scaling.test.js +63 -0
- package/dist/team/__tests__/scaling.test.js.map +1 -1
- package/dist/team/__tests__/state.test.js +24 -1
- package/dist/team/__tests__/state.test.js.map +1 -1
- package/dist/team/__tests__/tmux-session.test.js +512 -0
- package/dist/team/__tests__/tmux-session.test.js.map +1 -1
- package/dist/team/__tests__/worker-bootstrap.test.js +42 -9
- package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
- package/dist/team/model-contract.d.ts +16 -0
- package/dist/team/model-contract.d.ts.map +1 -1
- package/dist/team/model-contract.js +41 -1
- package/dist/team/model-contract.js.map +1 -1
- package/dist/team/runtime.d.ts.map +1 -1
- package/dist/team/runtime.js +116 -30
- package/dist/team/runtime.js.map +1 -1
- package/dist/team/scaling.d.ts.map +1 -1
- package/dist/team/scaling.js +9 -1
- package/dist/team/scaling.js.map +1 -1
- package/dist/team/state/types.d.ts +2 -0
- package/dist/team/state/types.d.ts.map +1 -1
- package/dist/team/state/types.js.map +1 -1
- package/dist/team/state.d.ts +3 -0
- package/dist/team/state.d.ts.map +1 -1
- package/dist/team/state.js +20 -0
- package/dist/team/state.js.map +1 -1
- package/dist/team/tmux-session.d.ts +38 -3
- package/dist/team/tmux-session.d.ts.map +1 -1
- package/dist/team/tmux-session.js +275 -36
- package/dist/team/tmux-session.js.map +1 -1
- package/dist/team/worker-bootstrap.d.ts.map +1 -1
- package/dist/team/worker-bootstrap.js +26 -1
- package/dist/team/worker-bootstrap.js.map +1 -1
- package/dist/ultragoal/__tests__/artifacts.test.js +388 -0
- package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
- package/dist/ultragoal/__tests__/docs-contract.test.js +3 -0
- package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
- package/dist/ultragoal/artifacts.d.ts +23 -0
- package/dist/ultragoal/artifacts.d.ts.map +1 -1
- package/dist/ultragoal/artifacts.js +275 -12
- package/dist/ultragoal/artifacts.js.map +1 -1
- package/dist/url-reader/__tests__/url-reader.test.d.ts +2 -0
- package/dist/url-reader/__tests__/url-reader.test.d.ts.map +1 -0
- package/dist/url-reader/__tests__/url-reader.test.js +433 -0
- package/dist/url-reader/__tests__/url-reader.test.js.map +1 -0
- package/dist/url-reader/index.d.ts +4 -0
- package/dist/url-reader/index.d.ts.map +1 -0
- package/dist/url-reader/index.js +522 -0
- package/dist/url-reader/index.js.map +1 -0
- package/dist/url-reader/types.d.ts +41 -0
- package/dist/url-reader/types.d.ts.map +1 -0
- package/dist/url-reader/types.js +2 -0
- package/dist/url-reader/types.js.map +1 -0
- package/dist/utils/__tests__/agents-md.test.js +39 -1
- package/dist/utils/__tests__/agents-md.test.js.map +1 -1
- package/dist/utils/__tests__/agents-model-table.test.js +28 -0
- package/dist/utils/__tests__/agents-model-table.test.js.map +1 -1
- package/dist/utils/agents-md.d.ts +4 -0
- package/dist/utils/agents-md.d.ts.map +1 -1
- package/dist/utils/agents-md.js +28 -0
- package/dist/utils/agents-md.js.map +1 -1
- package/dist/utils/agents-model-table.d.ts +7 -3
- package/dist/utils/agents-model-table.d.ts.map +1 -1
- package/dist/utils/agents-model-table.js +16 -8
- package/dist/utils/agents-model-table.js.map +1 -1
- package/dist/utils/platform-command.d.ts +7 -1
- package/dist/utils/platform-command.d.ts.map +1 -1
- package/dist/utils/platform-command.js +12 -1
- package/dist/utils/platform-command.js.map +1 -1
- package/dist/verification/__tests__/ci-rust-gates.test.js +4 -0
- package/dist/verification/__tests__/ci-rust-gates.test.js.map +1 -1
- package/dist/vscode/__tests__/index.test.d.ts +2 -0
- package/dist/vscode/__tests__/index.test.d.ts.map +1 -0
- package/dist/vscode/__tests__/index.test.js +236 -0
- package/dist/vscode/__tests__/index.test.js.map +1 -0
- package/dist/vscode/index.d.ts +76 -0
- package/dist/vscode/index.d.ts.map +1 -0
- package/dist/vscode/index.js +196 -0
- package/dist/vscode/index.js.map +1 -0
- package/package.json +3 -3
- package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/oh-my-codex/hooks/codex-native-hook.mjs +59 -8
- package/plugins/oh-my-codex/skills/autopilot/SKILL.md +9 -5
- package/plugins/oh-my-codex/skills/autoresearch-goal/SKILL.md +3 -0
- package/plugins/oh-my-codex/skills/performance-goal/SKILL.md +3 -0
- package/plugins/oh-my-codex/skills/ralplan/SKILL.md +1 -1
- package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +22 -4
- package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +2 -2
- package/plugins/oh-my-codex/skills/ultrawork/references/agent-tiers.md +61 -0
- package/skills/autopilot/SKILL.md +9 -5
- package/skills/autoresearch-goal/SKILL.md +3 -0
- package/skills/ecomode/SKILL.md +1 -1
- package/skills/ecomode/references/agent-tiers.md +61 -0
- package/skills/performance-goal/SKILL.md +3 -0
- package/skills/ralplan/SKILL.md +1 -1
- package/skills/ultragoal/SKILL.md +22 -4
- package/skills/ultrawork/SKILL.md +2 -2
- package/skills/ultrawork/references/agent-tiers.md +61 -0
- package/src/scripts/__tests__/codex-native-hook.test.ts +1560 -181
- package/src/scripts/codex-native-hook.ts +663 -24
- package/src/scripts/notify-hook/team-leader-nudge.ts +298 -91
- package/src/scripts/notify-hook/team-tmux-guard.ts +92 -8
- package/src/scripts/notify-hook/tmux-injection.ts +1 -1
- package/src/scripts/run-compiled-ci.ts +85 -0
- package/src/scripts/sync-plugin-mirror.ts +1 -0
- package/templates/AGENTS.md +6 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawnSync, execFile } from 'child_process';
|
|
2
2
|
import { promisify } from 'util';
|
|
3
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
3
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'fs';
|
|
4
4
|
import { homedir } from 'os';
|
|
5
5
|
import { dirname, isAbsolute, join, resolve } from 'path';
|
|
6
6
|
import { CODEX_BYPASS_FLAG, CLAUDE_SKIP_PERMISSIONS_FLAG, MADMAX_FLAG, CONFIG_FLAG, LONG_CONFIG_FLAG, MODEL_FLAG, } from '../cli/constants.js';
|
|
@@ -14,9 +14,10 @@ import { resolveOmxCliEntryPath } from '../utils/paths.js';
|
|
|
14
14
|
const execFileAsync = promisify(execFile);
|
|
15
15
|
import { HUD_RESIZE_RECONCILE_DELAY_SECONDS, HUD_TMUX_TEAM_HEIGHT_LINES } from '../hud/constants.js';
|
|
16
16
|
import { OMX_TMUX_HUD_OWNER_ENV } from '../hud/reconcile.js';
|
|
17
|
-
import { findHudWatchPaneIds, OMX_TMUX_HUD_LEADER_PANE_ENV } from '../hud/tmux.js';
|
|
17
|
+
import { findHudWatchPaneIds, hudPaneMatchesOwner, OMX_TMUX_HUD_LEADER_PANE_ENV } from '../hud/tmux.js';
|
|
18
18
|
const OMX_INSTANCE_OPTION = '@omx_instance_id';
|
|
19
19
|
const OMX_PANE_INSTANCE_OPTION = '@omx_pane_instance_id';
|
|
20
|
+
const OMX_TEAM_PANE_OWNER_OPTION = '@omx_team_pane_owner_id';
|
|
20
21
|
const INJECTION_MARKER = '[OMX_TMUX_INJECT]';
|
|
21
22
|
const MODEL_INSTRUCTIONS_FILE_KEY = 'model_instructions_file';
|
|
22
23
|
const OMX_BYPASS_DEFAULT_SYSTEM_PROMPT_ENV = 'OMX_BYPASS_DEFAULT_SYSTEM_PROMPT';
|
|
@@ -108,6 +109,16 @@ function tagPaneInstance(paneTarget, instanceId) {
|
|
|
108
109
|
throw new Error(`failed to tag tmux pane ${target}: ${result.stderr}`);
|
|
109
110
|
}
|
|
110
111
|
}
|
|
112
|
+
export function tagPaneTeamOwner(paneTarget, teamOwnerId) {
|
|
113
|
+
const target = paneTarget.trim();
|
|
114
|
+
const sanitized = teamOwnerId.trim();
|
|
115
|
+
if (!target || !sanitized)
|
|
116
|
+
return;
|
|
117
|
+
const result = runTmux(['set-option', '-p', '-t', target, OMX_TEAM_PANE_OWNER_OPTION, sanitized]);
|
|
118
|
+
if (!result.ok) {
|
|
119
|
+
throw new Error(`failed to tag tmux pane ${target}: ${result.stderr}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
111
122
|
export function mitigateCopyModeUnderlineArtifacts(sessionTarget) {
|
|
112
123
|
const normalizedTarget = sessionTarget.trim();
|
|
113
124
|
if (normalizedTarget === '')
|
|
@@ -227,15 +238,57 @@ export function chooseTeamLeaderPaneId(panes, preferredPaneId) {
|
|
|
227
238
|
return preferredPaneId;
|
|
228
239
|
}
|
|
229
240
|
function findHudPaneIds(target, leaderPaneId) {
|
|
230
|
-
|
|
231
|
-
return panes
|
|
232
|
-
.filter((pane) => pane.paneId !== leaderPaneId)
|
|
233
|
-
.filter((pane) => isHudWatchPane(pane))
|
|
234
|
-
.map((pane) => pane.paneId);
|
|
241
|
+
return findHudWatchPaneIds(listPanes(target), leaderPaneId, { leaderPaneId });
|
|
235
242
|
}
|
|
236
243
|
function findOwnedHudPaneIds(target, leaderPaneId) {
|
|
237
244
|
return findHudWatchPaneIds(listPanes(target), leaderPaneId, { leaderPaneId });
|
|
238
245
|
}
|
|
246
|
+
function readPaneCurrentPath(paneId) {
|
|
247
|
+
if (!paneId.startsWith('%'))
|
|
248
|
+
return null;
|
|
249
|
+
const result = runTmux(['display-message', '-p', '-t', paneId, '#{pane_current_path}']);
|
|
250
|
+
if (!result.ok)
|
|
251
|
+
return null;
|
|
252
|
+
const path = result.stdout.split('\n')[0]?.trim() ?? '';
|
|
253
|
+
return path === '' ? null : path;
|
|
254
|
+
}
|
|
255
|
+
function pathIsUsableDirectory(path) {
|
|
256
|
+
try {
|
|
257
|
+
return statSync(path).isDirectory();
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function isMsysDriveSlashPath(path) {
|
|
264
|
+
return /^\/[A-Za-z](?:\/|$)/.test(path);
|
|
265
|
+
}
|
|
266
|
+
function uniqueRestoreCwdCandidates(candidates) {
|
|
267
|
+
const seen = new Set();
|
|
268
|
+
const result = [];
|
|
269
|
+
for (const candidate of candidates) {
|
|
270
|
+
const normalized = typeof candidate.rawPath === 'string' ? candidate.rawPath.trim() : '';
|
|
271
|
+
if (!normalized || seen.has(normalized))
|
|
272
|
+
continue;
|
|
273
|
+
seen.add(normalized);
|
|
274
|
+
result.push({ source: candidate.source, rawPath: normalized });
|
|
275
|
+
}
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
function shouldAttemptRestoreCwdCandidate(candidate) {
|
|
279
|
+
if (candidate.source === 'live' && isMsysOrGitBash() && isMsysDriveSlashPath(candidate.rawPath)) {
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
return pathIsUsableDirectory(candidate.rawPath);
|
|
283
|
+
}
|
|
284
|
+
function resolveStandaloneHudRestoreCwdCandidates(leaderPaneId, fallbackCwd, explicitCwd) {
|
|
285
|
+
const liveLeaderCwd = readPaneCurrentPath(leaderPaneId);
|
|
286
|
+
return uniqueRestoreCwdCandidates([
|
|
287
|
+
{ source: 'explicit', rawPath: explicitCwd },
|
|
288
|
+
{ source: 'live', rawPath: liveLeaderCwd },
|
|
289
|
+
{ source: 'fallback', rawPath: fallbackCwd },
|
|
290
|
+
]).filter(shouldAttemptRestoreCwdCandidate);
|
|
291
|
+
}
|
|
239
292
|
const MAX_FRACTIONAL_SLEEP_MS = 60_000;
|
|
240
293
|
function toFractionalSleepMs(seconds) {
|
|
241
294
|
if (!Number.isFinite(seconds) || seconds <= 0)
|
|
@@ -1045,7 +1098,7 @@ export function isTmuxAvailable() {
|
|
|
1045
1098
|
// Create tmux session with N worker windows
|
|
1046
1099
|
// Split the current tmux leader window into worker panes.
|
|
1047
1100
|
// Returns TeamSession or throws if tmux not available
|
|
1048
|
-
export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs = [], workerStartups = []) {
|
|
1101
|
+
export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs = [], workerStartups = [], options = {}) {
|
|
1049
1102
|
if (!isTmuxAvailable()) {
|
|
1050
1103
|
throw new Error('tmux is not available');
|
|
1051
1104
|
}
|
|
@@ -1083,16 +1136,18 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1083
1136
|
throw new Error(`failed to parse current tmux target: ${context.stdout}`);
|
|
1084
1137
|
}
|
|
1085
1138
|
const teamTarget = `${sessionName}:${windowIndex}`;
|
|
1086
|
-
const
|
|
1087
|
-
|
|
1088
|
-
|
|
1139
|
+
const ownerSessionId = (options.ownerSessionId ?? process.env.OMX_SESSION_ID ?? '').trim();
|
|
1140
|
+
const teamPaneOwnerId = (options.teamPaneOwnerId ?? `team:${safeTeamName}`).trim();
|
|
1141
|
+
if (ownerSessionId) {
|
|
1142
|
+
const tagResult = runTmux(['set-option', '-t', sessionName, OMX_INSTANCE_OPTION, ownerSessionId]);
|
|
1089
1143
|
if (!tagResult.ok) {
|
|
1090
1144
|
throw new Error(`failed to tag tmux session ${sessionName}: ${tagResult.stderr}`);
|
|
1091
1145
|
}
|
|
1092
1146
|
}
|
|
1093
1147
|
const panes = listPanes(teamTarget);
|
|
1094
1148
|
const leaderPaneId = chooseTeamLeaderPaneId(panes, detectedLeaderPaneId);
|
|
1095
|
-
tagPaneInstance(leaderPaneId,
|
|
1149
|
+
tagPaneInstance(leaderPaneId, ownerSessionId);
|
|
1150
|
+
tagPaneTeamOwner(leaderPaneId, teamPaneOwnerId);
|
|
1096
1151
|
const initialHudPaneIds = findHudPaneIds(teamTarget, leaderPaneId);
|
|
1097
1152
|
const omxEntry = resolveOmxCliEntryPath();
|
|
1098
1153
|
const canRecreateTeamHud = Boolean(omxEntry && omxEntry.trim() !== '');
|
|
@@ -1141,7 +1196,8 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1141
1196
|
if (isNativeWindows() && !waitForPaneToRemainPresent(teamTarget, paneId)) {
|
|
1142
1197
|
throw new Error(`worker pane ${i} did not remain present after tmux split-window returned ${paneId}`);
|
|
1143
1198
|
}
|
|
1144
|
-
tagPaneInstance(paneId,
|
|
1199
|
+
tagPaneInstance(paneId, ownerSessionId);
|
|
1200
|
+
tagPaneTeamOwner(paneId, teamPaneOwnerId);
|
|
1145
1201
|
workerPaneIds.push(paneId);
|
|
1146
1202
|
if (i === 1)
|
|
1147
1203
|
rightStackRootPaneId = paneId;
|
|
@@ -1166,7 +1222,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1166
1222
|
let resizeHookName = null;
|
|
1167
1223
|
let resizeHookTarget = null;
|
|
1168
1224
|
if (canRecreateTeamHud && omxEntry) {
|
|
1169
|
-
const hudCmd = `exec env ${formatHudEnvAssignments(process.env, { sessionId:
|
|
1225
|
+
const hudCmd = `exec env ${formatHudEnvAssignments(process.env, { sessionId: ownerSessionId, leaderPaneId })} node ${shellQuoteSingle(translatePathForMsys(omxEntry))} hud --watch`;
|
|
1170
1226
|
const hudCwd = translatePathForMsys(cwd);
|
|
1171
1227
|
const hudResult = runTmux([
|
|
1172
1228
|
'split-window', '-v', '-f', '-l', String(HUD_TMUX_TEAM_HEIGHT_LINES), '-t', teamTarget, '-d', '-P', '-F', '#{pane_id}', '-c', hudCwd, hudCmd,
|
|
@@ -1178,7 +1234,8 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1178
1234
|
if (isNativeWindows() && !waitForPaneToRemainPresent(teamTarget, id)) {
|
|
1179
1235
|
throw new Error(`HUD pane did not remain present after tmux split-window returned ${id}`);
|
|
1180
1236
|
}
|
|
1181
|
-
tagPaneInstance(id,
|
|
1237
|
+
tagPaneInstance(id, ownerSessionId);
|
|
1238
|
+
tagPaneTeamOwner(id, teamPaneOwnerId);
|
|
1182
1239
|
hudPaneId = id;
|
|
1183
1240
|
if (isNativeWindows()) {
|
|
1184
1241
|
// Native Windows tmux support may flow through psmux; issuing a
|
|
@@ -1247,6 +1304,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1247
1304
|
hudPaneId,
|
|
1248
1305
|
resizeHookName,
|
|
1249
1306
|
resizeHookTarget,
|
|
1307
|
+
teamPaneOwnerId,
|
|
1250
1308
|
};
|
|
1251
1309
|
}
|
|
1252
1310
|
catch (error) {
|
|
@@ -1262,7 +1320,7 @@ export function createTeamSession(teamName, workerCount, cwd, workerLaunchArgs =
|
|
|
1262
1320
|
throw error;
|
|
1263
1321
|
}
|
|
1264
1322
|
}
|
|
1265
|
-
export function restoreStandaloneHudPane(leaderPaneId, cwd) {
|
|
1323
|
+
export function restoreStandaloneHudPane(leaderPaneId, cwd, options = {}) {
|
|
1266
1324
|
const normalizedLeaderPaneId = normalizePaneTarget(leaderPaneId);
|
|
1267
1325
|
if (!normalizedLeaderPaneId)
|
|
1268
1326
|
return null;
|
|
@@ -1284,24 +1342,30 @@ export function restoreStandaloneHudPane(leaderPaneId, cwd) {
|
|
|
1284
1342
|
runTmux(['select-pane', '-t', normalizedLeaderPaneId]);
|
|
1285
1343
|
return existingHudPaneId;
|
|
1286
1344
|
}
|
|
1287
|
-
const hudCmd = `exec env ${formatHudEnvAssignments(process.env, { leaderPaneId: normalizedLeaderPaneId })} ${shellQuoteSingle(translatePathForMsys(resolveLeaderNodePath()))} ${shellQuoteSingle(translatePathForMsys(omxEntry))} hud --watch`;
|
|
1288
|
-
|
|
1289
|
-
const
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1345
|
+
const hudCmd = `exec env ${formatHudEnvAssignments(process.env, { sessionId: options.sessionId, leaderPaneId: normalizedLeaderPaneId })} ${shellQuoteSingle(translatePathForMsys(resolveLeaderNodePath()))} ${shellQuoteSingle(translatePathForMsys(omxEntry))} hud --watch`;
|
|
1346
|
+
let hudResult = null;
|
|
1347
|
+
for (const restoreCwd of resolveStandaloneHudRestoreCwdCandidates(normalizedLeaderPaneId, cwd, options.cwd)) {
|
|
1348
|
+
const candidateResult = runTmux([
|
|
1349
|
+
'split-window',
|
|
1350
|
+
'-v',
|
|
1351
|
+
'-l',
|
|
1352
|
+
String(HUD_TMUX_TEAM_HEIGHT_LINES),
|
|
1353
|
+
'-t',
|
|
1354
|
+
normalizedLeaderPaneId,
|
|
1355
|
+
'-d',
|
|
1356
|
+
'-P',
|
|
1357
|
+
'-F',
|
|
1358
|
+
'#{pane_id}',
|
|
1359
|
+
'-c',
|
|
1360
|
+
translatePathForMsys(restoreCwd.rawPath),
|
|
1361
|
+
hudCmd,
|
|
1362
|
+
]);
|
|
1363
|
+
if (candidateResult.ok) {
|
|
1364
|
+
hudResult = candidateResult;
|
|
1365
|
+
break;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
if (!hudResult?.ok)
|
|
1305
1369
|
return null;
|
|
1306
1370
|
const paneId = hudResult.stdout.split('\n')[0]?.trim() ?? '';
|
|
1307
1371
|
if (!paneId.startsWith('%'))
|
|
@@ -1929,6 +1993,55 @@ export function killWorkerByPaneId(workerPaneId, leaderPaneId) {
|
|
|
1929
1993
|
return;
|
|
1930
1994
|
runTmux(['kill-pane', '-t', workerPaneId]);
|
|
1931
1995
|
}
|
|
1996
|
+
export function paneHasOmxInstanceTag(paneId, instanceId) {
|
|
1997
|
+
const normalizedPaneId = normalizePaneTarget(paneId);
|
|
1998
|
+
const expectedInstanceId = typeof instanceId === 'string' ? instanceId.trim() : '';
|
|
1999
|
+
if (!normalizedPaneId || !expectedInstanceId)
|
|
2000
|
+
return false;
|
|
2001
|
+
const result = runTmux(['show-option', '-qv', '-p', '-t', normalizedPaneId, OMX_PANE_INSTANCE_OPTION]);
|
|
2002
|
+
if (!result.ok)
|
|
2003
|
+
return false;
|
|
2004
|
+
return result.stdout.trim() === expectedInstanceId;
|
|
2005
|
+
}
|
|
2006
|
+
export function paneHasOmxTeamOwnerTag(paneId, teamOwnerId) {
|
|
2007
|
+
const expectedTeamOwnerId = typeof teamOwnerId === 'string' ? teamOwnerId.trim() : '';
|
|
2008
|
+
if (!expectedTeamOwnerId)
|
|
2009
|
+
return false;
|
|
2010
|
+
const result = readPaneTeamOwnerTagResult(paneId);
|
|
2011
|
+
return result.status === 'value' && result.value === expectedTeamOwnerId;
|
|
2012
|
+
}
|
|
2013
|
+
export function readPaneTeamOwnerTag(paneId) {
|
|
2014
|
+
const result = readPaneTeamOwnerTagResult(paneId);
|
|
2015
|
+
return result.status === 'value' ? result.value : null;
|
|
2016
|
+
}
|
|
2017
|
+
export function readPaneTeamOwnerTagResult(paneId) {
|
|
2018
|
+
const normalizedPaneId = normalizePaneTarget(paneId);
|
|
2019
|
+
if (!normalizedPaneId)
|
|
2020
|
+
return { status: 'error', error: 'invalid pane target' };
|
|
2021
|
+
const { result } = spawnPlatformCommandSync('tmux', [
|
|
2022
|
+
'show-option',
|
|
2023
|
+
'-qv',
|
|
2024
|
+
'-p',
|
|
2025
|
+
'-t',
|
|
2026
|
+
normalizedPaneId,
|
|
2027
|
+
OMX_TEAM_PANE_OWNER_OPTION,
|
|
2028
|
+
], { encoding: 'utf-8' });
|
|
2029
|
+
if (result.error) {
|
|
2030
|
+
return { status: 'error', error: result.error.message };
|
|
2031
|
+
}
|
|
2032
|
+
const stdout = typeof result.stdout === 'string' ? result.stdout.trim() : '';
|
|
2033
|
+
if (result.status === 0) {
|
|
2034
|
+
return stdout === '' ? { status: 'missing' } : { status: 'value', value: stdout };
|
|
2035
|
+
}
|
|
2036
|
+
const stderr = typeof result.stderr === 'string' ? result.stderr.trim() : '';
|
|
2037
|
+
// tmux reports an unset user option as status 1 with no diagnostic on
|
|
2038
|
+
// supported versions. Treat other failures, including signal/null exits,
|
|
2039
|
+
// as real read errors so shared-pane shutdown fails closed instead of
|
|
2040
|
+
// killing a pane whose owner could not be read.
|
|
2041
|
+
if (result.status === 1 && stderr === '')
|
|
2042
|
+
return { status: 'missing' };
|
|
2043
|
+
return { status: 'error', error: stderr || `tmux show-option exited ${result.status ?? 'unknown'}` };
|
|
2044
|
+
}
|
|
1932
2045
|
export async function killWorkerByPaneIdAsync(workerPaneId, leaderPaneId) {
|
|
1933
2046
|
if (!workerPaneId.startsWith('%'))
|
|
1934
2047
|
return;
|
|
@@ -1972,7 +2085,7 @@ function normalizePaneTargets(paneIds, options = {}) {
|
|
|
1972
2085
|
}
|
|
1973
2086
|
return { killablePaneIds, excluded };
|
|
1974
2087
|
}
|
|
1975
|
-
export function resolveSharedSessionShutdownTopology(sessionName, preferredLeaderPaneId) {
|
|
2088
|
+
export function resolveSharedSessionShutdownTopology(sessionName, preferredLeaderPaneId, teamName) {
|
|
1976
2089
|
const panes = listPanes(sessionName);
|
|
1977
2090
|
const livePaneIds = panes
|
|
1978
2091
|
.map((pane) => normalizePaneTarget(pane.paneId))
|
|
@@ -1981,22 +2094,148 @@ export function resolveSharedSessionShutdownTopology(sessionName, preferredLeade
|
|
|
1981
2094
|
if (panes.length === 0) {
|
|
1982
2095
|
return {
|
|
1983
2096
|
livePaneIds,
|
|
2097
|
+
teamWorkerPaneIds: [],
|
|
1984
2098
|
leaderPaneId: fallbackLeaderPaneId,
|
|
1985
2099
|
hudPaneIds: [],
|
|
2100
|
+
leaderOwnedHudPaneIds: [],
|
|
1986
2101
|
};
|
|
1987
2102
|
}
|
|
1988
|
-
const
|
|
2103
|
+
const normalizedTeamName = typeof teamName === 'string' ? teamName.trim() : '';
|
|
2104
|
+
const normalizedTeamWorkerPaneIds = normalizedTeamName
|
|
2105
|
+
? panes
|
|
2106
|
+
.filter((pane) => !isHudWatchPane(pane))
|
|
2107
|
+
.filter((pane) => paneLooksLikeTeamWorkerPane(pane, normalizedTeamName))
|
|
2108
|
+
.map((pane) => pane.paneId)
|
|
2109
|
+
.filter((paneId) => paneId.startsWith('%'))
|
|
2110
|
+
: [];
|
|
2111
|
+
const workerPaneIdSet = new Set(normalizedTeamWorkerPaneIds);
|
|
2112
|
+
const resolvedLeaderPaneId = chooseSharedSessionShutdownLeaderPaneId(panes, fallbackLeaderPaneId, workerPaneIdSet);
|
|
1989
2113
|
const hudPaneIds = panes
|
|
1990
2114
|
.filter((pane) => pane.paneId !== resolvedLeaderPaneId)
|
|
1991
2115
|
.filter((pane) => isHudWatchPane(pane))
|
|
1992
2116
|
.map((pane) => pane.paneId)
|
|
1993
2117
|
.filter((paneId) => paneId.startsWith('%'));
|
|
2118
|
+
const leaderOwnedHudPaneIds = resolvedLeaderPaneId
|
|
2119
|
+
? panes
|
|
2120
|
+
.filter((pane) => pane.paneId !== resolvedLeaderPaneId)
|
|
2121
|
+
.filter((pane) => hudPaneMatchesOwner(pane, { leaderPaneId: resolvedLeaderPaneId }))
|
|
2122
|
+
.map((pane) => pane.paneId)
|
|
2123
|
+
.filter((paneId) => paneId.startsWith('%'))
|
|
2124
|
+
: [];
|
|
1994
2125
|
return {
|
|
1995
2126
|
livePaneIds,
|
|
2127
|
+
teamWorkerPaneIds: normalizedTeamWorkerPaneIds,
|
|
1996
2128
|
leaderPaneId: resolvedLeaderPaneId,
|
|
1997
2129
|
hudPaneIds,
|
|
2130
|
+
leaderOwnedHudPaneIds,
|
|
1998
2131
|
};
|
|
1999
2132
|
}
|
|
2133
|
+
function chooseSharedSessionShutdownLeaderPaneId(panes, preferredLeaderPaneId, teamWorkerPaneIds) {
|
|
2134
|
+
const preferred = panes.find((pane) => pane.paneId === preferredLeaderPaneId);
|
|
2135
|
+
if (preferred && !isHudWatchPane(preferred) && !teamWorkerPaneIds.has(preferred.paneId)) {
|
|
2136
|
+
return preferred.paneId;
|
|
2137
|
+
}
|
|
2138
|
+
return null;
|
|
2139
|
+
}
|
|
2140
|
+
function paneLooksLikeTeamWorkerPane(pane, teamName) {
|
|
2141
|
+
const command = `${pane.startCommand || ''} ${pane.currentCommand || ''}`.replace(/\\/g, '/');
|
|
2142
|
+
if (!command.trim() || !teamName)
|
|
2143
|
+
return false;
|
|
2144
|
+
if (command.includes(`/team/${teamName}/runtime/worker-`) && command.includes('-startup.sh')) {
|
|
2145
|
+
return true;
|
|
2146
|
+
}
|
|
2147
|
+
const commandVariants = [command, ...decodePowerShellEncodedCommands(command)];
|
|
2148
|
+
return commandVariants.some((candidate) => (commandHasTeamWorkerEnvMarker(candidate, 'OMX_TEAM_INTERNAL_WORKER', teamName)
|
|
2149
|
+
|| commandHasTeamWorkerEnvMarker(candidate, 'OMX_TEAM_WORKER', teamName)));
|
|
2150
|
+
}
|
|
2151
|
+
function commandHasTeamWorkerEnvMarker(command, envName, teamName) {
|
|
2152
|
+
const normalized = command.replace(/\\/g, '/');
|
|
2153
|
+
const key = escapeRegExp(envName);
|
|
2154
|
+
const workerValue = `${escapeRegExp(teamName)}/worker-[A-Za-z0-9_-]+`;
|
|
2155
|
+
const shellAssignment = new RegExp(`(?:^|[\\s;])(?:export\\s+)?(?:["']${key}=${workerValue}|${key}=(?:["']?${workerValue}))`, 'g');
|
|
2156
|
+
const powerShellAssignment = new RegExp(`(?:^|;)\\s*\\$env:${key}\\s*=\\s*["']?${workerValue}`, 'gi');
|
|
2157
|
+
return hasWorkerCliAfterEnvAssignment(normalized, shellAssignment, hasSafeShellEnvAssignmentContext, shellTailInvokesWorkerCli)
|
|
2158
|
+
|| hasWorkerCliAfterEnvAssignment(normalized, powerShellAssignment, () => true, powerShellTailInvokesWorkerCli);
|
|
2159
|
+
}
|
|
2160
|
+
function hasWorkerCliAfterEnvAssignment(command, assignmentPattern, contextIsSafe = () => true, tailInvokesWorkerCli = shellTailInvokesWorkerCli) {
|
|
2161
|
+
assignmentPattern.lastIndex = 0;
|
|
2162
|
+
for (const match of command.matchAll(assignmentPattern)) {
|
|
2163
|
+
const matchIndex = match.index ?? 0;
|
|
2164
|
+
if (!contextIsSafe(command, matchIndex))
|
|
2165
|
+
continue;
|
|
2166
|
+
const afterAssignment = command.slice(matchIndex + match[0].length);
|
|
2167
|
+
if (tailInvokesWorkerCli(afterAssignment)) {
|
|
2168
|
+
return true;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
return false;
|
|
2172
|
+
}
|
|
2173
|
+
const WORKER_CLI_TOKEN_PATTERN = String.raw `(?:"[^"]*(?:^|[\/\\])?(?:codex|claude|gemini)(?:\.(?:js|mjs|cjs|cmd|exe|bat|ps1))?"|'[^']*(?:^|[\/\\])?(?:codex|claude|gemini)(?:\.(?:js|mjs|cjs|cmd|exe|bat|ps1))?'|(?:\S*[\/\\])?(?:codex|claude|gemini)(?:\.(?:js|mjs|cjs|cmd|exe|bat|ps1))?)`;
|
|
2174
|
+
function shellTailInvokesWorkerCli(tail) {
|
|
2175
|
+
const directTail = stripShellAssignmentTailPrefix(tail);
|
|
2176
|
+
const directCliPattern = new RegExp(`^(?:exec\\s+)?${WORKER_CLI_TOKEN_PATTERN}(?:[\\s;"'\`]|$)`, 'i');
|
|
2177
|
+
if (directCliPattern.test(directTail))
|
|
2178
|
+
return true;
|
|
2179
|
+
const shellCommandPattern = /(?:^|\s)-(?:c|lc)\s+(?:"([^"]*)"|'([^']*)'|(\S+))/gi;
|
|
2180
|
+
for (const match of directTail.matchAll(shellCommandPattern)) {
|
|
2181
|
+
const commandText = match[1] ?? match[2] ?? match[3] ?? '';
|
|
2182
|
+
const execCliPattern = new RegExp(`(?:^|[\\s;&|])exec\\s+${WORKER_CLI_TOKEN_PATTERN}(?:[\\s;"'\`]|$)`, 'i');
|
|
2183
|
+
if (execCliPattern.test(commandText))
|
|
2184
|
+
return true;
|
|
2185
|
+
}
|
|
2186
|
+
return false;
|
|
2187
|
+
}
|
|
2188
|
+
function stripShellAssignmentTailPrefix(tail) {
|
|
2189
|
+
let value = tail.trimStart();
|
|
2190
|
+
while (value.startsWith("'") || value.startsWith('"')) {
|
|
2191
|
+
value = value.slice(1).trimStart();
|
|
2192
|
+
}
|
|
2193
|
+
const envAssignmentPattern = /^[A-Za-z_][A-Za-z0-9_]*=(?:'[^']*'|"[^"]*"|\S+)\s+/;
|
|
2194
|
+
let changed = true;
|
|
2195
|
+
while (changed) {
|
|
2196
|
+
changed = false;
|
|
2197
|
+
const match = value.match(envAssignmentPattern);
|
|
2198
|
+
if (match) {
|
|
2199
|
+
value = value.slice(match[0].length).trimStart();
|
|
2200
|
+
changed = true;
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
return value;
|
|
2204
|
+
}
|
|
2205
|
+
function powerShellTailInvokesWorkerCli(tail) {
|
|
2206
|
+
return /(?:^|[\s;&|"'`\/\\])(?:codex|claude|gemini)(?:\.(?:js|mjs|cjs|cmd|exe|bat|ps1))?(?:[\s;"'`]|$)/i.test(tail);
|
|
2207
|
+
}
|
|
2208
|
+
function hasSafeShellEnvAssignmentContext(command, matchIndex) {
|
|
2209
|
+
const prefix = command.slice(0, matchIndex).trimEnd();
|
|
2210
|
+
if (!prefix)
|
|
2211
|
+
return true;
|
|
2212
|
+
const segment = prefix.split(/&&|\|\||[;|]/).pop()?.trimEnd() ?? '';
|
|
2213
|
+
if (!segment)
|
|
2214
|
+
return true;
|
|
2215
|
+
return /(?:^|\s)(?:env|export)(?:\s+(?:'[^']*'|"[^"]*"|\S+))*$/.test(segment)
|
|
2216
|
+
|| /(?:^|\s)worker[-_]wrapper(?:\s+(?:'[^']*'|"[^"]*"|\S+))*$/.test(segment);
|
|
2217
|
+
}
|
|
2218
|
+
function decodePowerShellEncodedCommands(command) {
|
|
2219
|
+
const decoded = [];
|
|
2220
|
+
const encodedCommandPattern = /(?:^|\s)-(?:EncodedCommand|enc|e)(?:\s+|:)([A-Za-z0-9+/=]+)/gi;
|
|
2221
|
+
for (const match of command.matchAll(encodedCommandPattern)) {
|
|
2222
|
+
const encoded = match[1];
|
|
2223
|
+
if (!encoded)
|
|
2224
|
+
continue;
|
|
2225
|
+
try {
|
|
2226
|
+
const text = Buffer.from(encoded, 'base64').toString('utf16le').trim();
|
|
2227
|
+
if (text)
|
|
2228
|
+
decoded.push(text.replace(/\\/g, '/'));
|
|
2229
|
+
}
|
|
2230
|
+
catch {
|
|
2231
|
+
// Ignore malformed pane command fragments; they are not team ownership evidence.
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
return decoded;
|
|
2235
|
+
}
|
|
2236
|
+
function escapeRegExp(value) {
|
|
2237
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2238
|
+
}
|
|
2000
2239
|
/**
|
|
2001
2240
|
* Shared pane-id-direct teardown primitive for worker pane cleanup.
|
|
2002
2241
|
* Must remain liveness-agnostic: do not gate on isWorkerAlive/killWorker.
|