@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.
Files changed (295) hide show
  1. package/dist/AgentManager.d.ts +0 -4
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +2 -2
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/capacity/anthropic.test.js +115 -0
  6. package/dist/__tests__/capacity/anthropic.test.js.map +1 -0
  7. package/dist/__tests__/capacity/boundaries.test.js +45 -0
  8. package/dist/__tests__/capacity/boundaries.test.js.map +1 -0
  9. package/dist/__tests__/capacity/claude.test.js +3 -3
  10. package/dist/__tests__/capacity/claude.test.js.map +1 -1
  11. package/dist/__tests__/capacity/codex.test.js +3 -1
  12. package/dist/__tests__/capacity/codex.test.js.map +1 -1
  13. package/dist/__tests__/capacity/openai.test.js +21 -12
  14. package/dist/__tests__/capacity/openai.test.js.map +1 -1
  15. package/dist/__tests__/capacity/wham.test.js +1 -1
  16. package/dist/__tests__/capacity/wham.test.js.map +1 -1
  17. package/dist/__tests__/capacity/zai.test.js +7 -8
  18. package/dist/__tests__/capacity/zai.test.js.map +1 -1
  19. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js +2 -1
  20. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -1
  21. package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -1
  22. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js +7 -15
  23. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -1
  24. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js +3 -1
  25. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -1
  26. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js +11 -26
  27. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -1
  28. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js +3 -7
  29. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -1
  30. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js +5 -11
  31. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js.map +1 -1
  32. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js +9 -19
  33. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js.map +1 -1
  34. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js +3 -7
  35. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js.map +1 -1
  36. package/dist/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.js +31 -10
  37. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -0
  38. package/dist/__tests__/harnesses/runtimeProfiles.test.js +89 -0
  39. package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -0
  40. package/dist/__tests__/print/DurableAgent.test.js +4 -6
  41. package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
  42. package/dist/__tests__/print/DurableAgentRepository.test.js +1 -12
  43. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
  44. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
  45. package/dist/__tests__/terminal/TmuxManager.test.js +1 -1
  46. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
  47. package/dist/capacity/index.d.ts +9 -19
  48. package/dist/capacity/index.d.ts.map +1 -1
  49. package/dist/capacity/index.js +11 -4
  50. package/dist/capacity/index.js.map +1 -1
  51. package/dist/capacity/providers/anthropic.d.ts +9 -0
  52. package/dist/capacity/providers/anthropic.d.ts.map +1 -0
  53. package/dist/capacity/{claude.js → providers/anthropic.js} +10 -128
  54. package/dist/capacity/providers/anthropic.js.map +1 -0
  55. package/dist/capacity/providers/openai-platform.d.ts +14 -0
  56. package/dist/capacity/providers/openai-platform.d.ts.map +1 -0
  57. package/dist/capacity/providers/openai-platform.js +120 -0
  58. package/dist/capacity/providers/openai-platform.js.map +1 -0
  59. package/dist/capacity/providers/openai-subscription.d.ts +20 -0
  60. package/dist/capacity/providers/openai-subscription.d.ts.map +1 -0
  61. package/dist/capacity/providers/openai-subscription.js +129 -0
  62. package/dist/capacity/providers/openai-subscription.js.map +1 -0
  63. package/dist/capacity/providers/zai.d.ts +8 -0
  64. package/dist/capacity/providers/zai.d.ts.map +1 -0
  65. package/dist/capacity/{zai.js → providers/zai.js} +17 -62
  66. package/dist/capacity/providers/zai.js.map +1 -0
  67. package/dist/capacity/sources/claude.d.ts +9 -0
  68. package/dist/capacity/sources/claude.d.ts.map +1 -0
  69. package/dist/capacity/sources/claude.js +17 -0
  70. package/dist/capacity/sources/claude.js.map +1 -0
  71. package/dist/capacity/{codex.d.ts → sources/codex.d.ts} +5 -9
  72. package/dist/capacity/sources/codex.d.ts.map +1 -0
  73. package/dist/capacity/{codex.js → sources/codex.js} +31 -84
  74. package/dist/capacity/sources/codex.js.map +1 -0
  75. package/dist/capacity/sources/pi.d.ts +30 -0
  76. package/dist/capacity/sources/pi.d.ts.map +1 -0
  77. package/dist/capacity/sources/pi.js +81 -0
  78. package/dist/capacity/sources/pi.js.map +1 -0
  79. package/dist/capacity/types.d.ts +2 -0
  80. package/dist/capacity/types.d.ts.map +1 -1
  81. package/dist/capacity/types.js +1 -1
  82. package/dist/capacity/types.js.map +1 -1
  83. package/dist/harnesses/claude/credentials.d.ts +10 -0
  84. package/dist/harnesses/claude/credentials.d.ts.map +1 -0
  85. package/dist/harnesses/claude/credentials.js +112 -0
  86. package/dist/harnesses/claude/credentials.js.map +1 -0
  87. package/dist/harnesses/claude/readiness.d.ts +3 -0
  88. package/dist/harnesses/claude/readiness.d.ts.map +1 -0
  89. package/dist/harnesses/claude/readiness.js +63 -0
  90. package/dist/harnesses/claude/readiness.js.map +1 -0
  91. package/dist/harnesses/codex/credentials.d.ts +15 -0
  92. package/dist/harnesses/codex/credentials.d.ts.map +1 -0
  93. package/dist/harnesses/codex/credentials.js +58 -0
  94. package/dist/harnesses/codex/credentials.js.map +1 -0
  95. package/dist/harnesses/codex/readiness.d.ts +3 -0
  96. package/dist/harnesses/codex/readiness.d.ts.map +1 -0
  97. package/dist/harnesses/codex/readiness.js +60 -0
  98. package/dist/harnesses/codex/readiness.js.map +1 -0
  99. package/dist/harnesses/copilot/readiness.d.ts +3 -0
  100. package/dist/harnesses/copilot/readiness.d.ts.map +1 -0
  101. package/dist/harnesses/copilot/readiness.js +39 -0
  102. package/dist/harnesses/copilot/readiness.js.map +1 -0
  103. package/dist/harnesses/opencode/readiness.d.ts +3 -0
  104. package/dist/harnesses/opencode/readiness.d.ts.map +1 -0
  105. package/dist/harnesses/opencode/readiness.js +50 -0
  106. package/dist/harnesses/opencode/readiness.js.map +1 -0
  107. package/dist/harnesses/pi/credentials.d.ts +22 -0
  108. package/dist/harnesses/pi/credentials.d.ts.map +1 -0
  109. package/dist/harnesses/pi/credentials.js +98 -0
  110. package/dist/harnesses/pi/credentials.js.map +1 -0
  111. package/dist/harnesses/pi/readiness.d.ts +3 -0
  112. package/dist/harnesses/pi/readiness.d.ts.map +1 -0
  113. package/dist/harnesses/pi/readiness.js +96 -0
  114. package/dist/harnesses/pi/readiness.js.map +1 -0
  115. package/dist/harnesses/readiness/AgentReadiness.d.ts +6 -0
  116. package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -0
  117. package/dist/harnesses/readiness/AgentReadiness.js +68 -0
  118. package/dist/harnesses/readiness/AgentReadiness.js.map +1 -0
  119. package/dist/harnesses/readiness/checks.d.ts +31 -0
  120. package/dist/harnesses/readiness/checks.d.ts.map +1 -0
  121. package/dist/harnesses/readiness/checks.js +270 -0
  122. package/dist/harnesses/readiness/checks.js.map +1 -0
  123. package/dist/{readiness/AgentReadiness.d.ts → harnesses/readiness/types.d.ts} +19 -10
  124. package/dist/harnesses/readiness/types.d.ts.map +1 -0
  125. package/dist/harnesses/readiness/types.js +4 -0
  126. package/dist/harnesses/readiness/types.js.map +1 -0
  127. package/dist/harnesses/runtimeProfiles.d.ts +11 -0
  128. package/dist/harnesses/runtimeProfiles.d.ts.map +1 -0
  129. package/dist/harnesses/runtimeProfiles.js +99 -0
  130. package/dist/harnesses/runtimeProfiles.js.map +1 -0
  131. package/dist/index.d.ts +16 -42
  132. package/dist/index.d.ts.map +1 -1
  133. package/dist/index.js +9 -23
  134. package/dist/index.js.map +1 -1
  135. package/dist/runtime/ManagedAgentRuntime.d.ts +3 -3
  136. package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -1
  137. package/dist/runtime/ManagedAgentRuntime.js +6 -20
  138. package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
  139. package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -1
  140. package/dist/runtime/herdr/HerdrAgentDiscovery.js +2 -43
  141. package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -1
  142. package/dist/runtime/tmux/PidPolling.d.ts +1 -1
  143. package/dist/runtime/tmux/PidPolling.d.ts.map +1 -1
  144. package/dist/runtime/tmux/PidPolling.js.map +1 -1
  145. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +1 -1
  146. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -1
  147. package/dist/runtime/tmux/TmuxAgentRuntime.js +1 -1
  148. package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -1
  149. package/dist/runtime/tmux/TmuxManager.d.ts +12 -0
  150. package/dist/runtime/tmux/TmuxManager.d.ts.map +1 -0
  151. package/dist/{terminal → runtime/tmux}/TmuxManager.js +9 -28
  152. package/dist/runtime/tmux/TmuxManager.js.map +1 -0
  153. package/dist/runtime/types.d.ts +1 -1
  154. package/dist/runtime/types.d.ts.map +1 -1
  155. package/dist/runtime/types.js.map +1 -1
  156. package/dist/terminal/TerminalFocusManager.d.ts +4 -32
  157. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  158. package/dist/terminal/TerminalFocusManager.js +17 -267
  159. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  160. package/dist/terminal/TtyWriter.d.ts +1 -44
  161. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  162. package/dist/terminal/TtyWriter.js +11 -347
  163. package/dist/terminal/TtyWriter.js.map +1 -1
  164. package/dist/terminal/backends/index.d.ts +5 -0
  165. package/dist/terminal/backends/index.d.ts.map +1 -0
  166. package/dist/terminal/backends/index.js +19 -0
  167. package/dist/terminal/backends/index.js.map +1 -0
  168. package/dist/terminal/backends/iterm2.d.ts +3 -0
  169. package/dist/terminal/backends/iterm2.d.ts.map +1 -0
  170. package/dist/terminal/backends/iterm2.js +135 -0
  171. package/dist/terminal/backends/iterm2.js.map +1 -0
  172. package/dist/terminal/backends/shared.d.ts +7 -0
  173. package/dist/terminal/backends/shared.d.ts.map +1 -0
  174. package/dist/terminal/backends/shared.js +35 -0
  175. package/dist/terminal/backends/shared.js.map +1 -0
  176. package/dist/terminal/backends/terminal-app.d.ts +3 -0
  177. package/dist/terminal/backends/terminal-app.d.ts.map +1 -0
  178. package/dist/terminal/backends/terminal-app.js +129 -0
  179. package/dist/terminal/backends/terminal-app.js.map +1 -0
  180. package/dist/terminal/backends/tmux.d.ts +3 -0
  181. package/dist/terminal/backends/tmux.d.ts.map +1 -0
  182. package/dist/terminal/backends/tmux.js +76 -0
  183. package/dist/terminal/backends/tmux.js.map +1 -0
  184. package/dist/terminal/backends/wezterm.d.ts +3 -0
  185. package/dist/terminal/backends/wezterm.d.ts.map +1 -0
  186. package/dist/terminal/backends/wezterm.js +71 -0
  187. package/dist/terminal/backends/wezterm.js.map +1 -0
  188. package/dist/terminal/types.d.ts +21 -0
  189. package/dist/terminal/types.d.ts.map +1 -0
  190. package/dist/terminal/types.js +10 -0
  191. package/dist/terminal/types.js.map +1 -0
  192. package/package.json +1 -1
  193. package/src/AgentManager.ts +1 -1
  194. package/src/__tests__/capacity/anthropic.test.ts +105 -0
  195. package/src/__tests__/capacity/boundaries.test.ts +36 -0
  196. package/src/__tests__/capacity/claude.test.ts +3 -8
  197. package/src/__tests__/capacity/codex.test.ts +12 -35
  198. package/src/__tests__/capacity/fixtures/openai-codex-auth.json +1 -1
  199. package/src/__tests__/capacity/openai.test.ts +15 -15
  200. package/src/__tests__/capacity/wham.test.ts +1 -1
  201. package/src/__tests__/capacity/zai.test.ts +27 -62
  202. package/src/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.ts +2 -2
  203. package/src/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.ts +1 -1
  204. package/src/__tests__/harnesses/codex/durable/CodexCliProbe.test.ts +14 -19
  205. package/src/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.ts +3 -3
  206. package/src/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.ts +24 -30
  207. package/src/__tests__/harnesses/codex/durable/CodexPrintRunner.test.ts +4 -8
  208. package/src/__tests__/harnesses/pi/durable/PiCliProbe.test.ts +7 -11
  209. package/src/__tests__/harnesses/pi/durable/PiPrintAgentService.test.ts +19 -22
  210. package/src/__tests__/harnesses/pi/durable/PiPrintRunner.test.ts +7 -8
  211. package/src/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.ts +36 -9
  212. package/src/__tests__/harnesses/runtimeProfiles.test.ts +110 -0
  213. package/src/__tests__/print/DurableAgent.test.ts +4 -13
  214. package/src/__tests__/print/DurableAgentRepository.test.ts +1 -13
  215. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +1 -1
  216. package/src/__tests__/terminal/TmuxManager.test.ts +1 -1
  217. package/src/capacity/index.ts +29 -23
  218. package/src/capacity/{claude.ts → providers/anthropic.ts} +16 -131
  219. package/src/capacity/providers/openai-platform.ts +150 -0
  220. package/src/capacity/{wham.ts → providers/openai-subscription.ts} +86 -8
  221. package/src/capacity/{zai.ts → providers/zai.ts} +29 -111
  222. package/src/capacity/sources/claude.ts +30 -0
  223. package/src/capacity/{codex.ts → sources/codex.ts} +54 -124
  224. package/src/capacity/sources/pi.ts +131 -0
  225. package/src/capacity/types.ts +3 -0
  226. package/src/harnesses/claude/credentials.ts +122 -0
  227. package/src/harnesses/claude/readiness.ts +69 -0
  228. package/src/harnesses/codex/credentials.ts +81 -0
  229. package/src/harnesses/codex/readiness.ts +72 -0
  230. package/src/harnesses/copilot/readiness.ts +33 -0
  231. package/src/harnesses/opencode/readiness.ts +48 -0
  232. package/src/harnesses/pi/credentials.ts +129 -0
  233. package/src/harnesses/pi/readiness.ts +104 -0
  234. package/src/harnesses/readiness/AgentReadiness.ts +87 -0
  235. package/src/harnesses/readiness/checks.ts +336 -0
  236. package/src/harnesses/readiness/types.ts +90 -0
  237. package/src/{utils/agents.ts → harnesses/runtimeProfiles.ts} +34 -38
  238. package/src/index.ts +15 -128
  239. package/src/runtime/ManagedAgentRuntime.ts +7 -22
  240. package/src/runtime/herdr/HerdrAgentDiscovery.ts +3 -19
  241. package/src/runtime/tmux/PidPolling.ts +1 -1
  242. package/src/runtime/tmux/TmuxAgentRuntime.ts +1 -1
  243. package/src/{terminal → runtime/tmux}/TmuxManager.ts +9 -30
  244. package/src/runtime/types.ts +1 -1
  245. package/src/terminal/TerminalFocusManager.ts +19 -292
  246. package/src/terminal/TtyWriter.ts +16 -336
  247. package/src/terminal/backends/index.ts +21 -0
  248. package/src/terminal/backends/iterm2.ts +126 -0
  249. package/src/terminal/backends/shared.ts +42 -0
  250. package/src/terminal/backends/terminal-app.ts +122 -0
  251. package/src/terminal/backends/tmux.ts +62 -0
  252. package/src/terminal/backends/wezterm.ts +65 -0
  253. package/src/terminal/types.ts +22 -0
  254. package/dist/__tests__/readiness/AgentReadiness.test.js.map +0 -1
  255. package/dist/__tests__/utils/agents.test.js +0 -93
  256. package/dist/__tests__/utils/agents.test.js.map +0 -1
  257. package/dist/capacity/claude.d.ts +0 -17
  258. package/dist/capacity/claude.d.ts.map +0 -1
  259. package/dist/capacity/claude.js.map +0 -1
  260. package/dist/capacity/codex.d.ts.map +0 -1
  261. package/dist/capacity/codex.js.map +0 -1
  262. package/dist/capacity/openai.d.ts +0 -47
  263. package/dist/capacity/openai.d.ts.map +0 -1
  264. package/dist/capacity/openai.js +0 -307
  265. package/dist/capacity/openai.js.map +0 -1
  266. package/dist/capacity/wham.d.ts +0 -16
  267. package/dist/capacity/wham.d.ts.map +0 -1
  268. package/dist/capacity/wham.js +0 -66
  269. package/dist/capacity/wham.js.map +0 -1
  270. package/dist/capacity/zai.d.ts +0 -14
  271. package/dist/capacity/zai.d.ts.map +0 -1
  272. package/dist/capacity/zai.js.map +0 -1
  273. package/dist/readiness/AgentReadiness.d.ts.map +0 -1
  274. package/dist/readiness/AgentReadiness.js +0 -614
  275. package/dist/readiness/AgentReadiness.js.map +0 -1
  276. package/dist/terminal/TmuxManager.d.ts +0 -28
  277. package/dist/terminal/TmuxManager.d.ts.map +0 -1
  278. package/dist/terminal/TmuxManager.js.map +0 -1
  279. package/dist/terminal/index.d.ts +0 -5
  280. package/dist/terminal/index.d.ts.map +0 -1
  281. package/dist/terminal/index.js +0 -5
  282. package/dist/terminal/index.js.map +0 -1
  283. package/dist/utils/agents.d.ts +0 -16
  284. package/dist/utils/agents.d.ts.map +0 -1
  285. package/dist/utils/agents.js +0 -117
  286. package/dist/utils/agents.js.map +0 -1
  287. package/dist/utils/index.d.ts +0 -8
  288. package/dist/utils/index.d.ts.map +0 -1
  289. package/dist/utils/index.js +0 -6
  290. package/dist/utils/index.js.map +0 -1
  291. package/src/__tests__/utils/agents.test.ts +0 -105
  292. package/src/capacity/openai.ts +0 -355
  293. package/src/readiness/AgentReadiness.ts +0 -730
  294. package/src/terminal/index.ts +0 -4
  295. 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 { escapeAppleScript } from "../utils/applescript.js";
5
- const execFileAsync = promisify(execFile);
6
- export var TerminalType = /*#__PURE__*/ function(TerminalType) {
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
- * Find the terminal location (emulator info) for a given process ID
21
- */ async findTerminal(pid) {
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/${ttyShort}`;
16
+ const fullTty = `/dev/${tty}`;
29
17
  this.debug?.(`findTerminal(pid=${pid}): resolving terminal for ${fullTty}`);
30
- // 1. Check tmux (most specific if running inside it)
31
- const tmuxLocation = await this.findTmuxPane(fullTty);
32
- if (tmuxLocation) {
33
- this.debug?.(`findTerminal: matched tmux (identifier=${tmuxLocation.identifier})`);
34
- return tmuxLocation;
35
- }
36
- this.debug?.("findTerminal: tmux no match");
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: "unknown",
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
- switch(location.type){
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 "./TerminalFocusManager.js";
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":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAmBlE,qBAAa,SAAS;IACpB;;;;;;;;;;;;;;OAcG;WACU,IAAI,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7E;;;;;;;;;;;;OAYG;WACU,OAAO,CAAC,QAAQ,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;mBAkBvD,cAAc;mBAOd,iBAAiB;mBAOjB,gBAAgB;mBAkChB,qBAAqB;mBA+BrB,cAAc;mBA8Bd,WAAW;mBAWX,iBAAiB;IAqBtC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAsBb,aAAa;mBAuBb,kBAAkB;CA0DxC"}
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"}