@ai-devkit/agent-manager 0.32.0 → 0.33.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 +3 -3
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +80 -79
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/AgentManager.test.js +413 -388
- package/dist/__tests__/AgentManager.test.js.map +1 -1
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +642 -642
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/CodexAdapter.test.js +322 -2321
- package/dist/__tests__/adapters/CodexAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/CopilotAdapter.test.js +254 -248
- package/dist/__tests__/adapters/CopilotAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/GeminiCliAdapter.test.js +564 -558
- package/dist/__tests__/adapters/GeminiCliAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/GrokCliAdapter.test.js +114 -114
- package/dist/__tests__/adapters/GrokCliAdapter.test.js.map +1 -1
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js +169 -169
- package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +1 -1
- package/dist/__tests__/capacity/codex.test.js +93 -93
- package/dist/__tests__/capacity/codex.test.js.map +1 -1
- package/dist/__tests__/capacity/index.test.js +17 -17
- package/dist/__tests__/capacity/index.test.js.map +1 -1
- package/dist/__tests__/durable/CodexCliProbe.test.js +60 -60
- package/dist/__tests__/durable/CodexCliProbe.test.js.map +1 -1
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +28 -28
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +30 -30
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/durable/CodexPrintAgentService.test.js +71 -71
- package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/durable/CodexPrintRunner.test.js +125 -125
- package/dist/__tests__/durable/CodexPrintRunner.test.js.map +1 -1
- package/dist/__tests__/print/ClaudeCliProbe.test.js +20 -20
- package/dist/__tests__/print/ClaudeCliProbe.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +20 -20
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgentService.test.js +58 -58
- package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintRunner.test.js +55 -55
- package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgent.test.js +9 -9
- package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js +40 -40
- package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgentRepository.test.js +66 -66
- package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +34 -34
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +1 -1
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +132 -132
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +1 -1
- package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +194 -0
- package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +1 -0
- package/dist/__tests__/providers/codex/CodexSessionMapping.test.js +86 -0
- package/dist/__tests__/providers/codex/CodexSessionMapping.test.js.map +1 -0
- package/dist/__tests__/providers/codex/CodexSessionParser.test.js +254 -0
- package/dist/__tests__/providers/codex/CodexSessionParser.test.js.map +1 -0
- package/dist/__tests__/providers/pi/PiAdapter.test.js +337 -0
- package/dist/__tests__/providers/pi/PiAdapter.test.js.map +1 -0
- package/dist/__tests__/providers/pi/PiSessionParser.test.js +246 -0
- package/dist/__tests__/providers/pi/PiSessionParser.test.js.map +1 -0
- package/dist/__tests__/providers/pi/PiSessionTracker.test.js +108 -0
- package/dist/__tests__/providers/pi/PiSessionTracker.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js +33 -33
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js +16 -16
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js +52 -52
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js +44 -44
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js +126 -126
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js.map +1 -1
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js +14 -14
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js.map +1 -1
- package/dist/__tests__/readiness/AgentReadiness.test.js +134 -134
- package/dist/__tests__/readiness/AgentReadiness.test.js.map +1 -1
- package/dist/__tests__/runtime/AgentRuntime.test.js +13 -0
- package/dist/__tests__/runtime/AgentRuntime.test.js.map +1 -0
- package/dist/__tests__/runtime/HerdrAgentRuntime.test.js +452 -0
- package/dist/__tests__/runtime/HerdrAgentRuntime.test.js.map +1 -0
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js +588 -0
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -0
- package/dist/__tests__/terminal/TerminalFocusManager.test.js +100 -100
- package/dist/__tests__/terminal/TerminalFocusManager.test.js.map +1 -1
- package/dist/__tests__/terminal/TmuxManager.test.js +101 -101
- package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
- package/dist/__tests__/terminal/TtyWriter.test.js +185 -185
- package/dist/__tests__/terminal/TtyWriter.test.js.map +1 -1
- package/dist/__tests__/utils/AgentRegistry.test.js +335 -217
- package/dist/__tests__/utils/AgentRegistry.test.js.map +1 -1
- package/dist/__tests__/utils/ClaudeSessionParser.test.js +103 -101
- package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +1 -1
- package/dist/__tests__/utils/agent-requests.test.js +43 -43
- package/dist/__tests__/utils/agent-requests.test.js.map +1 -1
- package/dist/__tests__/utils/agents.test.js +17 -17
- package/dist/__tests__/utils/agents.test.js.map +1 -1
- package/dist/__tests__/utils/matching.test.js +92 -92
- package/dist/__tests__/utils/matching.test.js.map +1 -1
- package/dist/__tests__/utils/process.test.js +108 -108
- package/dist/__tests__/utils/process.test.js.map +1 -1
- package/dist/__tests__/utils/session.test.js +53 -53
- package/dist/__tests__/utils/session.test.js.map +1 -1
- package/dist/adapters/AgentAdapter.d.ts +2 -2
- package/dist/adapters/AgentAdapter.d.ts.map +1 -1
- package/dist/adapters/AgentAdapter.js +1 -1
- package/dist/adapters/AgentAdapter.js.map +1 -1
- package/dist/adapters/CopilotAdapter.d.ts +2 -2
- package/dist/adapters/CopilotAdapter.d.ts.map +1 -1
- package/dist/adapters/CopilotAdapter.js +51 -51
- package/dist/adapters/CopilotAdapter.js.map +1 -1
- package/dist/adapters/GeminiCliAdapter.d.ts +2 -2
- package/dist/adapters/GeminiCliAdapter.d.ts.map +1 -1
- package/dist/adapters/GeminiCliAdapter.js +86 -86
- package/dist/adapters/GeminiCliAdapter.js.map +1 -1
- package/dist/adapters/GrokCliAdapter.d.ts +1 -1
- package/dist/adapters/GrokCliAdapter.d.ts.map +1 -1
- package/dist/adapters/GrokCliAdapter.js +80 -80
- package/dist/adapters/GrokCliAdapter.js.map +1 -1
- package/dist/adapters/OpenCodeAdapter.d.ts +1 -1
- package/dist/adapters/OpenCodeAdapter.d.ts.map +1 -1
- package/dist/adapters/OpenCodeAdapter.js +37 -36
- package/dist/adapters/OpenCodeAdapter.js.map +1 -1
- package/dist/adapters/index.d.ts +9 -9
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +8 -8
- package/dist/adapters/index.js.map +1 -1
- package/dist/capacity/codex.d.ts +3 -3
- package/dist/capacity/codex.d.ts.map +1 -1
- package/dist/capacity/codex.js +57 -57
- package/dist/capacity/codex.js.map +1 -1
- package/dist/capacity/index.d.ts +3 -3
- package/dist/capacity/index.d.ts.map +1 -1
- package/dist/capacity/index.js +8 -8
- package/dist/capacity/index.js.map +1 -1
- package/dist/capacity/types.d.ts +1 -1
- package/dist/capacity/types.js.map +1 -1
- package/dist/database/connection.d.ts +1 -1
- package/dist/database/connection.d.ts.map +1 -1
- package/dist/database/connection.js +15 -15
- package/dist/database/connection.js.map +1 -1
- package/dist/database/index.d.ts +3 -3
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/index.js +2 -2
- package/dist/database/index.js.map +1 -1
- package/dist/database/migrations/005_agent_runtime.sql +2 -0
- package/dist/database/schema.d.ts +1 -1
- package/dist/database/schema.d.ts.map +1 -1
- package/dist/database/schema.js +7 -7
- package/dist/database/schema.js.map +1 -1
- package/dist/durable/DurableAgent.d.ts +9 -9
- package/dist/durable/DurableAgent.d.ts.map +1 -1
- package/dist/durable/DurableAgent.js +16 -16
- package/dist/durable/DurableAgent.js.map +1 -1
- package/dist/durable/DurableAgentRepository.d.ts +4 -4
- package/dist/durable/DurableAgentRepository.d.ts.map +1 -1
- package/dist/durable/DurableAgentRepository.js +49 -48
- package/dist/durable/DurableAgentRepository.js.map +1 -1
- package/dist/durable/process.d.ts +1 -1
- package/dist/durable/process.d.ts.map +1 -1
- package/dist/durable/process.js +14 -14
- package/dist/durable/process.js.map +1 -1
- package/dist/durable/run.d.ts +2 -2
- package/dist/durable/run.d.ts.map +1 -1
- package/dist/durable/run.js +6 -6
- package/dist/durable/run.js.map +1 -1
- package/dist/durable/utils.d.ts +1 -1
- package/dist/durable/utils.d.ts.map +1 -1
- package/dist/durable/utils.js +4 -4
- package/dist/durable/utils.js.map +1 -1
- package/dist/index.d.ts +46 -43
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -26
- package/dist/index.js.map +1 -1
- package/dist/providers/claude/ClaudeAgentMapper.d.ts +4 -4
- package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +1 -1
- package/dist/providers/claude/ClaudeAgentMapper.js +10 -10
- package/dist/providers/claude/ClaudeAgentMapper.js.map +1 -1
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts +1 -1
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +1 -1
- package/dist/providers/claude/ClaudeCodeAdapter.js +14 -14
- package/dist/providers/claude/ClaudeCodeAdapter.js.map +1 -1
- package/dist/providers/claude/ClaudeSessionLocator.d.ts +4 -4
- package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +1 -1
- package/dist/providers/claude/ClaudeSessionLocator.js +79 -79
- package/dist/providers/claude/ClaudeSessionLocator.js.map +1 -1
- package/dist/providers/claude/ClaudeSessionParser.d.ts +2 -2
- package/dist/providers/claude/ClaudeSessionParser.d.ts.map +1 -1
- package/dist/providers/claude/ClaudeSessionParser.js +99 -99
- package/dist/providers/claude/ClaudeSessionParser.js.map +1 -1
- package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +1 -1
- package/dist/providers/claude/durable/ClaudeCliProbe.js +16 -16
- package/dist/providers/claude/durable/ClaudeCliProbe.js.map +1 -1
- package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts +5 -5
- package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +1 -1
- package/dist/providers/claude/durable/ClaudePrintAgentService.js +10 -10
- package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +1 -1
- package/dist/providers/claude/durable/ClaudePrintRunner.d.ts +4 -4
- package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +1 -1
- package/dist/providers/claude/durable/ClaudePrintRunner.js +18 -18
- package/dist/providers/claude/durable/ClaudePrintRunner.js.map +1 -1
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts +2 -2
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +1 -1
- package/dist/providers/claude/durable/ClaudeStreamParser.js +17 -17
- package/dist/providers/claude/durable/ClaudeStreamParser.js.map +1 -1
- package/dist/providers/codex/CodexAdapter.d.ts +27 -0
- package/dist/providers/codex/CodexAdapter.d.ts.map +1 -0
- package/dist/providers/codex/CodexAdapter.js +162 -0
- package/dist/providers/codex/CodexAdapter.js.map +1 -0
- package/dist/providers/codex/CodexAgentMapper.d.ts +9 -0
- package/dist/providers/codex/CodexAgentMapper.d.ts.map +1 -0
- package/dist/providers/codex/CodexAgentMapper.js +35 -0
- package/dist/providers/codex/CodexAgentMapper.js.map +1 -0
- package/dist/providers/codex/CodexSessionLocator.d.ts +44 -0
- package/dist/providers/codex/CodexSessionLocator.d.ts.map +1 -0
- package/dist/providers/codex/CodexSessionLocator.js +207 -0
- package/dist/providers/codex/CodexSessionLocator.js.map +1 -0
- package/dist/providers/codex/CodexSessionMapping.d.ts +23 -0
- package/dist/providers/codex/CodexSessionMapping.d.ts.map +1 -0
- package/dist/providers/codex/CodexSessionMapping.js +68 -0
- package/dist/providers/codex/CodexSessionMapping.js.map +1 -0
- package/dist/providers/codex/CodexSessionParser.d.ts +58 -0
- package/dist/providers/codex/CodexSessionParser.d.ts.map +1 -0
- package/dist/providers/codex/CodexSessionParser.js +262 -0
- package/dist/providers/codex/CodexSessionParser.js.map +1 -0
- package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +1 -1
- package/dist/providers/codex/durable/CodexCliProbe.js +22 -22
- package/dist/providers/codex/durable/CodexCliProbe.js.map +1 -1
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts +6 -6
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +1 -1
- package/dist/providers/codex/durable/CodexPrintAgentService.js +10 -10
- package/dist/providers/codex/durable/CodexPrintAgentService.js.map +1 -1
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts +4 -4
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +1 -1
- package/dist/providers/codex/durable/CodexPrintRunner.js +20 -20
- package/dist/providers/codex/durable/CodexPrintRunner.js.map +1 -1
- package/dist/providers/codex/durable/CodexStreamParser.d.ts +2 -2
- package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +1 -1
- package/dist/providers/codex/durable/CodexStreamParser.js +21 -21
- package/dist/providers/codex/durable/CodexStreamParser.js.map +1 -1
- package/dist/providers/pi/PiAdapter.d.ts +28 -0
- package/dist/providers/pi/PiAdapter.d.ts.map +1 -0
- package/dist/providers/pi/PiAdapter.js +153 -0
- package/dist/providers/pi/PiAdapter.js.map +1 -0
- package/dist/providers/pi/PiAgentMapper.d.ts +9 -0
- package/dist/providers/pi/PiAgentMapper.d.ts.map +1 -0
- package/dist/providers/pi/PiAgentMapper.js +37 -0
- package/dist/providers/pi/PiAgentMapper.js.map +1 -0
- package/dist/providers/pi/PiSessionLocator.d.ts +23 -0
- package/dist/providers/pi/PiSessionLocator.d.ts.map +1 -0
- package/dist/providers/pi/PiSessionLocator.js +79 -0
- package/dist/providers/pi/PiSessionLocator.js.map +1 -0
- package/dist/providers/pi/PiSessionParser.d.ts +36 -0
- package/dist/providers/pi/PiSessionParser.d.ts.map +1 -0
- package/dist/providers/pi/PiSessionParser.js +191 -0
- package/dist/providers/pi/PiSessionParser.js.map +1 -0
- package/dist/providers/pi/PiSessionTracker.d.ts +23 -0
- package/dist/providers/pi/PiSessionTracker.d.ts.map +1 -0
- package/dist/providers/pi/PiSessionTracker.js +69 -0
- package/dist/providers/pi/PiSessionTracker.js.map +1 -0
- package/dist/providers/pi/durable/PiCliProbe.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiCliProbe.js +15 -15
- package/dist/providers/pi/durable/PiCliProbe.js.map +1 -1
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts +6 -6
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiPrintAgentService.js +10 -10
- package/dist/providers/pi/durable/PiPrintAgentService.js.map +1 -1
- package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiPrintProtocol.js +18 -18
- package/dist/providers/pi/durable/PiPrintProtocol.js.map +1 -1
- package/dist/providers/pi/durable/PiPrintRunner.d.ts +4 -4
- package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiPrintRunner.js +15 -15
- package/dist/providers/pi/durable/PiPrintRunner.js.map +1 -1
- package/dist/providers/pi/durable/PiStreamParser.d.ts +1 -1
- package/dist/providers/pi/durable/PiStreamParser.d.ts.map +1 -1
- package/dist/providers/pi/durable/PiStreamParser.js +16 -16
- package/dist/providers/pi/durable/PiStreamParser.js.map +1 -1
- package/dist/readiness/AgentReadiness.d.ts +6 -6
- package/dist/readiness/AgentReadiness.d.ts.map +1 -1
- package/dist/readiness/AgentReadiness.js +130 -130
- package/dist/readiness/AgentReadiness.js.map +1 -1
- package/dist/runtime/ManagedAgentRuntime.d.ts +69 -0
- package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -0
- package/dist/runtime/ManagedAgentRuntime.js +156 -0
- package/dist/runtime/ManagedAgentRuntime.js.map +1 -0
- package/dist/runtime/RuntimeFactory.d.ts +4 -0
- package/dist/runtime/RuntimeFactory.d.ts.map +1 -0
- package/dist/runtime/RuntimeFactory.js +11 -0
- package/dist/runtime/RuntimeFactory.js.map +1 -0
- package/dist/runtime/errors.d.ts +27 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +42 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.d.ts +31 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.js +184 -0
- package/dist/runtime/herdr/HerdrAgentRuntime.js.map +1 -0
- package/dist/runtime/herdr/HerdrCliClient.d.ts +13 -0
- package/dist/runtime/herdr/HerdrCliClient.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrCliClient.js +60 -0
- package/dist/runtime/herdr/HerdrCliClient.js.map +1 -0
- package/dist/runtime/herdr/HerdrErrors.d.ts +7 -0
- package/dist/runtime/herdr/HerdrErrors.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrErrors.js +10 -0
- package/dist/runtime/herdr/HerdrErrors.js.map +1 -0
- package/dist/runtime/herdr/HerdrResponseParsers.d.ts +14 -0
- package/dist/runtime/herdr/HerdrResponseParsers.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrResponseParsers.js +96 -0
- package/dist/runtime/herdr/HerdrResponseParsers.js.map +1 -0
- package/dist/runtime/herdr/HerdrRuntimeRef.d.ts +9 -0
- package/dist/runtime/herdr/HerdrRuntimeRef.d.ts.map +1 -0
- package/dist/runtime/herdr/HerdrRuntimeRef.js +33 -0
- package/dist/runtime/herdr/HerdrRuntimeRef.js.map +1 -0
- package/dist/runtime/tmux/PidPolling.d.ts +5 -0
- package/dist/runtime/tmux/PidPolling.d.ts.map +1 -0
- package/dist/runtime/tmux/PidPolling.js +24 -0
- package/dist/runtime/tmux/PidPolling.js.map +1 -0
- package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +17 -0
- package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -0
- package/dist/runtime/tmux/TmuxAgentRuntime.js +80 -0
- package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -0
- package/dist/runtime/tmux/TmuxRuntimeRef.d.ts +5 -0
- package/dist/runtime/tmux/TmuxRuntimeRef.d.ts.map +1 -0
- package/dist/runtime/tmux/TmuxRuntimeRef.js +9 -0
- package/dist/runtime/tmux/TmuxRuntimeRef.js.map +1 -0
- package/dist/runtime/types.d.ts +54 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +3 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
- package/dist/terminal/TerminalFocusManager.js +50 -50
- package/dist/terminal/TerminalFocusManager.js.map +1 -1
- package/dist/terminal/TmuxManager.d.ts.map +1 -1
- package/dist/terminal/TmuxManager.js +47 -47
- package/dist/terminal/TmuxManager.js.map +1 -1
- package/dist/terminal/TtyWriter.d.ts +1 -1
- package/dist/terminal/TtyWriter.d.ts.map +1 -1
- package/dist/terminal/TtyWriter.js +89 -89
- package/dist/terminal/TtyWriter.js.map +1 -1
- package/dist/terminal/index.d.ts +4 -4
- package/dist/terminal/index.js +3 -3
- package/dist/terminal/index.js.map +1 -1
- package/dist/utils/AgentRegistry.d.ts +10 -2
- package/dist/utils/AgentRegistry.d.ts.map +1 -1
- package/dist/utils/AgentRegistry.js +57 -24
- package/dist/utils/AgentRegistry.js.map +1 -1
- package/dist/utils/agent-requests.d.ts.map +1 -1
- package/dist/utils/agent-requests.js +5 -5
- package/dist/utils/agent-requests.js.map +1 -1
- package/dist/utils/agents.d.ts +2 -2
- package/dist/utils/agents.d.ts.map +1 -1
- package/dist/utils/agents.js +15 -15
- package/dist/utils/agents.js.map +1 -1
- package/dist/utils/applescript.js +1 -1
- package/dist/utils/applescript.js.map +1 -1
- package/dist/utils/index.d.ts +6 -6
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/matching.d.ts +2 -2
- package/dist/utils/matching.d.ts.map +1 -1
- package/dist/utils/matching.js +4 -4
- package/dist/utils/matching.js.map +1 -1
- package/dist/utils/process.d.ts +1 -1
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +74 -74
- package/dist/utils/process.js.map +1 -1
- package/dist/utils/session.d.ts +1 -1
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +7 -7
- package/dist/utils/session.js.map +1 -1
- package/dist/utils/sortAgents.d.ts +2 -2
- package/dist/utils/sortAgents.d.ts.map +1 -1
- package/dist/utils/sortAgents.js +5 -5
- package/dist/utils/sortAgents.js.map +1 -1
- package/package.json +18 -19
- package/src/AgentManager.ts +283 -281
- package/src/__tests__/AgentManager.test.ts +917 -907
- package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +1657 -1368
- package/src/__tests__/adapters/CodexAdapter.test.ts +365 -1698
- package/src/__tests__/adapters/CopilotAdapter.test.ts +576 -481
- package/src/__tests__/adapters/GeminiCliAdapter.test.ts +1189 -1157
- package/src/__tests__/adapters/GrokCliAdapter.test.ts +325 -272
- package/src/__tests__/adapters/OpenCodeAdapter.test.ts +510 -455
- package/src/__tests__/capacity/codex.test.ts +178 -91
- package/src/__tests__/capacity/index.test.ts +27 -18
- package/src/__tests__/durable/CodexCliProbe.test.ts +75 -53
- package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +51 -40
- package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +89 -64
- package/src/__tests__/durable/CodexPrintAgentService.test.ts +196 -118
- package/src/__tests__/durable/CodexPrintRunner.test.ts +282 -162
- package/src/__tests__/fixtures/fake-claude.cjs +20 -13
- package/src/__tests__/fixtures/fake-codex.cjs +41 -30
- package/src/__tests__/print/ClaudeCliProbe.test.ts +27 -21
- package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +48 -40
- package/src/__tests__/print/ClaudePrintAgentService.test.ts +118 -67
- package/src/__tests__/print/ClaudePrintRunner.test.ts +136 -83
- package/src/__tests__/print/DurableAgent.test.ts +19 -16
- package/src/__tests__/print/DurableAgentRepository.sqlite.test.ts +109 -86
- package/src/__tests__/print/DurableAgentRepository.test.ts +170 -137
- package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +65 -65
- package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +400 -377
- package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +182 -0
- package/src/__tests__/providers/codex/CodexSessionMapping.test.ts +63 -0
- package/src/__tests__/providers/codex/CodexSessionParser.test.ts +192 -0
- package/src/__tests__/providers/pi/PiAdapter.test.ts +310 -0
- package/src/__tests__/providers/pi/PiSessionParser.test.ts +190 -0
- package/src/__tests__/providers/pi/PiSessionTracker.test.ts +79 -0
- package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +48 -32
- package/src/__tests__/providers/pi/durable/PiDurableAgentRepository.test.ts +24 -23
- package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +131 -59
- package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +66 -28
- package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +236 -90
- package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +20 -18
- package/src/__tests__/readiness/AgentReadiness.test.ts +217 -169
- package/src/__tests__/runtime/AgentRuntime.test.ts +8 -0
- package/src/__tests__/runtime/HerdrAgentRuntime.test.ts +358 -0
- package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +555 -0
- package/src/__tests__/terminal/TerminalFocusManager.test.ts +254 -253
- package/src/__tests__/terminal/TmuxManager.test.ts +157 -157
- package/src/__tests__/terminal/TtyWriter.test.ts +423 -419
- package/src/__tests__/utils/AgentRegistry.test.ts +506 -402
- package/src/__tests__/utils/ClaudeSessionParser.test.ts +276 -242
- package/src/__tests__/utils/agent-requests.test.ts +76 -56
- package/src/__tests__/utils/agents.test.ts +20 -20
- package/src/__tests__/utils/matching.test.ts +206 -171
- package/src/__tests__/utils/process.test.ts +276 -262
- package/src/__tests__/utils/session.test.ts +133 -139
- package/src/adapters/AgentAdapter.ts +134 -126
- package/src/adapters/CopilotAdapter.ts +405 -395
- package/src/adapters/GeminiCliAdapter.ts +598 -600
- package/src/adapters/GrokCliAdapter.ts +353 -342
- package/src/adapters/OpenCodeAdapter.ts +285 -259
- package/src/adapters/index.ts +15 -9
- package/src/capacity/codex.ts +137 -84
- package/src/capacity/index.ts +18 -13
- package/src/capacity/types.ts +1 -1
- package/src/database/connection.ts +73 -68
- package/src/database/index.ts +6 -6
- package/src/database/migrations/005_agent_runtime.sql +2 -0
- package/src/database/schema.ts +40 -38
- package/src/durable/DurableAgent.ts +85 -85
- package/src/durable/DurableAgentRepository.ts +409 -260
- package/src/durable/process.ts +22 -21
- package/src/durable/run.ts +61 -51
- package/src/durable/utils.ts +46 -41
- package/src/index.ts +144 -103
- package/src/providers/claude/ClaudeAgentMapper.ts +51 -50
- package/src/providers/claude/ClaudeCodeAdapter.ts +144 -136
- package/src/providers/claude/ClaudeSessionLocator.ts +291 -293
- package/src/providers/claude/ClaudeSessionParser.ts +322 -338
- package/src/providers/claude/durable/ClaudeCliProbe.ts +42 -37
- package/src/providers/claude/durable/ClaudePrintAgentService.ts +63 -50
- package/src/providers/claude/durable/ClaudePrintRunner.ts +79 -69
- package/src/providers/claude/durable/ClaudeStreamParser.ts +91 -62
- package/src/providers/codex/CodexAdapter.ts +205 -0
- package/src/providers/codex/CodexAgentMapper.ts +35 -0
- package/src/providers/codex/CodexSessionLocator.ts +279 -0
- package/src/providers/codex/CodexSessionMapping.ts +89 -0
- package/src/providers/codex/CodexSessionParser.ts +385 -0
- package/src/providers/codex/durable/CodexCliProbe.ts +50 -42
- package/src/providers/codex/durable/CodexPrintAgentService.ts +63 -49
- package/src/providers/codex/durable/CodexPrintRunner.ts +79 -69
- package/src/providers/codex/durable/CodexStreamParser.ts +97 -84
- package/src/providers/pi/PiAdapter.ts +183 -0
- package/src/providers/pi/PiAgentMapper.ts +36 -0
- package/src/providers/pi/PiSessionLocator.ts +95 -0
- package/src/providers/pi/PiSessionParser.ts +284 -0
- package/src/providers/pi/PiSessionTracker.ts +87 -0
- package/src/providers/pi/durable/PiCliProbe.ts +42 -34
- package/src/providers/pi/durable/PiPrintAgentService.ts +61 -53
- package/src/providers/pi/durable/PiPrintProtocol.ts +31 -29
- package/src/providers/pi/durable/PiPrintRunner.ts +75 -68
- package/src/providers/pi/durable/PiStreamParser.ts +82 -72
- package/src/readiness/AgentReadiness.ts +585 -513
- package/src/runtime/ManagedAgentRuntime.ts +266 -0
- package/src/runtime/RuntimeFactory.ts +13 -0
- package/src/runtime/errors.ts +50 -0
- package/src/runtime/herdr/HerdrAgentRuntime.ts +190 -0
- package/src/runtime/herdr/HerdrCliClient.ts +78 -0
- package/src/runtime/herdr/HerdrErrors.ts +9 -0
- package/src/runtime/herdr/HerdrResponseParsers.ts +76 -0
- package/src/runtime/herdr/HerdrRuntimeRef.ts +41 -0
- package/src/runtime/tmux/PidPolling.ts +34 -0
- package/src/runtime/tmux/TmuxAgentRuntime.ts +113 -0
- package/src/runtime/tmux/TmuxRuntimeRef.ts +9 -0
- package/src/runtime/types.ts +56 -0
- package/src/terminal/TerminalFocusManager.ts +215 -212
- package/src/terminal/TmuxManager.ts +99 -92
- package/src/terminal/TtyWriter.ts +203 -194
- package/src/terminal/index.ts +4 -4
- package/src/utils/AgentRegistry.ts +299 -238
- package/src/utils/agent-requests.ts +16 -16
- package/src/utils/agents.ts +41 -38
- package/src/utils/applescript.ts +4 -4
- package/src/utils/index.ts +12 -6
- package/src/utils/matching.ts +43 -43
- package/src/utils/process.ts +261 -258
- package/src/utils/session.ts +66 -66
- package/src/utils/sortAgents.ts +35 -33
- package/tsconfig.json +2 -8
- package/vitest.config.ts +16 -16
- package/.eslintrc.json +0 -31
- package/dist/__tests__/adapters/PiAdapter.test.js +0 -618
- package/dist/__tests__/adapters/PiAdapter.test.js.map +0 -1
- package/dist/__tests__/database/DurableAgentsDatabase.test.js +0 -128
- package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +0 -1
- package/dist/adapters/CodexAdapter.d.ts +0 -109
- package/dist/adapters/CodexAdapter.d.ts.map +0 -1
- package/dist/adapters/CodexAdapter.js +0 -710
- package/dist/adapters/CodexAdapter.js.map +0 -1
- package/dist/adapters/PiAdapter.d.ts +0 -63
- package/dist/adapters/PiAdapter.d.ts.map +0 -1
- package/dist/adapters/PiAdapter.js +0 -453
- package/dist/adapters/PiAdapter.js.map +0 -1
- package/src/__tests__/adapters/PiAdapter.test.ts +0 -458
- package/src/__tests__/database/DurableAgentsDatabase.test.ts +0 -102
- package/src/adapters/CodexAdapter.ts +0 -923
- package/src/adapters/PiAdapter.ts +0 -598
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { TmuxManager } from "../../terminal/TmuxManager.js";
|
|
2
|
+
import { TtyWriter } from "../../terminal/TtyWriter.js";
|
|
3
|
+
import { AgentPidPollTimeoutError, AgentTerminalNotFoundError } from "../errors.js";
|
|
4
|
+
import { pollForPid } from "./PidPolling.js";
|
|
5
|
+
import { parseTmuxRuntimeRef } from "./TmuxRuntimeRef.js";
|
|
6
|
+
export class TmuxAgentRuntime {
|
|
7
|
+
provider = "tmux";
|
|
8
|
+
tmux;
|
|
9
|
+
constructor(tmux = new TmuxManager()){
|
|
10
|
+
this.tmux = tmux;
|
|
11
|
+
}
|
|
12
|
+
async isAvailable() {
|
|
13
|
+
if (await this.tmux.isAvailable()) {
|
|
14
|
+
return {
|
|
15
|
+
ok: true,
|
|
16
|
+
insideRuntime: Boolean(process.env.TMUX)
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
ok: false,
|
|
21
|
+
reason: "binary-missing",
|
|
22
|
+
detail: "tmux is not installed or not in PATH."
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async startAgent(input) {
|
|
26
|
+
if (!input.command || !input.matches || input.pollIntervalMs === undefined) {
|
|
27
|
+
throw new Error("Tmux start requires command, process matcher, and poll interval.");
|
|
28
|
+
}
|
|
29
|
+
if (await this.tmux.sessionExists(input.name)) {
|
|
30
|
+
await this.tmux.killSession(input.name);
|
|
31
|
+
}
|
|
32
|
+
await this.tmux.createSession(input.name, input.cwd);
|
|
33
|
+
await this.tmux.sendKeys(input.name, input.command);
|
|
34
|
+
const pid = await pollForPid(this.tmux, input.name, input.matches, input.pollIntervalMs, input.timeoutMs);
|
|
35
|
+
if (pid === null) {
|
|
36
|
+
await this.tmux.killSession(input.name);
|
|
37
|
+
throw new AgentPidPollTimeoutError(input.name, input.command, input.timeoutMs);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
pid,
|
|
41
|
+
runtimeRef: {
|
|
42
|
+
session: input.name
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async send(input, deps) {
|
|
47
|
+
if (!deps) {
|
|
48
|
+
throw new Error("Tmux send requires terminal lookup dependencies.");
|
|
49
|
+
}
|
|
50
|
+
const location = await deps.focusManager.findTerminal(input.agent.pid);
|
|
51
|
+
if (!location) {
|
|
52
|
+
throw new AgentTerminalNotFoundError(input.agent.name, input.agent.pid);
|
|
53
|
+
}
|
|
54
|
+
await (deps.writer ?? TtyWriter.send)(location, input.prompt);
|
|
55
|
+
}
|
|
56
|
+
async focus(input) {
|
|
57
|
+
const location = await input.focusManager.findTerminal(input.agent.pid);
|
|
58
|
+
if (!location) return false;
|
|
59
|
+
return await input.focusManager.focusTerminal(location);
|
|
60
|
+
}
|
|
61
|
+
async stop(input) {
|
|
62
|
+
const killProcess = input.killProcess ?? ((pid, signal)=>process.kill(pid, signal));
|
|
63
|
+
try {
|
|
64
|
+
killProcess(input.agent.pid, "SIGTERM");
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (!isProcessAlreadyGone(error)) {
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const tmuxRef = parseTmuxRuntimeRef(input.runtimeRef);
|
|
71
|
+
if (tmuxRef) {
|
|
72
|
+
await this.tmux.killSession(tmuxRef.session);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function isProcessAlreadyGone(error) {
|
|
77
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=TmuxAgentRuntime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/tmux/TmuxAgentRuntime.ts"],"sourcesContent":["import { TmuxManager } from \"../../terminal/TmuxManager.js\";\nimport { TtyWriter } from \"../../terminal/TtyWriter.js\";\nimport { AgentPidPollTimeoutError, AgentTerminalNotFoundError } from \"../errors.js\";\nimport { pollForPid } from \"./PidPolling.js\";\nimport { parseTmuxRuntimeRef } from \"./TmuxRuntimeRef.js\";\nimport type {\n AgentRuntimeAvailability,\n InteractiveAgentRuntime,\n RuntimeFocusInput,\n RuntimeSendDeps,\n RuntimeSendInput,\n RuntimeStartInput,\n RuntimeStartResult,\n RuntimeStopInput,\n} from \"../types.js\";\n\nexport class TmuxAgentRuntime implements InteractiveAgentRuntime {\n readonly provider = \"tmux\" as const;\n private readonly tmux: TmuxManager;\n\n constructor(tmux: TmuxManager = new TmuxManager()) {\n this.tmux = tmux;\n }\n\n async isAvailable(): Promise<AgentRuntimeAvailability> {\n if (await this.tmux.isAvailable()) {\n return { ok: true, insideRuntime: Boolean(process.env.TMUX) };\n }\n return {\n ok: false,\n reason: \"binary-missing\",\n detail: \"tmux is not installed or not in PATH.\",\n };\n }\n\n async startAgent(\n input: RuntimeStartInput & {\n command?: string;\n matches?: (psCommand: string) => boolean;\n pollIntervalMs?: number;\n },\n ): Promise<RuntimeStartResult> {\n if (!input.command || !input.matches || input.pollIntervalMs === undefined) {\n throw new Error(\"Tmux start requires command, process matcher, and poll interval.\");\n }\n\n if (await this.tmux.sessionExists(input.name)) {\n await this.tmux.killSession(input.name);\n }\n\n await this.tmux.createSession(input.name, input.cwd);\n await this.tmux.sendKeys(input.name, input.command);\n\n const pid = await pollForPid(\n this.tmux,\n input.name,\n input.matches,\n input.pollIntervalMs,\n input.timeoutMs,\n );\n if (pid === null) {\n await this.tmux.killSession(input.name);\n throw new AgentPidPollTimeoutError(input.name, input.command, input.timeoutMs);\n }\n\n return {\n pid,\n runtimeRef: { session: input.name },\n };\n }\n\n async send(input: RuntimeSendInput, deps?: RuntimeSendDeps): Promise<void> {\n if (!deps) {\n throw new Error(\"Tmux send requires terminal lookup dependencies.\");\n }\n const location = await deps.focusManager.findTerminal(input.agent.pid);\n if (!location) {\n throw new AgentTerminalNotFoundError(input.agent.name, input.agent.pid);\n }\n await (deps.writer ?? TtyWriter.send)(location, input.prompt);\n }\n\n async focus(input: RuntimeFocusInput): Promise<boolean> {\n const location = await input.focusManager.findTerminal(input.agent.pid);\n if (!location) return false;\n return await input.focusManager.focusTerminal(location);\n }\n\n async stop(input: RuntimeStopInput): Promise<void> {\n const killProcess = input.killProcess ?? ((pid, signal) => process.kill(pid, signal));\n try {\n killProcess(input.agent.pid, \"SIGTERM\");\n } catch (error) {\n if (!isProcessAlreadyGone(error)) {\n throw error;\n }\n }\n\n const tmuxRef = parseTmuxRuntimeRef(input.runtimeRef);\n if (tmuxRef) {\n await this.tmux.killSession(tmuxRef.session);\n }\n }\n}\n\nfunction isProcessAlreadyGone(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as NodeJS.ErrnoException).code === \"ESRCH\"\n );\n}\n"],"names":["TmuxManager","TtyWriter","AgentPidPollTimeoutError","AgentTerminalNotFoundError","pollForPid","parseTmuxRuntimeRef","TmuxAgentRuntime","provider","tmux","isAvailable","ok","insideRuntime","Boolean","process","env","TMUX","reason","detail","startAgent","input","command","matches","pollIntervalMs","undefined","Error","sessionExists","name","killSession","createSession","cwd","sendKeys","pid","timeoutMs","runtimeRef","session","send","deps","location","focusManager","findTerminal","agent","writer","prompt","focus","focusTerminal","stop","killProcess","signal","kill","error","isProcessAlreadyGone","tmuxRef","code"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TmuxRuntimeRef.d.ts","sourceRoot":"","sources":["../../../src/runtime/tmux/TmuxRuntimeRef.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAIzE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function parseTmuxRuntimeRef(value) {
|
|
2
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
3
|
+
const session = value.session;
|
|
4
|
+
return typeof session === "string" && session.trim() ? {
|
|
5
|
+
session
|
|
6
|
+
} : null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=TmuxRuntimeRef.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/tmux/TmuxRuntimeRef.ts"],"sourcesContent":["export interface TmuxRuntimeRef {\n session: string;\n}\n\nexport function parseTmuxRuntimeRef(value: unknown): TmuxRuntimeRef | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n const session = (value as { session?: unknown }).session;\n return typeof session === \"string\" && session.trim() ? { session } : null;\n}\n"],"names":["parseTmuxRuntimeRef","value","Array","isArray","session","trim"],"mappings":"AAIA,OAAO,SAASA,oBAAoBC,KAAc;IAChD,IAAI,CAACA,SAAS,OAAOA,UAAU,YAAYC,MAAMC,OAAO,CAACF,QAAQ,OAAO;IACxE,MAAMG,UAAU,AAACH,MAAgCG,OAAO;IACxD,OAAO,OAAOA,YAAY,YAAYA,QAAQC,IAAI,KAAK;QAAED;IAAQ,IAAI;AACvE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AgentInfo } from "../adapters/AgentAdapter.js";
|
|
2
|
+
import type { TerminalLocation } from "../terminal/TerminalFocusManager.js";
|
|
3
|
+
import type { AgentRuntimeProvider } from "../utils/AgentRegistry.js";
|
|
4
|
+
export type AgentRuntimeAvailability = {
|
|
5
|
+
ok: true;
|
|
6
|
+
insideRuntime: boolean;
|
|
7
|
+
currentPaneId?: string;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
reason: "binary-missing" | "backend-unreachable";
|
|
11
|
+
detail: string;
|
|
12
|
+
};
|
|
13
|
+
export interface RuntimeStartInput {
|
|
14
|
+
name: string;
|
|
15
|
+
cwd: string;
|
|
16
|
+
kind: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
timeoutMs: number;
|
|
19
|
+
}
|
|
20
|
+
export interface RuntimeStartResult {
|
|
21
|
+
pid: number;
|
|
22
|
+
runtimeRef: unknown;
|
|
23
|
+
}
|
|
24
|
+
export interface RuntimeTargetInput {
|
|
25
|
+
agent: Pick<AgentInfo, "name" | "pid">;
|
|
26
|
+
runtimeRef: unknown | null;
|
|
27
|
+
}
|
|
28
|
+
export interface RuntimeSendInput extends RuntimeTargetInput {
|
|
29
|
+
prompt: string;
|
|
30
|
+
}
|
|
31
|
+
export interface RuntimeFocusInput extends RuntimeTargetInput {
|
|
32
|
+
focusManager: {
|
|
33
|
+
findTerminal(pid: number): Promise<TerminalLocation | null>;
|
|
34
|
+
focusTerminal(location: TerminalLocation): Promise<boolean>;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface RuntimeStopInput extends RuntimeTargetInput {
|
|
38
|
+
killProcess?: (pid: number, signal: NodeJS.Signals) => void;
|
|
39
|
+
}
|
|
40
|
+
export interface RuntimeSendDeps {
|
|
41
|
+
focusManager: {
|
|
42
|
+
findTerminal(pid: number): Promise<TerminalLocation | null>;
|
|
43
|
+
};
|
|
44
|
+
writer?: (location: TerminalLocation, text: string) => Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
export interface InteractiveAgentRuntime {
|
|
47
|
+
provider: AgentRuntimeProvider;
|
|
48
|
+
isAvailable(): Promise<AgentRuntimeAvailability>;
|
|
49
|
+
startAgent(input: RuntimeStartInput): Promise<RuntimeStartResult>;
|
|
50
|
+
send(input: RuntimeSendInput, deps?: RuntimeSendDeps): Promise<void>;
|
|
51
|
+
focus(input: RuntimeFocusInput): Promise<boolean>;
|
|
52
|
+
stop(input: RuntimeStopInput): Promise<void>;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +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,qCAAqC,CAAC;AAC5E,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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/types.ts"],"sourcesContent":["import type { AgentInfo } from \"../adapters/AgentAdapter.js\";\nimport type { TerminalLocation } from \"../terminal/TerminalFocusManager.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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TerminalFocusManager.d.ts","sourceRoot":"","sources":["../../src/terminal/TerminalFocusManager.ts"],"names":[],"mappings":"AAOA,oBAAY,YAAY;
|
|
1
|
+
{"version":3,"file":"TerminalFocusManager.d.ts","sourceRoot":"","sources":["../../src/terminal/TerminalFocusManager.ts"],"names":[],"mappings":"AAOA,oBAAY,YAAY;IACtB,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,YAAY,iBAAiB;IAC7B,OAAO,YAAY;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAaD;;;;GAIG;AACH,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;IAExD;;OAEG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAqDjE;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;YA6BnD,eAAe;YA2Bf,gBAAgB;YAShB,YAAY;YA2BZ,iBAAiB;YAsCjB,qBAAqB;YAoCrB,gBAAgB;YAQhB,aAAa;YASb,kBAAkB;YAqBlB,sBAAsB;CAmBrC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { execFile } from
|
|
2
|
-
import { promisify } from
|
|
3
|
-
import { getProcessTty } from
|
|
4
|
-
import { escapeAppleScript } from
|
|
1
|
+
import { execFile } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
import { getProcessTty } from "../utils/process.js";
|
|
4
|
+
import { escapeAppleScript } from "../utils/applescript.js";
|
|
5
5
|
const execFileAsync = promisify(execFile);
|
|
6
6
|
export var TerminalType = /*#__PURE__*/ function(TerminalType) {
|
|
7
7
|
TerminalType["TMUX"] = "tmux";
|
|
@@ -17,11 +17,11 @@ export class TerminalFocusManager {
|
|
|
17
17
|
this.debug = debug;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
* Find the terminal location (emulator info) for a given process ID
|
|
21
|
+
*/ async findTerminal(pid) {
|
|
22
22
|
const ttyShort = getProcessTty(pid);
|
|
23
23
|
// If no TTY or invalid, we can't find the terminal
|
|
24
|
-
if (!ttyShort || ttyShort ===
|
|
24
|
+
if (!ttyShort || ttyShort === "?") {
|
|
25
25
|
this.debug?.(`findTerminal(pid=${pid}): no usable TTY, cannot resolve terminal`);
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
@@ -33,39 +33,39 @@ export class TerminalFocusManager {
|
|
|
33
33
|
this.debug?.(`findTerminal: matched tmux (identifier=${tmuxLocation.identifier})`);
|
|
34
34
|
return tmuxLocation;
|
|
35
35
|
}
|
|
36
|
-
this.debug?.(
|
|
36
|
+
this.debug?.("findTerminal: tmux no match");
|
|
37
37
|
// 2. Check WezTerm (cross-platform, via its CLI — no AppleScript)
|
|
38
38
|
const weztermLocation = await this.findWeztermPane(fullTty);
|
|
39
39
|
if (weztermLocation) {
|
|
40
40
|
this.debug?.(`findTerminal: matched wezterm (pane_id=${weztermLocation.identifier})`);
|
|
41
41
|
return weztermLocation;
|
|
42
42
|
}
|
|
43
|
-
this.debug?.(
|
|
43
|
+
this.debug?.("findTerminal: wezterm no match");
|
|
44
44
|
// 3. Check iTerm2
|
|
45
45
|
const itermLocation = await this.findITerm2Session(fullTty);
|
|
46
46
|
if (itermLocation) {
|
|
47
47
|
this.debug?.(`findTerminal: matched iTerm2 (tty=${itermLocation.tty})`);
|
|
48
48
|
return itermLocation;
|
|
49
49
|
}
|
|
50
|
-
this.debug?.(
|
|
50
|
+
this.debug?.("findTerminal: iTerm2 no match");
|
|
51
51
|
// 4. Check Terminal.app
|
|
52
52
|
const terminalAppLocation = await this.findTerminalAppWindow(fullTty);
|
|
53
53
|
if (terminalAppLocation) {
|
|
54
54
|
this.debug?.(`findTerminal: matched Terminal.app (tty=${terminalAppLocation.tty})`);
|
|
55
55
|
return terminalAppLocation;
|
|
56
56
|
}
|
|
57
|
-
this.debug?.(
|
|
57
|
+
this.debug?.("findTerminal: Terminal.app no match");
|
|
58
58
|
// 5. Fallback: we know the TTY but not the emulator wrapper
|
|
59
|
-
this.debug?.(
|
|
59
|
+
this.debug?.("findTerminal: no emulator matched; returning UNKNOWN");
|
|
60
60
|
return {
|
|
61
61
|
type: "unknown",
|
|
62
|
-
identifier:
|
|
62
|
+
identifier: "",
|
|
63
63
|
tty: fullTty
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
* Focus the terminal identified by the location
|
|
68
|
+
*/ async focusTerminal(location) {
|
|
69
69
|
this.debug?.(`focusTerminal: focusing ${location.type} (identifier=${location.identifier}, tty=${location.tty})`);
|
|
70
70
|
let success = false;
|
|
71
71
|
try {
|
|
@@ -88,21 +88,21 @@ export class TerminalFocusManager {
|
|
|
88
88
|
} catch {
|
|
89
89
|
success = false;
|
|
90
90
|
}
|
|
91
|
-
this.debug?.(`focusTerminal: ${success ?
|
|
91
|
+
this.debug?.(`focusTerminal: ${success ? "succeeded" : "failed"} for ${location.type}`);
|
|
92
92
|
return success;
|
|
93
93
|
}
|
|
94
94
|
async findWeztermPane(tty) {
|
|
95
95
|
try {
|
|
96
|
-
const { stdout } = await execFileAsync(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
const { stdout } = await execFileAsync("wezterm", [
|
|
97
|
+
"cli",
|
|
98
|
+
"list",
|
|
99
|
+
"--format",
|
|
100
|
+
"json"
|
|
101
101
|
]);
|
|
102
102
|
const panes = JSON.parse(stdout);
|
|
103
103
|
if (!Array.isArray(panes)) return null;
|
|
104
104
|
for (const pane of panes){
|
|
105
|
-
if (pane && typeof pane.tty_name ===
|
|
105
|
+
if (pane && typeof pane.tty_name === "string" && pane.tty_name === tty && pane.pane_id != null) {
|
|
106
106
|
return {
|
|
107
107
|
type: "wezterm",
|
|
108
108
|
identifier: String(pane.pane_id),
|
|
@@ -117,10 +117,10 @@ export class TerminalFocusManager {
|
|
|
117
117
|
}
|
|
118
118
|
async focusWeztermPane(paneId) {
|
|
119
119
|
try {
|
|
120
|
-
await execFileAsync(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
await execFileAsync("wezterm", [
|
|
121
|
+
"cli",
|
|
122
|
+
"activate-pane",
|
|
123
|
+
"--pane-id",
|
|
124
124
|
paneId
|
|
125
125
|
]);
|
|
126
126
|
return true;
|
|
@@ -130,16 +130,16 @@ export class TerminalFocusManager {
|
|
|
130
130
|
}
|
|
131
131
|
async findTmuxPane(tty) {
|
|
132
132
|
try {
|
|
133
|
-
const { stdout } = await execFileAsync(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
133
|
+
const { stdout } = await execFileAsync("tmux", [
|
|
134
|
+
"list-panes",
|
|
135
|
+
"-a",
|
|
136
|
+
"-F",
|
|
137
|
+
"#{pane_tty}|#{session_name}:#{window_index}.#{pane_index}"
|
|
138
138
|
]);
|
|
139
|
-
const lines = stdout.trim().split(
|
|
139
|
+
const lines = stdout.trim().split("\n");
|
|
140
140
|
for (const line of lines){
|
|
141
141
|
if (!line.trim()) continue;
|
|
142
|
-
const [paneTty, identifier] = line.split(
|
|
142
|
+
const [paneTty, identifier] = line.split("|");
|
|
143
143
|
if (paneTty === tty && identifier) {
|
|
144
144
|
return {
|
|
145
145
|
type: "tmux",
|
|
@@ -156,7 +156,7 @@ export class TerminalFocusManager {
|
|
|
156
156
|
async findITerm2Session(tty) {
|
|
157
157
|
try {
|
|
158
158
|
// Check if iTerm2 is running first to avoid launching it.
|
|
159
|
-
if (!await this.isProcessRunning(
|
|
159
|
+
if (!await this.isProcessRunning("iTerm2")) return null;
|
|
160
160
|
} catch {
|
|
161
161
|
return null;
|
|
162
162
|
}
|
|
@@ -175,8 +175,8 @@ export class TerminalFocusManager {
|
|
|
175
175
|
end repeat
|
|
176
176
|
end tell
|
|
177
177
|
`;
|
|
178
|
-
const { stdout } = await execFileAsync(
|
|
179
|
-
|
|
178
|
+
const { stdout } = await execFileAsync("osascript", [
|
|
179
|
+
"-e",
|
|
180
180
|
script
|
|
181
181
|
]);
|
|
182
182
|
if (stdout.trim() === "found") {
|
|
@@ -194,7 +194,7 @@ export class TerminalFocusManager {
|
|
|
194
194
|
async findTerminalAppWindow(tty) {
|
|
195
195
|
try {
|
|
196
196
|
// Check if Terminal.app is running
|
|
197
|
-
if (!await this.isProcessRunning(
|
|
197
|
+
if (!await this.isProcessRunning("Terminal")) return null;
|
|
198
198
|
} catch {
|
|
199
199
|
return null;
|
|
200
200
|
}
|
|
@@ -211,8 +211,8 @@ export class TerminalFocusManager {
|
|
|
211
211
|
end repeat
|
|
212
212
|
end tell
|
|
213
213
|
`;
|
|
214
|
-
const { stdout } = await execFileAsync(
|
|
215
|
-
|
|
214
|
+
const { stdout } = await execFileAsync("osascript", [
|
|
215
|
+
"-e",
|
|
216
216
|
script
|
|
217
217
|
]);
|
|
218
218
|
if (stdout.trim() === "found") {
|
|
@@ -228,17 +228,17 @@ export class TerminalFocusManager {
|
|
|
228
228
|
return null;
|
|
229
229
|
}
|
|
230
230
|
async isProcessRunning(name) {
|
|
231
|
-
const { stdout } = await execFileAsync(
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
const { stdout } = await execFileAsync("ps", [
|
|
232
|
+
"-Axo",
|
|
233
|
+
"comm"
|
|
234
234
|
]);
|
|
235
|
-
return stdout.split(
|
|
235
|
+
return stdout.split("\n").map((line)=>line.trim()).some((command)=>command === name || command.endsWith(`/${name}`));
|
|
236
236
|
}
|
|
237
237
|
async focusTmuxPane(identifier) {
|
|
238
238
|
try {
|
|
239
|
-
await execFileAsync(
|
|
240
|
-
|
|
241
|
-
|
|
239
|
+
await execFileAsync("tmux", [
|
|
240
|
+
"switch-client",
|
|
241
|
+
"-t",
|
|
242
242
|
identifier
|
|
243
243
|
]);
|
|
244
244
|
return true;
|
|
@@ -263,8 +263,8 @@ export class TerminalFocusManager {
|
|
|
263
263
|
end repeat
|
|
264
264
|
end tell
|
|
265
265
|
`;
|
|
266
|
-
const { stdout } = await execFileAsync(
|
|
267
|
-
|
|
266
|
+
const { stdout } = await execFileAsync("osascript", [
|
|
267
|
+
"-e",
|
|
268
268
|
script
|
|
269
269
|
]);
|
|
270
270
|
return stdout.trim() === "true";
|
|
@@ -285,8 +285,8 @@ export class TerminalFocusManager {
|
|
|
285
285
|
end repeat
|
|
286
286
|
end tell
|
|
287
287
|
`;
|
|
288
|
-
const { stdout } = await execFileAsync(
|
|
289
|
-
|
|
288
|
+
const { stdout } = await execFileAsync("osascript", [
|
|
289
|
+
"-e",
|
|
290
290
|
script
|
|
291
291
|
]);
|
|
292
292
|
return stdout.trim() === "true";
|
|
@@ -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?.(`focusTerminal: focusing ${location.type} (identifier=${location.identifier}, tty=${location.tty})`);\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', [\n 'cli', 'list', '--format', 'json',\n ]);\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', '-a', '-F', '#{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 { 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TmuxManager.d.ts","sourceRoot":"","sources":["../../src/terminal/TmuxManager.ts"],"names":[],"mappings":"AAKA,qBAAa,WAAW;
|
|
1
|
+
{"version":3,"file":"TmuxManager.d.ts","sourceRoot":"","sources":["../../src/terminal/TmuxManager.ts"],"names":[],"mappings":"AAKA,qBAAa,WAAW;IAChB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAS/B,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS7C,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9C;;;;;;;;;;;;;;;OAeG;IACG,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,GACtC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAyBX,UAAU;YAgBV,aAAa;YAab,iBAAiB;CAShC"}
|