@ai-devkit/agent-manager 0.37.0 → 0.38.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/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 +31 -10
- 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/TmuxManager.test.js +1 -1
- package/dist/__tests__/terminal/TmuxManager.test.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/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 +68 -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 +99 -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 +11 -347
- package/dist/terminal/TtyWriter.js.map +1 -1
- 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 +19 -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 +7 -0
- package/dist/terminal/backends/shared.d.ts.map +1 -0
- package/dist/terminal/backends/shared.js +35 -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 +21 -0
- package/dist/terminal/types.d.ts.map +1 -0
- package/dist/terminal/types.js +10 -0
- package/dist/terminal/types.js.map +1 -0
- 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/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 +36 -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/TmuxManager.test.ts +1 -1
- 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/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 +87 -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} +34 -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 +16 -336
- package/src/terminal/backends/index.ts +21 -0
- package/src/terminal/backends/iterm2.ts +126 -0
- package/src/terminal/backends/shared.ts +42 -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 +22 -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,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;AAEnD,qBAAa,SAAS;WACP,IAAI,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAWhE,OAAO,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAU7E"}
|