@ai-devkit/agent-manager 0.37.0 → 0.39.0
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/dist/AgentManager.d.ts +0 -4
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +2 -2
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/capacity/anthropic.test.js +115 -0
- package/dist/__tests__/capacity/anthropic.test.js.map +1 -0
- package/dist/__tests__/capacity/boundaries.test.js +45 -0
- package/dist/__tests__/capacity/boundaries.test.js.map +1 -0
- package/dist/__tests__/capacity/claude.test.js +3 -3
- package/dist/__tests__/capacity/claude.test.js.map +1 -1
- package/dist/__tests__/capacity/codex.test.js +3 -1
- package/dist/__tests__/capacity/codex.test.js.map +1 -1
- package/dist/__tests__/capacity/openai.test.js +21 -12
- package/dist/__tests__/capacity/openai.test.js.map +1 -1
- package/dist/__tests__/capacity/wham.test.js +1 -1
- package/dist/__tests__/capacity/wham.test.js.map +1 -1
- package/dist/__tests__/capacity/zai.test.js +7 -8
- package/dist/__tests__/capacity/zai.test.js.map +1 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js +2 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js +7 -15
- package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js +3 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js +11 -26
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js +3 -7
- package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -1
- package/dist/__tests__/harnesses/devin/DevinAdapter.test.js +597 -0
- package/dist/__tests__/harnesses/devin/DevinAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/DevinAgentMapper.test.js +91 -0
- package/dist/__tests__/harnesses/devin/DevinAgentMapper.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/DevinSessionLocator.test.js +192 -0
- package/dist/__tests__/harnesses/devin/DevinSessionLocator.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js +407 -0
- package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/fixtures.js +95 -0
- package/dist/__tests__/harnesses/devin/fixtures.js.map +1 -0
- package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js +5 -11
- package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js.map +1 -1
- package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js +9 -19
- package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js +3 -7
- package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js.map +1 -1
- package/dist/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.js +95 -11
- package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -0
- package/dist/__tests__/harnesses/runtimeProfiles.test.js +89 -0
- package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -0
- package/dist/__tests__/print/DurableAgent.test.js +4 -6
- package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgentRepository.test.js +1 -12
- package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
- package/dist/__tests__/terminal/GhosttyBackend.test.js +334 -0
- package/dist/__tests__/terminal/GhosttyBackend.test.js.map +1 -0
- package/dist/__tests__/terminal/TmuxManager.test.js +1 -1
- package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
- package/dist/adapters/AgentAdapter.d.ts +1 -1
- package/dist/adapters/AgentAdapter.d.ts.map +1 -1
- package/dist/adapters/AgentAdapter.js +2 -1
- package/dist/adapters/AgentAdapter.js.map +1 -1
- package/dist/capacity/index.d.ts +9 -19
- package/dist/capacity/index.d.ts.map +1 -1
- package/dist/capacity/index.js +11 -4
- package/dist/capacity/index.js.map +1 -1
- package/dist/capacity/providers/anthropic.d.ts +9 -0
- package/dist/capacity/providers/anthropic.d.ts.map +1 -0
- package/dist/capacity/{claude.js → providers/anthropic.js} +10 -128
- package/dist/capacity/providers/anthropic.js.map +1 -0
- package/dist/capacity/providers/openai-platform.d.ts +14 -0
- package/dist/capacity/providers/openai-platform.d.ts.map +1 -0
- package/dist/capacity/providers/openai-platform.js +120 -0
- package/dist/capacity/providers/openai-platform.js.map +1 -0
- package/dist/capacity/providers/openai-subscription.d.ts +20 -0
- package/dist/capacity/providers/openai-subscription.d.ts.map +1 -0
- package/dist/capacity/providers/openai-subscription.js +129 -0
- package/dist/capacity/providers/openai-subscription.js.map +1 -0
- package/dist/capacity/providers/zai.d.ts +8 -0
- package/dist/capacity/providers/zai.d.ts.map +1 -0
- package/dist/capacity/{zai.js → providers/zai.js} +17 -62
- package/dist/capacity/providers/zai.js.map +1 -0
- package/dist/capacity/sources/claude.d.ts +9 -0
- package/dist/capacity/sources/claude.d.ts.map +1 -0
- package/dist/capacity/sources/claude.js +17 -0
- package/dist/capacity/sources/claude.js.map +1 -0
- package/dist/capacity/{codex.d.ts → sources/codex.d.ts} +5 -9
- package/dist/capacity/sources/codex.d.ts.map +1 -0
- package/dist/capacity/{codex.js → sources/codex.js} +31 -84
- package/dist/capacity/sources/codex.js.map +1 -0
- package/dist/capacity/sources/pi.d.ts +30 -0
- package/dist/capacity/sources/pi.d.ts.map +1 -0
- package/dist/capacity/sources/pi.js +81 -0
- package/dist/capacity/sources/pi.js.map +1 -0
- package/dist/capacity/types.d.ts +2 -0
- package/dist/capacity/types.d.ts.map +1 -1
- package/dist/capacity/types.js +1 -1
- package/dist/capacity/types.js.map +1 -1
- package/dist/harnesses/claude/credentials.d.ts +10 -0
- package/dist/harnesses/claude/credentials.d.ts.map +1 -0
- package/dist/harnesses/claude/credentials.js +112 -0
- package/dist/harnesses/claude/credentials.js.map +1 -0
- package/dist/harnesses/claude/readiness.d.ts +3 -0
- package/dist/harnesses/claude/readiness.d.ts.map +1 -0
- package/dist/harnesses/claude/readiness.js +63 -0
- package/dist/harnesses/claude/readiness.js.map +1 -0
- package/dist/harnesses/codex/credentials.d.ts +15 -0
- package/dist/harnesses/codex/credentials.d.ts.map +1 -0
- package/dist/harnesses/codex/credentials.js +58 -0
- package/dist/harnesses/codex/credentials.js.map +1 -0
- package/dist/harnesses/codex/readiness.d.ts +3 -0
- package/dist/harnesses/codex/readiness.d.ts.map +1 -0
- package/dist/harnesses/codex/readiness.js +60 -0
- package/dist/harnesses/codex/readiness.js.map +1 -0
- package/dist/harnesses/copilot/readiness.d.ts +3 -0
- package/dist/harnesses/copilot/readiness.d.ts.map +1 -0
- package/dist/harnesses/copilot/readiness.js +39 -0
- package/dist/harnesses/copilot/readiness.js.map +1 -0
- package/dist/harnesses/devin/DevinAdapter.d.ts +39 -0
- package/dist/harnesses/devin/DevinAdapter.d.ts.map +1 -0
- package/dist/harnesses/devin/DevinAdapter.js +177 -0
- package/dist/harnesses/devin/DevinAdapter.js.map +1 -0
- package/dist/harnesses/devin/DevinAgentMapper.d.ts +11 -0
- package/dist/harnesses/devin/DevinAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/devin/DevinAgentMapper.js +35 -0
- package/dist/harnesses/devin/DevinAgentMapper.js.map +1 -0
- package/dist/harnesses/devin/DevinSessionLocator.d.ts +46 -0
- package/dist/harnesses/devin/DevinSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/devin/DevinSessionLocator.js +176 -0
- package/dist/harnesses/devin/DevinSessionLocator.js.map +1 -0
- package/dist/harnesses/devin/DevinSessionParser.d.ts +29 -0
- package/dist/harnesses/devin/DevinSessionParser.d.ts.map +1 -0
- package/dist/harnesses/devin/DevinSessionParser.js +166 -0
- package/dist/harnesses/devin/DevinSessionParser.js.map +1 -0
- package/dist/harnesses/devin/readiness.d.ts +3 -0
- package/dist/harnesses/devin/readiness.d.ts.map +1 -0
- package/dist/harnesses/devin/readiness.js +39 -0
- package/dist/harnesses/devin/readiness.js.map +1 -0
- package/dist/harnesses/index.d.ts.map +1 -1
- package/dist/harnesses/index.js +3 -1
- package/dist/harnesses/index.js.map +1 -1
- package/dist/harnesses/opencode/readiness.d.ts +3 -0
- package/dist/harnesses/opencode/readiness.d.ts.map +1 -0
- package/dist/harnesses/opencode/readiness.js +50 -0
- package/dist/harnesses/opencode/readiness.js.map +1 -0
- package/dist/harnesses/pi/credentials.d.ts +22 -0
- package/dist/harnesses/pi/credentials.d.ts.map +1 -0
- package/dist/harnesses/pi/credentials.js +98 -0
- package/dist/harnesses/pi/credentials.js.map +1 -0
- package/dist/harnesses/pi/readiness.d.ts +3 -0
- package/dist/harnesses/pi/readiness.d.ts.map +1 -0
- package/dist/harnesses/pi/readiness.js +96 -0
- package/dist/harnesses/pi/readiness.js.map +1 -0
- package/dist/harnesses/readiness/AgentReadiness.d.ts +6 -0
- package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -0
- package/dist/harnesses/readiness/AgentReadiness.js +70 -0
- package/dist/harnesses/readiness/AgentReadiness.js.map +1 -0
- package/dist/harnesses/readiness/checks.d.ts +31 -0
- package/dist/harnesses/readiness/checks.d.ts.map +1 -0
- package/dist/harnesses/readiness/checks.js +270 -0
- package/dist/harnesses/readiness/checks.js.map +1 -0
- package/dist/{readiness/AgentReadiness.d.ts → harnesses/readiness/types.d.ts} +19 -10
- package/dist/harnesses/readiness/types.d.ts.map +1 -0
- package/dist/harnesses/readiness/types.js +4 -0
- package/dist/harnesses/readiness/types.js.map +1 -0
- package/dist/harnesses/runtimeProfiles.d.ts +11 -0
- package/dist/harnesses/runtimeProfiles.d.ts.map +1 -0
- package/dist/harnesses/runtimeProfiles.js +100 -0
- package/dist/harnesses/runtimeProfiles.js.map +1 -0
- package/dist/index.d.ts +16 -42
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -23
- package/dist/index.js.map +1 -1
- package/dist/runtime/ManagedAgentRuntime.d.ts +3 -3
- package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -1
- package/dist/runtime/ManagedAgentRuntime.js +6 -20
- package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
- package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -1
- package/dist/runtime/herdr/HerdrAgentDiscovery.js +2 -43
- package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -1
- package/dist/runtime/tmux/PidPolling.d.ts +1 -1
- package/dist/runtime/tmux/PidPolling.d.ts.map +1 -1
- package/dist/runtime/tmux/PidPolling.js.map +1 -1
- package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +1 -1
- package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -1
- package/dist/runtime/tmux/TmuxAgentRuntime.js +1 -1
- package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -1
- package/dist/runtime/tmux/TmuxManager.d.ts +12 -0
- package/dist/runtime/tmux/TmuxManager.d.ts.map +1 -0
- package/dist/{terminal → runtime/tmux}/TmuxManager.js +9 -28
- package/dist/runtime/tmux/TmuxManager.js.map +1 -0
- package/dist/runtime/types.d.ts +1 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/terminal/TerminalFocusManager.d.ts +4 -32
- package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
- package/dist/terminal/TerminalFocusManager.js +17 -267
- package/dist/terminal/TerminalFocusManager.js.map +1 -1
- package/dist/terminal/TtyWriter.d.ts +1 -44
- package/dist/terminal/TtyWriter.d.ts.map +1 -1
- package/dist/terminal/TtyWriter.js +12 -347
- package/dist/terminal/TtyWriter.js.map +1 -1
- package/dist/terminal/backends/ghostty.d.ts +3 -0
- package/dist/terminal/backends/ghostty.d.ts.map +1 -0
- package/dist/terminal/backends/ghostty.js +161 -0
- package/dist/terminal/backends/ghostty.js.map +1 -0
- package/dist/terminal/backends/index.d.ts +5 -0
- package/dist/terminal/backends/index.d.ts.map +1 -0
- package/dist/terminal/backends/index.js +21 -0
- package/dist/terminal/backends/index.js.map +1 -0
- package/dist/terminal/backends/iterm2.d.ts +3 -0
- package/dist/terminal/backends/iterm2.d.ts.map +1 -0
- package/dist/terminal/backends/iterm2.js +135 -0
- package/dist/terminal/backends/iterm2.js.map +1 -0
- package/dist/terminal/backends/shared.d.ts +9 -0
- package/dist/terminal/backends/shared.d.ts.map +1 -0
- package/dist/terminal/backends/shared.js +38 -0
- package/dist/terminal/backends/shared.js.map +1 -0
- package/dist/terminal/backends/terminal-app.d.ts +3 -0
- package/dist/terminal/backends/terminal-app.d.ts.map +1 -0
- package/dist/terminal/backends/terminal-app.js +129 -0
- package/dist/terminal/backends/terminal-app.js.map +1 -0
- package/dist/terminal/backends/tmux.d.ts +3 -0
- package/dist/terminal/backends/tmux.d.ts.map +1 -0
- package/dist/terminal/backends/tmux.js +76 -0
- package/dist/terminal/backends/tmux.js.map +1 -0
- package/dist/terminal/backends/wezterm.d.ts +3 -0
- package/dist/terminal/backends/wezterm.d.ts.map +1 -0
- package/dist/terminal/backends/wezterm.js +71 -0
- package/dist/terminal/backends/wezterm.js.map +1 -0
- package/dist/terminal/types.d.ts +22 -0
- package/dist/terminal/types.d.ts.map +1 -0
- package/dist/terminal/types.js +11 -0
- package/dist/terminal/types.js.map +1 -0
- package/dist/utils/process.d.ts +2 -0
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +3 -0
- package/dist/utils/process.js.map +1 -1
- package/package.json +1 -1
- package/src/AgentManager.ts +1 -1
- package/src/__tests__/capacity/anthropic.test.ts +105 -0
- package/src/__tests__/capacity/boundaries.test.ts +36 -0
- package/src/__tests__/capacity/claude.test.ts +3 -8
- package/src/__tests__/capacity/codex.test.ts +12 -35
- package/src/__tests__/capacity/fixtures/openai-codex-auth.json +1 -1
- package/src/__tests__/capacity/openai.test.ts +15 -15
- package/src/__tests__/capacity/wham.test.ts +1 -1
- package/src/__tests__/capacity/zai.test.ts +27 -62
- package/src/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.ts +2 -2
- package/src/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.ts +1 -1
- package/src/__tests__/harnesses/codex/durable/CodexCliProbe.test.ts +14 -19
- package/src/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.ts +3 -3
- package/src/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.ts +24 -30
- package/src/__tests__/harnesses/codex/durable/CodexPrintRunner.test.ts +4 -8
- package/src/__tests__/harnesses/devin/DevinAdapter.test.ts +292 -0
- package/src/__tests__/harnesses/devin/DevinAgentMapper.test.ts +88 -0
- package/src/__tests__/harnesses/devin/DevinSessionLocator.test.ts +139 -0
- package/src/__tests__/harnesses/devin/DevinSessionParser.test.ts +218 -0
- package/src/__tests__/harnesses/devin/fixtures.ts +144 -0
- package/src/__tests__/harnesses/pi/durable/PiCliProbe.test.ts +7 -11
- package/src/__tests__/harnesses/pi/durable/PiPrintAgentService.test.ts +19 -22
- package/src/__tests__/harnesses/pi/durable/PiPrintRunner.test.ts +7 -8
- package/src/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.ts +77 -9
- package/src/__tests__/harnesses/runtimeProfiles.test.ts +110 -0
- package/src/__tests__/print/DurableAgent.test.ts +4 -13
- package/src/__tests__/print/DurableAgentRepository.test.ts +1 -13
- package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +1 -1
- package/src/__tests__/terminal/GhosttyBackend.test.ts +271 -0
- package/src/__tests__/terminal/TmuxManager.test.ts +1 -1
- package/src/adapters/AgentAdapter.ts +1 -0
- package/src/capacity/index.ts +29 -23
- package/src/capacity/{claude.ts → providers/anthropic.ts} +16 -131
- package/src/capacity/providers/openai-platform.ts +150 -0
- package/src/capacity/{wham.ts → providers/openai-subscription.ts} +86 -8
- package/src/capacity/{zai.ts → providers/zai.ts} +29 -111
- package/src/capacity/sources/claude.ts +30 -0
- package/src/capacity/{codex.ts → sources/codex.ts} +54 -124
- package/src/capacity/sources/pi.ts +131 -0
- package/src/capacity/types.ts +3 -0
- package/src/harnesses/claude/credentials.ts +122 -0
- package/src/harnesses/claude/readiness.ts +69 -0
- package/src/harnesses/codex/credentials.ts +81 -0
- package/src/harnesses/codex/readiness.ts +72 -0
- package/src/harnesses/copilot/readiness.ts +33 -0
- package/src/harnesses/devin/DevinAdapter.ts +224 -0
- package/src/harnesses/devin/DevinAgentMapper.ts +43 -0
- package/src/harnesses/devin/DevinSessionLocator.ts +230 -0
- package/src/harnesses/devin/DevinSessionParser.ts +236 -0
- package/src/harnesses/devin/readiness.ts +36 -0
- package/src/harnesses/index.ts +2 -0
- package/src/harnesses/opencode/readiness.ts +48 -0
- package/src/harnesses/pi/credentials.ts +129 -0
- package/src/harnesses/pi/readiness.ts +104 -0
- package/src/harnesses/readiness/AgentReadiness.ts +89 -0
- package/src/harnesses/readiness/checks.ts +336 -0
- package/src/harnesses/readiness/types.ts +90 -0
- package/src/{utils/agents.ts → harnesses/runtimeProfiles.ts} +35 -38
- package/src/index.ts +15 -128
- package/src/runtime/ManagedAgentRuntime.ts +7 -22
- package/src/runtime/herdr/HerdrAgentDiscovery.ts +3 -19
- package/src/runtime/tmux/PidPolling.ts +1 -1
- package/src/runtime/tmux/TmuxAgentRuntime.ts +1 -1
- package/src/{terminal → runtime/tmux}/TmuxManager.ts +9 -30
- package/src/runtime/types.ts +1 -1
- package/src/terminal/TerminalFocusManager.ts +19 -292
- package/src/terminal/TtyWriter.ts +15 -335
- package/src/terminal/backends/ghostty.ts +180 -0
- package/src/terminal/backends/index.ts +23 -0
- package/src/terminal/backends/iterm2.ts +126 -0
- package/src/terminal/backends/shared.ts +47 -0
- package/src/terminal/backends/terminal-app.ts +122 -0
- package/src/terminal/backends/tmux.ts +62 -0
- package/src/terminal/backends/wezterm.ts +65 -0
- package/src/terminal/types.ts +23 -0
- package/src/utils/process.ts +5 -0
- package/dist/__tests__/readiness/AgentReadiness.test.js.map +0 -1
- package/dist/__tests__/utils/agents.test.js +0 -93
- package/dist/__tests__/utils/agents.test.js.map +0 -1
- package/dist/capacity/claude.d.ts +0 -17
- package/dist/capacity/claude.d.ts.map +0 -1
- package/dist/capacity/claude.js.map +0 -1
- package/dist/capacity/codex.d.ts.map +0 -1
- package/dist/capacity/codex.js.map +0 -1
- package/dist/capacity/openai.d.ts +0 -47
- package/dist/capacity/openai.d.ts.map +0 -1
- package/dist/capacity/openai.js +0 -307
- package/dist/capacity/openai.js.map +0 -1
- package/dist/capacity/wham.d.ts +0 -16
- package/dist/capacity/wham.d.ts.map +0 -1
- package/dist/capacity/wham.js +0 -66
- package/dist/capacity/wham.js.map +0 -1
- package/dist/capacity/zai.d.ts +0 -14
- package/dist/capacity/zai.d.ts.map +0 -1
- package/dist/capacity/zai.js.map +0 -1
- package/dist/readiness/AgentReadiness.d.ts.map +0 -1
- package/dist/readiness/AgentReadiness.js +0 -614
- package/dist/readiness/AgentReadiness.js.map +0 -1
- package/dist/terminal/TmuxManager.d.ts +0 -28
- package/dist/terminal/TmuxManager.d.ts.map +0 -1
- package/dist/terminal/TmuxManager.js.map +0 -1
- package/dist/terminal/index.d.ts +0 -5
- package/dist/terminal/index.d.ts.map +0 -1
- package/dist/terminal/index.js +0 -5
- package/dist/terminal/index.js.map +0 -1
- package/dist/utils/agents.d.ts +0 -16
- package/dist/utils/agents.d.ts.map +0 -1
- package/dist/utils/agents.js +0 -117
- package/dist/utils/agents.js.map +0 -1
- package/dist/utils/index.d.ts +0 -8
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -6
- package/dist/utils/index.js.map +0 -1
- package/src/__tests__/utils/agents.test.ts +0 -105
- package/src/capacity/openai.ts +0 -355
- package/src/readiness/AgentReadiness.ts +0 -730
- package/src/terminal/index.ts +0 -4
- package/src/utils/index.ts +0 -14
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { execFile } from "child_process";
|
|
2
|
-
import { promisify } from "util";
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
3
|
const execFileAsync = promisify(execFile);
|
|
4
4
|
export class TmuxManager {
|
|
5
5
|
async isAvailable() {
|
|
@@ -54,22 +54,7 @@ export class TmuxManager {
|
|
|
54
54
|
// Already gone — ignore
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
|
|
58
|
-
* Find the actual agent process PID inside a tmux pane.
|
|
59
|
-
*
|
|
60
|
-
* Strategy: BFS the process tree, return the deepest process whose
|
|
61
|
-
* `ps` command line is accepted by `matches`. The caller supplies the
|
|
62
|
-
* matcher so this method has no agent-type knowledge.
|
|
63
|
-
*
|
|
64
|
-
* This handles two real-world process shapes:
|
|
65
|
-
* - Wrapper case: shell → claude-wrapper (matches) → claude (matches, deeper)
|
|
66
|
-
* → returns the deeper one
|
|
67
|
-
* - Subprocess case: shell → claude (matches) → MCP server child (doesn't match)
|
|
68
|
-
* → returns claude, not the subprocess
|
|
69
|
-
*
|
|
70
|
-
* Returns null when no process matches yet (agent still starting); the
|
|
71
|
-
* caller's poll loop retries.
|
|
72
|
-
*/ async findAgentPid(session, matches) {
|
|
57
|
+
async findAgentPid(session, matches) {
|
|
73
58
|
const panePid = await this.getPanePid(session);
|
|
74
59
|
if (panePid === null) return null;
|
|
75
60
|
const visited = new Set();
|
|
@@ -82,11 +67,8 @@ export class TmuxManager {
|
|
|
82
67
|
if (visited.has(pid)) continue;
|
|
83
68
|
visited.add(pid);
|
|
84
69
|
const command = await this.getProcessCommand(pid);
|
|
85
|
-
if (command && matches(command))
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
const children = await this.pgrepChildren(pid);
|
|
89
|
-
queue.push(...children);
|
|
70
|
+
if (command && matches(command)) deepestMatch = pid;
|
|
71
|
+
queue.push(...await this.pgrepChildren(pid));
|
|
90
72
|
}
|
|
91
73
|
return deepestMatch;
|
|
92
74
|
}
|
|
@@ -99,8 +81,8 @@ export class TmuxManager {
|
|
|
99
81
|
"-F",
|
|
100
82
|
"#{pane_pid}"
|
|
101
83
|
]);
|
|
102
|
-
const panePid = parseInt(stdout.trim().split("\n")[0], 10);
|
|
103
|
-
return isNaN(panePid) ? null : panePid;
|
|
84
|
+
const panePid = Number.parseInt(stdout.trim().split("\n")[0], 10);
|
|
85
|
+
return Number.isNaN(panePid) ? null : panePid;
|
|
104
86
|
} catch {
|
|
105
87
|
return null;
|
|
106
88
|
}
|
|
@@ -111,7 +93,7 @@ export class TmuxManager {
|
|
|
111
93
|
"-P",
|
|
112
94
|
String(pid)
|
|
113
95
|
]);
|
|
114
|
-
return stdout.trim().split("\n").map((
|
|
96
|
+
return stdout.trim().split("\n").map((value)=>Number.parseInt(value, 10)).filter((value)=>!Number.isNaN(value));
|
|
115
97
|
} catch {
|
|
116
98
|
return [];
|
|
117
99
|
}
|
|
@@ -124,8 +106,7 @@ export class TmuxManager {
|
|
|
124
106
|
"-o",
|
|
125
107
|
"command="
|
|
126
108
|
]);
|
|
127
|
-
|
|
128
|
-
return trimmed || null;
|
|
109
|
+
return stdout.trim() || null;
|
|
129
110
|
} catch {
|
|
130
111
|
return null;
|
|
131
112
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/tmux/TmuxManager.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nexport class TmuxManager {\n async isAvailable(): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"-V\"]);\n return true;\n } catch {\n return false;\n }\n }\n\n async sessionExists(name: string): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"has-session\", \"-t\", name]);\n return true;\n } catch {\n return false;\n }\n }\n\n async createSession(name: string, cwd: string): Promise<void> {\n await execFileAsync(\"tmux\", [\"new-session\", \"-d\", \"-s\", name, \"-c\", cwd]);\n }\n\n async sendKeys(session: string, keys: string): Promise<void> {\n await execFileAsync(\"tmux\", [\"send-keys\", \"-t\", session, keys, \"Enter\"]);\n }\n\n async killSession(name: string): Promise<void> {\n try {\n await execFileAsync(\"tmux\", [\"kill-session\", \"-t\", name]);\n } catch {\n // Already gone — ignore\n }\n }\n\n async findAgentPid(\n session: string,\n matches: (psCommand: string) => boolean,\n ): Promise<number | null> {\n const panePid = await this.getPanePid(session);\n if (panePid === null) return null;\n\n const visited = new Set<number>();\n const queue: number[] = [panePid];\n let deepestMatch: number | null = null;\n\n while (queue.length > 0) {\n const pid = queue.shift()!;\n if (visited.has(pid)) continue;\n visited.add(pid);\n\n const command = await this.getProcessCommand(pid);\n if (command && matches(command)) deepestMatch = pid;\n queue.push(...(await this.pgrepChildren(pid)));\n }\n\n return deepestMatch;\n }\n\n private async getPanePid(session: string): Promise<number | null> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\n \"list-panes\",\n \"-t\",\n session,\n \"-F\",\n \"#{pane_pid}\",\n ]);\n const panePid = Number.parseInt(stdout.trim().split(\"\\n\")[0], 10);\n return Number.isNaN(panePid) ? null : panePid;\n } catch {\n return null;\n }\n }\n\n private async pgrepChildren(pid: number): Promise<number[]> {\n try {\n const { stdout } = await execFileAsync(\"pgrep\", [\"-P\", String(pid)]);\n return stdout\n .trim()\n .split(\"\\n\")\n .map((value) => Number.parseInt(value, 10))\n .filter((value) => !Number.isNaN(value));\n } catch {\n return [];\n }\n }\n\n private async getProcessCommand(pid: number): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"ps\", [\"-p\", String(pid), \"-o\", \"command=\"]);\n return stdout.trim() || null;\n } catch {\n return null;\n }\n }\n}\n"],"names":["execFile","promisify","execFileAsync","TmuxManager","isAvailable","sessionExists","name","createSession","cwd","sendKeys","session","keys","killSession","findAgentPid","matches","panePid","getPanePid","visited","Set","queue","deepestMatch","length","pid","shift","has","add","command","getProcessCommand","push","pgrepChildren","stdout","Number","parseInt","trim","split","isNaN","String","map","value","filter"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,qBAAqB;AAC9C,SAASC,SAAS,QAAQ,YAAY;AAEtC,MAAMC,gBAAgBD,UAAUD;AAEhC,OAAO,MAAMG;IACX,MAAMC,cAAgC;QACpC,IAAI;YACF,MAAMF,cAAc,QAAQ;gBAAC;aAAK;YAClC,OAAO;QACT,EAAE,OAAM;YACN,OAAO;QACT;IACF;IAEA,MAAMG,cAAcC,IAAY,EAAoB;QAClD,IAAI;YACF,MAAMJ,cAAc,QAAQ;gBAAC;gBAAe;gBAAMI;aAAK;YACvD,OAAO;QACT,EAAE,OAAM;YACN,OAAO;QACT;IACF;IAEA,MAAMC,cAAcD,IAAY,EAAEE,GAAW,EAAiB;QAC5D,MAAMN,cAAc,QAAQ;YAAC;YAAe;YAAM;YAAMI;YAAM;YAAME;SAAI;IAC1E;IAEA,MAAMC,SAASC,OAAe,EAAEC,IAAY,EAAiB;QAC3D,MAAMT,cAAc,QAAQ;YAAC;YAAa;YAAMQ;YAASC;YAAM;SAAQ;IACzE;IAEA,MAAMC,YAAYN,IAAY,EAAiB;QAC7C,IAAI;YACF,MAAMJ,cAAc,QAAQ;gBAAC;gBAAgB;gBAAMI;aAAK;QAC1D,EAAE,OAAM;QACN,wBAAwB;QAC1B;IACF;IAEA,MAAMO,aACJH,OAAe,EACfI,OAAuC,EACf;QACxB,MAAMC,UAAU,MAAM,IAAI,CAACC,UAAU,CAACN;QACtC,IAAIK,YAAY,MAAM,OAAO;QAE7B,MAAME,UAAU,IAAIC;QACpB,MAAMC,QAAkB;YAACJ;SAAQ;QACjC,IAAIK,eAA8B;QAElC,MAAOD,MAAME,MAAM,GAAG,EAAG;YACvB,MAAMC,MAAMH,MAAMI,KAAK;YACvB,IAAIN,QAAQO,GAAG,CAACF,MAAM;YACtBL,QAAQQ,GAAG,CAACH;YAEZ,MAAMI,UAAU,MAAM,IAAI,CAACC,iBAAiB,CAACL;YAC7C,IAAII,WAAWZ,QAAQY,UAAUN,eAAeE;YAChDH,MAAMS,IAAI,IAAK,MAAM,IAAI,CAACC,aAAa,CAACP;QAC1C;QAEA,OAAOF;IACT;IAEA,MAAcJ,WAAWN,OAAe,EAA0B;QAChE,IAAI;YACF,MAAM,EAAEoB,MAAM,EAAE,GAAG,MAAM5B,cAAc,QAAQ;gBAC7C;gBACA;gBACAQ;gBACA;gBACA;aACD;YACD,MAAMK,UAAUgB,OAAOC,QAAQ,CAACF,OAAOG,IAAI,GAAGC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE;YAC9D,OAAOH,OAAOI,KAAK,CAACpB,WAAW,OAAOA;QACxC,EAAE,OAAM;YACN,OAAO;QACT;IACF;IAEA,MAAcc,cAAcP,GAAW,EAAqB;QAC1D,IAAI;YACF,MAAM,EAAEQ,MAAM,EAAE,GAAG,MAAM5B,cAAc,SAAS;gBAAC;gBAAMkC,OAAOd;aAAK;YACnE,OAAOQ,OACJG,IAAI,GACJC,KAAK,CAAC,MACNG,GAAG,CAAC,CAACC,QAAUP,OAAOC,QAAQ,CAACM,OAAO,KACtCC,MAAM,CAAC,CAACD,QAAU,CAACP,OAAOI,KAAK,CAACG;QACrC,EAAE,OAAM;YACN,OAAO,EAAE;QACX;IACF;IAEA,MAAcX,kBAAkBL,GAAW,EAA0B;QACnE,IAAI;YACF,MAAM,EAAEQ,MAAM,EAAE,GAAG,MAAM5B,cAAc,MAAM;gBAAC;gBAAMkC,OAAOd;gBAAM;gBAAM;aAAW;YAClF,OAAOQ,OAAOG,IAAI,MAAM;QAC1B,EAAE,OAAM;YACN,OAAO;QACT;IACF;AACF"}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentInfo } from "../adapters/AgentAdapter.js";
|
|
2
|
-
import type { TerminalLocation } from "../terminal/
|
|
2
|
+
import type { TerminalLocation } from "../terminal/types.js";
|
|
3
3
|
import type { AgentRuntimeProvider } from "../utils/AgentRegistry.js";
|
|
4
4
|
export type AgentRuntimeAvailability = {
|
|
5
5
|
ok: true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,MAAM,MAAM,wBAAwB,GAChC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,gBAAgB,GAAG,qBAAqB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;IACvC,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,YAAY,EAAE;QACZ,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;QAC5D,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KAC7D,CAAC;CACH;AAED,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC;CAC7D;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE;QACZ,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;KAC7D,CAAC;IACF,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,WAAW,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACjD,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClE,IAAI,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,KAAK,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/types.ts"],"sourcesContent":["import type { AgentInfo } from \"../adapters/AgentAdapter.js\";\nimport type { TerminalLocation } from \"../terminal/
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/types.ts"],"sourcesContent":["import type { AgentInfo } from \"../adapters/AgentAdapter.js\";\nimport type { TerminalLocation } from \"../terminal/types.js\";\nimport type { AgentRuntimeProvider } from \"../utils/AgentRegistry.js\";\n\nexport type AgentRuntimeAvailability =\n | { ok: true; insideRuntime: boolean; currentPaneId?: string }\n | { ok: false; reason: \"binary-missing\" | \"backend-unreachable\"; detail: string };\n\nexport interface RuntimeStartInput {\n name: string;\n cwd: string;\n kind: string;\n args: string[];\n timeoutMs: number;\n}\n\nexport interface RuntimeStartResult {\n pid: number;\n runtimeRef: unknown;\n}\n\nexport interface RuntimeTargetInput {\n agent: Pick<AgentInfo, \"name\" | \"pid\">;\n runtimeRef: unknown | null;\n}\n\nexport interface RuntimeSendInput extends RuntimeTargetInput {\n prompt: string;\n}\n\nexport interface RuntimeFocusInput extends RuntimeTargetInput {\n focusManager: {\n findTerminal(pid: number): Promise<TerminalLocation | null>;\n focusTerminal(location: TerminalLocation): Promise<boolean>;\n };\n}\n\nexport interface RuntimeStopInput extends RuntimeTargetInput {\n killProcess?: (pid: number, signal: NodeJS.Signals) => void;\n}\n\nexport interface RuntimeSendDeps {\n focusManager: {\n findTerminal(pid: number): Promise<TerminalLocation | null>;\n };\n writer?: (location: TerminalLocation, text: string) => Promise<void>;\n}\n\nexport interface InteractiveAgentRuntime {\n provider: AgentRuntimeProvider;\n isAvailable(): Promise<AgentRuntimeAvailability>;\n startAgent(input: RuntimeStartInput): Promise<RuntimeStartResult>;\n send(input: RuntimeSendInput, deps?: RuntimeSendDeps): Promise<void>;\n focus(input: RuntimeFocusInput): Promise<boolean>;\n stop(input: RuntimeStopInput): Promise<void>;\n}\n"],"names":[],"mappings":"AAgDA,WAOC"}
|
|
@@ -1,40 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
TERMINAL_APP = "terminal-app",
|
|
6
|
-
UNKNOWN = "unknown"
|
|
7
|
-
}
|
|
8
|
-
export interface TerminalLocation {
|
|
9
|
-
type: TerminalType;
|
|
10
|
-
identifier: string;
|
|
11
|
-
tty: string;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Optional trace sink. When provided to {@link TerminalFocusManager}, each
|
|
15
|
-
* discovery/focus step reports a human-readable line so callers (e.g. the
|
|
16
|
-
* `agent open --debug` command) can inspect the matching/focus decision path.
|
|
17
|
-
*/
|
|
1
|
+
import { TerminalType, type TerminalLocation } from "./types.js";
|
|
2
|
+
export { TerminalType };
|
|
3
|
+
export type { TerminalLocation };
|
|
4
|
+
/** Optional trace sink for terminal discovery and focus decisions. */
|
|
18
5
|
export type TerminalDebugLogger = (message: string) => void;
|
|
19
6
|
export declare class TerminalFocusManager {
|
|
20
7
|
private readonly debug?;
|
|
21
8
|
constructor(debug?: TerminalDebugLogger | undefined);
|
|
22
|
-
/**
|
|
23
|
-
* Find the terminal location (emulator info) for a given process ID
|
|
24
|
-
*/
|
|
25
9
|
findTerminal(pid: number): Promise<TerminalLocation | null>;
|
|
26
|
-
/**
|
|
27
|
-
* Focus the terminal identified by the location
|
|
28
|
-
*/
|
|
29
10
|
focusTerminal(location: TerminalLocation): Promise<boolean>;
|
|
30
|
-
private findWeztermPane;
|
|
31
|
-
private focusWeztermPane;
|
|
32
|
-
private findTmuxPane;
|
|
33
|
-
private findITerm2Session;
|
|
34
|
-
private findTerminalAppWindow;
|
|
35
|
-
private isProcessRunning;
|
|
36
|
-
private focusTmuxPane;
|
|
37
|
-
private focusITerm2Session;
|
|
38
|
-
private focusTerminalAppWindow;
|
|
39
11
|
}
|
|
40
12
|
//# sourceMappingURL=TerminalFocusManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TerminalFocusManager.d.ts","sourceRoot":"","sources":["../../src/terminal/TerminalFocusManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TerminalFocusManager.d.ts","sourceRoot":"","sources":["../../src/terminal/TerminalFocusManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC,sEAAsE;AACtE,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAE5D,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAN,KAAK,CAAC,EAAE,mBAAmB,YAAA;IAElD,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAuB3D,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CAelE"}
|
|
@@ -1,296 +1,46 @@
|
|
|
1
|
-
import { execFile } from "child_process";
|
|
2
|
-
import { promisify } from "util";
|
|
3
1
|
import { getProcessTty } from "../utils/process.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
TerminalType["TMUX"] = "tmux";
|
|
8
|
-
TerminalType["WEZTERM"] = "wezterm";
|
|
9
|
-
TerminalType["ITERM2"] = "iterm2";
|
|
10
|
-
TerminalType["TERMINAL_APP"] = "terminal-app";
|
|
11
|
-
TerminalType["UNKNOWN"] = "unknown";
|
|
12
|
-
return TerminalType;
|
|
13
|
-
}({});
|
|
2
|
+
import { TERMINAL_BACKENDS, terminalBackendFor } from "./backends/index.js";
|
|
3
|
+
import { TerminalType } from "./types.js";
|
|
4
|
+
export { TerminalType };
|
|
14
5
|
export class TerminalFocusManager {
|
|
15
6
|
debug;
|
|
16
7
|
constructor(debug){
|
|
17
8
|
this.debug = debug;
|
|
18
9
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const ttyShort = getProcessTty(pid);
|
|
23
|
-
// If no TTY or invalid, we can't find the terminal
|
|
24
|
-
if (!ttyShort || ttyShort === "?") {
|
|
10
|
+
async findTerminal(pid) {
|
|
11
|
+
const tty = getProcessTty(pid);
|
|
12
|
+
if (!tty || tty === "?") {
|
|
25
13
|
this.debug?.(`findTerminal(pid=${pid}): no usable TTY, cannot resolve terminal`);
|
|
26
14
|
return null;
|
|
27
15
|
}
|
|
28
|
-
const fullTty = `/dev/${
|
|
16
|
+
const fullTty = `/dev/${tty}`;
|
|
29
17
|
this.debug?.(`findTerminal(pid=${pid}): resolving terminal for ${fullTty}`);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// 2. Check WezTerm (cross-platform, via its CLI — no AppleScript)
|
|
38
|
-
const weztermLocation = await this.findWeztermPane(fullTty);
|
|
39
|
-
if (weztermLocation) {
|
|
40
|
-
this.debug?.(`findTerminal: matched wezterm (pane_id=${weztermLocation.identifier})`);
|
|
41
|
-
return weztermLocation;
|
|
42
|
-
}
|
|
43
|
-
this.debug?.("findTerminal: wezterm no match");
|
|
44
|
-
// 3. Check iTerm2
|
|
45
|
-
const itermLocation = await this.findITerm2Session(fullTty);
|
|
46
|
-
if (itermLocation) {
|
|
47
|
-
this.debug?.(`findTerminal: matched iTerm2 (tty=${itermLocation.tty})`);
|
|
48
|
-
return itermLocation;
|
|
49
|
-
}
|
|
50
|
-
this.debug?.("findTerminal: iTerm2 no match");
|
|
51
|
-
// 4. Check Terminal.app
|
|
52
|
-
const terminalAppLocation = await this.findTerminalAppWindow(fullTty);
|
|
53
|
-
if (terminalAppLocation) {
|
|
54
|
-
this.debug?.(`findTerminal: matched Terminal.app (tty=${terminalAppLocation.tty})`);
|
|
55
|
-
return terminalAppLocation;
|
|
18
|
+
for (const backend of TERMINAL_BACKENDS){
|
|
19
|
+
const location = await backend.find(fullTty);
|
|
20
|
+
if (location) {
|
|
21
|
+
this.debug?.(`findTerminal: matched ${backend.label} (identifier=${location.identifier})`);
|
|
22
|
+
return location;
|
|
23
|
+
}
|
|
24
|
+
this.debug?.(`findTerminal: ${backend.label} no match`);
|
|
56
25
|
}
|
|
57
|
-
this.debug?.("findTerminal: Terminal.app no match");
|
|
58
|
-
// 5. Fallback: we know the TTY but not the emulator wrapper
|
|
59
26
|
this.debug?.("findTerminal: no emulator matched; returning UNKNOWN");
|
|
60
27
|
return {
|
|
61
|
-
type:
|
|
28
|
+
type: TerminalType.UNKNOWN,
|
|
62
29
|
identifier: "",
|
|
63
30
|
tty: fullTty
|
|
64
31
|
};
|
|
65
32
|
}
|
|
66
|
-
|
|
67
|
-
* Focus the terminal identified by the location
|
|
68
|
-
*/ async focusTerminal(location) {
|
|
33
|
+
async focusTerminal(location) {
|
|
69
34
|
this.debug?.(`focusTerminal: focusing ${location.type} (identifier=${location.identifier}, tty=${location.tty})`);
|
|
70
35
|
let success = false;
|
|
71
36
|
try {
|
|
72
|
-
|
|
73
|
-
case "tmux":
|
|
74
|
-
success = await this.focusTmuxPane(location.identifier);
|
|
75
|
-
break;
|
|
76
|
-
case "wezterm":
|
|
77
|
-
success = await this.focusWeztermPane(location.identifier);
|
|
78
|
-
break;
|
|
79
|
-
case "iterm2":
|
|
80
|
-
success = await this.focusITerm2Session(location.tty);
|
|
81
|
-
break;
|
|
82
|
-
case "terminal-app":
|
|
83
|
-
success = await this.focusTerminalAppWindow(location.tty);
|
|
84
|
-
break;
|
|
85
|
-
default:
|
|
86
|
-
success = false;
|
|
87
|
-
}
|
|
37
|
+
success = await terminalBackendFor(location.type)?.focus(location) ?? false;
|
|
88
38
|
} catch {
|
|
89
39
|
success = false;
|
|
90
40
|
}
|
|
91
41
|
this.debug?.(`focusTerminal: ${success ? "succeeded" : "failed"} for ${location.type}`);
|
|
92
42
|
return success;
|
|
93
43
|
}
|
|
94
|
-
async findWeztermPane(tty) {
|
|
95
|
-
try {
|
|
96
|
-
const { stdout } = await execFileAsync("wezterm", [
|
|
97
|
-
"cli",
|
|
98
|
-
"list",
|
|
99
|
-
"--format",
|
|
100
|
-
"json"
|
|
101
|
-
]);
|
|
102
|
-
const panes = JSON.parse(stdout);
|
|
103
|
-
if (!Array.isArray(panes)) return null;
|
|
104
|
-
for (const pane of panes){
|
|
105
|
-
if (pane && typeof pane.tty_name === "string" && pane.tty_name === tty && pane.pane_id != null) {
|
|
106
|
-
return {
|
|
107
|
-
type: "wezterm",
|
|
108
|
-
identifier: String(pane.pane_id),
|
|
109
|
-
tty
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
} catch {
|
|
114
|
-
// wezterm not installed, not running, or returned invalid JSON
|
|
115
|
-
}
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
async focusWeztermPane(paneId) {
|
|
119
|
-
try {
|
|
120
|
-
await execFileAsync("wezterm", [
|
|
121
|
-
"cli",
|
|
122
|
-
"activate-pane",
|
|
123
|
-
"--pane-id",
|
|
124
|
-
paneId
|
|
125
|
-
]);
|
|
126
|
-
return true;
|
|
127
|
-
} catch {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
async findTmuxPane(tty) {
|
|
132
|
-
try {
|
|
133
|
-
const { stdout } = await execFileAsync("tmux", [
|
|
134
|
-
"list-panes",
|
|
135
|
-
"-a",
|
|
136
|
-
"-F",
|
|
137
|
-
"#{pane_tty}|#{session_name}:#{window_index}.#{pane_index}"
|
|
138
|
-
]);
|
|
139
|
-
const lines = stdout.trim().split("\n");
|
|
140
|
-
for (const line of lines){
|
|
141
|
-
if (!line.trim()) continue;
|
|
142
|
-
const [paneTty, identifier] = line.split("|");
|
|
143
|
-
if (paneTty === tty && identifier) {
|
|
144
|
-
return {
|
|
145
|
-
type: "tmux",
|
|
146
|
-
identifier,
|
|
147
|
-
tty
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
} catch {
|
|
152
|
-
// tmux might not be installed or running
|
|
153
|
-
}
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
async findITerm2Session(tty) {
|
|
157
|
-
try {
|
|
158
|
-
// Check if iTerm2 is running first to avoid launching it.
|
|
159
|
-
if (!await this.isProcessRunning("iTerm2")) return null;
|
|
160
|
-
} catch {
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
try {
|
|
164
|
-
const escapedTty = escapeAppleScript(tty);
|
|
165
|
-
const script = `
|
|
166
|
-
tell application "iTerm"
|
|
167
|
-
repeat with w in windows
|
|
168
|
-
repeat with t in tabs of w
|
|
169
|
-
repeat with s in sessions of t
|
|
170
|
-
if tty of s is "${escapedTty}" then
|
|
171
|
-
return "found"
|
|
172
|
-
end if
|
|
173
|
-
end repeat
|
|
174
|
-
end repeat
|
|
175
|
-
end repeat
|
|
176
|
-
end tell
|
|
177
|
-
`;
|
|
178
|
-
const { stdout } = await execFileAsync("osascript", [
|
|
179
|
-
"-e",
|
|
180
|
-
script
|
|
181
|
-
]);
|
|
182
|
-
if (stdout.trim() === "found") {
|
|
183
|
-
return {
|
|
184
|
-
type: "iterm2",
|
|
185
|
-
identifier: tty,
|
|
186
|
-
tty
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
} catch {
|
|
190
|
-
// iTerm2 script failed
|
|
191
|
-
}
|
|
192
|
-
return null;
|
|
193
|
-
}
|
|
194
|
-
async findTerminalAppWindow(tty) {
|
|
195
|
-
try {
|
|
196
|
-
// Check if Terminal.app is running
|
|
197
|
-
if (!await this.isProcessRunning("Terminal")) return null;
|
|
198
|
-
} catch {
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
try {
|
|
202
|
-
const escapedTty = escapeAppleScript(tty);
|
|
203
|
-
const script = `
|
|
204
|
-
tell application "Terminal"
|
|
205
|
-
repeat with w in windows
|
|
206
|
-
repeat with t in tabs of w
|
|
207
|
-
if tty of t is "${escapedTty}" then
|
|
208
|
-
return "found"
|
|
209
|
-
end if
|
|
210
|
-
end repeat
|
|
211
|
-
end repeat
|
|
212
|
-
end tell
|
|
213
|
-
`;
|
|
214
|
-
const { stdout } = await execFileAsync("osascript", [
|
|
215
|
-
"-e",
|
|
216
|
-
script
|
|
217
|
-
]);
|
|
218
|
-
if (stdout.trim() === "found") {
|
|
219
|
-
return {
|
|
220
|
-
type: "terminal-app",
|
|
221
|
-
identifier: tty,
|
|
222
|
-
tty
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
} catch {
|
|
226
|
-
// Terminal.app script failed
|
|
227
|
-
}
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
async isProcessRunning(name) {
|
|
231
|
-
const { stdout } = await execFileAsync("ps", [
|
|
232
|
-
"-Axo",
|
|
233
|
-
"comm"
|
|
234
|
-
]);
|
|
235
|
-
return stdout.split("\n").map((line)=>line.trim()).some((command)=>command === name || command.endsWith(`/${name}`));
|
|
236
|
-
}
|
|
237
|
-
async focusTmuxPane(identifier) {
|
|
238
|
-
try {
|
|
239
|
-
await execFileAsync("tmux", [
|
|
240
|
-
"switch-client",
|
|
241
|
-
"-t",
|
|
242
|
-
identifier
|
|
243
|
-
]);
|
|
244
|
-
return true;
|
|
245
|
-
} catch {
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
async focusITerm2Session(tty) {
|
|
250
|
-
const escapedTty = escapeAppleScript(tty);
|
|
251
|
-
const script = `
|
|
252
|
-
tell application "iTerm"
|
|
253
|
-
activate
|
|
254
|
-
repeat with w in windows
|
|
255
|
-
repeat with t in tabs of w
|
|
256
|
-
repeat with s in sessions of t
|
|
257
|
-
if tty of s is "${escapedTty}" then
|
|
258
|
-
select s
|
|
259
|
-
return "true"
|
|
260
|
-
end if
|
|
261
|
-
end repeat
|
|
262
|
-
end repeat
|
|
263
|
-
end repeat
|
|
264
|
-
end tell
|
|
265
|
-
`;
|
|
266
|
-
const { stdout } = await execFileAsync("osascript", [
|
|
267
|
-
"-e",
|
|
268
|
-
script
|
|
269
|
-
]);
|
|
270
|
-
return stdout.trim() === "true";
|
|
271
|
-
}
|
|
272
|
-
async focusTerminalAppWindow(tty) {
|
|
273
|
-
const escapedTty = escapeAppleScript(tty);
|
|
274
|
-
const script = `
|
|
275
|
-
tell application "Terminal"
|
|
276
|
-
activate
|
|
277
|
-
repeat with w in windows
|
|
278
|
-
repeat with t in tabs of w
|
|
279
|
-
if tty of t is "${escapedTty}" then
|
|
280
|
-
set index of w to 1
|
|
281
|
-
set selected tab of w to t
|
|
282
|
-
return "true"
|
|
283
|
-
end if
|
|
284
|
-
end repeat
|
|
285
|
-
end repeat
|
|
286
|
-
end tell
|
|
287
|
-
`;
|
|
288
|
-
const { stdout } = await execFileAsync("osascript", [
|
|
289
|
-
"-e",
|
|
290
|
-
script
|
|
291
|
-
]);
|
|
292
|
-
return stdout.trim() === "true";
|
|
293
|
-
}
|
|
294
44
|
}
|
|
295
45
|
|
|
296
46
|
//# sourceMappingURL=TerminalFocusManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/terminal/TerminalFocusManager.ts"],"sourcesContent":["import { execFile } from \"child_process\";\nimport { promisify } from \"util\";\nimport { getProcessTty } from \"../utils/process.js\";\nimport { escapeAppleScript } from \"../utils/applescript.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport enum TerminalType {\n TMUX = \"tmux\",\n WEZTERM = \"wezterm\",\n ITERM2 = \"iterm2\",\n TERMINAL_APP = \"terminal-app\",\n UNKNOWN = \"unknown\",\n}\n\nexport interface TerminalLocation {\n type: TerminalType;\n identifier: string; // e.g., \"session:window.pane\" for tmux, WezTerm pane id, or TTY for others\n tty: string; // e.g., \"/dev/ttys030\"\n}\n\n/**\n * Subset of a `wezterm cli list --format json` entry. Only `pane_id` and\n * `tty_name` are read; extra fields are ignored so schema additions across\n * WezTerm versions don't break parsing. (The TTY is exposed as `tty_name` in\n * the JSON, not `tty`.)\n */\ninterface WeztermPaneEntry {\n pane_id?: number;\n tty_name?: string | null;\n}\n\n/**\n * Optional trace sink. When provided to {@link TerminalFocusManager}, each\n * discovery/focus step reports a human-readable line so callers (e.g. the\n * `agent open --debug` command) can inspect the matching/focus decision path.\n */\nexport type TerminalDebugLogger = (message: string) => void;\n\nexport class TerminalFocusManager {\n constructor(private readonly debug?: TerminalDebugLogger) {}\n\n /**\n * Find the terminal location (emulator info) for a given process ID\n */\n async findTerminal(pid: number): Promise<TerminalLocation | null> {\n const ttyShort = getProcessTty(pid);\n\n // If no TTY or invalid, we can't find the terminal\n if (!ttyShort || ttyShort === \"?\") {\n this.debug?.(`findTerminal(pid=${pid}): no usable TTY, cannot resolve terminal`);\n return null;\n }\n\n const fullTty = `/dev/${ttyShort}`;\n this.debug?.(`findTerminal(pid=${pid}): resolving terminal for ${fullTty}`);\n\n // 1. Check tmux (most specific if running inside it)\n const tmuxLocation = await this.findTmuxPane(fullTty);\n if (tmuxLocation) {\n this.debug?.(`findTerminal: matched tmux (identifier=${tmuxLocation.identifier})`);\n return tmuxLocation;\n }\n this.debug?.(\"findTerminal: tmux no match\");\n\n // 2. Check WezTerm (cross-platform, via its CLI — no AppleScript)\n const weztermLocation = await this.findWeztermPane(fullTty);\n if (weztermLocation) {\n this.debug?.(`findTerminal: matched wezterm (pane_id=${weztermLocation.identifier})`);\n return weztermLocation;\n }\n this.debug?.(\"findTerminal: wezterm no match\");\n\n // 3. Check iTerm2\n const itermLocation = await this.findITerm2Session(fullTty);\n if (itermLocation) {\n this.debug?.(`findTerminal: matched iTerm2 (tty=${itermLocation.tty})`);\n return itermLocation;\n }\n this.debug?.(\"findTerminal: iTerm2 no match\");\n\n // 4. Check Terminal.app\n const terminalAppLocation = await this.findTerminalAppWindow(fullTty);\n if (terminalAppLocation) {\n this.debug?.(`findTerminal: matched Terminal.app (tty=${terminalAppLocation.tty})`);\n return terminalAppLocation;\n }\n this.debug?.(\"findTerminal: Terminal.app no match\");\n\n // 5. Fallback: we know the TTY but not the emulator wrapper\n this.debug?.(\"findTerminal: no emulator matched; returning UNKNOWN\");\n return {\n type: TerminalType.UNKNOWN,\n identifier: \"\",\n tty: fullTty,\n };\n }\n\n /**\n * Focus the terminal identified by the location\n */\n async focusTerminal(location: TerminalLocation): Promise<boolean> {\n this.debug?.(\n `focusTerminal: focusing ${location.type} (identifier=${location.identifier}, tty=${location.tty})`,\n );\n let success = false;\n try {\n switch (location.type) {\n case TerminalType.TMUX:\n success = await this.focusTmuxPane(location.identifier);\n break;\n case TerminalType.WEZTERM:\n success = await this.focusWeztermPane(location.identifier);\n break;\n case TerminalType.ITERM2:\n success = await this.focusITerm2Session(location.tty);\n break;\n case TerminalType.TERMINAL_APP:\n success = await this.focusTerminalAppWindow(location.tty);\n break;\n default:\n success = false;\n }\n } catch {\n success = false;\n }\n this.debug?.(`focusTerminal: ${success ? \"succeeded\" : \"failed\"} for ${location.type}`);\n return success;\n }\n\n private async findWeztermPane(tty: string): Promise<TerminalLocation | null> {\n try {\n const { stdout } = await execFileAsync(\"wezterm\", [\"cli\", \"list\", \"--format\", \"json\"]);\n\n const panes = JSON.parse(stdout) as WeztermPaneEntry[];\n if (!Array.isArray(panes)) return null;\n\n for (const pane of panes) {\n if (\n pane &&\n typeof pane.tty_name === \"string\" &&\n pane.tty_name === tty &&\n pane.pane_id != null\n ) {\n return {\n type: TerminalType.WEZTERM,\n identifier: String(pane.pane_id),\n tty,\n };\n }\n }\n } catch {\n // wezterm not installed, not running, or returned invalid JSON\n }\n return null;\n }\n\n private async focusWeztermPane(paneId: string): Promise<boolean> {\n try {\n await execFileAsync(\"wezterm\", [\"cli\", \"activate-pane\", \"--pane-id\", paneId]);\n return true;\n } catch {\n return false;\n }\n }\n\n private async findTmuxPane(tty: string): Promise<TerminalLocation | null> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\n \"list-panes\",\n \"-a\",\n \"-F\",\n \"#{pane_tty}|#{session_name}:#{window_index}.#{pane_index}\",\n ]);\n\n const lines = stdout.trim().split(\"\\n\");\n for (const line of lines) {\n if (!line.trim()) continue;\n const [paneTty, identifier] = line.split(\"|\");\n if (paneTty === tty && identifier) {\n return {\n type: TerminalType.TMUX,\n identifier,\n tty,\n };\n }\n }\n } catch {\n // tmux might not be installed or running\n }\n return null;\n }\n\n private async findITerm2Session(tty: string): Promise<TerminalLocation | null> {\n try {\n // Check if iTerm2 is running first to avoid launching it.\n if (!(await this.isProcessRunning(\"iTerm2\"))) return null;\n } catch {\n return null;\n }\n\n try {\n const escapedTty = escapeAppleScript(tty);\n const script = `\n tell application \"iTerm\"\n repeat with w in windows\n repeat with t in tabs of w\n repeat with s in sessions of t\n if tty of s is \"${escapedTty}\" then\n return \"found\"\n end if\n end repeat\n end repeat\n end repeat\n end tell\n `;\n\n const { stdout } = await execFileAsync(\"osascript\", [\"-e\", script]);\n if (stdout.trim() === \"found\") {\n return {\n type: TerminalType.ITERM2,\n identifier: tty,\n tty,\n };\n }\n } catch {\n // iTerm2 script failed\n }\n return null;\n }\n\n private async findTerminalAppWindow(tty: string): Promise<TerminalLocation | null> {\n try {\n // Check if Terminal.app is running\n if (!(await this.isProcessRunning(\"Terminal\"))) return null;\n } catch {\n return null;\n }\n\n try {\n const escapedTty = escapeAppleScript(tty);\n const script = `\n tell application \"Terminal\"\n repeat with w in windows\n repeat with t in tabs of w\n if tty of t is \"${escapedTty}\" then\n return \"found\"\n end if\n end repeat\n end repeat\n end tell\n `;\n\n const { stdout } = await execFileAsync(\"osascript\", [\"-e\", script]);\n if (stdout.trim() === \"found\") {\n return {\n type: TerminalType.TERMINAL_APP,\n identifier: tty,\n tty,\n };\n }\n } catch {\n // Terminal.app script failed\n }\n return null;\n }\n\n private async isProcessRunning(name: string): Promise<boolean> {\n const { stdout } = await execFileAsync(\"ps\", [\"-Axo\", \"comm\"]);\n return stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .some((command) => command === name || command.endsWith(`/${name}`));\n }\n\n private async focusTmuxPane(identifier: string): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"switch-client\", \"-t\", identifier]);\n return true;\n } catch {\n return false;\n }\n }\n\n private async focusITerm2Session(tty: string): Promise<boolean> {\n const escapedTty = escapeAppleScript(tty);\n const script = `\n tell application \"iTerm\"\n activate\n repeat with w in windows\n repeat with t in tabs of w\n repeat with s in sessions of t\n if tty of s is \"${escapedTty}\" then\n select s\n return \"true\"\n end if\n end repeat\n end repeat\n end repeat\n end tell\n `;\n const { stdout } = await execFileAsync(\"osascript\", [\"-e\", script]);\n return stdout.trim() === \"true\";\n }\n\n private async focusTerminalAppWindow(tty: string): Promise<boolean> {\n const escapedTty = escapeAppleScript(tty);\n const script = `\n tell application \"Terminal\"\n activate\n repeat with w in windows\n repeat with t in tabs of w\n if tty of t is \"${escapedTty}\" then\n set index of w to 1\n set selected tab of w to t\n return \"true\"\n end if\n end repeat\n end repeat\n end tell\n `;\n const { stdout } = await execFileAsync(\"osascript\", [\"-e\", script]);\n return stdout.trim() === \"true\";\n }\n}\n"],"names":["execFile","promisify","getProcessTty","escapeAppleScript","execFileAsync","TerminalType","TerminalFocusManager","debug","findTerminal","pid","ttyShort","fullTty","tmuxLocation","findTmuxPane","identifier","weztermLocation","findWeztermPane","itermLocation","findITerm2Session","tty","terminalAppLocation","findTerminalAppWindow","type","focusTerminal","location","success","focusTmuxPane","focusWeztermPane","focusITerm2Session","focusTerminalAppWindow","stdout","panes","JSON","parse","Array","isArray","pane","tty_name","pane_id","String","paneId","lines","trim","split","line","paneTty","isProcessRunning","escapedTty","script","name","map","some","command","endsWith"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/terminal/TerminalFocusManager.ts"],"sourcesContent":["import { getProcessTty } from \"../utils/process.js\";\nimport { TERMINAL_BACKENDS, terminalBackendFor } from \"./backends/index.js\";\nimport { TerminalType, type TerminalLocation } from \"./types.js\";\n\nexport { TerminalType };\nexport type { TerminalLocation };\n\n/** Optional trace sink for terminal discovery and focus decisions. */\nexport type TerminalDebugLogger = (message: string) => void;\n\nexport class TerminalFocusManager {\n constructor(private readonly debug?: TerminalDebugLogger) {}\n\n async findTerminal(pid: number): Promise<TerminalLocation | null> {\n const tty = getProcessTty(pid);\n if (!tty || tty === \"?\") {\n this.debug?.(`findTerminal(pid=${pid}): no usable TTY, cannot resolve terminal`);\n return null;\n }\n\n const fullTty = `/dev/${tty}`;\n this.debug?.(`findTerminal(pid=${pid}): resolving terminal for ${fullTty}`);\n\n for (const backend of TERMINAL_BACKENDS) {\n const location = await backend.find(fullTty);\n if (location) {\n this.debug?.(`findTerminal: matched ${backend.label} (identifier=${location.identifier})`);\n return location;\n }\n this.debug?.(`findTerminal: ${backend.label} no match`);\n }\n\n this.debug?.(\"findTerminal: no emulator matched; returning UNKNOWN\");\n return { type: TerminalType.UNKNOWN, identifier: \"\", tty: fullTty };\n }\n\n async focusTerminal(location: TerminalLocation): Promise<boolean> {\n this.debug?.(\n `focusTerminal: focusing ${location.type} (identifier=${location.identifier}, tty=${location.tty})`,\n );\n\n let success = false;\n try {\n success = (await terminalBackendFor(location.type)?.focus(location)) ?? false;\n } catch {\n success = false;\n }\n\n this.debug?.(`focusTerminal: ${success ? \"succeeded\" : \"failed\"} for ${location.type}`);\n return success;\n }\n}\n"],"names":["getProcessTty","TERMINAL_BACKENDS","terminalBackendFor","TerminalType","TerminalFocusManager","debug","findTerminal","pid","tty","fullTty","backend","location","find","label","identifier","type","UNKNOWN","focusTerminal","success","focus"],"mappings":"AAAA,SAASA,aAAa,QAAQ,sBAAsB;AACpD,SAASC,iBAAiB,EAAEC,kBAAkB,QAAQ,sBAAsB;AAC5E,SAASC,YAAY,QAA+B,aAAa;AAEjE,SAASA,YAAY,GAAG;AAMxB,OAAO,MAAMC;;IACX,YAAY,AAAiBC,KAA2B,CAAE;aAA7BA,QAAAA;IAA8B;IAE3D,MAAMC,aAAaC,GAAW,EAAoC;QAChE,MAAMC,MAAMR,cAAcO;QAC1B,IAAI,CAACC,OAAOA,QAAQ,KAAK;YACvB,IAAI,CAACH,KAAK,GAAG,CAAC,iBAAiB,EAAEE,IAAI,yCAAyC,CAAC;YAC/E,OAAO;QACT;QAEA,MAAME,UAAU,CAAC,KAAK,EAAED,KAAK;QAC7B,IAAI,CAACH,KAAK,GAAG,CAAC,iBAAiB,EAAEE,IAAI,0BAA0B,EAAEE,SAAS;QAE1E,KAAK,MAAMC,WAAWT,kBAAmB;YACvC,MAAMU,WAAW,MAAMD,QAAQE,IAAI,CAACH;YACpC,IAAIE,UAAU;gBACZ,IAAI,CAACN,KAAK,GAAG,CAAC,sBAAsB,EAAEK,QAAQG,KAAK,CAAC,aAAa,EAAEF,SAASG,UAAU,CAAC,CAAC,CAAC;gBACzF,OAAOH;YACT;YACA,IAAI,CAACN,KAAK,GAAG,CAAC,cAAc,EAAEK,QAAQG,KAAK,CAAC,SAAS,CAAC;QACxD;QAEA,IAAI,CAACR,KAAK,GAAG;QACb,OAAO;YAAEU,MAAMZ,aAAaa,OAAO;YAAEF,YAAY;YAAIN,KAAKC;QAAQ;IACpE;IAEA,MAAMQ,cAAcN,QAA0B,EAAoB;QAChE,IAAI,CAACN,KAAK,GACR,CAAC,wBAAwB,EAAEM,SAASI,IAAI,CAAC,aAAa,EAAEJ,SAASG,UAAU,CAAC,MAAM,EAAEH,SAASH,GAAG,CAAC,CAAC,CAAC;QAGrG,IAAIU,UAAU;QACd,IAAI;YACFA,UAAU,AAAC,MAAMhB,mBAAmBS,SAASI,IAAI,GAAGI,MAAMR,aAAc;QAC1E,EAAE,OAAM;YACNO,UAAU;QACZ;QAEA,IAAI,CAACb,KAAK,GAAG,CAAC,eAAe,EAAEa,UAAU,cAAc,SAAS,KAAK,EAAEP,SAASI,IAAI,EAAE;QACtF,OAAOG;IACT;AACF"}
|
|
@@ -1,49 +1,6 @@
|
|
|
1
|
-
import type { TerminalLocation } from "./
|
|
1
|
+
import type { TerminalLocation } from "./types.js";
|
|
2
2
|
export declare class TtyWriter {
|
|
3
|
-
/**
|
|
4
|
-
* Send a message as keyboard input to a terminal session.
|
|
5
|
-
*
|
|
6
|
-
* Dispatches to the correct mechanism based on terminal type:
|
|
7
|
-
* - tmux: `tmux send-keys`
|
|
8
|
-
* - iTerm2: Two separate AppleScript `write text` calls (text then newline)
|
|
9
|
-
* - Terminal.app: Two separate AppleScript `do script` calls (text then newline)
|
|
10
|
-
*
|
|
11
|
-
* All AppleScript is executed via `execFile('osascript', ['-e', script])`
|
|
12
|
-
* to avoid shell interpolation and command injection.
|
|
13
|
-
*
|
|
14
|
-
* @param location Terminal location from TerminalFocusManager.findTerminal()
|
|
15
|
-
* @param message Text to send
|
|
16
|
-
* @throws Error if terminal type is unsupported or send fails
|
|
17
|
-
*/
|
|
18
3
|
static send(location: TerminalLocation, message: string): Promise<void>;
|
|
19
|
-
/**
|
|
20
|
-
* Send a single raw key (e.g. "1", "Enter", "Up") to the terminal as a
|
|
21
|
-
* keystroke — bypassing bracketed paste and without auto-appending Enter.
|
|
22
|
-
*
|
|
23
|
-
* Use this when the target TUI distinguishes between typed text and raw
|
|
24
|
-
* keypresses (e.g. an `AskUserQuestion` picker that selects on digit-key
|
|
25
|
-
* press, not on a pasted digit followed by Enter).
|
|
26
|
-
*
|
|
27
|
-
* - tmux: `tmux send-keys -t <id> <key>` — direct keystroke, no paste buffer.
|
|
28
|
-
* - WezTerm: `wezterm cli send-text --pane-id <id> --no-paste <key>`.
|
|
29
|
-
* - iTerm2 / Terminal.app: AppleScript via System Events. Requires
|
|
30
|
-
* Accessibility permissions.
|
|
31
|
-
*/
|
|
32
4
|
static sendKey(location: TerminalLocation, key: string): Promise<void>;
|
|
33
|
-
private static sendKeyViaTmux;
|
|
34
|
-
private static sendKeyViaWezterm;
|
|
35
|
-
private static sendKeyViaITerm2;
|
|
36
|
-
private static sendKeyViaTerminalApp;
|
|
37
|
-
private static sendViaWezterm;
|
|
38
|
-
private static sendViaTmux;
|
|
39
|
-
private static execFileWithInput;
|
|
40
|
-
/**
|
|
41
|
-
* Build an AppleScript that finds an iTerm2 session by TTY and runs a
|
|
42
|
-
* command against it. The `sessionCommand` is inserted inside a
|
|
43
|
-
* `tell targetSession` block.
|
|
44
|
-
*/
|
|
45
|
-
private static iterm2SessionScript;
|
|
46
|
-
private static sendViaITerm2;
|
|
47
|
-
private static sendViaTerminalApp;
|
|
48
5
|
}
|
|
49
6
|
//# sourceMappingURL=TtyWriter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TtyWriter.d.ts","sourceRoot":"","sources":["../../src/terminal/TtyWriter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TtyWriter.d.ts","sourceRoot":"","sources":["../../src/terminal/TtyWriter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,qBAAa,SAAS;WACP,IAAI,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAUhE,OAAO,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAS7E"}
|