@ai-devkit/agent-manager 0.31.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.
Files changed (519) hide show
  1. package/dist/AgentManager.d.ts +3 -3
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +80 -79
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/AgentManager.test.js +413 -388
  6. package/dist/__tests__/AgentManager.test.js.map +1 -1
  7. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +642 -642
  8. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +1 -1
  9. package/dist/__tests__/adapters/CodexAdapter.test.js +322 -2321
  10. package/dist/__tests__/adapters/CodexAdapter.test.js.map +1 -1
  11. package/dist/__tests__/adapters/CopilotAdapter.test.js +254 -248
  12. package/dist/__tests__/adapters/CopilotAdapter.test.js.map +1 -1
  13. package/dist/__tests__/adapters/GeminiCliAdapter.test.js +564 -558
  14. package/dist/__tests__/adapters/GeminiCliAdapter.test.js.map +1 -1
  15. package/dist/__tests__/adapters/GrokCliAdapter.test.js +114 -114
  16. package/dist/__tests__/adapters/GrokCliAdapter.test.js.map +1 -1
  17. package/dist/__tests__/adapters/OpenCodeAdapter.test.js +169 -169
  18. package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +1 -1
  19. package/dist/__tests__/capacity/codex.test.js +93 -93
  20. package/dist/__tests__/capacity/codex.test.js.map +1 -1
  21. package/dist/__tests__/capacity/index.test.js +17 -17
  22. package/dist/__tests__/capacity/index.test.js.map +1 -1
  23. package/dist/__tests__/durable/CodexCliProbe.test.js +60 -60
  24. package/dist/__tests__/durable/CodexCliProbe.test.js.map +1 -1
  25. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +28 -28
  26. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +1 -1
  27. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +30 -30
  28. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +1 -1
  29. package/dist/__tests__/durable/CodexPrintAgentService.test.js +71 -71
  30. package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +1 -1
  31. package/dist/__tests__/durable/CodexPrintRunner.test.js +125 -125
  32. package/dist/__tests__/durable/CodexPrintRunner.test.js.map +1 -1
  33. package/dist/__tests__/print/ClaudeCliProbe.test.js +20 -20
  34. package/dist/__tests__/print/ClaudeCliProbe.test.js.map +1 -1
  35. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +20 -20
  36. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
  37. package/dist/__tests__/print/ClaudePrintAgentService.test.js +58 -58
  38. package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
  39. package/dist/__tests__/print/ClaudePrintRunner.test.js +55 -55
  40. package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
  41. package/dist/__tests__/print/DurableAgent.test.js +9 -9
  42. package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
  43. package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js +40 -40
  44. package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js.map +1 -1
  45. package/dist/__tests__/print/DurableAgentRepository.test.js +66 -66
  46. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
  47. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +34 -34
  48. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +1 -1
  49. package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +132 -132
  50. package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +1 -1
  51. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +194 -0
  52. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +1 -0
  53. package/dist/__tests__/providers/codex/CodexSessionMapping.test.js +86 -0
  54. package/dist/__tests__/providers/codex/CodexSessionMapping.test.js.map +1 -0
  55. package/dist/__tests__/providers/codex/CodexSessionParser.test.js +254 -0
  56. package/dist/__tests__/providers/codex/CodexSessionParser.test.js.map +1 -0
  57. package/dist/__tests__/providers/pi/PiAdapter.test.js +337 -0
  58. package/dist/__tests__/providers/pi/PiAdapter.test.js.map +1 -0
  59. package/dist/__tests__/providers/pi/PiSessionParser.test.js +246 -0
  60. package/dist/__tests__/providers/pi/PiSessionParser.test.js.map +1 -0
  61. package/dist/__tests__/providers/pi/PiSessionTracker.test.js +108 -0
  62. package/dist/__tests__/providers/pi/PiSessionTracker.test.js.map +1 -0
  63. package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js +33 -33
  64. package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js.map +1 -1
  65. package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js +16 -16
  66. package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js.map +1 -1
  67. package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js +52 -52
  68. package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js.map +1 -1
  69. package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js +44 -44
  70. package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js.map +1 -1
  71. package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js +126 -126
  72. package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js.map +1 -1
  73. package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js +14 -14
  74. package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js.map +1 -1
  75. package/dist/__tests__/readiness/AgentReadiness.test.js +301 -0
  76. package/dist/__tests__/readiness/AgentReadiness.test.js.map +1 -0
  77. package/dist/__tests__/runtime/AgentRuntime.test.js +13 -0
  78. package/dist/__tests__/runtime/AgentRuntime.test.js.map +1 -0
  79. package/dist/__tests__/runtime/HerdrAgentRuntime.test.js +452 -0
  80. package/dist/__tests__/runtime/HerdrAgentRuntime.test.js.map +1 -0
  81. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js +588 -0
  82. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -0
  83. package/dist/__tests__/terminal/TerminalFocusManager.test.js +100 -100
  84. package/dist/__tests__/terminal/TerminalFocusManager.test.js.map +1 -1
  85. package/dist/__tests__/terminal/TmuxManager.test.js +101 -101
  86. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
  87. package/dist/__tests__/terminal/TtyWriter.test.js +185 -185
  88. package/dist/__tests__/terminal/TtyWriter.test.js.map +1 -1
  89. package/dist/__tests__/utils/AgentRegistry.test.js +335 -217
  90. package/dist/__tests__/utils/AgentRegistry.test.js.map +1 -1
  91. package/dist/__tests__/utils/ClaudeSessionParser.test.js +103 -101
  92. package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +1 -1
  93. package/dist/__tests__/utils/agent-requests.test.js +43 -43
  94. package/dist/__tests__/utils/agent-requests.test.js.map +1 -1
  95. package/dist/__tests__/utils/agents.test.js +17 -17
  96. package/dist/__tests__/utils/agents.test.js.map +1 -1
  97. package/dist/__tests__/utils/matching.test.js +92 -92
  98. package/dist/__tests__/utils/matching.test.js.map +1 -1
  99. package/dist/__tests__/utils/process.test.js +108 -108
  100. package/dist/__tests__/utils/process.test.js.map +1 -1
  101. package/dist/__tests__/utils/session.test.js +53 -53
  102. package/dist/__tests__/utils/session.test.js.map +1 -1
  103. package/dist/adapters/AgentAdapter.d.ts +2 -2
  104. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  105. package/dist/adapters/AgentAdapter.js +1 -1
  106. package/dist/adapters/AgentAdapter.js.map +1 -1
  107. package/dist/adapters/CopilotAdapter.d.ts +2 -2
  108. package/dist/adapters/CopilotAdapter.d.ts.map +1 -1
  109. package/dist/adapters/CopilotAdapter.js +51 -51
  110. package/dist/adapters/CopilotAdapter.js.map +1 -1
  111. package/dist/adapters/GeminiCliAdapter.d.ts +2 -2
  112. package/dist/adapters/GeminiCliAdapter.d.ts.map +1 -1
  113. package/dist/adapters/GeminiCliAdapter.js +86 -86
  114. package/dist/adapters/GeminiCliAdapter.js.map +1 -1
  115. package/dist/adapters/GrokCliAdapter.d.ts +1 -1
  116. package/dist/adapters/GrokCliAdapter.d.ts.map +1 -1
  117. package/dist/adapters/GrokCliAdapter.js +80 -80
  118. package/dist/adapters/GrokCliAdapter.js.map +1 -1
  119. package/dist/adapters/OpenCodeAdapter.d.ts +1 -1
  120. package/dist/adapters/OpenCodeAdapter.d.ts.map +1 -1
  121. package/dist/adapters/OpenCodeAdapter.js +37 -36
  122. package/dist/adapters/OpenCodeAdapter.js.map +1 -1
  123. package/dist/adapters/index.d.ts +9 -9
  124. package/dist/adapters/index.d.ts.map +1 -1
  125. package/dist/adapters/index.js +8 -8
  126. package/dist/adapters/index.js.map +1 -1
  127. package/dist/capacity/codex.d.ts +3 -3
  128. package/dist/capacity/codex.d.ts.map +1 -1
  129. package/dist/capacity/codex.js +57 -57
  130. package/dist/capacity/codex.js.map +1 -1
  131. package/dist/capacity/index.d.ts +3 -3
  132. package/dist/capacity/index.d.ts.map +1 -1
  133. package/dist/capacity/index.js +8 -8
  134. package/dist/capacity/index.js.map +1 -1
  135. package/dist/capacity/types.d.ts +1 -1
  136. package/dist/capacity/types.js.map +1 -1
  137. package/dist/database/connection.d.ts +1 -1
  138. package/dist/database/connection.d.ts.map +1 -1
  139. package/dist/database/connection.js +15 -15
  140. package/dist/database/connection.js.map +1 -1
  141. package/dist/database/index.d.ts +3 -3
  142. package/dist/database/index.d.ts.map +1 -1
  143. package/dist/database/index.js +2 -2
  144. package/dist/database/index.js.map +1 -1
  145. package/dist/database/migrations/005_agent_runtime.sql +2 -0
  146. package/dist/database/schema.d.ts +1 -1
  147. package/dist/database/schema.d.ts.map +1 -1
  148. package/dist/database/schema.js +7 -7
  149. package/dist/database/schema.js.map +1 -1
  150. package/dist/durable/DurableAgent.d.ts +9 -9
  151. package/dist/durable/DurableAgent.d.ts.map +1 -1
  152. package/dist/durable/DurableAgent.js +16 -16
  153. package/dist/durable/DurableAgent.js.map +1 -1
  154. package/dist/durable/DurableAgentRepository.d.ts +4 -4
  155. package/dist/durable/DurableAgentRepository.d.ts.map +1 -1
  156. package/dist/durable/DurableAgentRepository.js +49 -48
  157. package/dist/durable/DurableAgentRepository.js.map +1 -1
  158. package/dist/durable/process.d.ts +1 -1
  159. package/dist/durable/process.d.ts.map +1 -1
  160. package/dist/durable/process.js +14 -14
  161. package/dist/durable/process.js.map +1 -1
  162. package/dist/durable/run.d.ts +2 -2
  163. package/dist/durable/run.d.ts.map +1 -1
  164. package/dist/durable/run.js +6 -6
  165. package/dist/durable/run.js.map +1 -1
  166. package/dist/durable/utils.d.ts +1 -1
  167. package/dist/durable/utils.d.ts.map +1 -1
  168. package/dist/durable/utils.js +4 -4
  169. package/dist/durable/utils.js.map +1 -1
  170. package/dist/index.d.ts +46 -41
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +27 -25
  173. package/dist/index.js.map +1 -1
  174. package/dist/providers/claude/ClaudeAgentMapper.d.ts +4 -4
  175. package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +1 -1
  176. package/dist/providers/claude/ClaudeAgentMapper.js +10 -10
  177. package/dist/providers/claude/ClaudeAgentMapper.js.map +1 -1
  178. package/dist/providers/claude/ClaudeCodeAdapter.d.ts +1 -1
  179. package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +1 -1
  180. package/dist/providers/claude/ClaudeCodeAdapter.js +14 -14
  181. package/dist/providers/claude/ClaudeCodeAdapter.js.map +1 -1
  182. package/dist/providers/claude/ClaudeSessionLocator.d.ts +4 -4
  183. package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +1 -1
  184. package/dist/providers/claude/ClaudeSessionLocator.js +79 -79
  185. package/dist/providers/claude/ClaudeSessionLocator.js.map +1 -1
  186. package/dist/providers/claude/ClaudeSessionParser.d.ts +2 -2
  187. package/dist/providers/claude/ClaudeSessionParser.d.ts.map +1 -1
  188. package/dist/providers/claude/ClaudeSessionParser.js +99 -99
  189. package/dist/providers/claude/ClaudeSessionParser.js.map +1 -1
  190. package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +1 -1
  191. package/dist/providers/claude/durable/ClaudeCliProbe.js +16 -16
  192. package/dist/providers/claude/durable/ClaudeCliProbe.js.map +1 -1
  193. package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts +5 -5
  194. package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +1 -1
  195. package/dist/providers/claude/durable/ClaudePrintAgentService.js +10 -10
  196. package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +1 -1
  197. package/dist/providers/claude/durable/ClaudePrintRunner.d.ts +4 -4
  198. package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +1 -1
  199. package/dist/providers/claude/durable/ClaudePrintRunner.js +18 -18
  200. package/dist/providers/claude/durable/ClaudePrintRunner.js.map +1 -1
  201. package/dist/providers/claude/durable/ClaudeStreamParser.d.ts +2 -2
  202. package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +1 -1
  203. package/dist/providers/claude/durable/ClaudeStreamParser.js +17 -17
  204. package/dist/providers/claude/durable/ClaudeStreamParser.js.map +1 -1
  205. package/dist/providers/codex/CodexAdapter.d.ts +27 -0
  206. package/dist/providers/codex/CodexAdapter.d.ts.map +1 -0
  207. package/dist/providers/codex/CodexAdapter.js +162 -0
  208. package/dist/providers/codex/CodexAdapter.js.map +1 -0
  209. package/dist/providers/codex/CodexAgentMapper.d.ts +9 -0
  210. package/dist/providers/codex/CodexAgentMapper.d.ts.map +1 -0
  211. package/dist/providers/codex/CodexAgentMapper.js +35 -0
  212. package/dist/providers/codex/CodexAgentMapper.js.map +1 -0
  213. package/dist/providers/codex/CodexSessionLocator.d.ts +44 -0
  214. package/dist/providers/codex/CodexSessionLocator.d.ts.map +1 -0
  215. package/dist/providers/codex/CodexSessionLocator.js +207 -0
  216. package/dist/providers/codex/CodexSessionLocator.js.map +1 -0
  217. package/dist/providers/codex/CodexSessionMapping.d.ts +23 -0
  218. package/dist/providers/codex/CodexSessionMapping.d.ts.map +1 -0
  219. package/dist/providers/codex/CodexSessionMapping.js +68 -0
  220. package/dist/providers/codex/CodexSessionMapping.js.map +1 -0
  221. package/dist/providers/codex/CodexSessionParser.d.ts +58 -0
  222. package/dist/providers/codex/CodexSessionParser.d.ts.map +1 -0
  223. package/dist/providers/codex/CodexSessionParser.js +262 -0
  224. package/dist/providers/codex/CodexSessionParser.js.map +1 -0
  225. package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +1 -1
  226. package/dist/providers/codex/durable/CodexCliProbe.js +22 -22
  227. package/dist/providers/codex/durable/CodexCliProbe.js.map +1 -1
  228. package/dist/providers/codex/durable/CodexPrintAgentService.d.ts +6 -6
  229. package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +1 -1
  230. package/dist/providers/codex/durable/CodexPrintAgentService.js +10 -10
  231. package/dist/providers/codex/durable/CodexPrintAgentService.js.map +1 -1
  232. package/dist/providers/codex/durable/CodexPrintRunner.d.ts +4 -4
  233. package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +1 -1
  234. package/dist/providers/codex/durable/CodexPrintRunner.js +20 -20
  235. package/dist/providers/codex/durable/CodexPrintRunner.js.map +1 -1
  236. package/dist/providers/codex/durable/CodexStreamParser.d.ts +2 -2
  237. package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +1 -1
  238. package/dist/providers/codex/durable/CodexStreamParser.js +21 -21
  239. package/dist/providers/codex/durable/CodexStreamParser.js.map +1 -1
  240. package/dist/providers/pi/PiAdapter.d.ts +28 -0
  241. package/dist/providers/pi/PiAdapter.d.ts.map +1 -0
  242. package/dist/providers/pi/PiAdapter.js +153 -0
  243. package/dist/providers/pi/PiAdapter.js.map +1 -0
  244. package/dist/providers/pi/PiAgentMapper.d.ts +9 -0
  245. package/dist/providers/pi/PiAgentMapper.d.ts.map +1 -0
  246. package/dist/providers/pi/PiAgentMapper.js +37 -0
  247. package/dist/providers/pi/PiAgentMapper.js.map +1 -0
  248. package/dist/providers/pi/PiSessionLocator.d.ts +23 -0
  249. package/dist/providers/pi/PiSessionLocator.d.ts.map +1 -0
  250. package/dist/providers/pi/PiSessionLocator.js +79 -0
  251. package/dist/providers/pi/PiSessionLocator.js.map +1 -0
  252. package/dist/providers/pi/PiSessionParser.d.ts +36 -0
  253. package/dist/providers/pi/PiSessionParser.d.ts.map +1 -0
  254. package/dist/providers/pi/PiSessionParser.js +191 -0
  255. package/dist/providers/pi/PiSessionParser.js.map +1 -0
  256. package/dist/providers/pi/PiSessionTracker.d.ts +23 -0
  257. package/dist/providers/pi/PiSessionTracker.d.ts.map +1 -0
  258. package/dist/providers/pi/PiSessionTracker.js +69 -0
  259. package/dist/providers/pi/PiSessionTracker.js.map +1 -0
  260. package/dist/providers/pi/durable/PiCliProbe.d.ts.map +1 -1
  261. package/dist/providers/pi/durable/PiCliProbe.js +15 -15
  262. package/dist/providers/pi/durable/PiCliProbe.js.map +1 -1
  263. package/dist/providers/pi/durable/PiPrintAgentService.d.ts +6 -6
  264. package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +1 -1
  265. package/dist/providers/pi/durable/PiPrintAgentService.js +10 -10
  266. package/dist/providers/pi/durable/PiPrintAgentService.js.map +1 -1
  267. package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +1 -1
  268. package/dist/providers/pi/durable/PiPrintProtocol.js +18 -18
  269. package/dist/providers/pi/durable/PiPrintProtocol.js.map +1 -1
  270. package/dist/providers/pi/durable/PiPrintRunner.d.ts +4 -4
  271. package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +1 -1
  272. package/dist/providers/pi/durable/PiPrintRunner.js +15 -15
  273. package/dist/providers/pi/durable/PiPrintRunner.js.map +1 -1
  274. package/dist/providers/pi/durable/PiStreamParser.d.ts +1 -1
  275. package/dist/providers/pi/durable/PiStreamParser.d.ts.map +1 -1
  276. package/dist/providers/pi/durable/PiStreamParser.js +16 -16
  277. package/dist/providers/pi/durable/PiStreamParser.js.map +1 -1
  278. package/dist/readiness/AgentReadiness.d.ts +67 -0
  279. package/dist/readiness/AgentReadiness.d.ts.map +1 -0
  280. package/dist/readiness/AgentReadiness.js +614 -0
  281. package/dist/readiness/AgentReadiness.js.map +1 -0
  282. package/dist/runtime/ManagedAgentRuntime.d.ts +69 -0
  283. package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -0
  284. package/dist/runtime/ManagedAgentRuntime.js +156 -0
  285. package/dist/runtime/ManagedAgentRuntime.js.map +1 -0
  286. package/dist/runtime/RuntimeFactory.d.ts +4 -0
  287. package/dist/runtime/RuntimeFactory.d.ts.map +1 -0
  288. package/dist/runtime/RuntimeFactory.js +11 -0
  289. package/dist/runtime/RuntimeFactory.js.map +1 -0
  290. package/dist/runtime/errors.d.ts +27 -0
  291. package/dist/runtime/errors.d.ts.map +1 -0
  292. package/dist/runtime/errors.js +42 -0
  293. package/dist/runtime/errors.js.map +1 -0
  294. package/dist/runtime/herdr/HerdrAgentRuntime.d.ts +31 -0
  295. package/dist/runtime/herdr/HerdrAgentRuntime.d.ts.map +1 -0
  296. package/dist/runtime/herdr/HerdrAgentRuntime.js +184 -0
  297. package/dist/runtime/herdr/HerdrAgentRuntime.js.map +1 -0
  298. package/dist/runtime/herdr/HerdrCliClient.d.ts +13 -0
  299. package/dist/runtime/herdr/HerdrCliClient.d.ts.map +1 -0
  300. package/dist/runtime/herdr/HerdrCliClient.js +60 -0
  301. package/dist/runtime/herdr/HerdrCliClient.js.map +1 -0
  302. package/dist/runtime/herdr/HerdrErrors.d.ts +7 -0
  303. package/dist/runtime/herdr/HerdrErrors.d.ts.map +1 -0
  304. package/dist/runtime/herdr/HerdrErrors.js +10 -0
  305. package/dist/runtime/herdr/HerdrErrors.js.map +1 -0
  306. package/dist/runtime/herdr/HerdrResponseParsers.d.ts +14 -0
  307. package/dist/runtime/herdr/HerdrResponseParsers.d.ts.map +1 -0
  308. package/dist/runtime/herdr/HerdrResponseParsers.js +96 -0
  309. package/dist/runtime/herdr/HerdrResponseParsers.js.map +1 -0
  310. package/dist/runtime/herdr/HerdrRuntimeRef.d.ts +9 -0
  311. package/dist/runtime/herdr/HerdrRuntimeRef.d.ts.map +1 -0
  312. package/dist/runtime/herdr/HerdrRuntimeRef.js +33 -0
  313. package/dist/runtime/herdr/HerdrRuntimeRef.js.map +1 -0
  314. package/dist/runtime/tmux/PidPolling.d.ts +5 -0
  315. package/dist/runtime/tmux/PidPolling.d.ts.map +1 -0
  316. package/dist/runtime/tmux/PidPolling.js +24 -0
  317. package/dist/runtime/tmux/PidPolling.js.map +1 -0
  318. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +17 -0
  319. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -0
  320. package/dist/runtime/tmux/TmuxAgentRuntime.js +80 -0
  321. package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -0
  322. package/dist/runtime/tmux/TmuxRuntimeRef.d.ts +5 -0
  323. package/dist/runtime/tmux/TmuxRuntimeRef.d.ts.map +1 -0
  324. package/dist/runtime/tmux/TmuxRuntimeRef.js +9 -0
  325. package/dist/runtime/tmux/TmuxRuntimeRef.js.map +1 -0
  326. package/dist/runtime/types.d.ts +54 -0
  327. package/dist/runtime/types.d.ts.map +1 -0
  328. package/dist/runtime/types.js +3 -0
  329. package/dist/runtime/types.js.map +1 -0
  330. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  331. package/dist/terminal/TerminalFocusManager.js +50 -50
  332. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  333. package/dist/terminal/TmuxManager.d.ts.map +1 -1
  334. package/dist/terminal/TmuxManager.js +47 -47
  335. package/dist/terminal/TmuxManager.js.map +1 -1
  336. package/dist/terminal/TtyWriter.d.ts +1 -1
  337. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  338. package/dist/terminal/TtyWriter.js +89 -89
  339. package/dist/terminal/TtyWriter.js.map +1 -1
  340. package/dist/terminal/index.d.ts +4 -4
  341. package/dist/terminal/index.js +3 -3
  342. package/dist/terminal/index.js.map +1 -1
  343. package/dist/utils/AgentRegistry.d.ts +10 -2
  344. package/dist/utils/AgentRegistry.d.ts.map +1 -1
  345. package/dist/utils/AgentRegistry.js +57 -24
  346. package/dist/utils/AgentRegistry.js.map +1 -1
  347. package/dist/utils/agent-requests.d.ts.map +1 -1
  348. package/dist/utils/agent-requests.js +5 -5
  349. package/dist/utils/agent-requests.js.map +1 -1
  350. package/dist/utils/agents.d.ts +2 -2
  351. package/dist/utils/agents.d.ts.map +1 -1
  352. package/dist/utils/agents.js +15 -15
  353. package/dist/utils/agents.js.map +1 -1
  354. package/dist/utils/applescript.js +1 -1
  355. package/dist/utils/applescript.js.map +1 -1
  356. package/dist/utils/index.d.ts +6 -6
  357. package/dist/utils/index.d.ts.map +1 -1
  358. package/dist/utils/index.js +4 -4
  359. package/dist/utils/index.js.map +1 -1
  360. package/dist/utils/matching.d.ts +2 -2
  361. package/dist/utils/matching.d.ts.map +1 -1
  362. package/dist/utils/matching.js +4 -4
  363. package/dist/utils/matching.js.map +1 -1
  364. package/dist/utils/process.d.ts +1 -1
  365. package/dist/utils/process.d.ts.map +1 -1
  366. package/dist/utils/process.js +74 -74
  367. package/dist/utils/process.js.map +1 -1
  368. package/dist/utils/session.d.ts +1 -1
  369. package/dist/utils/session.d.ts.map +1 -1
  370. package/dist/utils/session.js +7 -7
  371. package/dist/utils/session.js.map +1 -1
  372. package/dist/utils/sortAgents.d.ts +2 -2
  373. package/dist/utils/sortAgents.d.ts.map +1 -1
  374. package/dist/utils/sortAgents.js +5 -5
  375. package/dist/utils/sortAgents.js.map +1 -1
  376. package/package.json +18 -19
  377. package/src/AgentManager.ts +283 -281
  378. package/src/__tests__/AgentManager.test.ts +917 -907
  379. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +1657 -1368
  380. package/src/__tests__/adapters/CodexAdapter.test.ts +365 -1698
  381. package/src/__tests__/adapters/CopilotAdapter.test.ts +576 -481
  382. package/src/__tests__/adapters/GeminiCliAdapter.test.ts +1189 -1157
  383. package/src/__tests__/adapters/GrokCliAdapter.test.ts +325 -272
  384. package/src/__tests__/adapters/OpenCodeAdapter.test.ts +510 -455
  385. package/src/__tests__/capacity/codex.test.ts +178 -91
  386. package/src/__tests__/capacity/index.test.ts +27 -18
  387. package/src/__tests__/durable/CodexCliProbe.test.ts +75 -53
  388. package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +51 -40
  389. package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +89 -64
  390. package/src/__tests__/durable/CodexPrintAgentService.test.ts +196 -118
  391. package/src/__tests__/durable/CodexPrintRunner.test.ts +282 -162
  392. package/src/__tests__/fixtures/fake-claude.cjs +20 -13
  393. package/src/__tests__/fixtures/fake-codex.cjs +41 -30
  394. package/src/__tests__/print/ClaudeCliProbe.test.ts +27 -21
  395. package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +48 -40
  396. package/src/__tests__/print/ClaudePrintAgentService.test.ts +118 -67
  397. package/src/__tests__/print/ClaudePrintRunner.test.ts +136 -83
  398. package/src/__tests__/print/DurableAgent.test.ts +19 -16
  399. package/src/__tests__/print/DurableAgentRepository.sqlite.test.ts +109 -86
  400. package/src/__tests__/print/DurableAgentRepository.test.ts +170 -137
  401. package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +65 -65
  402. package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +400 -377
  403. package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +182 -0
  404. package/src/__tests__/providers/codex/CodexSessionMapping.test.ts +63 -0
  405. package/src/__tests__/providers/codex/CodexSessionParser.test.ts +192 -0
  406. package/src/__tests__/providers/pi/PiAdapter.test.ts +310 -0
  407. package/src/__tests__/providers/pi/PiSessionParser.test.ts +190 -0
  408. package/src/__tests__/providers/pi/PiSessionTracker.test.ts +79 -0
  409. package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +48 -32
  410. package/src/__tests__/providers/pi/durable/PiDurableAgentRepository.test.ts +24 -23
  411. package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +131 -59
  412. package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +66 -28
  413. package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +236 -90
  414. package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +20 -18
  415. package/src/__tests__/readiness/AgentReadiness.test.ts +242 -0
  416. package/src/__tests__/runtime/AgentRuntime.test.ts +8 -0
  417. package/src/__tests__/runtime/HerdrAgentRuntime.test.ts +358 -0
  418. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +555 -0
  419. package/src/__tests__/terminal/TerminalFocusManager.test.ts +254 -253
  420. package/src/__tests__/terminal/TmuxManager.test.ts +157 -157
  421. package/src/__tests__/terminal/TtyWriter.test.ts +423 -419
  422. package/src/__tests__/utils/AgentRegistry.test.ts +506 -402
  423. package/src/__tests__/utils/ClaudeSessionParser.test.ts +276 -242
  424. package/src/__tests__/utils/agent-requests.test.ts +76 -56
  425. package/src/__tests__/utils/agents.test.ts +20 -20
  426. package/src/__tests__/utils/matching.test.ts +206 -171
  427. package/src/__tests__/utils/process.test.ts +276 -262
  428. package/src/__tests__/utils/session.test.ts +133 -139
  429. package/src/adapters/AgentAdapter.ts +134 -126
  430. package/src/adapters/CopilotAdapter.ts +405 -395
  431. package/src/adapters/GeminiCliAdapter.ts +598 -600
  432. package/src/adapters/GrokCliAdapter.ts +353 -342
  433. package/src/adapters/OpenCodeAdapter.ts +285 -259
  434. package/src/adapters/index.ts +15 -9
  435. package/src/capacity/codex.ts +137 -84
  436. package/src/capacity/index.ts +18 -13
  437. package/src/capacity/types.ts +1 -1
  438. package/src/database/connection.ts +73 -68
  439. package/src/database/index.ts +6 -6
  440. package/src/database/migrations/005_agent_runtime.sql +2 -0
  441. package/src/database/schema.ts +40 -38
  442. package/src/durable/DurableAgent.ts +85 -85
  443. package/src/durable/DurableAgentRepository.ts +409 -260
  444. package/src/durable/process.ts +22 -21
  445. package/src/durable/run.ts +61 -51
  446. package/src/durable/utils.ts +46 -41
  447. package/src/index.ts +145 -86
  448. package/src/providers/claude/ClaudeAgentMapper.ts +51 -50
  449. package/src/providers/claude/ClaudeCodeAdapter.ts +144 -136
  450. package/src/providers/claude/ClaudeSessionLocator.ts +291 -293
  451. package/src/providers/claude/ClaudeSessionParser.ts +322 -338
  452. package/src/providers/claude/durable/ClaudeCliProbe.ts +42 -37
  453. package/src/providers/claude/durable/ClaudePrintAgentService.ts +63 -50
  454. package/src/providers/claude/durable/ClaudePrintRunner.ts +79 -69
  455. package/src/providers/claude/durable/ClaudeStreamParser.ts +91 -62
  456. package/src/providers/codex/CodexAdapter.ts +205 -0
  457. package/src/providers/codex/CodexAgentMapper.ts +35 -0
  458. package/src/providers/codex/CodexSessionLocator.ts +279 -0
  459. package/src/providers/codex/CodexSessionMapping.ts +89 -0
  460. package/src/providers/codex/CodexSessionParser.ts +385 -0
  461. package/src/providers/codex/durable/CodexCliProbe.ts +50 -42
  462. package/src/providers/codex/durable/CodexPrintAgentService.ts +63 -49
  463. package/src/providers/codex/durable/CodexPrintRunner.ts +79 -69
  464. package/src/providers/codex/durable/CodexStreamParser.ts +97 -84
  465. package/src/providers/pi/PiAdapter.ts +183 -0
  466. package/src/providers/pi/PiAgentMapper.ts +36 -0
  467. package/src/providers/pi/PiSessionLocator.ts +95 -0
  468. package/src/providers/pi/PiSessionParser.ts +284 -0
  469. package/src/providers/pi/PiSessionTracker.ts +87 -0
  470. package/src/providers/pi/durable/PiCliProbe.ts +42 -34
  471. package/src/providers/pi/durable/PiPrintAgentService.ts +61 -53
  472. package/src/providers/pi/durable/PiPrintProtocol.ts +31 -29
  473. package/src/providers/pi/durable/PiPrintRunner.ts +75 -68
  474. package/src/providers/pi/durable/PiStreamParser.ts +82 -72
  475. package/src/readiness/AgentReadiness.ts +727 -0
  476. package/src/runtime/ManagedAgentRuntime.ts +266 -0
  477. package/src/runtime/RuntimeFactory.ts +13 -0
  478. package/src/runtime/errors.ts +50 -0
  479. package/src/runtime/herdr/HerdrAgentRuntime.ts +190 -0
  480. package/src/runtime/herdr/HerdrCliClient.ts +78 -0
  481. package/src/runtime/herdr/HerdrErrors.ts +9 -0
  482. package/src/runtime/herdr/HerdrResponseParsers.ts +76 -0
  483. package/src/runtime/herdr/HerdrRuntimeRef.ts +41 -0
  484. package/src/runtime/tmux/PidPolling.ts +34 -0
  485. package/src/runtime/tmux/TmuxAgentRuntime.ts +113 -0
  486. package/src/runtime/tmux/TmuxRuntimeRef.ts +9 -0
  487. package/src/runtime/types.ts +56 -0
  488. package/src/terminal/TerminalFocusManager.ts +215 -212
  489. package/src/terminal/TmuxManager.ts +99 -92
  490. package/src/terminal/TtyWriter.ts +203 -194
  491. package/src/terminal/index.ts +4 -4
  492. package/src/utils/AgentRegistry.ts +299 -238
  493. package/src/utils/agent-requests.ts +16 -16
  494. package/src/utils/agents.ts +41 -38
  495. package/src/utils/applescript.ts +4 -4
  496. package/src/utils/index.ts +12 -6
  497. package/src/utils/matching.ts +43 -43
  498. package/src/utils/process.ts +261 -258
  499. package/src/utils/session.ts +66 -66
  500. package/src/utils/sortAgents.ts +35 -33
  501. package/tsconfig.json +2 -8
  502. package/vitest.config.ts +16 -16
  503. package/.eslintrc.json +0 -31
  504. package/dist/__tests__/adapters/PiAdapter.test.js +0 -618
  505. package/dist/__tests__/adapters/PiAdapter.test.js.map +0 -1
  506. package/dist/__tests__/database/DurableAgentsDatabase.test.js +0 -128
  507. package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +0 -1
  508. package/dist/adapters/CodexAdapter.d.ts +0 -109
  509. package/dist/adapters/CodexAdapter.d.ts.map +0 -1
  510. package/dist/adapters/CodexAdapter.js +0 -710
  511. package/dist/adapters/CodexAdapter.js.map +0 -1
  512. package/dist/adapters/PiAdapter.d.ts +0 -63
  513. package/dist/adapters/PiAdapter.d.ts.map +0 -1
  514. package/dist/adapters/PiAdapter.js +0 -453
  515. package/dist/adapters/PiAdapter.js.map +0 -1
  516. package/src/__tests__/adapters/PiAdapter.test.ts +0 -458
  517. package/src/__tests__/database/DurableAgentsDatabase.test.ts +0 -102
  518. package/src/adapters/CodexAdapter.ts +0 -923
  519. package/src/adapters/PiAdapter.ts +0 -598
@@ -1,11 +1,11 @@
1
- import { execFile } from 'child_process';
2
- import { promisify } from 'util';
1
+ import { execFile } from "child_process";
2
+ import { promisify } from "util";
3
3
  const execFileAsync = promisify(execFile);
4
4
  export class TmuxManager {
5
5
  async isAvailable() {
6
6
  try {
7
- await execFileAsync('tmux', [
8
- '-V'
7
+ await execFileAsync("tmux", [
8
+ "-V"
9
9
  ]);
10
10
  return true;
11
11
  } catch {
@@ -14,9 +14,9 @@ export class TmuxManager {
14
14
  }
15
15
  async sessionExists(name) {
16
16
  try {
17
- await execFileAsync('tmux', [
18
- 'has-session',
19
- '-t',
17
+ await execFileAsync("tmux", [
18
+ "has-session",
19
+ "-t",
20
20
  name
21
21
  ]);
22
22
  return true;
@@ -25,29 +25,29 @@ export class TmuxManager {
25
25
  }
26
26
  }
27
27
  async createSession(name, cwd) {
28
- await execFileAsync('tmux', [
29
- 'new-session',
30
- '-d',
31
- '-s',
28
+ await execFileAsync("tmux", [
29
+ "new-session",
30
+ "-d",
31
+ "-s",
32
32
  name,
33
- '-c',
33
+ "-c",
34
34
  cwd
35
35
  ]);
36
36
  }
37
37
  async sendKeys(session, keys) {
38
- await execFileAsync('tmux', [
39
- 'send-keys',
40
- '-t',
38
+ await execFileAsync("tmux", [
39
+ "send-keys",
40
+ "-t",
41
41
  session,
42
42
  keys,
43
- 'Enter'
43
+ "Enter"
44
44
  ]);
45
45
  }
46
46
  async killSession(name) {
47
47
  try {
48
- await execFileAsync('tmux', [
49
- 'kill-session',
50
- '-t',
48
+ await execFileAsync("tmux", [
49
+ "kill-session",
50
+ "-t",
51
51
  name
52
52
  ]);
53
53
  } catch {
@@ -55,21 +55,21 @@ export class TmuxManager {
55
55
  }
56
56
  }
57
57
  /**
58
- * Find the actual agent process PID inside a tmux pane.
59
- *
60
- * Strategy: BFS the process tree, return the deepest process whose
61
- * `ps` command line is accepted by `matches`. The caller supplies the
62
- * matcher so this method has no agent-type knowledge.
63
- *
64
- * This handles two real-world process shapes:
65
- * - Wrapper case: shell → claude-wrapper (matches) → claude (matches, deeper)
66
- * → returns the deeper one
67
- * - Subprocess case: shell → claude (matches) → MCP server child (doesn't match)
68
- * → returns claude, not the subprocess
69
- *
70
- * Returns null when no process matches yet (agent still starting); the
71
- * caller's poll loop retries.
72
- */ async findAgentPid(session, matches) {
58
+ * Find the actual agent process PID inside a tmux pane.
59
+ *
60
+ * Strategy: BFS the process tree, return the deepest process whose
61
+ * `ps` command line is accepted by `matches`. The caller supplies the
62
+ * matcher so this method has no agent-type knowledge.
63
+ *
64
+ * This handles two real-world process shapes:
65
+ * - Wrapper case: shell → claude-wrapper (matches) → claude (matches, deeper)
66
+ * → returns the deeper one
67
+ * - Subprocess case: shell → claude (matches) → MCP server child (doesn't match)
68
+ * → returns claude, not the subprocess
69
+ *
70
+ * Returns null when no process matches yet (agent still starting); the
71
+ * caller's poll loop retries.
72
+ */ async findAgentPid(session, matches) {
73
73
  const panePid = await this.getPanePid(session);
74
74
  if (panePid === null) return null;
75
75
  const visited = new Set();
@@ -92,14 +92,14 @@ export class TmuxManager {
92
92
  }
93
93
  async getPanePid(session) {
94
94
  try {
95
- const { stdout } = await execFileAsync('tmux', [
96
- 'list-panes',
97
- '-t',
95
+ const { stdout } = await execFileAsync("tmux", [
96
+ "list-panes",
97
+ "-t",
98
98
  session,
99
- '-F',
100
- '#{pane_pid}'
99
+ "-F",
100
+ "#{pane_pid}"
101
101
  ]);
102
- const panePid = parseInt(stdout.trim().split('\n')[0], 10);
102
+ const panePid = parseInt(stdout.trim().split("\n")[0], 10);
103
103
  return isNaN(panePid) ? null : panePid;
104
104
  } catch {
105
105
  return null;
@@ -107,22 +107,22 @@ export class TmuxManager {
107
107
  }
108
108
  async pgrepChildren(pid) {
109
109
  try {
110
- const { stdout } = await execFileAsync('pgrep', [
111
- '-P',
110
+ const { stdout } = await execFileAsync("pgrep", [
111
+ "-P",
112
112
  String(pid)
113
113
  ]);
114
- return stdout.trim().split('\n').map((s)=>parseInt(s, 10)).filter((n)=>!isNaN(n));
114
+ return stdout.trim().split("\n").map((s)=>parseInt(s, 10)).filter((n)=>!isNaN(n));
115
115
  } catch {
116
116
  return [];
117
117
  }
118
118
  }
119
119
  async getProcessCommand(pid) {
120
120
  try {
121
- const { stdout } = await execFileAsync('ps', [
122
- '-p',
121
+ const { stdout } = await execFileAsync("ps", [
122
+ "-p",
123
123
  String(pid),
124
- '-o',
125
- 'command='
124
+ "-o",
125
+ "command="
126
126
  ]);
127
127
  const trimmed = stdout.trim();
128
128
  return trimmed || null;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/terminal/TmuxManager.ts"],"sourcesContent":["import { execFile } from 'child_process';\nimport { promisify } from 'util';\n\nconst execFileAsync = promisify(execFile);\n\nexport class TmuxManager {\n async isAvailable(): Promise<boolean> {\n try {\n await execFileAsync('tmux', ['-V']);\n return true;\n } catch {\n return false;\n }\n }\n\n async sessionExists(name: string): Promise<boolean> {\n try {\n await execFileAsync('tmux', ['has-session', '-t', name]);\n return true;\n } catch {\n return false;\n }\n }\n\n async createSession(name: string, cwd: string): Promise<void> {\n await execFileAsync('tmux', ['new-session', '-d', '-s', name, '-c', cwd]);\n }\n\n async sendKeys(session: string, keys: string): Promise<void> {\n await execFileAsync('tmux', ['send-keys', '-t', session, keys, 'Enter']);\n }\n\n async killSession(name: string): Promise<void> {\n try {\n await execFileAsync('tmux', ['kill-session', '-t', name]);\n } catch {\n // Already gone — ignore\n }\n }\n\n /**\n * Find the actual agent process PID inside a tmux pane.\n *\n * Strategy: BFS the process tree, return the deepest process whose\n * `ps` command line is accepted by `matches`. The caller supplies the\n * matcher so this method has no agent-type knowledge.\n *\n * This handles two real-world process shapes:\n * - Wrapper case: shell → claude-wrapper (matches) → claude (matches, deeper)\n * → returns the deeper one\n * - Subprocess case: shell → claude (matches) → MCP server child (doesn't match)\n * → returns claude, not the subprocess\n *\n * Returns null when no process matches yet (agent still starting); the\n * caller's poll loop retries.\n */\n async findAgentPid(session: string, matches: (psCommand: string) => boolean): Promise<number | null> {\n const panePid = await this.getPanePid(session);\n if (panePid === null) return null;\n\n const visited = new Set<number>();\n const queue: number[] = [panePid];\n let deepestMatch: number | null = null;\n\n while (queue.length > 0) {\n const pid = queue.shift()!;\n if (visited.has(pid)) continue;\n visited.add(pid);\n\n const command = await this.getProcessCommand(pid);\n if (command && matches(command)) {\n deepestMatch = pid;\n }\n\n const children = await this.pgrepChildren(pid);\n queue.push(...children);\n }\n\n return deepestMatch;\n }\n\n private async getPanePid(session: string): Promise<number | null> {\n try {\n const { stdout } = await execFileAsync('tmux', [\n 'list-panes', '-t', session, '-F', '#{pane_pid}',\n ]);\n const panePid = parseInt(stdout.trim().split('\\n')[0], 10);\n return isNaN(panePid) ? null : panePid;\n } catch {\n return null;\n }\n }\n\n private async pgrepChildren(pid: number): Promise<number[]> {\n try {\n const { stdout } = await execFileAsync('pgrep', ['-P', String(pid)]);\n return stdout\n .trim()\n .split('\\n')\n .map((s) => parseInt(s, 10))\n .filter((n) => !isNaN(n));\n } catch {\n return [];\n }\n }\n\n private async getProcessCommand(pid: number): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('ps', ['-p', String(pid), '-o', 'command=']);\n const trimmed = stdout.trim();\n return trimmed || null;\n } catch {\n return null;\n }\n }\n}\n"],"names":["execFile","promisify","execFileAsync","TmuxManager","isAvailable","sessionExists","name","createSession","cwd","sendKeys","session","keys","killSession","findAgentPid","matches","panePid","getPanePid","visited","Set","queue","deepestMatch","length","pid","shift","has","add","command","getProcessCommand","children","pgrepChildren","push","stdout","parseInt","trim","split","isNaN","String","map","s","filter","n","trimmed"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,gBAAgB;AACzC,SAASC,SAAS,QAAQ,OAAO;AAEjC,MAAMC,gBAAgBD,UAAUD;AAEhC,OAAO,MAAMG;IACT,MAAMC,cAAgC;QAClC,IAAI;YACA,MAAMF,cAAc,QAAQ;gBAAC;aAAK;YAClC,OAAO;QACX,EAAE,OAAM;YACJ,OAAO;QACX;IACJ;IAEA,MAAMG,cAAcC,IAAY,EAAoB;QAChD,IAAI;YACA,MAAMJ,cAAc,QAAQ;gBAAC;gBAAe;gBAAMI;aAAK;YACvD,OAAO;QACX,EAAE,OAAM;YACJ,OAAO;QACX;IACJ;IAEA,MAAMC,cAAcD,IAAY,EAAEE,GAAW,EAAiB;QAC1D,MAAMN,cAAc,QAAQ;YAAC;YAAe;YAAM;YAAMI;YAAM;YAAME;SAAI;IAC5E;IAEA,MAAMC,SAASC,OAAe,EAAEC,IAAY,EAAiB;QACzD,MAAMT,cAAc,QAAQ;YAAC;YAAa;YAAMQ;YAASC;YAAM;SAAQ;IAC3E;IAEA,MAAMC,YAAYN,IAAY,EAAiB;QAC3C,IAAI;YACA,MAAMJ,cAAc,QAAQ;gBAAC;gBAAgB;gBAAMI;aAAK;QAC5D,EAAE,OAAM;QACJ,wBAAwB;QAC5B;IACJ;IAEA;;;;;;;;;;;;;;;KAeC,GACD,MAAMO,aAAaH,OAAe,EAAEI,OAAuC,EAA0B;QACjG,MAAMC,UAAU,MAAM,IAAI,CAACC,UAAU,CAACN;QACtC,IAAIK,YAAY,MAAM,OAAO;QAE7B,MAAME,UAAU,IAAIC;QACpB,MAAMC,QAAkB;YAACJ;SAAQ;QACjC,IAAIK,eAA8B;QAElC,MAAOD,MAAME,MAAM,GAAG,EAAG;YACrB,MAAMC,MAAMH,MAAMI,KAAK;YACvB,IAAIN,QAAQO,GAAG,CAACF,MAAM;YACtBL,QAAQQ,GAAG,CAACH;YAEZ,MAAMI,UAAU,MAAM,IAAI,CAACC,iBAAiB,CAACL;YAC7C,IAAII,WAAWZ,QAAQY,UAAU;gBAC7BN,eAAeE;YACnB;YAEA,MAAMM,WAAW,MAAM,IAAI,CAACC,aAAa,CAACP;YAC1CH,MAAMW,IAAI,IAAIF;QAClB;QAEA,OAAOR;IACX;IAEA,MAAcJ,WAAWN,OAAe,EAA0B;QAC9D,IAAI;YACA,MAAM,EAAEqB,MAAM,EAAE,GAAG,MAAM7B,cAAc,QAAQ;gBAC3C;gBAAc;gBAAMQ;gBAAS;gBAAM;aACtC;YACD,MAAMK,UAAUiB,SAASD,OAAOE,IAAI,GAAGC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE;YACvD,OAAOC,MAAMpB,WAAW,OAAOA;QACnC,EAAE,OAAM;YACJ,OAAO;QACX;IACJ;IAEA,MAAcc,cAAcP,GAAW,EAAqB;QACxD,IAAI;YACA,MAAM,EAAES,MAAM,EAAE,GAAG,MAAM7B,cAAc,SAAS;gBAAC;gBAAMkC,OAAOd;aAAK;YACnE,OAAOS,OACFE,IAAI,GACJC,KAAK,CAAC,MACNG,GAAG,CAAC,CAACC,IAAMN,SAASM,GAAG,KACvBC,MAAM,CAAC,CAACC,IAAM,CAACL,MAAMK;QAC9B,EAAE,OAAM;YACJ,OAAO,EAAE;QACb;IACJ;IAEA,MAAcb,kBAAkBL,GAAW,EAA0B;QACjE,IAAI;YACA,MAAM,EAAES,MAAM,EAAE,GAAG,MAAM7B,cAAc,MAAM;gBAAC;gBAAMkC,OAAOd;gBAAM;gBAAM;aAAW;YAClF,MAAMmB,UAAUV,OAAOE,IAAI;YAC3B,OAAOQ,WAAW;QACtB,EAAE,OAAM;YACJ,OAAO;QACX;IACJ;AACJ"}
1
+ {"version":3,"sources":["../../src/terminal/TmuxManager.ts"],"sourcesContent":["import { execFile } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execFileAsync = promisify(execFile);\n\nexport class TmuxManager {\n async isAvailable(): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"-V\"]);\n return true;\n } catch {\n return false;\n }\n }\n\n async sessionExists(name: string): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"has-session\", \"-t\", name]);\n return true;\n } catch {\n return false;\n }\n }\n\n async createSession(name: string, cwd: string): Promise<void> {\n await execFileAsync(\"tmux\", [\"new-session\", \"-d\", \"-s\", name, \"-c\", cwd]);\n }\n\n async sendKeys(session: string, keys: string): Promise<void> {\n await execFileAsync(\"tmux\", [\"send-keys\", \"-t\", session, keys, \"Enter\"]);\n }\n\n async killSession(name: string): Promise<void> {\n try {\n await execFileAsync(\"tmux\", [\"kill-session\", \"-t\", name]);\n } catch {\n // Already gone — ignore\n }\n }\n\n /**\n * Find the actual agent process PID inside a tmux pane.\n *\n * Strategy: BFS the process tree, return the deepest process whose\n * `ps` command line is accepted by `matches`. The caller supplies the\n * matcher so this method has no agent-type knowledge.\n *\n * This handles two real-world process shapes:\n * - Wrapper case: shell → claude-wrapper (matches) → claude (matches, deeper)\n * → returns the deeper one\n * - Subprocess case: shell → claude (matches) → MCP server child (doesn't match)\n * → returns claude, not the subprocess\n *\n * Returns null when no process matches yet (agent still starting); the\n * caller's poll loop retries.\n */\n async findAgentPid(\n session: string,\n matches: (psCommand: string) => boolean,\n ): Promise<number | null> {\n const panePid = await this.getPanePid(session);\n if (panePid === null) return null;\n\n const visited = new Set<number>();\n const queue: number[] = [panePid];\n let deepestMatch: number | null = null;\n\n while (queue.length > 0) {\n const pid = queue.shift()!;\n if (visited.has(pid)) continue;\n visited.add(pid);\n\n const command = await this.getProcessCommand(pid);\n if (command && matches(command)) {\n deepestMatch = pid;\n }\n\n const children = await this.pgrepChildren(pid);\n queue.push(...children);\n }\n\n return deepestMatch;\n }\n\n private async getPanePid(session: string): Promise<number | null> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\n \"list-panes\",\n \"-t\",\n session,\n \"-F\",\n \"#{pane_pid}\",\n ]);\n const panePid = parseInt(stdout.trim().split(\"\\n\")[0], 10);\n return isNaN(panePid) ? null : panePid;\n } catch {\n return null;\n }\n }\n\n private async pgrepChildren(pid: number): Promise<number[]> {\n try {\n const { stdout } = await execFileAsync(\"pgrep\", [\"-P\", String(pid)]);\n return stdout\n .trim()\n .split(\"\\n\")\n .map((s) => parseInt(s, 10))\n .filter((n) => !isNaN(n));\n } catch {\n return [];\n }\n }\n\n private async getProcessCommand(pid: number): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"ps\", [\"-p\", String(pid), \"-o\", \"command=\"]);\n const trimmed = stdout.trim();\n return trimmed || null;\n } catch {\n return null;\n }\n }\n}\n"],"names":["execFile","promisify","execFileAsync","TmuxManager","isAvailable","sessionExists","name","createSession","cwd","sendKeys","session","keys","killSession","findAgentPid","matches","panePid","getPanePid","visited","Set","queue","deepestMatch","length","pid","shift","has","add","command","getProcessCommand","children","pgrepChildren","push","stdout","parseInt","trim","split","isNaN","String","map","s","filter","n","trimmed"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,gBAAgB;AACzC,SAASC,SAAS,QAAQ,OAAO;AAEjC,MAAMC,gBAAgBD,UAAUD;AAEhC,OAAO,MAAMG;IACX,MAAMC,cAAgC;QACpC,IAAI;YACF,MAAMF,cAAc,QAAQ;gBAAC;aAAK;YAClC,OAAO;QACT,EAAE,OAAM;YACN,OAAO;QACT;IACF;IAEA,MAAMG,cAAcC,IAAY,EAAoB;QAClD,IAAI;YACF,MAAMJ,cAAc,QAAQ;gBAAC;gBAAe;gBAAMI;aAAK;YACvD,OAAO;QACT,EAAE,OAAM;YACN,OAAO;QACT;IACF;IAEA,MAAMC,cAAcD,IAAY,EAAEE,GAAW,EAAiB;QAC5D,MAAMN,cAAc,QAAQ;YAAC;YAAe;YAAM;YAAMI;YAAM;YAAME;SAAI;IAC1E;IAEA,MAAMC,SAASC,OAAe,EAAEC,IAAY,EAAiB;QAC3D,MAAMT,cAAc,QAAQ;YAAC;YAAa;YAAMQ;YAASC;YAAM;SAAQ;IACzE;IAEA,MAAMC,YAAYN,IAAY,EAAiB;QAC7C,IAAI;YACF,MAAMJ,cAAc,QAAQ;gBAAC;gBAAgB;gBAAMI;aAAK;QAC1D,EAAE,OAAM;QACN,wBAAwB;QAC1B;IACF;IAEA;;;;;;;;;;;;;;;GAeC,GACD,MAAMO,aACJH,OAAe,EACfI,OAAuC,EACf;QACxB,MAAMC,UAAU,MAAM,IAAI,CAACC,UAAU,CAACN;QACtC,IAAIK,YAAY,MAAM,OAAO;QAE7B,MAAME,UAAU,IAAIC;QACpB,MAAMC,QAAkB;YAACJ;SAAQ;QACjC,IAAIK,eAA8B;QAElC,MAAOD,MAAME,MAAM,GAAG,EAAG;YACvB,MAAMC,MAAMH,MAAMI,KAAK;YACvB,IAAIN,QAAQO,GAAG,CAACF,MAAM;YACtBL,QAAQQ,GAAG,CAACH;YAEZ,MAAMI,UAAU,MAAM,IAAI,CAACC,iBAAiB,CAACL;YAC7C,IAAII,WAAWZ,QAAQY,UAAU;gBAC/BN,eAAeE;YACjB;YAEA,MAAMM,WAAW,MAAM,IAAI,CAACC,aAAa,CAACP;YAC1CH,MAAMW,IAAI,IAAIF;QAChB;QAEA,OAAOR;IACT;IAEA,MAAcJ,WAAWN,OAAe,EAA0B;QAChE,IAAI;YACF,MAAM,EAAEqB,MAAM,EAAE,GAAG,MAAM7B,cAAc,QAAQ;gBAC7C;gBACA;gBACAQ;gBACA;gBACA;aACD;YACD,MAAMK,UAAUiB,SAASD,OAAOE,IAAI,GAAGC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE;YACvD,OAAOC,MAAMpB,WAAW,OAAOA;QACjC,EAAE,OAAM;YACN,OAAO;QACT;IACF;IAEA,MAAcc,cAAcP,GAAW,EAAqB;QAC1D,IAAI;YACF,MAAM,EAAES,MAAM,EAAE,GAAG,MAAM7B,cAAc,SAAS;gBAAC;gBAAMkC,OAAOd;aAAK;YACnE,OAAOS,OACJE,IAAI,GACJC,KAAK,CAAC,MACNG,GAAG,CAAC,CAACC,IAAMN,SAASM,GAAG,KACvBC,MAAM,CAAC,CAACC,IAAM,CAACL,MAAMK;QAC1B,EAAE,OAAM;YACN,OAAO,EAAE;QACX;IACF;IAEA,MAAcb,kBAAkBL,GAAW,EAA0B;QACnE,IAAI;YACF,MAAM,EAAES,MAAM,EAAE,GAAG,MAAM7B,cAAc,MAAM;gBAAC;gBAAMkC,OAAOd;gBAAM;gBAAM;aAAW;YAClF,MAAMmB,UAAUV,OAAOE,IAAI;YAC3B,OAAOQ,WAAW;QACpB,EAAE,OAAM;YACN,OAAO;QACT;IACF;AACF"}
@@ -1,4 +1,4 @@
1
- import type { TerminalLocation } from './TerminalFocusManager.js';
1
+ import type { TerminalLocation } from "./TerminalFocusManager.js";
2
2
  export declare class TtyWriter {
3
3
  /**
4
4
  * Send a message as keyboard input to a terminal session.
@@ -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;IAClB;;;;;;;;;;;;;;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;mBASjB,gBAAgB;mBAkChB,qBAAqB;mBA+BrB,cAAc;mBAuBd,WAAW;mBAWX,iBAAiB;IAiBtC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAsBb,aAAa;mBAuBb,kBAAkB;CA0D1C"}
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,33 +1,33 @@
1
- import { execFile } from 'child_process';
2
- import { promisify } from 'util';
3
- import { TerminalType } from './TerminalFocusManager.js';
4
- import { escapeAppleScript } from '../utils/applescript.js';
1
+ import { execFile } from "child_process";
2
+ import { promisify } from "util";
3
+ import { TerminalType } from "./TerminalFocusManager.js";
4
+ import { escapeAppleScript } from "../utils/applescript.js";
5
5
  const execFileAsync = promisify(execFile);
6
6
  /**
7
7
  * Carriage return byte (0x0d). Sent as a fixed discrete argv element with
8
8
  * `--no-paste` to deliver Enter literally (shell equivalent: $'\x0d').
9
- */ const CARRIAGE_RETURN = '\x0d';
9
+ */ const CARRIAGE_RETURN = "\x0d";
10
10
  /**
11
11
  * Escape byte (0x1b). Recognized by `sendKey` and translated to the
12
12
  * backend-native representation (`Escape` for tmux, `key code 53` for
13
13
  * AppleScript, the literal byte for WezTerm).
14
- */ const ESCAPE_BYTE = '\x1b';
14
+ */ const ESCAPE_BYTE = "\x1b";
15
15
  export class TtyWriter {
16
16
  /**
17
- * Send a message as keyboard input to a terminal session.
18
- *
19
- * Dispatches to the correct mechanism based on terminal type:
20
- * - tmux: `tmux send-keys`
21
- * - iTerm2: Two separate AppleScript `write text` calls (text then newline)
22
- * - Terminal.app: Two separate AppleScript `do script` calls (text then newline)
23
- *
24
- * All AppleScript is executed via `execFile('osascript', ['-e', script])`
25
- * to avoid shell interpolation and command injection.
26
- *
27
- * @param location Terminal location from TerminalFocusManager.findTerminal()
28
- * @param message Text to send
29
- * @throws Error if terminal type is unsupported or send fails
30
- */ static async send(location, message) {
17
+ * Send a message as keyboard input to a terminal session.
18
+ *
19
+ * Dispatches to the correct mechanism based on terminal type:
20
+ * - tmux: `tmux send-keys`
21
+ * - iTerm2: Two separate AppleScript `write text` calls (text then newline)
22
+ * - Terminal.app: Two separate AppleScript `do script` calls (text then newline)
23
+ *
24
+ * All AppleScript is executed via `execFile('osascript', ['-e', script])`
25
+ * to avoid shell interpolation and command injection.
26
+ *
27
+ * @param location Terminal location from TerminalFocusManager.findTerminal()
28
+ * @param message Text to send
29
+ * @throws Error if terminal type is unsupported or send fails
30
+ */ static async send(location, message) {
31
31
  switch(location.type){
32
32
  case TerminalType.TMUX:
33
33
  return TtyWriter.sendViaTmux(location.identifier, message);
@@ -38,22 +38,22 @@ export class TtyWriter {
38
38
  case TerminalType.TERMINAL_APP:
39
39
  return TtyWriter.sendViaTerminalApp(location.tty, message);
40
40
  default:
41
- throw new Error(`Cannot send input: unsupported terminal type "${location.type}". ` + 'Supported: tmux, WezTerm, iTerm2, Terminal.app.');
41
+ throw new Error(`Cannot send input: unsupported terminal type "${location.type}". ` + "Supported: tmux, WezTerm, iTerm2, Terminal.app.");
42
42
  }
43
43
  }
44
44
  /**
45
- * Send a single raw key (e.g. "1", "Enter", "Up") to the terminal as a
46
- * keystroke — bypassing bracketed paste and without auto-appending Enter.
47
- *
48
- * Use this when the target TUI distinguishes between typed text and raw
49
- * keypresses (e.g. an `AskUserQuestion` picker that selects on digit-key
50
- * press, not on a pasted digit followed by Enter).
51
- *
52
- * - tmux: `tmux send-keys -t <id> <key>` — direct keystroke, no paste buffer.
53
- * - WezTerm: `wezterm cli send-text --pane-id <id> --no-paste <key>`.
54
- * - iTerm2 / Terminal.app: AppleScript via System Events. Requires
55
- * Accessibility permissions.
56
- */ static async sendKey(location, key) {
45
+ * Send a single raw key (e.g. "1", "Enter", "Up") to the terminal as a
46
+ * keystroke — bypassing bracketed paste and without auto-appending Enter.
47
+ *
48
+ * Use this when the target TUI distinguishes between typed text and raw
49
+ * keypresses (e.g. an `AskUserQuestion` picker that selects on digit-key
50
+ * press, not on a pasted digit followed by Enter).
51
+ *
52
+ * - tmux: `tmux send-keys -t <id> <key>` — direct keystroke, no paste buffer.
53
+ * - WezTerm: `wezterm cli send-text --pane-id <id> --no-paste <key>`.
54
+ * - iTerm2 / Terminal.app: AppleScript via System Events. Requires
55
+ * Accessibility permissions.
56
+ */ static async sendKey(location, key) {
57
57
  switch(location.type){
58
58
  case TerminalType.TMUX:
59
59
  return TtyWriter.sendKeyViaTmux(location.identifier, key);
@@ -64,16 +64,16 @@ export class TtyWriter {
64
64
  case TerminalType.TERMINAL_APP:
65
65
  return TtyWriter.sendKeyViaTerminalApp(location.tty, key);
66
66
  default:
67
- throw new Error(`Cannot send key: unsupported terminal type "${location.type}". ` + 'Supported: tmux, WezTerm, iTerm2, Terminal.app.');
67
+ throw new Error(`Cannot send key: unsupported terminal type "${location.type}". ` + "Supported: tmux, WezTerm, iTerm2, Terminal.app.");
68
68
  }
69
69
  }
70
70
  static async sendKeyViaTmux(identifier, key) {
71
71
  // tmux send-keys interprets named keys (Enter, Up, Escape, ...) and
72
72
  // passes literals through. No bracketed paste, no auto-Enter.
73
- const arg = key === ESCAPE_BYTE ? 'Escape' : key;
74
- await execFileAsync('tmux', [
75
- 'send-keys',
76
- '-t',
73
+ const arg = key === ESCAPE_BYTE ? "Escape" : key;
74
+ await execFileAsync("tmux", [
75
+ "send-keys",
76
+ "-t",
77
77
  identifier,
78
78
  arg
79
79
  ]);
@@ -82,12 +82,12 @@ export class TtyWriter {
82
82
  // --no-paste delivers the key bytes literally outside bracketed-paste
83
83
  // markers; the TUI sees a raw keystroke. For Esc (`\x1b`), wezterm
84
84
  // accepts the byte directly.
85
- await execFileAsync('wezterm', [
86
- 'cli',
87
- 'send-text',
88
- '--pane-id',
85
+ await execFileAsync("wezterm", [
86
+ "cli",
87
+ "send-text",
88
+ "--pane-id",
89
89
  paneId,
90
- '--no-paste',
90
+ "--no-paste",
91
91
  key
92
92
  ]);
93
93
  }
@@ -118,11 +118,11 @@ tell application "iTerm"
118
118
  end tell
119
119
  tell application "System Events" to ${action}
120
120
  return "ok"`;
121
- const { stdout } = await execFileAsync('osascript', [
122
- '-e',
121
+ const { stdout } = await execFileAsync("osascript", [
122
+ "-e",
123
123
  script
124
124
  ]);
125
- if (stdout.trim() !== 'ok') {
125
+ if (stdout.trim() !== "ok") {
126
126
  throw new Error(`iTerm2 session not found for TTY ${tty}`);
127
127
  }
128
128
  }
@@ -150,11 +150,11 @@ tell application "Terminal"
150
150
  end tell
151
151
  tell application "System Events" to ${action}
152
152
  return "ok"`;
153
- const { stdout } = await execFileAsync('osascript', [
154
- '-e',
153
+ const { stdout } = await execFileAsync("osascript", [
154
+ "-e",
155
155
  script
156
156
  ]);
157
- if (stdout.trim() !== 'ok') {
157
+ if (stdout.trim() !== "ok") {
158
158
  throw new Error(`Terminal.app tab not found for TTY ${tty}`);
159
159
  }
160
160
  }
@@ -172,19 +172,19 @@ return "ok"`;
172
172
  // equivalent shell command is:
173
173
  // wezterm cli send-text --pane-id <id> --no-paste $'\x0d'
174
174
  // (ANSI-C quoting, note the leading $).
175
- await TtyWriter.execFileWithInput('wezterm', [
176
- 'cli',
177
- 'send-text',
178
- '--pane-id',
175
+ await TtyWriter.execFileWithInput("wezterm", [
176
+ "cli",
177
+ "send-text",
178
+ "--pane-id",
179
179
  paneId
180
180
  ], message);
181
181
  await new Promise((resolve)=>setTimeout(resolve, 150));
182
- await execFileAsync('wezterm', [
183
- 'cli',
184
- 'send-text',
185
- '--pane-id',
182
+ await execFileAsync("wezterm", [
183
+ "cli",
184
+ "send-text",
185
+ "--pane-id",
186
186
  paneId,
187
- '--no-paste',
187
+ "--no-paste",
188
188
  CARRIAGE_RETURN
189
189
  ]);
190
190
  }
@@ -193,27 +193,27 @@ return "ok"`;
193
193
  // a separate key so the inner TUI treats it as submission rather than
194
194
  // pasted content.
195
195
  const bufferName = `ai-devkit-send-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
196
- await TtyWriter.execFileWithInput('tmux', [
197
- 'load-buffer',
198
- '-b',
196
+ await TtyWriter.execFileWithInput("tmux", [
197
+ "load-buffer",
198
+ "-b",
199
199
  bufferName,
200
- '-'
200
+ "-"
201
201
  ], message);
202
- await execFileAsync('tmux', [
203
- 'paste-buffer',
204
- '-t',
202
+ await execFileAsync("tmux", [
203
+ "paste-buffer",
204
+ "-t",
205
205
  identifier,
206
- '-b',
206
+ "-b",
207
207
  bufferName,
208
- '-p',
209
- '-d'
208
+ "-p",
209
+ "-d"
210
210
  ]);
211
211
  await new Promise((resolve)=>setTimeout(resolve, 150));
212
- await execFileAsync('tmux', [
213
- 'send-keys',
214
- '-t',
212
+ await execFileAsync("tmux", [
213
+ "send-keys",
214
+ "-t",
215
215
  identifier,
216
- 'Enter'
216
+ "Enter"
217
217
  ]);
218
218
  }
219
219
  static async execFileWithInput(command, args, input) {
@@ -233,10 +233,10 @@ return "ok"`;
233
233
  });
234
234
  }
235
235
  /**
236
- * Build an AppleScript that finds an iTerm2 session by TTY and runs a
237
- * command against it. The `sessionCommand` is inserted inside a
238
- * `tell targetSession` block.
239
- */ static iterm2SessionScript(tty, sessionCommand) {
236
+ * Build an AppleScript that finds an iTerm2 session by TTY and runs a
237
+ * command against it. The `sessionCommand` is inserted inside a
238
+ * `tell targetSession` block.
239
+ */ static iterm2SessionScript(tty, sessionCommand) {
240
240
  return `
241
241
  tell application "iTerm"
242
242
  set targetSession to missing value
@@ -264,21 +264,21 @@ return "ok"`;
264
264
  // iTerm2 appends the newline after the paste-end marker (\e[201~), so
265
265
  // the inner TUI (Claude Code, Codex) sees it as a real submit action.
266
266
  const textScript = TtyWriter.iterm2SessionScript(tty, `write text "${escaped}" newline no`);
267
- const { stdout: textResult } = await execFileAsync('osascript', [
268
- '-e',
267
+ const { stdout: textResult } = await execFileAsync("osascript", [
268
+ "-e",
269
269
  textScript
270
270
  ]);
271
- if (textResult.trim() !== 'ok') {
271
+ if (textResult.trim() !== "ok") {
272
272
  throw new Error(`iTerm2 session not found for TTY ${tty}`);
273
273
  }
274
274
  // Wait for the paste to complete before sending Enter separately
275
275
  await new Promise((resolve)=>setTimeout(resolve, 150));
276
276
  const enterScript = TtyWriter.iterm2SessionScript(tty, 'write text "" newline yes');
277
- const { stdout: enterResult } = await execFileAsync('osascript', [
278
- '-e',
277
+ const { stdout: enterResult } = await execFileAsync("osascript", [
278
+ "-e",
279
279
  enterScript
280
280
  ]);
281
- if (enterResult.trim() !== 'ok') {
281
+ if (enterResult.trim() !== "ok") {
282
282
  throw new Error(`iTerm2 session disappeared before Enter could be sent for TTY ${tty}`);
283
283
  }
284
284
  }
@@ -308,11 +308,11 @@ tell application "Terminal"
308
308
  do script "${escaped}" in targetTab
309
309
  end tell
310
310
  return "ok"`;
311
- const { stdout: textResult } = await execFileAsync('osascript', [
312
- '-e',
311
+ const { stdout: textResult } = await execFileAsync("osascript", [
312
+ "-e",
313
313
  textScript
314
314
  ]);
315
- if (textResult.trim() !== 'ok') {
315
+ if (textResult.trim() !== "ok") {
316
316
  throw new Error(`Terminal.app tab not found for TTY ${tty}`);
317
317
  }
318
318
  // Wait for the text to be delivered before sending Enter
@@ -334,11 +334,11 @@ tell application "Terminal"
334
334
  do script "" in targetTab
335
335
  end tell
336
336
  return "ok"`;
337
- const { stdout: enterResult } = await execFileAsync('osascript', [
338
- '-e',
337
+ const { stdout: enterResult } = await execFileAsync("osascript", [
338
+ "-e",
339
339
  enterScript
340
340
  ]);
341
- if (enterResult.trim() !== 'ok') {
341
+ if (enterResult.trim() !== "ok") {
342
342
  throw new Error(`Terminal.app tab disappeared before Enter could be sent for TTY ${tty}`);
343
343
  }
344
344
  }
@@ -348,7 +348,7 @@ return "ok"`;
348
348
  * keys (Esc, arrows, F-keys, …) must be sent via `key code <N>`. Add more
349
349
  * mappings here as new special keys are needed.
350
350
  */ function appleScriptKeyAction(key) {
351
- if (key === ESCAPE_BYTE) return 'key code 53';
351
+ if (key === ESCAPE_BYTE) return "key code 53";
352
352
  return `keystroke "${escapeAppleScript(key)}"`;
353
353
  }
354
354
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/terminal/TtyWriter.ts"],"sourcesContent":["import { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport type { TerminalLocation } from './TerminalFocusManager.js';\nimport { TerminalType } from './TerminalFocusManager.js';\nimport { escapeAppleScript } from '../utils/applescript.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Carriage return byte (0x0d). Sent as a fixed discrete argv element with\n * `--no-paste` to deliver Enter literally (shell equivalent: $'\\x0d').\n */\nconst CARRIAGE_RETURN = '\\x0d';\n\n/**\n * Escape byte (0x1b). Recognized by `sendKey` and translated to the\n * backend-native representation (`Escape` for tmux, `key code 53` for\n * AppleScript, the literal byte for WezTerm).\n */\nconst ESCAPE_BYTE = '\\x1b';\n\nexport class TtyWriter {\n /**\n * Send a message as keyboard input to a terminal session.\n *\n * Dispatches to the correct mechanism based on terminal type:\n * - tmux: `tmux send-keys`\n * - iTerm2: Two separate AppleScript `write text` calls (text then newline)\n * - Terminal.app: Two separate AppleScript `do script` calls (text then newline)\n *\n * All AppleScript is executed via `execFile('osascript', ['-e', script])`\n * to avoid shell interpolation and command injection.\n *\n * @param location Terminal location from TerminalFocusManager.findTerminal()\n * @param message Text to send\n * @throws Error if terminal type is unsupported or send fails\n */\n static async send(location: TerminalLocation, message: string): Promise<void> {\n switch (location.type) {\n case TerminalType.TMUX:\n return TtyWriter.sendViaTmux(location.identifier, message);\n case TerminalType.WEZTERM:\n return TtyWriter.sendViaWezterm(location.identifier, message);\n case TerminalType.ITERM2:\n return TtyWriter.sendViaITerm2(location.tty, message);\n case TerminalType.TERMINAL_APP:\n return TtyWriter.sendViaTerminalApp(location.tty, message);\n default:\n throw new Error(\n `Cannot send input: unsupported terminal type \"${location.type}\". ` +\n 'Supported: tmux, WezTerm, iTerm2, Terminal.app.'\n );\n }\n }\n\n /**\n * Send a single raw key (e.g. \"1\", \"Enter\", \"Up\") to the terminal as a\n * keystroke — bypassing bracketed paste and without auto-appending Enter.\n *\n * Use this when the target TUI distinguishes between typed text and raw\n * keypresses (e.g. an `AskUserQuestion` picker that selects on digit-key\n * press, not on a pasted digit followed by Enter).\n *\n * - tmux: `tmux send-keys -t <id> <key>` — direct keystroke, no paste buffer.\n * - WezTerm: `wezterm cli send-text --pane-id <id> --no-paste <key>`.\n * - iTerm2 / Terminal.app: AppleScript via System Events. Requires\n * Accessibility permissions.\n */\n static async sendKey(location: TerminalLocation, key: string): Promise<void> {\n switch (location.type) {\n case TerminalType.TMUX:\n return TtyWriter.sendKeyViaTmux(location.identifier, key);\n case TerminalType.WEZTERM:\n return TtyWriter.sendKeyViaWezterm(location.identifier, key);\n case TerminalType.ITERM2:\n return TtyWriter.sendKeyViaITerm2(location.tty, key);\n case TerminalType.TERMINAL_APP:\n return TtyWriter.sendKeyViaTerminalApp(location.tty, key);\n default:\n throw new Error(\n `Cannot send key: unsupported terminal type \"${location.type}\". ` +\n 'Supported: tmux, WezTerm, iTerm2, Terminal.app.'\n );\n }\n }\n\n private static async sendKeyViaTmux(identifier: string, key: string): Promise<void> {\n // tmux send-keys interprets named keys (Enter, Up, Escape, ...) and\n // passes literals through. No bracketed paste, no auto-Enter.\n const arg = key === ESCAPE_BYTE ? 'Escape' : key;\n await execFileAsync('tmux', ['send-keys', '-t', identifier, arg]);\n }\n\n private static async sendKeyViaWezterm(paneId: string, key: string): Promise<void> {\n // --no-paste delivers the key bytes literally outside bracketed-paste\n // markers; the TUI sees a raw keystroke. For Esc (`\\x1b`), wezterm\n // accepts the byte directly.\n await execFileAsync('wezterm', [\n 'cli', 'send-text', '--pane-id', paneId, '--no-paste', key,\n ]);\n }\n\n private static async sendKeyViaITerm2(tty: string, key: string): Promise<void> {\n // Focus the target session, then press the key via System Events so the\n // inner TUI sees a raw keystroke (not a bracketed-paste text run).\n const action = appleScriptKeyAction(key);\n const script = `\ntell application \"iTerm\"\n set targetSession to missing value\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 \"${tty}\" then\n set targetSession to s\n set frontmost of w to true\n tell t to select\n tell s to select\n exit repeat\n end if\n end repeat\n if targetSession is not missing value then exit repeat\n end repeat\n if targetSession is not missing value then exit repeat\n end repeat\n if targetSession is missing value then return \"not_found\"\n activate\nend tell\ntell application \"System Events\" to ${action}\nreturn \"ok\"`;\n\n const { stdout } = await execFileAsync('osascript', ['-e', script]);\n if (stdout.trim() !== 'ok') {\n throw new Error(`iTerm2 session not found for TTY ${tty}`);\n }\n }\n\n private static async sendKeyViaTerminalApp(tty: string, key: string): Promise<void> {\n const action = appleScriptKeyAction(key);\n const script = `\ntell application \"Terminal\"\n set targetTab to missing value\n set targetWindow to missing value\n repeat with w in windows\n repeat with i from 1 to count of tabs of w\n set t to tab i of w\n if tty of t is \"${tty}\" then\n set targetTab to t\n set targetWindow to w\n exit repeat\n end if\n end repeat\n if targetTab is not missing value then exit repeat\n end repeat\n if targetTab is missing value then return \"not_found\"\n set selected of targetTab to true\n set frontmost of targetWindow to true\n activate\nend tell\ntell application \"System Events\" to ${action}\nreturn \"ok\"`;\n\n const { stdout } = await execFileAsync('osascript', ['-e', script]);\n if (stdout.trim() !== 'ok') {\n throw new Error(`Terminal.app tab not found for TTY ${tty}`);\n }\n }\n\n private static async sendViaWezterm(paneId: string, message: string): Promise<void> {\n // Two explicit CLI calls, mirroring the text-then-Enter convention used\n // by tmux / iTerm2 / Terminal.app so a bracketed-paste-aware TUI still\n // sees Enter as a submit.\n //\n // Step 1 (text): write the message to stdin so prompt contents are not\n // exposed through process arguments. execFile still spawns wezterm\n // directly (no shell), so shell metacharacters remain inert.\n // Step 2 (Enter): pass a fixed carriage return (0x0d) as a discrete\n // argv element (the JS char '\\x0d') with --no-paste, so the CR is\n // delivered literally rather than wrapped in paste brackets. The\n // equivalent shell command is:\n // wezterm cli send-text --pane-id <id> --no-paste $'\\x0d'\n // (ANSI-C quoting, note the leading $).\n await TtyWriter.execFileWithInput('wezterm', [\n 'cli', 'send-text', '--pane-id', paneId,\n ], message);\n await new Promise((resolve) => setTimeout(resolve, 150));\n await execFileAsync('wezterm', [\n 'cli', 'send-text', '--pane-id', paneId, '--no-paste', CARRIAGE_RETURN,\n ]);\n }\n\n private static async sendViaTmux(identifier: string, message: string): Promise<void> {\n // Paste the message body using tmux bracketed paste, then send Enter as\n // a separate key so the inner TUI treats it as submission rather than\n // pasted content.\n const bufferName = `ai-devkit-send-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n await TtyWriter.execFileWithInput('tmux', ['load-buffer', '-b', bufferName, '-'], message);\n await execFileAsync('tmux', ['paste-buffer', '-t', identifier, '-b', bufferName, '-p', '-d']);\n await new Promise((resolve) => setTimeout(resolve, 150));\n await execFileAsync('tmux', ['send-keys', '-t', identifier, 'Enter']);\n }\n\n private static async execFileWithInput(command: string, args: string[], input: string): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = execFile(command, args, (error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n if (!child.stdin) {\n reject(new Error(`Cannot write stdin to ${command}`));\n return;\n }\n child.stdin.end(input);\n });\n }\n\n /**\n * Build an AppleScript that finds an iTerm2 session by TTY and runs a\n * command against it. The `sessionCommand` is inserted inside a\n * `tell targetSession` block.\n */\n private static iterm2SessionScript(tty: string, sessionCommand: string): string {\n return `\ntell application \"iTerm\"\n set targetSession to missing value\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 \"${tty}\" then\n set targetSession to s\n exit repeat\n end if\n end repeat\n if targetSession is not missing value then exit repeat\n end repeat\n if targetSession is not missing value then exit repeat\n end repeat\n if targetSession is missing value then return \"not_found\"\n tell targetSession to ${sessionCommand}\nend tell\nreturn \"ok\"`;\n }\n\n private static async sendViaITerm2(tty: string, message: string): Promise<void> {\n const escaped = escapeAppleScript(message);\n // Send text and Enter as two separate write text calls so the newline\n // is delivered outside the bracketed paste sequence of the message body.\n // iTerm2 appends the newline after the paste-end marker (\\e[201~), so\n // the inner TUI (Claude Code, Codex) sees it as a real submit action.\n const textScript = TtyWriter.iterm2SessionScript(tty, `write text \"${escaped}\" newline no`);\n\n const { stdout: textResult } = await execFileAsync('osascript', ['-e', textScript]);\n if (textResult.trim() !== 'ok') {\n throw new Error(`iTerm2 session not found for TTY ${tty}`);\n }\n\n // Wait for the paste to complete before sending Enter separately\n await new Promise((resolve) => setTimeout(resolve, 150));\n\n const enterScript = TtyWriter.iterm2SessionScript(tty, 'write text \"\" newline yes');\n const { stdout: enterResult } = await execFileAsync('osascript', ['-e', enterScript]);\n if (enterResult.trim() !== 'ok') {\n throw new Error(`iTerm2 session disappeared before Enter could be sent for TTY ${tty}`);\n }\n }\n\n private static async sendViaTerminalApp(tty: string, message: string): Promise<void> {\n const escaped = escapeAppleScript(message);\n // Use Terminal.app's `do script` to send text to the correct tab by TTY.\n // We avoid System Events `keystroke` + `key code 36` because it requires\n // accessibility permissions and unreliably delivers the Return key.\n //\n // `do script` with `in` targets a specific tab without opening a new one.\n // We send text and Enter as two separate calls so the newline arrives\n // outside of bracketed paste mode — same pattern as iTerm2 and tmux.\n const textScript = `\ntell application \"Terminal\"\n set targetTab to missing value\n repeat with w in windows\n repeat with i from 1 to count of tabs of w\n set t to tab i of w\n if tty of t is \"${tty}\" then\n set targetTab to t\n exit repeat\n end if\n end repeat\n if targetTab is not missing value then exit repeat\n end repeat\n if targetTab is missing value then return \"not_found\"\n do script \"${escaped}\" in targetTab\nend tell\nreturn \"ok\"`;\n\n const { stdout: textResult } = await execFileAsync('osascript', ['-e', textScript]);\n if (textResult.trim() !== 'ok') {\n throw new Error(`Terminal.app tab not found for TTY ${tty}`);\n }\n\n // Wait for the text to be delivered before sending Enter\n await new Promise((resolve) => setTimeout(resolve, 150));\n\n const enterScript = `\ntell application \"Terminal\"\n set targetTab to missing value\n repeat with w in windows\n repeat with i from 1 to count of tabs of w\n set t to tab i of w\n if tty of t is \"${tty}\" then\n set targetTab to t\n exit repeat\n end if\n end repeat\n if targetTab is not missing value then exit repeat\n end repeat\n if targetTab is missing value then return \"not_found\"\n do script \"\" in targetTab\nend tell\nreturn \"ok\"`;\n\n const { stdout: enterResult } = await execFileAsync('osascript', ['-e', enterScript]);\n if (enterResult.trim() !== 'ok') {\n throw new Error(`Terminal.app tab disappeared before Enter could be sent for TTY ${tty}`);\n }\n }\n}\n\n/**\n * AppleScript `keystroke` only delivers typeable characters; non-typeable\n * keys (Esc, arrows, F-keys, …) must be sent via `key code <N>`. Add more\n * mappings here as new special keys are needed.\n */\nfunction appleScriptKeyAction(key: string): string {\n if (key === ESCAPE_BYTE) return 'key code 53';\n return `keystroke \"${escapeAppleScript(key)}\"`;\n}\n"],"names":["execFile","promisify","TerminalType","escapeAppleScript","execFileAsync","CARRIAGE_RETURN","ESCAPE_BYTE","TtyWriter","send","location","message","type","TMUX","sendViaTmux","identifier","WEZTERM","sendViaWezterm","ITERM2","sendViaITerm2","tty","TERMINAL_APP","sendViaTerminalApp","Error","sendKey","key","sendKeyViaTmux","sendKeyViaWezterm","sendKeyViaITerm2","sendKeyViaTerminalApp","arg","paneId","action","appleScriptKeyAction","script","stdout","trim","execFileWithInput","Promise","resolve","setTimeout","bufferName","process","pid","Date","now","Math","random","toString","slice","command","args","input","reject","child","error","stdin","end","iterm2SessionScript","sessionCommand","escaped","textScript","textResult","enterScript","enterResult"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/terminal/TtyWriter.ts"],"sourcesContent":["import { execFile } from \"child_process\";\nimport { promisify } from \"util\";\nimport type { TerminalLocation } from \"./TerminalFocusManager.js\";\nimport { TerminalType } from \"./TerminalFocusManager.js\";\nimport { escapeAppleScript } from \"../utils/applescript.js\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Carriage return byte (0x0d). Sent as a fixed discrete argv element with\n * `--no-paste` to deliver Enter literally (shell equivalent: $'\\x0d').\n */\nconst CARRIAGE_RETURN = \"\\x0d\";\n\n/**\n * Escape byte (0x1b). Recognized by `sendKey` and translated to the\n * backend-native representation (`Escape` for tmux, `key code 53` for\n * AppleScript, the literal byte for WezTerm).\n */\nconst ESCAPE_BYTE = \"\\x1b\";\n\nexport class TtyWriter {\n /**\n * Send a message as keyboard input to a terminal session.\n *\n * Dispatches to the correct mechanism based on terminal type:\n * - tmux: `tmux send-keys`\n * - iTerm2: Two separate AppleScript `write text` calls (text then newline)\n * - Terminal.app: Two separate AppleScript `do script` calls (text then newline)\n *\n * All AppleScript is executed via `execFile('osascript', ['-e', script])`\n * to avoid shell interpolation and command injection.\n *\n * @param location Terminal location from TerminalFocusManager.findTerminal()\n * @param message Text to send\n * @throws Error if terminal type is unsupported or send fails\n */\n static async send(location: TerminalLocation, message: string): Promise<void> {\n switch (location.type) {\n case TerminalType.TMUX:\n return TtyWriter.sendViaTmux(location.identifier, message);\n case TerminalType.WEZTERM:\n return TtyWriter.sendViaWezterm(location.identifier, message);\n case TerminalType.ITERM2:\n return TtyWriter.sendViaITerm2(location.tty, message);\n case TerminalType.TERMINAL_APP:\n return TtyWriter.sendViaTerminalApp(location.tty, message);\n default:\n throw new Error(\n `Cannot send input: unsupported terminal type \"${location.type}\". ` +\n \"Supported: tmux, WezTerm, iTerm2, Terminal.app.\",\n );\n }\n }\n\n /**\n * Send a single raw key (e.g. \"1\", \"Enter\", \"Up\") to the terminal as a\n * keystroke — bypassing bracketed paste and without auto-appending Enter.\n *\n * Use this when the target TUI distinguishes between typed text and raw\n * keypresses (e.g. an `AskUserQuestion` picker that selects on digit-key\n * press, not on a pasted digit followed by Enter).\n *\n * - tmux: `tmux send-keys -t <id> <key>` — direct keystroke, no paste buffer.\n * - WezTerm: `wezterm cli send-text --pane-id <id> --no-paste <key>`.\n * - iTerm2 / Terminal.app: AppleScript via System Events. Requires\n * Accessibility permissions.\n */\n static async sendKey(location: TerminalLocation, key: string): Promise<void> {\n switch (location.type) {\n case TerminalType.TMUX:\n return TtyWriter.sendKeyViaTmux(location.identifier, key);\n case TerminalType.WEZTERM:\n return TtyWriter.sendKeyViaWezterm(location.identifier, key);\n case TerminalType.ITERM2:\n return TtyWriter.sendKeyViaITerm2(location.tty, key);\n case TerminalType.TERMINAL_APP:\n return TtyWriter.sendKeyViaTerminalApp(location.tty, key);\n default:\n throw new Error(\n `Cannot send key: unsupported terminal type \"${location.type}\". ` +\n \"Supported: tmux, WezTerm, iTerm2, Terminal.app.\",\n );\n }\n }\n\n private static async sendKeyViaTmux(identifier: string, key: string): Promise<void> {\n // tmux send-keys interprets named keys (Enter, Up, Escape, ...) and\n // passes literals through. No bracketed paste, no auto-Enter.\n const arg = key === ESCAPE_BYTE ? \"Escape\" : key;\n await execFileAsync(\"tmux\", [\"send-keys\", \"-t\", identifier, arg]);\n }\n\n private static async sendKeyViaWezterm(paneId: string, key: string): Promise<void> {\n // --no-paste delivers the key bytes literally outside bracketed-paste\n // markers; the TUI sees a raw keystroke. For Esc (`\\x1b`), wezterm\n // accepts the byte directly.\n await execFileAsync(\"wezterm\", [\"cli\", \"send-text\", \"--pane-id\", paneId, \"--no-paste\", key]);\n }\n\n private static async sendKeyViaITerm2(tty: string, key: string): Promise<void> {\n // Focus the target session, then press the key via System Events so the\n // inner TUI sees a raw keystroke (not a bracketed-paste text run).\n const action = appleScriptKeyAction(key);\n const script = `\ntell application \"iTerm\"\n set targetSession to missing value\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 \"${tty}\" then\n set targetSession to s\n set frontmost of w to true\n tell t to select\n tell s to select\n exit repeat\n end if\n end repeat\n if targetSession is not missing value then exit repeat\n end repeat\n if targetSession is not missing value then exit repeat\n end repeat\n if targetSession is missing value then return \"not_found\"\n activate\nend tell\ntell application \"System Events\" to ${action}\nreturn \"ok\"`;\n\n const { stdout } = await execFileAsync(\"osascript\", [\"-e\", script]);\n if (stdout.trim() !== \"ok\") {\n throw new Error(`iTerm2 session not found for TTY ${tty}`);\n }\n }\n\n private static async sendKeyViaTerminalApp(tty: string, key: string): Promise<void> {\n const action = appleScriptKeyAction(key);\n const script = `\ntell application \"Terminal\"\n set targetTab to missing value\n set targetWindow to missing value\n repeat with w in windows\n repeat with i from 1 to count of tabs of w\n set t to tab i of w\n if tty of t is \"${tty}\" then\n set targetTab to t\n set targetWindow to w\n exit repeat\n end if\n end repeat\n if targetTab is not missing value then exit repeat\n end repeat\n if targetTab is missing value then return \"not_found\"\n set selected of targetTab to true\n set frontmost of targetWindow to true\n activate\nend tell\ntell application \"System Events\" to ${action}\nreturn \"ok\"`;\n\n const { stdout } = await execFileAsync(\"osascript\", [\"-e\", script]);\n if (stdout.trim() !== \"ok\") {\n throw new Error(`Terminal.app tab not found for TTY ${tty}`);\n }\n }\n\n private static async sendViaWezterm(paneId: string, message: string): Promise<void> {\n // Two explicit CLI calls, mirroring the text-then-Enter convention used\n // by tmux / iTerm2 / Terminal.app so a bracketed-paste-aware TUI still\n // sees Enter as a submit.\n //\n // Step 1 (text): write the message to stdin so prompt contents are not\n // exposed through process arguments. execFile still spawns wezterm\n // directly (no shell), so shell metacharacters remain inert.\n // Step 2 (Enter): pass a fixed carriage return (0x0d) as a discrete\n // argv element (the JS char '\\x0d') with --no-paste, so the CR is\n // delivered literally rather than wrapped in paste brackets. The\n // equivalent shell command is:\n // wezterm cli send-text --pane-id <id> --no-paste $'\\x0d'\n // (ANSI-C quoting, note the leading $).\n await TtyWriter.execFileWithInput(\n \"wezterm\",\n [\"cli\", \"send-text\", \"--pane-id\", paneId],\n message,\n );\n await new Promise((resolve) => setTimeout(resolve, 150));\n await execFileAsync(\"wezterm\", [\n \"cli\",\n \"send-text\",\n \"--pane-id\",\n paneId,\n \"--no-paste\",\n CARRIAGE_RETURN,\n ]);\n }\n\n private static async sendViaTmux(identifier: string, message: string): Promise<void> {\n // Paste the message body using tmux bracketed paste, then send Enter as\n // a separate key so the inner TUI treats it as submission rather than\n // pasted content.\n const bufferName = `ai-devkit-send-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n await TtyWriter.execFileWithInput(\"tmux\", [\"load-buffer\", \"-b\", bufferName, \"-\"], message);\n await execFileAsync(\"tmux\", [\"paste-buffer\", \"-t\", identifier, \"-b\", bufferName, \"-p\", \"-d\"]);\n await new Promise((resolve) => setTimeout(resolve, 150));\n await execFileAsync(\"tmux\", [\"send-keys\", \"-t\", identifier, \"Enter\"]);\n }\n\n private static async execFileWithInput(\n command: string,\n args: string[],\n input: string,\n ): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = execFile(command, args, (error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n if (!child.stdin) {\n reject(new Error(`Cannot write stdin to ${command}`));\n return;\n }\n child.stdin.end(input);\n });\n }\n\n /**\n * Build an AppleScript that finds an iTerm2 session by TTY and runs a\n * command against it. The `sessionCommand` is inserted inside a\n * `tell targetSession` block.\n */\n private static iterm2SessionScript(tty: string, sessionCommand: string): string {\n return `\ntell application \"iTerm\"\n set targetSession to missing value\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 \"${tty}\" then\n set targetSession to s\n exit repeat\n end if\n end repeat\n if targetSession is not missing value then exit repeat\n end repeat\n if targetSession is not missing value then exit repeat\n end repeat\n if targetSession is missing value then return \"not_found\"\n tell targetSession to ${sessionCommand}\nend tell\nreturn \"ok\"`;\n }\n\n private static async sendViaITerm2(tty: string, message: string): Promise<void> {\n const escaped = escapeAppleScript(message);\n // Send text and Enter as two separate write text calls so the newline\n // is delivered outside the bracketed paste sequence of the message body.\n // iTerm2 appends the newline after the paste-end marker (\\e[201~), so\n // the inner TUI (Claude Code, Codex) sees it as a real submit action.\n const textScript = TtyWriter.iterm2SessionScript(tty, `write text \"${escaped}\" newline no`);\n\n const { stdout: textResult } = await execFileAsync(\"osascript\", [\"-e\", textScript]);\n if (textResult.trim() !== \"ok\") {\n throw new Error(`iTerm2 session not found for TTY ${tty}`);\n }\n\n // Wait for the paste to complete before sending Enter separately\n await new Promise((resolve) => setTimeout(resolve, 150));\n\n const enterScript = TtyWriter.iterm2SessionScript(tty, 'write text \"\" newline yes');\n const { stdout: enterResult } = await execFileAsync(\"osascript\", [\"-e\", enterScript]);\n if (enterResult.trim() !== \"ok\") {\n throw new Error(`iTerm2 session disappeared before Enter could be sent for TTY ${tty}`);\n }\n }\n\n private static async sendViaTerminalApp(tty: string, message: string): Promise<void> {\n const escaped = escapeAppleScript(message);\n // Use Terminal.app's `do script` to send text to the correct tab by TTY.\n // We avoid System Events `keystroke` + `key code 36` because it requires\n // accessibility permissions and unreliably delivers the Return key.\n //\n // `do script` with `in` targets a specific tab without opening a new one.\n // We send text and Enter as two separate calls so the newline arrives\n // outside of bracketed paste mode — same pattern as iTerm2 and tmux.\n const textScript = `\ntell application \"Terminal\"\n set targetTab to missing value\n repeat with w in windows\n repeat with i from 1 to count of tabs of w\n set t to tab i of w\n if tty of t is \"${tty}\" then\n set targetTab to t\n exit repeat\n end if\n end repeat\n if targetTab is not missing value then exit repeat\n end repeat\n if targetTab is missing value then return \"not_found\"\n do script \"${escaped}\" in targetTab\nend tell\nreturn \"ok\"`;\n\n const { stdout: textResult } = await execFileAsync(\"osascript\", [\"-e\", textScript]);\n if (textResult.trim() !== \"ok\") {\n throw new Error(`Terminal.app tab not found for TTY ${tty}`);\n }\n\n // Wait for the text to be delivered before sending Enter\n await new Promise((resolve) => setTimeout(resolve, 150));\n\n const enterScript = `\ntell application \"Terminal\"\n set targetTab to missing value\n repeat with w in windows\n repeat with i from 1 to count of tabs of w\n set t to tab i of w\n if tty of t is \"${tty}\" then\n set targetTab to t\n exit repeat\n end if\n end repeat\n if targetTab is not missing value then exit repeat\n end repeat\n if targetTab is missing value then return \"not_found\"\n do script \"\" in targetTab\nend tell\nreturn \"ok\"`;\n\n const { stdout: enterResult } = await execFileAsync(\"osascript\", [\"-e\", enterScript]);\n if (enterResult.trim() !== \"ok\") {\n throw new Error(`Terminal.app tab disappeared before Enter could be sent for TTY ${tty}`);\n }\n }\n}\n\n/**\n * AppleScript `keystroke` only delivers typeable characters; non-typeable\n * keys (Esc, arrows, F-keys, …) must be sent via `key code <N>`. Add more\n * mappings here as new special keys are needed.\n */\nfunction appleScriptKeyAction(key: string): string {\n if (key === ESCAPE_BYTE) return \"key code 53\";\n return `keystroke \"${escapeAppleScript(key)}\"`;\n}\n"],"names":["execFile","promisify","TerminalType","escapeAppleScript","execFileAsync","CARRIAGE_RETURN","ESCAPE_BYTE","TtyWriter","send","location","message","type","TMUX","sendViaTmux","identifier","WEZTERM","sendViaWezterm","ITERM2","sendViaITerm2","tty","TERMINAL_APP","sendViaTerminalApp","Error","sendKey","key","sendKeyViaTmux","sendKeyViaWezterm","sendKeyViaITerm2","sendKeyViaTerminalApp","arg","paneId","action","appleScriptKeyAction","script","stdout","trim","execFileWithInput","Promise","resolve","setTimeout","bufferName","process","pid","Date","now","Math","random","toString","slice","command","args","input","reject","child","error","stdin","end","iterm2SessionScript","sessionCommand","escaped","textScript","textResult","enterScript","enterResult"],"mappings":"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"}