@ashx-j/lunr-dev 0.2.13-dev.8.1 → 0.2.19-dev.10.1

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 (484) hide show
  1. package/CHANGELOG.md +60 -1
  2. package/README.md +7 -1
  3. package/dist/builtin-extensions/ashxj-thinking.d.ts +1 -0
  4. package/dist/builtin-extensions/ashxj-thinking.d.ts.map +1 -1
  5. package/dist/builtin-extensions/ashxj-thinking.js +44 -19
  6. package/dist/builtin-extensions/ashxj-thinking.js.map +1 -1
  7. package/dist/builtin-extensions/ashxj-tui.d.ts +14 -0
  8. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  9. package/dist/builtin-extensions/ashxj-tui.js +37 -3
  10. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  11. package/dist/builtin-extensions/index.d.ts +1 -15
  12. package/dist/builtin-extensions/index.d.ts.map +1 -1
  13. package/dist/builtin-extensions/index.js +8 -21
  14. package/dist/builtin-extensions/index.js.map +1 -1
  15. package/dist/builtin-extensions/lunr-computer-use.d.ts +3 -0
  16. package/dist/builtin-extensions/lunr-computer-use.d.ts.map +1 -0
  17. package/dist/builtin-extensions/lunr-computer-use.js +157 -0
  18. package/dist/builtin-extensions/lunr-computer-use.js.map +1 -0
  19. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.d.ts.map +1 -1
  20. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js +6 -2
  21. package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js.map +1 -1
  22. package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts +4 -0
  23. package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts.map +1 -1
  24. package/dist/builtin-extensions/pi-lsp-extension/src/index.js +172 -171
  25. package/dist/builtin-extensions/pi-lsp-extension/src/index.js.map +1 -1
  26. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts +50 -0
  27. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts.map +1 -0
  28. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js +131 -0
  29. package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js.map +1 -0
  30. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts +7 -0
  31. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts.map +1 -0
  32. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js +211 -0
  33. package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js.map +1 -0
  34. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts +0 -5
  35. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts.map +1 -1
  36. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js +0 -202
  37. package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js.map +1 -1
  38. package/dist/builtin-extensions/pi-mcp-adapter/index.d.ts.map +1 -1
  39. package/dist/builtin-extensions/pi-mcp-adapter/index.js +276 -109
  40. package/dist/builtin-extensions/pi-mcp-adapter/index.js.map +1 -1
  41. package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts +4 -1
  42. package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts.map +1 -1
  43. package/dist/builtin-extensions/pi-mcp-adapter/init.js +10 -3
  44. package/dist/builtin-extensions/pi-mcp-adapter/init.js.map +1 -1
  45. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.d.ts.map +1 -1
  46. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.js +6 -1
  47. package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.js.map +1 -1
  48. package/dist/builtin-extensions/pi-mcp-adapter/server-manager.d.ts +6 -1
  49. package/dist/builtin-extensions/pi-mcp-adapter/server-manager.d.ts.map +1 -1
  50. package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js +33 -8
  51. package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js.map +1 -1
  52. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.d.ts.map +1 -1
  53. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js +2 -1
  54. package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js.map +1 -1
  55. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts +1 -1
  56. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts.map +1 -1
  57. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js +1 -1
  58. package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +1 -1
  60. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  61. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +68 -15
  62. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  63. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +6 -2
  65. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  66. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts +1 -1
  67. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
  68. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +5 -2
  69. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
  70. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.d.ts +10 -0
  71. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.d.ts.map +1 -0
  72. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.js +38 -0
  73. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.js.map +1 -0
  74. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  75. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +3 -16
  76. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  77. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +1 -1
  78. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -1
  79. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +2 -0
  80. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -1
  81. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.d.ts.map +1 -1
  82. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.js +1 -1
  83. package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.js.map +1 -1
  84. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +1 -1
  85. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  86. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +1 -1
  87. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  88. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -1
  89. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  90. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +72 -31
  91. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  92. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts +1 -1
  93. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts.map +1 -1
  94. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js +2 -1
  95. package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js.map +1 -1
  96. package/dist/builtin-extensions/pi-web-access/extract.d.ts.map +1 -1
  97. package/dist/builtin-extensions/pi-web-access/extract.js +105 -54
  98. package/dist/builtin-extensions/pi-web-access/extract.js.map +1 -1
  99. package/dist/builtin-extensions/pi-web-access/gemini-search.d.ts +1 -1
  100. package/dist/builtin-extensions/pi-web-access/gemini-search.d.ts.map +1 -1
  101. package/dist/builtin-extensions/pi-web-access/gemini-search.js +82 -65
  102. package/dist/builtin-extensions/pi-web-access/gemini-search.js.map +1 -1
  103. package/dist/builtin-extensions/pi-web-access/github-extract.d.ts.map +1 -1
  104. package/dist/builtin-extensions/pi-web-access/github-extract.js +2 -0
  105. package/dist/builtin-extensions/pi-web-access/github-extract.js.map +1 -1
  106. package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
  107. package/dist/builtin-extensions/pi-web-access/index.js +259 -168
  108. package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
  109. package/dist/builtin-extensions/pi-web-access/lazy.d.ts +18 -0
  110. package/dist/builtin-extensions/pi-web-access/lazy.d.ts.map +1 -0
  111. package/dist/builtin-extensions/pi-web-access/lazy.js +19 -0
  112. package/dist/builtin-extensions/pi-web-access/lazy.js.map +1 -0
  113. package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts +6 -0
  114. package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts.map +1 -0
  115. package/dist/builtin-extensions/pi-web-access/session-cleanup.js +17 -0
  116. package/dist/builtin-extensions/pi-web-access/session-cleanup.js.map +1 -0
  117. package/dist/catalog/publication.json +12 -12
  118. package/dist/cli-runtime.d.ts +3 -0
  119. package/dist/cli-runtime.d.ts.map +1 -0
  120. package/dist/cli-runtime.js +73 -0
  121. package/dist/cli-runtime.js.map +1 -0
  122. package/dist/cli.d.ts.map +1 -1
  123. package/dist/cli.js +14 -53
  124. package/dist/cli.js.map +1 -1
  125. package/dist/config.d.ts +1 -0
  126. package/dist/config.d.ts.map +1 -1
  127. package/dist/config.js +1 -0
  128. package/dist/config.js.map +1 -1
  129. package/dist/core/agent-session-services.d.ts.map +1 -1
  130. package/dist/core/agent-session-services.js +1 -1
  131. package/dist/core/agent-session-services.js.map +1 -1
  132. package/dist/core/agent-session.d.ts +3 -0
  133. package/dist/core/agent-session.d.ts.map +1 -1
  134. package/dist/core/agent-session.js +56 -12
  135. package/dist/core/agent-session.js.map +1 -1
  136. package/dist/core/compaction/compaction.d.ts.map +1 -1
  137. package/dist/core/compaction/compaction.js +10 -5
  138. package/dist/core/compaction/compaction.js.map +1 -1
  139. package/dist/core/computer-use/adapter.d.ts +23 -0
  140. package/dist/core/computer-use/adapter.d.ts.map +1 -0
  141. package/dist/core/computer-use/adapter.js +116 -0
  142. package/dist/core/computer-use/adapter.js.map +1 -0
  143. package/dist/core/computer-use/lease.d.ts +18 -0
  144. package/dist/core/computer-use/lease.d.ts.map +1 -0
  145. package/dist/core/computer-use/lease.js +129 -0
  146. package/dist/core/computer-use/lease.js.map +1 -0
  147. package/dist/core/computer-use/macos-runtime.d.ts +14 -0
  148. package/dist/core/computer-use/macos-runtime.d.ts.map +1 -0
  149. package/dist/core/computer-use/macos-runtime.js +148 -0
  150. package/dist/core/computer-use/macos-runtime.js.map +1 -0
  151. package/dist/core/computer-use/policy.d.ts +19 -0
  152. package/dist/core/computer-use/policy.d.ts.map +1 -0
  153. package/dist/core/computer-use/policy.js +66 -0
  154. package/dist/core/computer-use/policy.js.map +1 -0
  155. package/dist/core/computer-use/release.generated.d.ts +31 -0
  156. package/dist/core/computer-use/release.generated.d.ts.map +1 -0
  157. package/dist/core/computer-use/release.generated.js +36 -0
  158. package/dist/core/computer-use/release.generated.js.map +1 -0
  159. package/dist/core/computer-use/runtime.d.ts +13 -0
  160. package/dist/core/computer-use/runtime.d.ts.map +1 -0
  161. package/dist/core/computer-use/runtime.js +158 -0
  162. package/dist/core/computer-use/runtime.js.map +1 -0
  163. package/dist/core/computer-use/schemas.d.ts +88 -0
  164. package/dist/core/computer-use/schemas.d.ts.map +1 -0
  165. package/dist/core/computer-use/schemas.js +80 -0
  166. package/dist/core/computer-use/schemas.js.map +1 -0
  167. package/dist/core/computer-use/windows-desktop.d.ts +3 -0
  168. package/dist/core/computer-use/windows-desktop.d.ts.map +1 -0
  169. package/dist/core/computer-use/windows-desktop.js +48 -0
  170. package/dist/core/computer-use/windows-desktop.js.map +1 -0
  171. package/dist/core/computer-use/workflow.d.ts +24 -0
  172. package/dist/core/computer-use/workflow.d.ts.map +1 -0
  173. package/dist/core/computer-use/workflow.js +330 -0
  174. package/dist/core/computer-use/workflow.js.map +1 -0
  175. package/dist/core/extensions/host-static.d.ts.map +1 -1
  176. package/dist/core/extensions/host-static.js +34 -12
  177. package/dist/core/extensions/host-static.js.map +1 -1
  178. package/dist/core/extensions/loader.d.ts +1 -2
  179. package/dist/core/extensions/loader.d.ts.map +1 -1
  180. package/dist/core/extensions/loader.js +10 -64
  181. package/dist/core/extensions/loader.js.map +1 -1
  182. package/dist/core/extensions/types.d.ts +2 -2
  183. package/dist/core/extensions/types.d.ts.map +1 -1
  184. package/dist/core/extensions/types.js.map +1 -1
  185. package/dist/core/footer-data-provider.d.ts.map +1 -1
  186. package/dist/core/footer-data-provider.js +2 -0
  187. package/dist/core/footer-data-provider.js.map +1 -1
  188. package/dist/core/keybindings.d.ts +2 -2
  189. package/dist/core/keybindings.d.ts.map +1 -1
  190. package/dist/core/keybindings.js +2 -2
  191. package/dist/core/keybindings.js.map +1 -1
  192. package/dist/core/model-runtime.d.ts +0 -3
  193. package/dist/core/model-runtime.d.ts.map +1 -1
  194. package/dist/core/model-runtime.js +1 -10
  195. package/dist/core/model-runtime.js.map +1 -1
  196. package/dist/core/package-manager.d.ts.map +1 -1
  197. package/dist/core/package-manager.js +1 -1
  198. package/dist/core/package-manager.js.map +1 -1
  199. package/dist/core/permissions.d.ts +1 -3
  200. package/dist/core/permissions.d.ts.map +1 -1
  201. package/dist/core/permissions.js +33 -25
  202. package/dist/core/permissions.js.map +1 -1
  203. package/dist/core/plan-mode.d.ts.map +1 -1
  204. package/dist/core/plan-mode.js +9 -0
  205. package/dist/core/plan-mode.js.map +1 -1
  206. package/dist/core/rollback.d.ts.map +1 -1
  207. package/dist/core/rollback.js +13 -90
  208. package/dist/core/rollback.js.map +1 -1
  209. package/dist/core/sdk.d.ts +1 -1
  210. package/dist/core/sdk.d.ts.map +1 -1
  211. package/dist/core/sdk.js +1 -1
  212. package/dist/core/sdk.js.map +1 -1
  213. package/dist/core/session-manager.d.ts +0 -1
  214. package/dist/core/session-manager.d.ts.map +1 -1
  215. package/dist/core/session-manager.js +21 -79
  216. package/dist/core/session-manager.js.map +1 -1
  217. package/dist/core/settings-manager.d.ts +6 -0
  218. package/dist/core/settings-manager.d.ts.map +1 -1
  219. package/dist/core/settings-manager.js +19 -0
  220. package/dist/core/settings-manager.js.map +1 -1
  221. package/dist/core/slash-commands.d.ts.map +1 -1
  222. package/dist/core/slash-commands.js +0 -1
  223. package/dist/core/slash-commands.js.map +1 -1
  224. package/dist/core/timings.d.ts +2 -1
  225. package/dist/core/timings.d.ts.map +1 -1
  226. package/dist/core/timings.js +17 -2
  227. package/dist/core/timings.js.map +1 -1
  228. package/dist/dev-cli.js +0 -0
  229. package/dist/gateway/agent-bridge.d.ts +6 -1
  230. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  231. package/dist/gateway/agent-bridge.js +23 -6
  232. package/dist/gateway/agent-bridge.js.map +1 -1
  233. package/dist/gateway/commands.d.ts +1 -1
  234. package/dist/gateway/commands.d.ts.map +1 -1
  235. package/dist/gateway/commands.js +1 -18
  236. package/dist/gateway/commands.js.map +1 -1
  237. package/dist/gateway/cron.d.ts +1 -1
  238. package/dist/gateway/cron.d.ts.map +1 -1
  239. package/dist/gateway/cron.js +23 -7
  240. package/dist/gateway/cron.js.map +1 -1
  241. package/dist/main.d.ts +2 -2
  242. package/dist/main.d.ts.map +1 -1
  243. package/dist/main.js +57 -48
  244. package/dist/main.js.map +1 -1
  245. package/dist/modes/interactive/components/footer.d.ts +4 -2
  246. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  247. package/dist/modes/interactive/components/footer.js +23 -32
  248. package/dist/modes/interactive/components/footer.js.map +1 -1
  249. package/dist/modes/interactive/components/processes-selector.d.ts +2 -3
  250. package/dist/modes/interactive/components/processes-selector.d.ts.map +1 -1
  251. package/dist/modes/interactive/components/processes-selector.js +5 -10
  252. package/dist/modes/interactive/components/processes-selector.js.map +1 -1
  253. package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  254. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  255. package/dist/modes/interactive/components/settings-selector.js +20 -0
  256. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  257. package/dist/modes/interactive/interactive-mode.d.ts +12 -21
  258. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  259. package/dist/modes/interactive/interactive-mode.js +138 -152
  260. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  261. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  262. package/dist/modes/interactive/theme/theme.js +95 -84
  263. package/dist/modes/interactive/theme/theme.js.map +1 -1
  264. package/dist/modes/interactive/thinking-level-slash.d.ts +4 -0
  265. package/dist/modes/interactive/thinking-level-slash.d.ts.map +1 -0
  266. package/dist/modes/interactive/thinking-level-slash.js +23 -0
  267. package/dist/modes/interactive/thinking-level-slash.js.map +1 -0
  268. package/dist/node-runtime/adapter-AZMY335J.js +279 -0
  269. package/dist/node-runtime/agent-session-services-RSGP5GDN.js +39 -0
  270. package/dist/node-runtime/benchmark-request-UC7PD3V3.js +57 -0
  271. package/dist/node-runtime/brave-UWDA3I22.js +143 -0
  272. package/dist/node-runtime/builtin-extensions-7STLFW3A.js +29 -0
  273. package/dist/node-runtime/chunk-2IDTZAG5.js +1415 -0
  274. package/dist/node-runtime/chunk-3GHXVUAK.js +21 -0
  275. package/dist/node-runtime/chunk-3RCWXWAY.js +466 -0
  276. package/dist/node-runtime/chunk-3WFAEVKS.js +115 -0
  277. package/dist/node-runtime/chunk-3X3KZKMI.js +49 -0
  278. package/dist/node-runtime/chunk-4HXHDDCF.js +16 -0
  279. package/dist/node-runtime/chunk-4SJWFTUP.js +24 -0
  280. package/dist/node-runtime/chunk-4ZWGEEAS.js +69 -0
  281. package/dist/node-runtime/chunk-53YJI7JU.js +137 -0
  282. package/dist/node-runtime/chunk-5NWQCSKR.js +19218 -0
  283. package/dist/node-runtime/chunk-5OLJGVCB.js +68 -0
  284. package/dist/node-runtime/chunk-5Q45AVQG.js +108 -0
  285. package/dist/node-runtime/chunk-5SQDLSZJ.js +949 -0
  286. package/dist/node-runtime/chunk-6SPPH4FY.js +1269 -0
  287. package/dist/node-runtime/chunk-6UB6NKA3.js +860 -0
  288. package/dist/node-runtime/chunk-7AFOFSDY.js +105 -0
  289. package/dist/node-runtime/chunk-7N3YHTYF.js +26 -0
  290. package/dist/node-runtime/chunk-ARC4KOTI.js +11178 -0
  291. package/dist/node-runtime/chunk-AUXVGBO4.js +19 -0
  292. package/dist/node-runtime/chunk-AY6CAJSL.js +30 -0
  293. package/dist/node-runtime/chunk-BHO7O6E5.js +296 -0
  294. package/dist/node-runtime/chunk-BI3DHYCN.js +8845 -0
  295. package/dist/node-runtime/chunk-BKAZ6BKX.js +2185 -0
  296. package/dist/node-runtime/chunk-BR7YDUKA.js +109 -0
  297. package/dist/node-runtime/chunk-BRJX2PRC.js +53 -0
  298. package/dist/node-runtime/chunk-C4O2RSQQ.js +37 -0
  299. package/dist/node-runtime/chunk-CCZJ3PYY.js +17 -0
  300. package/dist/node-runtime/chunk-CGBXPL3E.js +1171 -0
  301. package/dist/node-runtime/chunk-CH6OL6P2.js +295 -0
  302. package/dist/node-runtime/chunk-CJECDQKP.js +19 -0
  303. package/dist/node-runtime/chunk-DAPBPCBP.js +53 -0
  304. package/dist/node-runtime/chunk-DDGMHUOW.js +305 -0
  305. package/dist/node-runtime/chunk-DMMTJQMQ.js +43 -0
  306. package/dist/node-runtime/chunk-DVGWF6A2.js +1180 -0
  307. package/dist/node-runtime/chunk-EH2LJQPM.js +64 -0
  308. package/dist/node-runtime/chunk-EHMBW7FA.js +772 -0
  309. package/dist/node-runtime/chunk-FLYMHKCS.js +966 -0
  310. package/dist/node-runtime/chunk-FVDOXRUD.js +96 -0
  311. package/dist/node-runtime/chunk-GZQHMEWL.js +126 -0
  312. package/dist/node-runtime/chunk-H2EOZYMP.js +57 -0
  313. package/dist/node-runtime/chunk-HQCKFM2O.js +56 -0
  314. package/dist/node-runtime/chunk-HRS4HMDX.js +610 -0
  315. package/dist/node-runtime/chunk-HYHJIRDW.js +19 -0
  316. package/dist/node-runtime/chunk-I6R76AG7.js +22 -0
  317. package/dist/node-runtime/chunk-ISQDQIZN.js +296 -0
  318. package/dist/node-runtime/chunk-J7QGQD45.js +24921 -0
  319. package/dist/node-runtime/chunk-JHYKXIMM.js +378 -0
  320. package/dist/node-runtime/chunk-JT6YCS5B.js +5648 -0
  321. package/dist/node-runtime/chunk-JZHEUQRL.js +180 -0
  322. package/dist/node-runtime/chunk-K72NVGUB.js +2834 -0
  323. package/dist/node-runtime/chunk-KKSIVROT.js +88 -0
  324. package/dist/node-runtime/chunk-LCACDWHJ.js +1743 -0
  325. package/dist/node-runtime/chunk-LTXUQJI4.js +173 -0
  326. package/dist/node-runtime/chunk-LWJXTA6Z.js +6814 -0
  327. package/dist/node-runtime/chunk-M3LZLQW2.js +98 -0
  328. package/dist/node-runtime/chunk-MGSB2C3M.js +46 -0
  329. package/dist/node-runtime/chunk-MGWCVY6Y.js +47 -0
  330. package/dist/node-runtime/chunk-MJQDX3BA.js +72 -0
  331. package/dist/node-runtime/chunk-MUMMMTW4.js +8392 -0
  332. package/dist/node-runtime/chunk-MX3GJNXJ.js +986 -0
  333. package/dist/node-runtime/chunk-NUIFPZWX.js +209 -0
  334. package/dist/node-runtime/chunk-OBMWP3I5.js +68 -0
  335. package/dist/node-runtime/chunk-OR4L3IB2.js +42 -0
  336. package/dist/node-runtime/chunk-OTT6JMPU.js +807 -0
  337. package/dist/node-runtime/chunk-PCIGF2XK.js +250 -0
  338. package/dist/node-runtime/chunk-PL6JKXWI.js +3622 -0
  339. package/dist/node-runtime/chunk-PVCDKGR6.js +55 -0
  340. package/dist/node-runtime/chunk-Q4Q6D4IY.js +364 -0
  341. package/dist/node-runtime/chunk-Q5ZU2VRT.js +83 -0
  342. package/dist/node-runtime/chunk-QFWG2RVL.js +5477 -0
  343. package/dist/node-runtime/chunk-RQ2Q5IYR.js +72 -0
  344. package/dist/node-runtime/chunk-RQ5DNUNG.js +429 -0
  345. package/dist/node-runtime/chunk-RRIZE6QQ.js +17 -0
  346. package/dist/node-runtime/chunk-SN6G4OU6.js +4753 -0
  347. package/dist/node-runtime/chunk-SWSN6HAB.js +53 -0
  348. package/dist/node-runtime/chunk-T5GM5BFH.js +7558 -0
  349. package/dist/node-runtime/chunk-TAP7QTUT.js +1346 -0
  350. package/dist/node-runtime/chunk-U6C7VTR5.js +2033 -0
  351. package/dist/node-runtime/chunk-URD2SLIT.js +1019 -0
  352. package/dist/node-runtime/chunk-VRB2IYGG.js +53 -0
  353. package/dist/node-runtime/chunk-W3CVH5RX.js +62 -0
  354. package/dist/node-runtime/chunk-W7S2REEG.js +9478 -0
  355. package/dist/node-runtime/chunk-XBWPBZBN.js +125 -0
  356. package/dist/node-runtime/chunk-XTHQ7XR7.js +509 -0
  357. package/dist/node-runtime/chunk-ZCHMJ34K.js +130 -0
  358. package/dist/node-runtime/chunk-ZRDIMBEQ.js +651 -0
  359. package/dist/node-runtime/chunk-ZSEZY3II.js +247 -0
  360. package/dist/node-runtime/cli-runtime.js +81 -0
  361. package/dist/node-runtime/clipboard-OZ63BBC6.js +12 -0
  362. package/dist/node-runtime/clipboard-image-7QR6GXVA.js +13 -0
  363. package/dist/node-runtime/command-6UXQ6XZN.js +13 -0
  364. package/dist/node-runtime/commands-LGR5VT5X.js +293 -0
  365. package/dist/node-runtime/config-FMEOZSWE.js +77 -0
  366. package/dist/node-runtime/curator-server-XCM43VEF.js +3816 -0
  367. package/dist/node-runtime/customize-XEXL2DGQ.js +12 -0
  368. package/dist/node-runtime/direct-tool-executor-TDJS7TBD.js +191 -0
  369. package/dist/node-runtime/exa-LL64QZR2.js +329 -0
  370. package/dist/node-runtime/export-html-E4DT6ZJQ.js +150 -0
  371. package/dist/node-runtime/extension-input-RV5N6APL.js +14 -0
  372. package/dist/node-runtime/extension-selector-CPD5LWDD.js +14 -0
  373. package/dist/node-runtime/extract-IUCVZCWC.js +17 -0
  374. package/dist/node-runtime/file-sync-HCOP2QVF.js +117 -0
  375. package/dist/node-runtime/gateway-3OLC4GQN.js +2139 -0
  376. package/dist/node-runtime/gemini-api-QE7ANVDZ.js +29 -0
  377. package/dist/node-runtime/gemini-search-NCIDF7NE.js +330 -0
  378. package/dist/node-runtime/gemini-url-context-OKIN7AIP.js +103 -0
  379. package/dist/node-runtime/gemini-web-MM446SEH.js +14 -0
  380. package/dist/node-runtime/github-extract-F64RZOEA.js +619 -0
  381. package/dist/node-runtime/goal-CZQ7FFQJ.js +1831 -0
  382. package/dist/node-runtime/image-resize-6ZPBFMWW.js +11 -0
  383. package/dist/node-runtime/index.js +863 -0
  384. package/dist/node-runtime/init-EKE277AG.js +30 -0
  385. package/dist/node-runtime/install-cli-TH7IJJQQ.js +308 -0
  386. package/dist/node-runtime/interactive-mode-S5M26CQ7.js +59 -0
  387. package/dist/node-runtime/interactive-view-N6F4KUIT.js +247 -0
  388. package/dist/node-runtime/lsp-manager-3ASUSO4T.js +1104 -0
  389. package/dist/node-runtime/lunr-computer-use-4X3KUNF4.js +206 -0
  390. package/dist/node-runtime/lunr-cron-KKBOGAEF.js +274 -0
  391. package/dist/node-runtime/main.js +57 -0
  392. package/dist/node-runtime/mcp-auth-flow-YL6RWPYG.js +33 -0
  393. package/dist/node-runtime/mcp-panel-IIGMXQGP.js +501 -0
  394. package/dist/node-runtime/mcp-setup-panel-FEK7663I.js +355 -0
  395. package/dist/node-runtime/memory-cap-3S4XRLNP.js +20 -0
  396. package/dist/node-runtime/model-tiers-NJLHUEGK.js +20 -0
  397. package/dist/node-runtime/openai-search-B3MSNCQA.js +288 -0
  398. package/dist/node-runtime/package-manager-cli-C4EJOO5Q.js +751 -0
  399. package/dist/node-runtime/parallel-AI2MNSCU.js +265 -0
  400. package/dist/node-runtime/parser-manager-TQHWYDH7.js +152 -0
  401. package/dist/node-runtime/pdf-extract-IPE6H4HP.js +57 -0
  402. package/dist/node-runtime/perplexity-QVJW3I35.js +12 -0
  403. package/dist/node-runtime/pi-intercom-EEMBGQID.js +2215 -0
  404. package/dist/node-runtime/pi-mcp-adapter-DPTJGAAL.js +428 -0
  405. package/dist/node-runtime/pi-ollama-cloud-4VZRMULP.js +1440 -0
  406. package/dist/node-runtime/pi-prompt-template-model-4QT4LLXF.js +3946 -0
  407. package/dist/node-runtime/pi-subagents-VKCLYIBY.js +6050 -0
  408. package/dist/node-runtime/pi-web-access-BV6DSZOP.js +1867 -0
  409. package/dist/node-runtime/print-mode-VWIRFDAC.js +12 -0
  410. package/dist/node-runtime/proxy-modes-R64LU6WZ.js +688 -0
  411. package/dist/node-runtime/rpc-entry.js +65 -0
  412. package/dist/node-runtime/rpc-mode-SJNSOA4G.js +13 -0
  413. package/dist/node-runtime/runtime-3SB5ATHQ.js +21 -0
  414. package/dist/node-runtime/runtime-bridges-UJ5WJJLN.js +14 -0
  415. package/dist/node-runtime/session-manager-QEMZBMTM.js +33 -0
  416. package/dist/node-runtime/session-selector-URVJLOTK.js +14 -0
  417. package/dist/node-runtime/settings-manager-K6IPIQTI.js +23 -0
  418. package/dist/node-runtime/src-GPFAU3N6.js +2427 -0
  419. package/dist/node-runtime/subagent-executor-EFLTO32A.js +8501 -0
  420. package/dist/node-runtime/summary-review-YSMXKITO.js +228 -0
  421. package/dist/node-runtime/tavily-WEZFVFP7.js +154 -0
  422. package/dist/node-runtime/timings-UAD5BEAS.js +16 -0
  423. package/dist/node-runtime/tool-renderer-MV5O452K.js +204 -0
  424. package/dist/node-runtime/update-cli-I6OVDRPL.js +75 -0
  425. package/dist/node-runtime/v4-5MNC3H7G.js +424 -0
  426. package/dist/node-runtime/video-extract-ETA5RA7U.js +304 -0
  427. package/dist/node-runtime/workflow-SA34S4VX.js +325 -0
  428. package/dist/node-runtime/workspace-index-6DBXSTJ6.js +163 -0
  429. package/dist/node-runtime/youtube-extract-SRVGNN26.js +264 -0
  430. package/dist/rpc.d.ts +3 -0
  431. package/dist/rpc.d.ts.map +1 -0
  432. package/dist/rpc.js +18 -0
  433. package/dist/rpc.js.map +1 -0
  434. package/dist/startup/benchmark-request.d.ts +3 -0
  435. package/dist/startup/benchmark-request.d.ts.map +1 -0
  436. package/dist/startup/benchmark-request.js +65 -0
  437. package/dist/startup/benchmark-request.js.map +1 -0
  438. package/dist/startup/{interactive-shell.d.ts → interactive-view.d.ts} +18 -18
  439. package/dist/startup/interactive-view.d.ts.map +1 -0
  440. package/dist/startup/{interactive-shell.js → interactive-view.js} +119 -52
  441. package/dist/startup/interactive-view.js.map +1 -0
  442. package/dist/startup/launch-routing.d.ts.map +1 -1
  443. package/dist/startup/launch-routing.js +9 -10
  444. package/dist/startup/launch-routing.js.map +1 -1
  445. package/dist/startup/startup-milestones.d.ts +1 -1
  446. package/dist/startup/startup-milestones.d.ts.map +1 -1
  447. package/dist/startup/startup-milestones.js +3 -2
  448. package/dist/startup/startup-milestones.js.map +1 -1
  449. package/dist/utils/await-with-abort.d.ts +2 -0
  450. package/dist/utils/await-with-abort.d.ts.map +1 -0
  451. package/dist/utils/await-with-abort.js +19 -0
  452. package/dist/utils/await-with-abort.js.map +1 -0
  453. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  454. package/dist/utils/syntax-highlight.js +10 -4
  455. package/dist/utils/syntax-highlight.js.map +1 -1
  456. package/docs/compaction.md +5 -3
  457. package/docs/computer-use.md +277 -0
  458. package/docs/development.md +5 -33
  459. package/docs/features.md +2 -3
  460. package/docs/interactive-startup.md +105 -0
  461. package/docs/keybindings.md +2 -2
  462. package/docs/terminal-setup.md +1 -1
  463. package/docs/usage.md +1 -2
  464. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  465. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  466. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  467. package/examples/extensions/gondolin/package-lock.json +2 -2
  468. package/examples/extensions/gondolin/package.json +1 -1
  469. package/examples/extensions/hidden-thinking-label.ts +1 -1
  470. package/examples/extensions/sandbox/package-lock.json +2 -2
  471. package/examples/extensions/sandbox/package.json +1 -1
  472. package/examples/extensions/with-deps/package-lock.json +2 -2
  473. package/examples/extensions/with-deps/package.json +1 -1
  474. package/install-lock/package-lock.json +3827 -0
  475. package/install-lock/package.json +18 -0
  476. package/native/computer-use/LICENSE.md +21 -0
  477. package/npm-shrinkwrap.json +3808 -0
  478. package/package.json +30 -24
  479. package/dist/core/swarm.d.ts +0 -23
  480. package/dist/core/swarm.d.ts.map +0 -1
  481. package/dist/core/swarm.js +0 -45
  482. package/dist/core/swarm.js.map +0 -1
  483. package/dist/startup/interactive-shell.d.ts.map +0 -1
  484. package/dist/startup/interactive-shell.js.map +0 -1
@@ -0,0 +1,2215 @@
1
+ import { createRequire as __lunrRequire } from "node:module"; const require = __lunrRequire(import.meta.url);
2
+ import "./chunk-BRJX2PRC.js";
3
+
4
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/index.js
5
+ import { StringEnum } from "@ashx-j/lunr-ai";
6
+ import { randomUUID as randomUUID3 } from "crypto";
7
+ import { Type } from "typebox";
8
+ import { Text } from "@ashx-j/lunr-tui";
9
+
10
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/broker/client.js
11
+ import { EventEmitter } from "events";
12
+ import net from "net";
13
+ import { randomUUID } from "crypto";
14
+
15
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/broker/framing.js
16
+ function writeMessage(socket, msg) {
17
+ let json = JSON.stringify(msg), payload = Buffer.from(json, "utf-8"), header = Buffer.alloc(4);
18
+ header.writeUInt32BE(payload.length, 0), socket.write(Buffer.concat([header, payload]));
19
+ }
20
+ function createMessageReader(onMessage, onError, maxFrameBytes = 1048576) {
21
+ let buffer = Buffer.alloc(0);
22
+ function reportMessage(payload) {
23
+ let msg;
24
+ try {
25
+ msg = JSON.parse(payload.toString("utf-8"));
26
+ } catch (error) {
27
+ let message = error instanceof Error ? error.message : String(error);
28
+ return onError(new Error(`Failed to parse intercom message: ${message}`, { cause: error })), !1;
29
+ }
30
+ try {
31
+ return onMessage(msg), !0;
32
+ } catch (error) {
33
+ let message = error instanceof Error ? error.message : String(error);
34
+ return onError(new Error(`Failed to handle intercom message: ${message}`, { cause: error })), !1;
35
+ }
36
+ }
37
+ return (data) => {
38
+ let remaining = data;
39
+ for (; remaining.length > 0; ) {
40
+ if (buffer.length < 4) {
41
+ let headerBytes = Math.min(4 - buffer.length, remaining.length);
42
+ if (buffer = Buffer.concat([buffer, remaining.subarray(0, headerBytes)]), remaining = remaining.subarray(headerBytes), buffer.length < 4)
43
+ return;
44
+ }
45
+ let length = buffer.readUInt32BE(0);
46
+ if (length > maxFrameBytes) {
47
+ buffer = Buffer.alloc(0), onError(new Error(`Intercom frame length ${length} exceeds maximum ${maxFrameBytes} bytes`));
48
+ return;
49
+ }
50
+ let missingPayloadBytes = length - Math.max(0, buffer.length - 4), payloadBytes = Math.min(missingPayloadBytes, remaining.length);
51
+ if (payloadBytes > 0 && (buffer = Buffer.concat([buffer, remaining.subarray(0, payloadBytes)]), remaining = remaining.subarray(payloadBytes)), buffer.length < 4 + length)
52
+ return;
53
+ let payload = buffer.subarray(4, 4 + length);
54
+ if (buffer = Buffer.alloc(0), !reportMessage(payload))
55
+ return;
56
+ }
57
+ };
58
+ }
59
+
60
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/broker/paths.js
61
+ import { chmodSync, mkdirSync, readFileSync } from "fs";
62
+ import { isAbsolute, join, resolve } from "path";
63
+ import { homedir } from "os";
64
+ var INTERCOM_DIR_MODE = 448, INTERCOM_RUNTIME_FILE_MODE = 384, INTERCOM_TCP_HOST = "127.0.0.1", INTERCOM_PROTOCOL_NAME = "pi-intercom", INTERCOM_PROTOCOL_VERSION = 1;
65
+ function sanitizePipeSegment(value) {
66
+ return value.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() || "default";
67
+ }
68
+ function getAgentDirPath(env = process.env, homeDir = homedir(), cwd = process.cwd()) {
69
+ let configured = env.PI_CODING_AGENT_DIR?.trim();
70
+ return configured ? isAbsolute(configured) ? configured : resolve(cwd, configured) : join(homeDir, ".lunr/agent");
71
+ }
72
+ function getIntercomDirPath(agentDir = getAgentDirPath()) {
73
+ return join(agentDir, "intercom");
74
+ }
75
+ function shouldUseWindowsTcpTransport(platform = process.platform, env = process.env) {
76
+ if (platform !== "win32")
77
+ return !1;
78
+ if (env.PI_INTERCOM_TRANSPORT?.trim().toLowerCase() === "tcp")
79
+ return !0;
80
+ let legacyOptIn = env.PI_INTERCOM_TCP?.trim().toLowerCase();
81
+ return legacyOptIn === "1" || legacyOptIn === "true";
82
+ }
83
+ function getBrokerPortFilePath(intercomDir = getIntercomDirPath()) {
84
+ return join(intercomDir, "broker.port.json");
85
+ }
86
+ function getBrokerSocketPath(platform = process.platform, agentDir = getAgentDirPath()) {
87
+ return platform === "win32" ? `\\\\.\\pipe\\pi-intercom-${sanitizePipeSegment(agentDir)}` : join(getIntercomDirPath(agentDir), "broker.sock");
88
+ }
89
+ function getBrokerConnectTarget(platform = process.platform, env = process.env, intercomDir = getIntercomDirPath(getAgentDirPath(env))) {
90
+ if (shouldUseWindowsTcpTransport(platform, env)) {
91
+ let endpointFile = getBrokerPortFilePath(intercomDir), raw = readFileSync(endpointFile, "utf-8"), parsed = JSON.parse(raw);
92
+ if (typeof parsed != "object" || parsed === null || Array.isArray(parsed))
93
+ throw new Error(`Invalid intercom TCP endpoint at ${endpointFile}: expected a JSON object`);
94
+ let endpoint = parsed;
95
+ if (endpoint.transport !== "tcp" || endpoint.host !== INTERCOM_TCP_HOST || typeof endpoint.port != "number" || !Number.isSafeInteger(endpoint.port) || endpoint.port <= 0 || endpoint.port > 65535 || typeof endpoint.stateId != "string" || endpoint.stateId.length === 0)
96
+ throw new Error(`Invalid intercom TCP endpoint at ${endpointFile}`);
97
+ return { transport: "tcp", host: endpoint.host, port: endpoint.port, stateId: endpoint.stateId };
98
+ }
99
+ return getBrokerSocketPath(platform, getAgentDirPath(env));
100
+ }
101
+ function ensureIntercomRuntimeDir(intercomDir = getIntercomDirPath(), platform = process.platform) {
102
+ mkdirSync(intercomDir, { recursive: !0, mode: INTERCOM_DIR_MODE }), platform !== "win32" && chmodSync(intercomDir, INTERCOM_DIR_MODE);
103
+ }
104
+ function restrictIntercomRuntimeFile(filePath, platform = process.platform) {
105
+ platform !== "win32" && chmodSync(filePath, INTERCOM_RUNTIME_FILE_MODE);
106
+ }
107
+
108
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/broker/client.js
109
+ function toError(error) {
110
+ return error instanceof Error ? error : new Error(String(error));
111
+ }
112
+ function connectToBrokerTarget(target) {
113
+ return typeof target == "string" ? net.connect(target) : net.connect({ host: target.host, port: target.port });
114
+ }
115
+ function isAttachment(value) {
116
+ if (typeof value != "object" || value === null)
117
+ return !1;
118
+ let attachment = value;
119
+ return attachment.type !== "file" && attachment.type !== "snippet" && attachment.type !== "context" || typeof attachment.name != "string" || typeof attachment.content != "string" ? !1 : attachment.language === void 0 || typeof attachment.language == "string";
120
+ }
121
+ function isMessage(value) {
122
+ if (typeof value != "object" || value === null)
123
+ return !1;
124
+ let message = value;
125
+ if (typeof message.id != "string" || typeof message.timestamp != "number" || message.replyTo !== void 0 && typeof message.replyTo != "string" || message.expectsReply !== void 0 && typeof message.expectsReply != "boolean" || typeof message.content != "object" || message.content === null)
126
+ return !1;
127
+ let content = message.content;
128
+ return typeof content.text != "string" ? !1 : content.attachments === void 0 || Array.isArray(content.attachments) && content.attachments.every(isAttachment);
129
+ }
130
+ function isSessionInfo(value) {
131
+ if (typeof value != "object" || value === null)
132
+ return !1;
133
+ let session = value;
134
+ return typeof session.id != "string" || typeof session.cwd != "string" || typeof session.model != "string" || typeof session.pid != "number" || typeof session.startedAt != "number" || typeof session.lastActivity != "number" || session.name !== void 0 && typeof session.name != "string" || session.status !== void 0 && typeof session.status != "string" || session.peerUid !== void 0 && typeof session.peerUid != "number" ? !1 : session.trustedLocal === void 0 || typeof session.trustedLocal == "boolean";
135
+ }
136
+ var IntercomClient = class extends EventEmitter {
137
+ socket = null;
138
+ _sessionId = null;
139
+ pendingSends = /* @__PURE__ */ new Map();
140
+ pendingLists = /* @__PURE__ */ new Map();
141
+ disconnecting = !1;
142
+ disconnectError = null;
143
+ failPending(error) {
144
+ for (let pending of this.pendingSends.values())
145
+ pending.reject(error);
146
+ this.pendingSends.clear();
147
+ for (let pending of this.pendingLists.values())
148
+ pending.reject(error);
149
+ this.pendingLists.clear();
150
+ }
151
+ get sessionId() {
152
+ return this._sessionId;
153
+ }
154
+ isConnected() {
155
+ let socket = this.socket;
156
+ return !!(socket && this._sessionId && !this.disconnecting && !socket.destroyed && !socket.writableEnded && socket.writable);
157
+ }
158
+ requireActiveSocket() {
159
+ if (this.disconnecting)
160
+ throw new Error("Client disconnecting");
161
+ let socket = this.socket;
162
+ if (!socket || !this._sessionId)
163
+ throw new Error("Not connected");
164
+ if (socket.destroyed || socket.writableEnded || !socket.writable)
165
+ throw new Error("Client disconnected");
166
+ return socket;
167
+ }
168
+ connect(session, sessionId) {
169
+ return this.socket ? Promise.reject(new Error("Already connected")) : new Promise((resolve2, reject) => {
170
+ let socket, target;
171
+ try {
172
+ target = getBrokerConnectTarget(), socket = connectToBrokerTarget(target);
173
+ } catch (error) {
174
+ reject(toError(error));
175
+ return;
176
+ }
177
+ this.socket = socket, this.disconnectError = null;
178
+ let settled = !1, timeout = setTimeout(() => {
179
+ this._sessionId || (cleanupConnectionAttempt(), cleanupSocketListeners(), this.socket === socket && (this.socket = null), socket.destroy(), reject(new Error("Connection timeout")));
180
+ }, 1e4), connectionEstablished = !1, onRegistered = () => {
181
+ settled = !0, connectionEstablished = !0, cleanupConnectionAttempt(), resolve2();
182
+ }, onError = (err) => {
183
+ settled = !0, cleanupConnectionAttempt(), cleanupSocketListeners(), this.socket === socket && (this.socket = null), socket.destroy(), reject(err);
184
+ }, onClose = () => {
185
+ let wasConnecting = !settled && !this._sessionId, wasDisconnecting = this.disconnecting, disconnectError = this.disconnectError ?? new Error("Client disconnected");
186
+ this.disconnecting = !1, cleanupConnectionAttempt(), cleanupSocketListeners(), this.failPending(disconnectError), this.socket === socket && (this.socket = null), this._sessionId = null, this.disconnectError = null, connectionEstablished && !wasDisconnecting && this.emit("disconnected", disconnectError), wasConnecting && reject(new Error("Connection closed before registration"));
187
+ }, onSocketError = (err) => {
188
+ connectionEstablished && (this.disconnectError = err, this.emit("error", err));
189
+ }, reader = createMessageReader((msg) => {
190
+ this.handleBrokerMessage(msg);
191
+ }, (error) => {
192
+ let protocolError = new Error(`Intercom protocol error: ${error.message}`, { cause: error });
193
+ if (!connectionEstablished) {
194
+ onError(protocolError);
195
+ return;
196
+ }
197
+ this.disconnectError = protocolError, this.emit("error", protocolError), socket.destroy();
198
+ }), cleanupConnectionAttempt = () => {
199
+ this.off("_registered", onRegistered), socket.off("error", onError), clearTimeout(timeout);
200
+ }, cleanupSocketListeners = () => {
201
+ socket.off("data", reader), socket.off("error", onSocketError), socket.off("close", onClose);
202
+ };
203
+ socket.on("data", reader), socket.on("error", onError), socket.on("close", onClose), socket.on("error", onSocketError), this.once("_registered", onRegistered);
204
+ try {
205
+ writeMessage(socket, {
206
+ type: "register",
207
+ session,
208
+ ...sessionId ? { sessionId } : {},
209
+ ...typeof target == "string" ? {} : { stateId: target.stateId }
210
+ });
211
+ } catch (error) {
212
+ cleanupConnectionAttempt(), cleanupSocketListeners(), this.socket === socket && (this.socket = null), socket.destroy(), reject(toError(error));
213
+ }
214
+ });
215
+ }
216
+ handleBrokerMessage(msg) {
217
+ if (typeof msg != "object" || msg === null || !("type" in msg) || typeof msg.type != "string")
218
+ throw new Error("Invalid broker message");
219
+ let brokerMessage = msg;
220
+ if (this._sessionId === null && brokerMessage.type !== "registered" && brokerMessage.type !== "error")
221
+ throw new Error(`Received ${brokerMessage.type} before registered`);
222
+ switch (brokerMessage.type) {
223
+ case "registered": {
224
+ if (typeof brokerMessage.sessionId != "string")
225
+ throw new Error("Invalid registered message");
226
+ if (this._sessionId !== null)
227
+ throw new Error("Received duplicate registered message");
228
+ this._sessionId = brokerMessage.sessionId, this.emit("_registered", { type: "registered", sessionId: brokerMessage.sessionId });
229
+ break;
230
+ }
231
+ case "sessions": {
232
+ let { requestId, sessions } = brokerMessage;
233
+ if (typeof requestId != "string" || !Array.isArray(sessions) || !sessions.every(isSessionInfo))
234
+ throw new Error("Invalid sessions message");
235
+ let pending = this.pendingLists.get(requestId);
236
+ if (!pending)
237
+ return;
238
+ this.pendingLists.delete(requestId), pending.resolve(sessions);
239
+ break;
240
+ }
241
+ case "message": {
242
+ let { from, message } = brokerMessage;
243
+ if (!isSessionInfo(from) || !isMessage(message))
244
+ throw new Error("Invalid message event");
245
+ this.emit("message", from, message);
246
+ break;
247
+ }
248
+ case "delivered": {
249
+ let { messageId } = brokerMessage;
250
+ if (typeof messageId != "string")
251
+ throw new Error("Invalid delivered message");
252
+ let pending = this.pendingSends.get(messageId);
253
+ if (!pending)
254
+ return;
255
+ this.pendingSends.delete(messageId), pending.resolve({ id: messageId, delivered: !0 });
256
+ break;
257
+ }
258
+ case "delivery_failed": {
259
+ let { messageId, reason } = brokerMessage;
260
+ if (typeof messageId != "string" || typeof reason != "string")
261
+ throw new Error("Invalid delivery_failed message");
262
+ let pending = this.pendingSends.get(messageId);
263
+ if (!pending)
264
+ return;
265
+ this.pendingSends.delete(messageId), pending.resolve({ id: messageId, delivered: !1, reason });
266
+ break;
267
+ }
268
+ case "session_joined": {
269
+ if (!isSessionInfo(brokerMessage.session))
270
+ throw new Error("Invalid session_joined message");
271
+ this.emit("session_joined", brokerMessage.session);
272
+ break;
273
+ }
274
+ case "session_left": {
275
+ if (typeof brokerMessage.sessionId != "string")
276
+ throw new Error("Invalid session_left message");
277
+ this.emit("session_left", brokerMessage.sessionId);
278
+ break;
279
+ }
280
+ case "presence_update": {
281
+ if (!isSessionInfo(brokerMessage.session))
282
+ throw new Error("Invalid presence_update message");
283
+ this.emit("presence_update", brokerMessage.session);
284
+ break;
285
+ }
286
+ case "error": {
287
+ if (typeof brokerMessage.error != "string")
288
+ throw new Error("Invalid error message");
289
+ if (this._sessionId === null)
290
+ throw new Error(brokerMessage.error);
291
+ this.emit("error", new Error(brokerMessage.error));
292
+ break;
293
+ }
294
+ default:
295
+ throw new Error(`Unknown broker message type: ${brokerMessage.type}`);
296
+ }
297
+ }
298
+ async disconnect() {
299
+ let socket = this.socket;
300
+ socket && (this.disconnecting = !0, this.disconnectError = null, this.failPending(new Error("Client disconnected")), await new Promise((resolve2) => {
301
+ let settled = !1, finish = () => {
302
+ settled || (settled = !0, clearTimeout(timeout), socket.off("close", onClose), socket.off("error", onError), resolve2());
303
+ }, onClose = () => finish(), onError = () => {
304
+ socket.destroy();
305
+ }, timeout = setTimeout(() => {
306
+ socket.destroy();
307
+ }, 2e3);
308
+ socket.once("close", onClose), socket.once("error", onError);
309
+ try {
310
+ writeMessage(socket, { type: "unregister" }), socket.end();
311
+ } catch {
312
+ socket.destroy();
313
+ }
314
+ }));
315
+ }
316
+ listSessions() {
317
+ let socket;
318
+ try {
319
+ socket = this.requireActiveSocket();
320
+ } catch (error) {
321
+ return Promise.reject(toError(error));
322
+ }
323
+ return new Promise((resolve2, reject) => {
324
+ let requestId = randomUUID(), wrappedResolve = (sessions) => {
325
+ clearTimeout(timeout), resolve2(sessions);
326
+ }, wrappedReject = (error) => {
327
+ clearTimeout(timeout), reject(error);
328
+ }, timeout = setTimeout(() => {
329
+ this.pendingLists.has(requestId) && (this.pendingLists.delete(requestId), wrappedReject(new Error("List sessions timeout")));
330
+ }, 5e3);
331
+ this.pendingLists.set(requestId, { resolve: wrappedResolve, reject: wrappedReject });
332
+ try {
333
+ writeMessage(socket, { type: "list", requestId });
334
+ } catch (error) {
335
+ clearTimeout(timeout), this.pendingLists.delete(requestId), reject(toError(error));
336
+ }
337
+ });
338
+ }
339
+ send(to, options) {
340
+ let socket;
341
+ try {
342
+ socket = this.requireActiveSocket();
343
+ } catch (error) {
344
+ return Promise.reject(toError(error));
345
+ }
346
+ let messageId = options.messageId ?? randomUUID(), message = {
347
+ id: messageId,
348
+ timestamp: Date.now(),
349
+ replyTo: options.replyTo,
350
+ expectsReply: options.expectsReply,
351
+ content: {
352
+ text: options.text,
353
+ attachments: options.attachments
354
+ }
355
+ };
356
+ return new Promise((resolve2, reject) => {
357
+ let wrappedResolve = (result) => {
358
+ clearTimeout(timeout), resolve2(result);
359
+ }, wrappedReject = (error) => {
360
+ clearTimeout(timeout), reject(error);
361
+ }, timeout = setTimeout(() => {
362
+ this.pendingSends.has(messageId) && (this.pendingSends.delete(messageId), wrappedReject(new Error("Send timeout")));
363
+ }, 1e4);
364
+ this.pendingSends.set(messageId, { resolve: wrappedResolve, reject: wrappedReject });
365
+ try {
366
+ writeMessage(socket, { type: "send", to, message });
367
+ } catch (error) {
368
+ clearTimeout(timeout), this.pendingSends.delete(messageId), reject(toError(error));
369
+ }
370
+ });
371
+ }
372
+ cancelAsk(messageId) {
373
+ if (this.disconnecting)
374
+ return;
375
+ let socket = this.socket;
376
+ if (!(!socket || !this._sessionId || socket.destroyed || socket.writableEnded || !socket.writable))
377
+ try {
378
+ writeMessage(socket, { type: "cancel_ask", messageId });
379
+ } catch {
380
+ }
381
+ }
382
+ updatePresence(updates) {
383
+ if (this.disconnecting)
384
+ return;
385
+ let socket = this.socket;
386
+ !socket || !this._sessionId || socket.destroyed || socket.writableEnded || !socket.writable || writeMessage(socket, { type: "presence", ...updates });
387
+ }
388
+ };
389
+
390
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/broker/spawn.js
391
+ import { spawn } from "child_process";
392
+ import { existsSync, readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
393
+ import { join as join2, dirname } from "path";
394
+ import { fileURLToPath } from "url";
395
+ import { createRequire } from "module";
396
+ import net2 from "net";
397
+ import { randomUUID as randomUUID2 } from "crypto";
398
+ var INTERCOM_DIR = getIntercomDirPath(), EXTENSION_DIR = join2(dirname(fileURLToPath(new URL("../builtin-extensions/pi-intercom/broker/spawn.js", import.meta.url).href)), ".."), BROKER_PID = join2(INTERCOM_DIR, "broker.pid"), BROKER_SPAWN_LOCK = join2(INTERCOM_DIR, "broker.spawn.lock");
399
+ function sleep(ms) {
400
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
401
+ }
402
+ function getTsxCliPath(extensionDir = EXTENSION_DIR) {
403
+ try {
404
+ let tsxMain = createRequire(new URL("../builtin-extensions/pi-intercom/broker/spawn.js", import.meta.url).href).resolve("tsx");
405
+ return join2(dirname(tsxMain), "cli.mjs");
406
+ } catch {
407
+ return join2(extensionDir, "node_modules", "tsx", "dist", "cli.mjs");
408
+ }
409
+ }
410
+ function quoteWindowsArg(value) {
411
+ return `"${value.replace(/"/g, '""')}"`;
412
+ }
413
+ function getWindowsHiddenLauncherPath(intercomDir = INTERCOM_DIR) {
414
+ return join2(intercomDir, "broker-launch.vbs");
415
+ }
416
+ function usesDefaultBrokerCommand(brokerCommand, brokerArgs) {
417
+ return brokerCommand === "npx" && brokerArgs.length === 2 && brokerArgs[0] === "--no-install" && brokerArgs[1] === "tsx";
418
+ }
419
+ function getWindowsBrokerCommandLine(brokerPath, extensionDir = EXTENSION_DIR, nodePath = process.execPath, brokerCommand = "npx", brokerArgs = ["--no-install", "tsx"]) {
420
+ return usesDefaultBrokerCommand(brokerCommand, brokerArgs) ? [quoteWindowsArg(nodePath), quoteWindowsArg(getTsxCliPath(extensionDir)), quoteWindowsArg(brokerPath)].join(" ") : [quoteWindowsArg(brokerCommand), ...brokerArgs.map(quoteWindowsArg), quoteWindowsArg(brokerPath)].join(" ");
421
+ }
422
+ function getWindowsHiddenLauncherScript(commandLine) {
423
+ return [
424
+ 'Set WshShell = CreateObject("WScript.Shell")',
425
+ `WshShell.Run "${commandLine.replace(/"/g, '""')}", 0, False`,
426
+ "Set WshShell = Nothing",
427
+ ""
428
+ ].join(`\r
429
+ `);
430
+ }
431
+ function isBrokerHealthOkMessage(message, requestId) {
432
+ if (typeof message != "object" || message === null || !("type" in message))
433
+ return !1;
434
+ let response = message;
435
+ return response.type === "health_ok" && response.requestId === requestId && response.protocol === INTERCOM_PROTOCOL_NAME && response.version === INTERCOM_PROTOCOL_VERSION;
436
+ }
437
+ function writeWindowsHiddenLauncher(commandLine, launcherPath = getWindowsHiddenLauncherPath()) {
438
+ return ensureIntercomRuntimeDir(dirname(launcherPath)), writeFileSync(launcherPath, getWindowsHiddenLauncherScript(commandLine), {
439
+ encoding: "utf-8",
440
+ mode: INTERCOM_RUNTIME_FILE_MODE
441
+ }), restrictIntercomRuntimeFile(launcherPath), launcherPath;
442
+ }
443
+ function getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs, extensionDir = EXTENSION_DIR, platform = process.platform, intercomDir = INTERCOM_DIR, nodePath = process.execPath) {
444
+ if (platform === "win32") {
445
+ let launcherPath = getWindowsHiddenLauncherPath(intercomDir);
446
+ return {
447
+ kind: "windows-launcher",
448
+ command: "wscript.exe",
449
+ args: [launcherPath],
450
+ launcherPath,
451
+ launcherCommandLine: getWindowsBrokerCommandLine(brokerPath, extensionDir, nodePath, brokerCommand, brokerArgs)
452
+ };
453
+ }
454
+ return usesDefaultBrokerCommand(brokerCommand, brokerArgs) ? {
455
+ kind: "direct",
456
+ command: nodePath,
457
+ args: [getTsxCliPath(extensionDir), brokerPath]
458
+ } : {
459
+ kind: "direct",
460
+ command: brokerCommand,
461
+ args: [...brokerArgs, brokerPath]
462
+ };
463
+ }
464
+ function getBrokerSpawnOptions(extensionDir = EXTENSION_DIR, env = process.env) {
465
+ return {
466
+ detached: !0,
467
+ stdio: "ignore",
468
+ cwd: extensionDir,
469
+ env: { ...env, PI_CODING_AGENT_DIR: getAgentDirPath(env), NODE_NO_WARNINGS: "1" },
470
+ windowsHide: !0
471
+ };
472
+ }
473
+ function toError2(error) {
474
+ return error instanceof Error ? error : new Error(String(error));
475
+ }
476
+ async function spawnBrokerIfNeeded(brokerCommand, brokerArgs) {
477
+ if (ensureIntercomRuntimeDir(INTERCOM_DIR), await isBrokerRunning())
478
+ return;
479
+ if (!acquireSpawnLock()) {
480
+ await waitForBroker();
481
+ return;
482
+ }
483
+ try {
484
+ if (await isBrokerRunning())
485
+ return;
486
+ let brokerPath = join2(dirname(fileURLToPath(new URL("../builtin-extensions/pi-intercom/broker/spawn.js", import.meta.url).href)), "broker.ts"), launch = getBrokerLaunchSpec(brokerPath, brokerCommand, brokerArgs);
487
+ launch.kind === "windows-launcher" && writeWindowsHiddenLauncher(launch.launcherCommandLine, launch.launcherPath);
488
+ let child = spawn(launch.command, launch.args, getBrokerSpawnOptions());
489
+ child.unref(), await new Promise((resolve2, reject) => {
490
+ let cleanup = () => {
491
+ child.off("error", onError), child.off("exit", onExit);
492
+ }, onError = (error) => {
493
+ cleanup(), reject(new Error(`Failed to spawn intercom broker: ${error.message}`, { cause: error }));
494
+ }, onExit = (code, signal) => {
495
+ if (!(launch.kind === "windows-launcher" && code === 0 && signal === null)) {
496
+ if (cleanup(), signal) {
497
+ reject(new Error(`Intercom broker exited before startup with signal ${signal}`));
498
+ return;
499
+ }
500
+ reject(new Error(`Intercom broker exited before startup with code ${code ?? "unknown"}`));
501
+ }
502
+ };
503
+ child.once("error", onError), child.once("exit", onExit), waitForBroker().then(() => {
504
+ cleanup(), resolve2();
505
+ }, (error) => {
506
+ cleanup(), reject(toError2(error));
507
+ });
508
+ });
509
+ } finally {
510
+ releaseSpawnLock();
511
+ }
512
+ }
513
+ async function isBrokerRunning() {
514
+ if (await checkSocketConnectable())
515
+ return !0;
516
+ if (!existsSync(BROKER_PID))
517
+ return !1;
518
+ try {
519
+ let pid = parseInt(readFileSync2(BROKER_PID, "utf-8").trim(), 10);
520
+ return Number.isFinite(pid) ? (process.kill(pid, 0), checkSocketConnectable()) : !1;
521
+ } catch {
522
+ return !1;
523
+ }
524
+ }
525
+ function connectToBrokerTarget2(target) {
526
+ return typeof target == "string" ? net2.connect(target) : net2.connect({ host: target.host, port: target.port });
527
+ }
528
+ function checkSocketConnectable() {
529
+ return new Promise((resolve2) => {
530
+ let target;
531
+ try {
532
+ target = getBrokerConnectTarget();
533
+ } catch {
534
+ resolve2(!1);
535
+ return;
536
+ }
537
+ let socket = connectToBrokerTarget2(target), requestId = randomUUID2(), expectedStateId = typeof target == "string" ? void 0 : target.stateId, settled = !1, finish = (isConnected) => {
538
+ settled || (settled = !0, clearTimeout(timeout), socket.off("connect", onConnect), socket.off("error", onError), socket.off("data", reader), socket.destroy(), resolve2(isConnected));
539
+ }, onConnect = () => {
540
+ try {
541
+ writeMessage(socket, {
542
+ type: "health",
543
+ requestId,
544
+ ...expectedStateId ? { stateId: expectedStateId } : {}
545
+ });
546
+ } catch {
547
+ finish(!1);
548
+ }
549
+ }, onError = () => finish(!1), reader = createMessageReader((message) => {
550
+ finish(isBrokerHealthOkMessage(message, requestId));
551
+ }, () => finish(!1));
552
+ socket.on("connect", onConnect), socket.on("error", onError), socket.on("data", reader);
553
+ let timeout = setTimeout(() => finish(!1), 1e3);
554
+ });
555
+ }
556
+ function acquireSpawnLock() {
557
+ for (let attempt = 0; attempt < 5; attempt++)
558
+ try {
559
+ return writeFileSync(BROKER_SPAWN_LOCK, `${process.pid}
560
+ ${Date.now()}
561
+ `, {
562
+ flag: "wx",
563
+ mode: INTERCOM_RUNTIME_FILE_MODE
564
+ }), restrictIntercomRuntimeFile(BROKER_SPAWN_LOCK), !0;
565
+ } catch (error) {
566
+ if (!(error instanceof Error) || error.code !== "EEXIST")
567
+ throw error;
568
+ if (isSpawnLockStale()) {
569
+ try {
570
+ unlinkSync(BROKER_SPAWN_LOCK);
571
+ } catch {
572
+ }
573
+ continue;
574
+ }
575
+ return !1;
576
+ }
577
+ return !1;
578
+ }
579
+ function isSpawnLockStale() {
580
+ if (!existsSync(BROKER_SPAWN_LOCK))
581
+ return !1;
582
+ try {
583
+ let [pidLine = "", createdAtLine = "0"] = readFileSync2(BROKER_SPAWN_LOCK, "utf-8").trim().split(`
584
+ `), pid = Number.parseInt(pidLine, 10), createdAt = Number.parseInt(createdAtLine, 10), ageMs = Date.now() - createdAt;
585
+ if (Number.isFinite(pid))
586
+ try {
587
+ process.kill(pid, 0);
588
+ } catch {
589
+ return !0;
590
+ }
591
+ return !Number.isFinite(createdAt) || ageMs > 1e4;
592
+ } catch {
593
+ return !0;
594
+ }
595
+ }
596
+ function releaseSpawnLock() {
597
+ try {
598
+ unlinkSync(BROKER_SPAWN_LOCK);
599
+ } catch {
600
+ }
601
+ }
602
+ async function waitForBroker(timeoutMs = 5e3) {
603
+ let start = Date.now();
604
+ for (; Date.now() - start < timeoutMs; ) {
605
+ if (await checkSocketConnectable())
606
+ return;
607
+ await sleep(100);
608
+ }
609
+ throw new Error("Broker failed to start within timeout");
610
+ }
611
+
612
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/ui/session-list.js
613
+ import { truncateToWidth, visibleWidth } from "@ashx-j/lunr-tui";
614
+ function middleTruncate(text, maxWidth) {
615
+ if (visibleWidth(text) <= maxWidth)
616
+ return text;
617
+ if (maxWidth <= 3)
618
+ return truncateToWidth(text, maxWidth, "");
619
+ let chars = [...text], targetSideWidth = Math.max(1, Math.floor((maxWidth - 1) / 2)), left = "";
620
+ for (let char of chars) {
621
+ if (visibleWidth(left + char) > targetSideWidth)
622
+ break;
623
+ left += char;
624
+ }
625
+ let right = "";
626
+ for (let char of chars.slice().reverse()) {
627
+ if (visibleWidth(char + right) > targetSideWidth)
628
+ break;
629
+ right = char + right;
630
+ }
631
+ return truncateToWidth(`${left}\u2026${right}`, maxWidth, "");
632
+ }
633
+ function shortSessionId(sessionId) {
634
+ return sessionId.slice(0, 8);
635
+ }
636
+ function sessionTitle(session, options) {
637
+ let name = session.name || "Unnamed session", tags = [options?.self ? "self" : void 0, options?.sameCwd ? "same cwd" : void 0].filter((tag) => !!tag), suffix = tags.length ? ` [${tags.join(", ")}]` : "";
638
+ return `${name} (${shortSessionId(session.id)})${suffix}`;
639
+ }
640
+ var SessionListOverlay = class {
641
+ theme;
642
+ keybindings;
643
+ currentSession;
644
+ done;
645
+ sessions;
646
+ selectedIndex = 0;
647
+ maxVisible = 8;
648
+ constructor(theme, keybindings, currentSession, sessions, done) {
649
+ this.theme = theme, this.keybindings = keybindings, this.currentSession = currentSession, this.sessions = sessions, this.done = done;
650
+ }
651
+ onSessionSelect(sessionId) {
652
+ let session = this.sessions.find((s) => s.id === sessionId);
653
+ session && this.done(session);
654
+ }
655
+ invalidate() {
656
+ }
657
+ handleInput(data) {
658
+ if (this.keybindings.matches(data, "tui.select.cancel")) {
659
+ this.done(void 0);
660
+ return;
661
+ }
662
+ if (this.sessions.length !== 0) {
663
+ if (this.keybindings.matches(data, "tui.select.up")) {
664
+ this.selectedIndex = this.selectedIndex === 0 ? this.sessions.length - 1 : this.selectedIndex - 1;
665
+ return;
666
+ }
667
+ if (this.keybindings.matches(data, "tui.select.down")) {
668
+ this.selectedIndex = this.selectedIndex === this.sessions.length - 1 ? 0 : this.selectedIndex + 1;
669
+ return;
670
+ }
671
+ if (this.keybindings.matches(data, "tui.select.confirm")) {
672
+ let session = this.sessions[this.selectedIndex];
673
+ session && this.onSessionSelect(session.id);
674
+ }
675
+ }
676
+ }
677
+ render(width) {
678
+ let innerWidth = Math.max(1, Math.min(width, 88));
679
+ if (innerWidth === 1)
680
+ return [this.theme.fg("accent", "\u2502")];
681
+ let contentWidth = Math.max(0, innerWidth - 2), footer = `${this.keybindings.getKeys("tui.select.confirm").join("/")}: Message \u2022 ${this.keybindings.getKeys("tui.select.cancel").join("/")}: Close`, border = (text) => this.theme.fg("accent", text), row = (text = "") => {
682
+ let clipped = truncateToWidth(text, contentWidth, "", !0);
683
+ return `${border("\u2502")}${clipped}${" ".repeat(Math.max(0, contentWidth - visibleWidth(clipped)))}${border("\u2502")}`;
684
+ }, lines = [];
685
+ if (lines.push(border(`\u256D${"\u2500".repeat(contentWidth)}\u256E`)), lines.push(row(this.theme.bold(" Current Session"))), lines.push(border(`\u251C${"\u2500".repeat(contentWidth)}\u2524`)), lines.push(row()), lines.push(row(` ${this.theme.fg("dim", sessionTitle(this.currentSession, { self: !0 }))}`)), lines.push(row(` ${this.theme.fg("dim", `${middleTruncate(this.currentSession.cwd, Math.max(8, contentWidth - 4))} \u2022 ${this.currentSession.model}`)}`)), lines.push(row()), lines.push(border(`\u251C${"\u2500".repeat(contentWidth)}\u2524`)), lines.push(row(this.theme.bold(" Other Sessions"))), lines.push(row()), this.sessions.length === 0)
686
+ lines.push(row(this.theme.fg("dim", " No other intercom-connected sessions")));
687
+ else {
688
+ let startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.sessions.length - this.maxVisible)), endIndex = Math.min(startIndex + this.maxVisible, this.sessions.length);
689
+ for (let index = startIndex; index < endIndex; index += 1) {
690
+ let session = this.sessions[index], isSelected = index === this.selectedIndex, sameCwd = session.cwd === this.currentSession.cwd, prefix = isSelected ? this.theme.fg("accent", "\u2192 ") : " ", title = sessionTitle(session, { sameCwd }), pathText = `${middleTruncate(session.cwd, Math.max(8, contentWidth - 4))} \u2022 ${session.model}`;
691
+ lines.push(row(`${prefix}${isSelected ? this.theme.fg("accent", title) : title}`)), lines.push(row(` ${this.theme.fg("dim", pathText)}`)), index < endIndex - 1 && lines.push(row());
692
+ }
693
+ (startIndex > 0 || endIndex < this.sessions.length) && (lines.push(row()), lines.push(row(this.theme.fg("dim", ` ${this.selectedIndex + 1}/${this.sessions.length}`))));
694
+ }
695
+ return lines.push(row()), lines.push(border(`\u251C${"\u2500".repeat(contentWidth)}\u2524`)), lines.push(row(this.theme.fg("dim", ` ${footer}`))), lines.push(border(`\u2570${"\u2500".repeat(contentWidth)}\u256F`)), lines;
696
+ }
697
+ };
698
+
699
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/ui/compose.js
700
+ import { truncateToWidth as truncateToWidth2, visibleWidth as visibleWidth2 } from "@ashx-j/lunr-tui";
701
+ var ComposeOverlay = class {
702
+ tui;
703
+ theme;
704
+ keybindings;
705
+ target;
706
+ targetLabel;
707
+ client;
708
+ done;
709
+ inputBuffer = "";
710
+ sending = !1;
711
+ error = null;
712
+ constructor(tui, theme, keybindings, target, targetLabel, client, done) {
713
+ this.tui = tui, this.theme = theme, this.keybindings = keybindings, this.target = target, this.targetLabel = targetLabel, this.client = client, this.done = done;
714
+ }
715
+ invalidate() {
716
+ }
717
+ handleInput(data) {
718
+ if (this.sending)
719
+ return;
720
+ if (this.keybindings.matches(data, "tui.select.cancel")) {
721
+ this.done({ sent: !1 });
722
+ return;
723
+ }
724
+ if (data.startsWith("\x1B"))
725
+ return;
726
+ if (this.keybindings.matches(data, "tui.select.confirm")) {
727
+ this.inputBuffer.trim() && this.sendMessage();
728
+ return;
729
+ }
730
+ if (this.keybindings.matches(data, "tui.editor.deleteCharBackward")) {
731
+ this.inputBuffer = [...this.inputBuffer].slice(0, -1).join(""), this.tui.requestRender();
732
+ return;
733
+ }
734
+ let printable = [...data].filter((c) => c >= " ").join("");
735
+ printable && (this.inputBuffer += printable, this.tui.requestRender());
736
+ }
737
+ async sendMessage() {
738
+ this.sending = !0, this.error = null, this.tui.requestRender();
739
+ try {
740
+ let result = await this.client.send(this.target.id, {
741
+ text: this.inputBuffer.trim()
742
+ });
743
+ if (!result.delivered) {
744
+ this.error = result.reason ?? "Message not delivered. Session may not exist or has disconnected.", this.sending = !1, this.tui.requestRender();
745
+ return;
746
+ }
747
+ this.done({
748
+ sent: !0,
749
+ messageId: result.id,
750
+ text: this.inputBuffer.trim()
751
+ });
752
+ } catch (error) {
753
+ this.error = error instanceof Error ? error.message : String(error), this.sending = !1, this.tui.requestRender();
754
+ }
755
+ }
756
+ render(width) {
757
+ let innerWidth = Math.max(1, Math.min(width, 72));
758
+ if (innerWidth === 1)
759
+ return [this.theme.fg("accent", "\u2502")];
760
+ let contentWidth = Math.max(0, innerWidth - 2), footer = `${this.keybindings.getKeys("tui.select.confirm").join("/")}: Send \u2022 ${this.keybindings.getKeys("tui.select.cancel").join("/")}: Close`, border = (text) => this.theme.fg("accent", text), row = (text = "") => {
761
+ let clipped = truncateToWidth2(text, contentWidth, "", !0);
762
+ return `${border("\u2502")}${clipped}${" ".repeat(Math.max(0, contentWidth - visibleWidth2(clipped)))}${border("\u2502")}`;
763
+ }, lines = [];
764
+ return lines.push(border(`\u256D${"\u2500".repeat(contentWidth)}\u256E`)), lines.push(row(this.theme.bold(` Send to: ${this.targetLabel}`))), lines.push(row(this.theme.fg("dim", ` ${this.target.cwd} \u2022 ${this.target.model}`))), lines.push(border(`\u251C${"\u2500".repeat(contentWidth)}\u2524`)), lines.push(row()), this.sending ? lines.push(row(this.theme.fg("dim", " Sending..."))) : this.error ? (lines.push(row(this.theme.fg("error", ` Error: ${this.error}`))), lines.push(row()), lines.push(row(` > ${this.inputBuffer}\u2588`))) : lines.push(row(` > ${this.inputBuffer}\u2588`)), lines.push(row()), lines.push(border(`\u251C${"\u2500".repeat(contentWidth)}\u2524`)), lines.push(row(this.theme.fg("dim", ` ${footer}`))), lines.push(border(`\u2570${"\u2500".repeat(contentWidth)}\u256F`)), lines;
765
+ }
766
+ };
767
+
768
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/ui/inline-message.js
769
+ import { truncateToWidth as truncateToWidth3, visibleWidth as visibleWidth3, wrapTextWithAnsi } from "@ashx-j/lunr-tui";
770
+ var InlineMessageComponent = class {
771
+ from;
772
+ message;
773
+ theme;
774
+ replyCommand;
775
+ bodyText;
776
+ collapsed;
777
+ constructor(from, message, theme, replyCommand, bodyText, collapsed = !1) {
778
+ this.from = from, this.message = message, this.theme = theme, this.replyCommand = replyCommand, this.bodyText = bodyText, this.collapsed = collapsed;
779
+ }
780
+ invalidate() {
781
+ }
782
+ render(width) {
783
+ let lines = [], senderName = this.from.name || this.from.id.slice(0, 8);
784
+ if (width < 3)
785
+ return [truncateToWidth3(`From ${senderName}`, width)];
786
+ let bodyWidth = Math.max(1, width - 2), header = ` \u{1F4E8} From: ${senderName} (${this.from.cwd}) `, headerText = truncateToWidth3(this.collapsed ? `${header} Ctrl+O expands ` : header, bodyWidth, ""), headerPadding = Math.max(0, bodyWidth - visibleWidth3(headerText));
787
+ if (lines.push(this.theme.fg("accent", `\u256D${headerText}${"\u2500".repeat(headerPadding)}\u256E`)), this.collapsed) {
788
+ let preview = (this.bodyText || this.message.content.text).replace(/\s+/g, " ").trim(), previewText2 = truncateToWidth3(preview, bodyWidth, ""), previewPadding = Math.max(0, bodyWidth - visibleWidth3(previewText2));
789
+ lines.push(this.theme.fg("accent", `\u2502${previewText2}${" ".repeat(previewPadding)}\u2502`));
790
+ let meta = [];
791
+ if (this.replyCommand && meta.push(`\u21A9 To reply: ${this.replyCommand}`), this.message.content.attachments?.length) {
792
+ let count = this.message.content.attachments.length;
793
+ meta.push(`\u{1F4CE} ${count} attachment${count === 1 ? "" : "s"}`);
794
+ }
795
+ this.message.replyTo && !this.message.expectsReply && meta.push(`\u21B3 Reply to ${this.message.replyTo.slice(0, 8)}`), meta.push("Ctrl+O to expand");
796
+ let metaText = truncateToWidth3(this.theme.fg("dim", ` ${meta.join(" \xB7 ")}`), bodyWidth, ""), metaPadding = Math.max(0, bodyWidth - visibleWidth3(metaText));
797
+ return lines.push(this.theme.fg("accent", `\u2502${metaText}${" ".repeat(metaPadding)}\u2502`)), lines.push(this.theme.fg("accent", `\u2570${"\u2500".repeat(bodyWidth)}\u256F`)), lines;
798
+ }
799
+ let contentLines = wrapTextWithAnsi(this.bodyText || this.message.content.text, bodyWidth);
800
+ for (let line of contentLines) {
801
+ let text = truncateToWidth3(line, bodyWidth, ""), padding = Math.max(0, bodyWidth - visibleWidth3(text));
802
+ lines.push(this.theme.fg("accent", `\u2502${text}${" ".repeat(padding)}\u2502`));
803
+ }
804
+ if (this.replyCommand) {
805
+ lines.push(this.theme.fg("accent", `\u2502${" ".repeat(bodyWidth)}\u2502`));
806
+ let replyLines = wrapTextWithAnsi(this.theme.fg("dim", ` \u21A9 To reply: ${this.replyCommand}`), bodyWidth);
807
+ for (let line of replyLines) {
808
+ let text = truncateToWidth3(line, bodyWidth, ""), padding = Math.max(0, bodyWidth - visibleWidth3(text));
809
+ lines.push(this.theme.fg("accent", `\u2502${text}${" ".repeat(padding)}\u2502`));
810
+ }
811
+ }
812
+ if (this.message.content.attachments?.length) {
813
+ lines.push(this.theme.fg("accent", `\u2502${" ".repeat(bodyWidth)}\u2502`));
814
+ for (let att of this.message.content.attachments) {
815
+ let label = this.theme.fg("dim", ` \u{1F4CE} ${att.name}`), text = truncateToWidth3(label, bodyWidth, ""), padding = Math.max(0, bodyWidth - visibleWidth3(text));
816
+ lines.push(this.theme.fg("accent", `\u2502${text}${" ".repeat(padding)}\u2502`));
817
+ }
818
+ }
819
+ if (this.message.replyTo && !this.message.expectsReply) {
820
+ lines.push(this.theme.fg("accent", `\u2502${" ".repeat(bodyWidth)}\u2502`));
821
+ let reply = this.theme.fg("dim", ` \u21B3 Reply to ${this.message.replyTo.slice(0, 8)}`), text = truncateToWidth3(reply, bodyWidth, ""), padding = Math.max(0, bodyWidth - visibleWidth3(text));
822
+ lines.push(this.theme.fg("accent", `\u2502${text}${" ".repeat(padding)}\u2502`));
823
+ }
824
+ return lines.push(this.theme.fg("accent", `\u2570${"\u2500".repeat(bodyWidth)}\u256F`)), lines;
825
+ }
826
+ };
827
+
828
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/config.js
829
+ import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
830
+ import { join as join3 } from "path";
831
+ var DEFAULT_ASK_TIMEOUT_MS = 600 * 1e3;
832
+ function getAskTimeoutMs() {
833
+ let raw = process.env.PI_INTERCOM_ASK_TIMEOUT_MS;
834
+ if (raw === void 0 || raw.trim() === "")
835
+ return DEFAULT_ASK_TIMEOUT_MS;
836
+ let value = Number(raw);
837
+ if (!Number.isSafeInteger(value) || value <= 0)
838
+ throw new Error("PI_INTERCOM_ASK_TIMEOUT_MS must be a positive integer number of milliseconds");
839
+ return value;
840
+ }
841
+ function getConfigPath(intercomDir = getIntercomDirPath()) {
842
+ return join3(intercomDir, "config.json");
843
+ }
844
+ var defaults = {
845
+ brokerCommand: "npx",
846
+ brokerArgs: ["--no-install", "tsx"],
847
+ confirmSend: !1,
848
+ inboundTrigger: "always",
849
+ enabled: !0,
850
+ replyHint: !0
851
+ };
852
+ function loadConfig() {
853
+ let configPath = getConfigPath();
854
+ if (!existsSync2(configPath))
855
+ return { ...defaults };
856
+ try {
857
+ let raw = readFileSync3(configPath, "utf-8"), parsed = JSON.parse(raw);
858
+ if (typeof parsed != "object" || parsed === null || Array.isArray(parsed))
859
+ throw new Error("Config must be a JSON object");
860
+ let parsedConfig = parsed, config = { ...defaults };
861
+ if (Object.hasOwn(parsedConfig, "brokerCommand")) {
862
+ if (typeof parsedConfig.brokerCommand != "string")
863
+ throw new Error('"brokerCommand" must be a string');
864
+ let brokerCommand = parsedConfig.brokerCommand.trim();
865
+ if (!brokerCommand)
866
+ throw new Error('"brokerCommand" must not be empty');
867
+ config.brokerCommand = brokerCommand;
868
+ }
869
+ if (Object.hasOwn(parsedConfig, "brokerArgs")) {
870
+ if (!Array.isArray(parsedConfig.brokerArgs))
871
+ throw new Error('"brokerArgs" must be an array');
872
+ let brokerArgs = [];
873
+ for (let arg of parsedConfig.brokerArgs) {
874
+ if (typeof arg != "string")
875
+ throw new Error('"brokerArgs" items must be strings');
876
+ brokerArgs.push(arg);
877
+ }
878
+ config.brokerArgs = brokerArgs;
879
+ }
880
+ if (Object.hasOwn(parsedConfig, "confirmSend")) {
881
+ if (typeof parsedConfig.confirmSend != "boolean")
882
+ throw new Error('"confirmSend" must be a boolean');
883
+ config.confirmSend = parsedConfig.confirmSend;
884
+ }
885
+ if (Object.hasOwn(parsedConfig, "enabled")) {
886
+ if (typeof parsedConfig.enabled != "boolean")
887
+ throw new Error('"enabled" must be a boolean');
888
+ config.enabled = parsedConfig.enabled;
889
+ }
890
+ if (Object.hasOwn(parsedConfig, "inboundTrigger")) {
891
+ if (parsedConfig.inboundTrigger !== "always" && parsedConfig.inboundTrigger !== "replies" && parsedConfig.inboundTrigger !== "never")
892
+ throw new Error('"inboundTrigger" must be "always", "replies", or "never"');
893
+ config.inboundTrigger = parsedConfig.inboundTrigger;
894
+ }
895
+ if (Object.hasOwn(parsedConfig, "replyHint")) {
896
+ if (typeof parsedConfig.replyHint != "boolean")
897
+ throw new Error('"replyHint" must be a boolean');
898
+ config.replyHint = parsedConfig.replyHint;
899
+ }
900
+ if (Object.hasOwn(parsedConfig, "status")) {
901
+ if (typeof parsedConfig.status != "string")
902
+ throw new Error('"status" must be a string');
903
+ config.status = parsedConfig.status;
904
+ }
905
+ return config;
906
+ } catch (error) {
907
+ return console.error(`Failed to load intercom config at ${configPath}:`, error), { ...defaults, inboundTrigger: "never" };
908
+ }
909
+ }
910
+
911
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/reply-tracker.js
912
+ function matchesPendingSender(context, to) {
913
+ return context.from.id === to ? !0 : context.from.name?.toLowerCase() === to.toLowerCase();
914
+ }
915
+ var ReplyTracker = class {
916
+ askTimeoutMs;
917
+ pendingAsks = /* @__PURE__ */ new Map();
918
+ pendingTurnContexts = [];
919
+ currentTurnContext = null;
920
+ constructor(askTimeoutMs = getAskTimeoutMs()) {
921
+ this.askTimeoutMs = askTimeoutMs;
922
+ }
923
+ recordIncomingMessage(from, message, receivedAt = Date.now()) {
924
+ let context = { from, message, receivedAt };
925
+ return message.expectsReply && this.pendingAsks.set(message.id, context), context;
926
+ }
927
+ queueTurnContext(context) {
928
+ this.pendingTurnContexts.push(context);
929
+ }
930
+ beginTurn(now = Date.now()) {
931
+ this.pruneExpired(now), this.currentTurnContext = this.pendingTurnContexts.shift() ?? null;
932
+ }
933
+ endTurn() {
934
+ this.currentTurnContext = null;
935
+ }
936
+ reset() {
937
+ this.pendingAsks.clear(), this.pendingTurnContexts.length = 0, this.currentTurnContext = null;
938
+ }
939
+ resolveReplyTarget(options, now = Date.now()) {
940
+ if (this.pruneExpired(now), options.replyTo) {
941
+ let target = this.pendingAsks.get(options.replyTo);
942
+ if (!target)
943
+ throw new Error(`No pending ask with message ID "${options.replyTo}"`);
944
+ if (options.to && !matchesPendingSender(target, options.to))
945
+ throw new Error(`Pending ask "${options.replyTo}" is not from "${options.to}"`);
946
+ return target;
947
+ }
948
+ if (this.currentTurnContext)
949
+ return this.currentTurnContext;
950
+ let pending = Array.from(this.pendingAsks.values());
951
+ if (pending.length === 1)
952
+ return pending[0];
953
+ if (options.to) {
954
+ let matches = pending.filter((context) => matchesPendingSender(context, options.to));
955
+ if (matches.length === 1)
956
+ return matches[0];
957
+ if (matches.length > 1)
958
+ throw new Error(`Multiple pending asks from "${options.to}" \u2014 use the sender session ID instead.`);
959
+ if (pending.length > 1)
960
+ throw new Error(`No pending ask from "${options.to}"`);
961
+ }
962
+ throw pending.length === 0 ? new Error("No active intercom context to reply to") : new Error("Multiple pending asks \u2014 specify `to`");
963
+ }
964
+ markReplied(replyTo) {
965
+ this.dismissPendingAsk(replyTo);
966
+ }
967
+ dismissPendingAsk(replyTo) {
968
+ this.pendingAsks.delete(replyTo);
969
+ for (let index = this.pendingTurnContexts.length - 1; index >= 0; index -= 1)
970
+ this.pendingTurnContexts[index]?.message.id === replyTo && this.pendingTurnContexts.splice(index, 1);
971
+ this.currentTurnContext?.message.id === replyTo && (this.currentTurnContext = null);
972
+ }
973
+ listPending(now = Date.now()) {
974
+ return this.pruneExpired(now), Array.from(this.pendingAsks.values()).sort((a, b) => a.receivedAt - b.receivedAt);
975
+ }
976
+ pruneExpired(now) {
977
+ for (let [messageId, context] of this.pendingAsks)
978
+ now - context.receivedAt > this.askTimeoutMs && this.dismissPendingAsk(messageId);
979
+ }
980
+ };
981
+
982
+ // packages/coding-agent/dist/builtin-extensions/pi-intercom/index.js
983
+ var SUBAGENT_CONTROL_INTERCOM_EVENT = "subagent:control-intercom", SUBAGENT_RESULT_INTERCOM_EVENT = "subagent:result-intercom", SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT = "subagent:result-intercom-delivery", INBOUND_FLUSH_DELAY_MS = 200, INBOUND_IDLE_RETRY_MS = 500, DEFAULT_UNNAMED_SESSION_ALIAS_PREFIX = "subagent-chat", SUBAGENT_ORCHESTRATOR_TARGET_ENV = "PI_SUBAGENT_ORCHESTRATOR_TARGET", SUBAGENT_ORCHESTRATOR_SESSION_ID_ENV = "PI_SUBAGENT_ORCHESTRATOR_SESSION_ID", INTERCOM_SESSION_ID_ENV = "PI_INTERCOM_SESSION_ID", NAME_POLL_MS_ENV = "PI_INTERCOM_NAME_POLL_MS", SUBAGENT_RUN_ID_ENV = "PI_SUBAGENT_RUN_ID", SUBAGENT_CHILD_AGENT_ENV = "PI_SUBAGENT_CHILD_AGENT", SUBAGENT_CHILD_INDEX_ENV = "PI_SUBAGENT_CHILD_INDEX", SUBAGENT_INTERCOM_SESSION_NAME_ENV = "PI_SUBAGENT_INTERCOM_SESSION_NAME";
984
+ function getErrorMessage(error) {
985
+ return error instanceof Error ? error.message : String(error);
986
+ }
987
+ function toError3(error) {
988
+ return error instanceof Error ? error : new Error(String(error));
989
+ }
990
+ function formatAttachments(attachments) {
991
+ let text = "";
992
+ for (let att of attachments)
993
+ att.language ? text += `
994
+
995
+ ---
996
+ \u{1F4CE} ${att.name}
997
+ ~~~${att.language}
998
+ ${att.content}
999
+ ~~~` : text += `
1000
+
1001
+ ---
1002
+ \u{1F4CE} ${att.name}
1003
+ ${att.content}`;
1004
+ return text;
1005
+ }
1006
+ function readChildOrchestratorMetadata() {
1007
+ let orchestratorTarget = process.env[SUBAGENT_ORCHESTRATOR_TARGET_ENV]?.trim(), orchestratorSessionId = process.env[SUBAGENT_ORCHESTRATOR_SESSION_ID_ENV]?.trim() || process.env[INTERCOM_SESSION_ID_ENV]?.trim(), runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim(), agent = process.env[SUBAGENT_CHILD_AGENT_ENV]?.trim(), index = process.env[SUBAGENT_CHILD_INDEX_ENV]?.trim();
1008
+ if (!orchestratorTarget || !runId || !agent || !index)
1009
+ return null;
1010
+ let sessionName = process.env[SUBAGENT_INTERCOM_SESSION_NAME_ENV]?.trim();
1011
+ return {
1012
+ orchestratorTarget,
1013
+ ...orchestratorSessionId ? { orchestratorSessionId } : {},
1014
+ runId,
1015
+ agent,
1016
+ index,
1017
+ ...sessionName ? { sessionName } : {}
1018
+ };
1019
+ }
1020
+ function formatChildOrchestratorMessage(kind, metadata, message) {
1021
+ return [
1022
+ kind === "ask" ? "Subagent needs a supervisor decision." : kind === "interview" ? "Subagent requests a structured supervisor interview." : "Subagent progress update.",
1023
+ `Run: ${metadata.runId}`,
1024
+ `Agent: ${metadata.agent}`,
1025
+ `Child index: ${metadata.index}`,
1026
+ metadata.sessionName ? `Child intercom target: ${metadata.sessionName}` : void 0,
1027
+ "",
1028
+ message
1029
+ ].filter((line) => line !== void 0).join(`
1030
+ `);
1031
+ }
1032
+ function validateSupervisorInterviewRequest(input) {
1033
+ if (!input || typeof input != "object" || Array.isArray(input))
1034
+ return { ok: !1, error: "interview must be an object with a questions array" };
1035
+ let raw = input;
1036
+ if (raw.title !== void 0 && typeof raw.title != "string")
1037
+ return { ok: !1, error: "interview.title must be a string when provided" };
1038
+ if (raw.description !== void 0 && typeof raw.description != "string")
1039
+ return { ok: !1, error: "interview.description must be a string when provided" };
1040
+ if (!Array.isArray(raw.questions) || raw.questions.length === 0)
1041
+ return { ok: !1, error: "interview.questions must be a non-empty array" };
1042
+ let validTypes = /* @__PURE__ */ new Set(["single", "multi", "text", "image", "info"]), ids = /* @__PURE__ */ new Set(), questions = [];
1043
+ for (let index = 0; index < raw.questions.length; index++) {
1044
+ let questionInput = raw.questions[index];
1045
+ if (!questionInput || typeof questionInput != "object" || Array.isArray(questionInput))
1046
+ return { ok: !1, error: `interview.questions[${index}] must be an object` };
1047
+ let question = questionInput;
1048
+ if (typeof question.id != "string" || question.id.trim() === "")
1049
+ return { ok: !1, error: `interview.questions[${index}].id must be a non-empty string` };
1050
+ let id = question.id.trim();
1051
+ if (ids.has(id))
1052
+ return { ok: !1, error: `interview question id must be unique: ${id}` };
1053
+ if (ids.add(id), typeof question.type != "string" || !validTypes.has(question.type))
1054
+ return { ok: !1, error: `interview.questions[${index}].type must be one of: single, multi, text, image, info` };
1055
+ if (typeof question.question != "string" || question.question.trim() === "")
1056
+ return { ok: !1, error: `interview.questions[${index}].question must be a non-empty string` };
1057
+ if (question.context !== void 0 && typeof question.context != "string")
1058
+ return { ok: !1, error: `interview.questions[${index}].context must be a string when provided` };
1059
+ let options;
1060
+ if (question.options !== void 0) {
1061
+ if (!Array.isArray(question.options))
1062
+ return { ok: !1, error: `interview.questions[${index}].options must be an array when provided` };
1063
+ options = [];
1064
+ for (let optionIndex = 0; optionIndex < question.options.length; optionIndex++) {
1065
+ let option = question.options[optionIndex];
1066
+ if (typeof option == "string") {
1067
+ let label = option.trim();
1068
+ if (!label)
1069
+ return { ok: !1, error: `interview.questions[${index}].options[${optionIndex}] must not be empty` };
1070
+ options.push(label);
1071
+ } else {
1072
+ if (!option || typeof option != "object" || Array.isArray(option) || typeof option.label != "string" || option.label.trim() === "")
1073
+ return { ok: !1, error: `interview.questions[${index}].options[${optionIndex}] must be a non-empty string or an object with a non-empty label` };
1074
+ options.push({ ...option, label: option.label.trim() });
1075
+ }
1076
+ }
1077
+ }
1078
+ if ((question.type === "single" || question.type === "multi") && (!options || options.length === 0))
1079
+ return { ok: !1, error: `interview.questions[${index}].options must be a non-empty array for ${question.type} questions` };
1080
+ if (question.type !== "single" && question.type !== "multi" && options)
1081
+ return { ok: !1, error: `interview.questions[${index}].options is only valid for single and multi questions` };
1082
+ questions.push({
1083
+ ...question,
1084
+ id,
1085
+ type: question.type,
1086
+ question: question.question.trim(),
1087
+ ...options ? { options } : {}
1088
+ });
1089
+ }
1090
+ return {
1091
+ ok: !0,
1092
+ interview: {
1093
+ ...raw,
1094
+ ...typeof raw.title == "string" ? { title: raw.title.trim() } : {},
1095
+ ...typeof raw.description == "string" ? { description: raw.description.trim() } : {},
1096
+ questions
1097
+ }
1098
+ };
1099
+ }
1100
+ function interviewOptionLabel(option) {
1101
+ return typeof option == "string" ? option : option.label;
1102
+ }
1103
+ function interviewExampleValue(question) {
1104
+ return question.type === "multi" ? question.options?.slice(0, 2).map(interviewOptionLabel) ?? [] : question.type === "single" ? question.options?.[0] !== void 0 ? interviewOptionLabel(question.options[0]) : "option label" : question.type === "image" ? "image/file reference or description" : "answer text";
1105
+ }
1106
+ function formatSupervisorInterviewRequest(interview, message) {
1107
+ let lines = [], title = interview.title?.trim();
1108
+ title && lines.push(`Interview: ${title}`);
1109
+ let description = interview.description?.trim();
1110
+ description && lines.push(description);
1111
+ let note = message?.trim();
1112
+ note && lines.push(`Child note: ${note}`), lines.length > 0 && lines.push(""), lines.push("Questions:"), interview.questions.forEach((question, index) => {
1113
+ if (lines.push(`${index + 1}. [${question.id}] (${question.type}) ${question.question}`), typeof question.context == "string" && question.context.trim() && lines.push(` Context: ${question.context.trim()}`), question.options?.length) {
1114
+ lines.push(" Options:");
1115
+ for (let option of question.options)
1116
+ lines.push(` - ${interviewOptionLabel(option)}`);
1117
+ }
1118
+ });
1119
+ let responseExample = {
1120
+ responses: interview.questions.filter((question) => question.type !== "info").map((question) => ({
1121
+ id: question.id,
1122
+ value: interviewExampleValue(question)
1123
+ }))
1124
+ };
1125
+ return lines.push("", "Supervisor reply instructions:", "Reply with plain JSON or a fenced ```json block using this stable shape. Use the question ids exactly. Info questions are context-only and do not need responses. For single questions, value is one option label. For multi questions, value is an array of option labels. For text/image questions, value is a string unless the question asks otherwise.", "", "```json", JSON.stringify(responseExample, null, 2), "```"), lines.join(`
1126
+ `);
1127
+ }
1128
+ function validateSupervisorInterviewReply(value, interview) {
1129
+ if (!value || typeof value != "object" || Array.isArray(value))
1130
+ throw new Error("reply JSON must be an object with a responses array");
1131
+ let responsesInput = value.responses;
1132
+ if (!Array.isArray(responsesInput))
1133
+ throw new Error("reply JSON must include a responses array");
1134
+ let questionById = new Map(interview.questions.filter((question) => question.type !== "info").map((question) => [question.id, question])), seenIds = /* @__PURE__ */ new Set(), responses = [];
1135
+ for (let index = 0; index < responsesInput.length; index++) {
1136
+ let response = responsesInput[index];
1137
+ if (!response || typeof response != "object" || Array.isArray(response))
1138
+ throw new Error(`responses[${index}] must be an object`);
1139
+ let raw = response;
1140
+ if (typeof raw.id != "string" || raw.id.trim() === "")
1141
+ throw new Error(`responses[${index}].id must be a non-empty string`);
1142
+ let id = raw.id.trim(), question = questionById.get(id);
1143
+ if (!question)
1144
+ throw new Error(`responses[${index}].id must match a non-info interview question id`);
1145
+ if (seenIds.has(id))
1146
+ throw new Error(`responses[${index}].id is duplicated: ${id}`);
1147
+ if (seenIds.add(id), !Object.hasOwn(raw, "value"))
1148
+ throw new Error(`responses[${index}].value is required`);
1149
+ let value2 = raw.value;
1150
+ if (question.type === "single") {
1151
+ if (typeof value2 != "string")
1152
+ throw new Error(`responses[${index}].value must be a string for single questions`);
1153
+ if (!new Set(question.options?.map(interviewOptionLabel)).has(value2.trim()))
1154
+ throw new Error(`responses[${index}].value must match one of the question options`);
1155
+ responses.push({ id, value: value2.trim() });
1156
+ continue;
1157
+ }
1158
+ if (question.type === "multi") {
1159
+ if (!Array.isArray(value2) || value2.some((item) => typeof item != "string"))
1160
+ throw new Error(`responses[${index}].value must be an array of strings for multi questions`);
1161
+ let optionLabels = new Set(question.options?.map(interviewOptionLabel)), selected = value2.map((item) => item.trim()), invalid = selected.find((item) => !optionLabels.has(item));
1162
+ if (invalid)
1163
+ throw new Error(`responses[${index}].value contains an option that is not in the question options: ${invalid}`);
1164
+ responses.push({ id, value: selected });
1165
+ continue;
1166
+ }
1167
+ if (typeof value2 != "string")
1168
+ throw new Error(`responses[${index}].value must be a string for ${question.type} questions`);
1169
+ responses.push({ id, value: value2 });
1170
+ }
1171
+ return { responses };
1172
+ }
1173
+ function parseStructuredSupervisorReply(text, interview) {
1174
+ let candidate = (text.match(/```(?:json)?\s*([\s\S]*?)```/i)?.[1] ?? text).trim();
1175
+ if (!(!candidate.startsWith("{") && !candidate.startsWith("[")))
1176
+ try {
1177
+ return { value: validateSupervisorInterviewReply(JSON.parse(candidate), interview) };
1178
+ } catch (error) {
1179
+ return { error: getErrorMessage(error) };
1180
+ }
1181
+ }
1182
+ function duplicateSessionNames(sessions) {
1183
+ return new Set(sessions.map((s) => s.name?.toLowerCase()).filter((name) => !!name).filter((name, index, names) => names.indexOf(name) !== index));
1184
+ }
1185
+ function shortSessionId2(sessionId) {
1186
+ return sessionId.slice(0, 8);
1187
+ }
1188
+ function parseSubagentIntercomPayload(payload) {
1189
+ if (typeof payload != "object" || payload === null)
1190
+ return null;
1191
+ let record = payload;
1192
+ if (typeof record.to != "string" || typeof record.message != "string")
1193
+ return null;
1194
+ let requestId = typeof record.requestId == "string" ? record.requestId : void 0;
1195
+ return { to: record.to, message: record.message, ...requestId ? { requestId } : {} };
1196
+ }
1197
+ function resolveIntercomPresenceName(sessionName, sessionId) {
1198
+ let trimmedName = sessionName?.trim();
1199
+ if (trimmedName)
1200
+ return trimmedName;
1201
+ let normalizedSessionId = sessionId.startsWith("session-") ? sessionId.slice(8) : sessionId;
1202
+ return `${DEFAULT_UNNAMED_SESSION_ALIAS_PREFIX}-${normalizedSessionId.slice(0, 8)}`;
1203
+ }
1204
+ function buildPresenceIdentity(pi, sessionId) {
1205
+ return {
1206
+ name: resolveIntercomPresenceName(pi.getSessionName(), sessionId)
1207
+ };
1208
+ }
1209
+ function formatSessionLabel(session, duplicates) {
1210
+ return session.name ? duplicates.has(session.name.toLowerCase()) ? `${session.name} (${shortSessionId2(session.id)})` : session.name : session.id;
1211
+ }
1212
+ function formatSessionListRow(session, currentCwd, isSelf) {
1213
+ let name = session.name || "Unnamed session", tags = [isSelf ? "self" : session.cwd === currentCwd ? "same cwd" : void 0, session.status].filter((tag) => !!tag), suffix = tags.length ? ` [${tags.join(", ")}]` : "";
1214
+ return `\u2022 ${name} (${shortSessionId2(session.id)}) \u2014 ${session.cwd} (${session.model})${suffix}`;
1215
+ }
1216
+ function previewText(value, maxLength = 72) {
1217
+ if (typeof value != "string")
1218
+ return;
1219
+ let normalized = value.replace(/\s+/g, " ").trim();
1220
+ if (normalized)
1221
+ return normalized.length > maxLength ? `${normalized.slice(0, maxLength - 1)}\u2026` : normalized;
1222
+ }
1223
+ function firstTextContent(result) {
1224
+ return result.content?.find((item) => item.type === "text" && typeof item.text == "string")?.text?.replace(/\*\*/g, "") ?? "";
1225
+ }
1226
+ function getNamePollMs() {
1227
+ let configured = process.env[NAME_POLL_MS_ENV];
1228
+ if (configured !== void 0) {
1229
+ let value = Number(configured);
1230
+ if (Number.isFinite(value) && value > 0)
1231
+ return value;
1232
+ }
1233
+ return 1e3;
1234
+ }
1235
+ function piIntercomExtension(pi) {
1236
+ let client = null, config = loadConfig(), askTimeoutMs = getAskTimeoutMs(), runtimeContext = null, currentSessionId = null, currentModel = "unknown", sessionStartedAt = null, reconnectTimer = null, namePollTimer = null, lastPresenceName = null, previousIntercomSessionId = process.env[INTERCOM_SESSION_ID_ENV], reconnectPromise = null, reconnectPromiseGeneration = null, startupConnectTimer = null, reconnectAttempt = 0, shuttingDown = !1, disposed = !0, runtimeStarted = !1, runtimeGeneration = 0, agentRunning = !1, activeTools = /* @__PURE__ */ new Map(), replyTracker = new ReplyTracker(), pendingIdleMessages = [], inboundFlushTimer = null, replyWaiter = null;
1237
+ function waitForReply(from, replyTo, signal, onCancel) {
1238
+ return replyWaiter ? Promise.reject(new Error("Already waiting for a reply")) : signal?.aborted ? Promise.reject(new Error("Cancelled")) : new Promise((resolve2, reject) => {
1239
+ let timeout = setTimeout(() => {
1240
+ onCancel?.();
1241
+ let timeoutDescription = askTimeoutMs % 6e4 === 0 ? `${askTimeoutMs / 6e4} minutes` : `${askTimeoutMs}ms`;
1242
+ rejectReplyWaiter(new Error(`No reply from "${from}" within ${timeoutDescription}`));
1243
+ }, askTimeoutMs), cleanup = () => {
1244
+ clearTimeout(timeout), signal?.removeEventListener("abort", onAbort), replyWaiter?.replyTo === replyTo && (replyWaiter = null);
1245
+ }, onAbort = () => {
1246
+ onCancel?.(), cleanup(), reject(new Error("Cancelled"));
1247
+ };
1248
+ signal?.addEventListener("abort", onAbort, { once: !0 }), replyWaiter = {
1249
+ from,
1250
+ replyTo,
1251
+ resolve: (message) => {
1252
+ cleanup(), resolve2(message);
1253
+ },
1254
+ reject: (error) => {
1255
+ cleanup(), reject(error);
1256
+ }
1257
+ };
1258
+ });
1259
+ }
1260
+ function rejectReplyWaiter(error) {
1261
+ replyWaiter?.reject(error);
1262
+ }
1263
+ function clearReconnectTimer() {
1264
+ reconnectTimer && (clearTimeout(reconnectTimer), reconnectTimer = null);
1265
+ }
1266
+ function clearStartupConnectTimer() {
1267
+ startupConnectTimer && (clearTimeout(startupConnectTimer), startupConnectTimer = null);
1268
+ }
1269
+ function clearNamePollTimer() {
1270
+ namePollTimer && (clearInterval(namePollTimer), namePollTimer = null);
1271
+ }
1272
+ function clearInboundFlushTimer() {
1273
+ inboundFlushTimer && (clearTimeout(inboundFlushTimer), inboundFlushTimer = null);
1274
+ }
1275
+ function getLiveContext(ctx = runtimeContext, generation = runtimeGeneration) {
1276
+ if (disposed || shuttingDown || generation !== runtimeGeneration || !ctx)
1277
+ return null;
1278
+ try {
1279
+ return currentSessionId && ctx.sessionManager.getSessionId() !== currentSessionId ? null : (ctx.hasUI, ctx);
1280
+ } catch {
1281
+ return null;
1282
+ }
1283
+ }
1284
+ function notifyIfLive(ctx, message, level, generation = runtimeGeneration) {
1285
+ let liveContext = getLiveContext(ctx, generation);
1286
+ if (liveContext?.hasUI)
1287
+ try {
1288
+ liveContext.ui.notify(message, level);
1289
+ } catch {
1290
+ }
1291
+ }
1292
+ function getReconnectDelayMs() {
1293
+ let backoffMs = [1e3, 2e3, 5e3, 1e4, 3e4];
1294
+ return backoffMs[Math.min(reconnectAttempt, backoffMs.length - 1)];
1295
+ }
1296
+ function currentStatus() {
1297
+ let activeToolName = activeTools.values().next().value, lifecycleStatus = activeToolName ? `tool:${activeToolName}` : agentRunning ? "thinking" : "idle";
1298
+ return config.status ? `${lifecycleStatus} \xB7 ${config.status}` : lifecycleStatus;
1299
+ }
1300
+ function buildRegistration() {
1301
+ let liveContext = getLiveContext();
1302
+ if (!liveContext || !currentSessionId || sessionStartedAt === null)
1303
+ throw new Error("Intercom runtime not initialized");
1304
+ return {
1305
+ name: buildPresenceIdentity(pi, currentSessionId).name,
1306
+ cwd: liveContext.cwd,
1307
+ model: currentModel,
1308
+ pid: process.pid,
1309
+ startedAt: sessionStartedAt,
1310
+ lastActivity: Date.now(),
1311
+ status: currentStatus()
1312
+ };
1313
+ }
1314
+ function syncPresenceIdentity(sessionId) {
1315
+ if (!client || !getLiveContext())
1316
+ return;
1317
+ let identity = buildPresenceIdentity(pi, sessionId);
1318
+ lastPresenceName = identity.name, client.updatePresence({ ...identity, status: currentStatus() });
1319
+ }
1320
+ function startNamePoll() {
1321
+ clearNamePollTimer(), lastPresenceName = currentSessionId ? buildPresenceIdentity(pi, currentSessionId).name : null, namePollTimer = setInterval(() => {
1322
+ if (!currentSessionId || !getLiveContext())
1323
+ return;
1324
+ buildPresenceIdentity(pi, currentSessionId).name !== lastPresenceName && syncPresenceIdentity(currentSessionId);
1325
+ }, getNamePollMs()), namePollTimer.unref?.();
1326
+ }
1327
+ function publishIntercomSessionId(sessionId) {
1328
+ process.env[INTERCOM_SESSION_ID_ENV] = sessionId;
1329
+ }
1330
+ function restoreIntercomSessionId() {
1331
+ if (previousIntercomSessionId === void 0) {
1332
+ delete process.env[INTERCOM_SESSION_ID_ENV];
1333
+ return;
1334
+ }
1335
+ process.env[INTERCOM_SESSION_ID_ENV] = previousIntercomSessionId;
1336
+ }
1337
+ function syncPresenceStatus() {
1338
+ !client || !currentSessionId || !getLiveContext() || client.updatePresence({ status: currentStatus() });
1339
+ }
1340
+ function currentSessionTargetMatches(to, resolvedTo, activeClient) {
1341
+ let targets = /* @__PURE__ */ new Set(), addTarget = (target) => {
1342
+ let trimmed = target?.trim();
1343
+ trimmed && targets.add(trimmed.toLowerCase());
1344
+ };
1345
+ return addTarget(currentSessionId), addTarget(activeClient?.sessionId), addTarget(pi.getSessionName()), currentSessionId && addTarget(buildPresenceIdentity(pi, currentSessionId).name), !!(resolvedTo && activeClient?.sessionId && resolvedTo === activeClient.sessionId) || targets.has(to.trim().toLowerCase());
1346
+ }
1347
+ function shouldTriggerInboundMessage(entry, forceTrigger = !1) {
1348
+ return forceTrigger || config.inboundTrigger === "always" ? !0 : config.inboundTrigger === "replies" ? !!entry.message.replyTo : !1;
1349
+ }
1350
+ function sendIncomingMessage(entry, delivery, generation = runtimeGeneration, forceTrigger = !1) {
1351
+ if (runtimeStarted && !getLiveContext(runtimeContext, generation))
1352
+ return;
1353
+ delivery !== "followUp" && replyTracker.queueTurnContext({ from: entry.from, message: entry.message, receivedAt: Date.now() });
1354
+ let senderDisplay = entry.from.name || entry.from.id.slice(0, 8), replyInstruction = entry.replyCommand ? `
1355
+
1356
+ To reply, use the intercom tool: ${entry.replyCommand}` : "";
1357
+ pi.sendMessage({
1358
+ customType: "intercom_message",
1359
+ content: `**\u{1F4E8} From ${senderDisplay}** (${entry.from.cwd})${replyInstruction}
1360
+
1361
+ ${entry.bodyText}`,
1362
+ display: !0,
1363
+ details: entry
1364
+ }, delivery === "trigger" && shouldTriggerInboundMessage(entry, forceTrigger) ? { triggerTurn: !0 } : { deliverAs: "followUp" });
1365
+ }
1366
+ function scheduleInboundFlush(delayMs = INBOUND_FLUSH_DELAY_MS) {
1367
+ if (!getLiveContext())
1368
+ return;
1369
+ let scheduledGeneration = runtimeGeneration;
1370
+ clearInboundFlushTimer(), inboundFlushTimer = setTimeout(() => {
1371
+ inboundFlushTimer = null, flushIdleMessages(scheduledGeneration);
1372
+ }, delayMs);
1373
+ }
1374
+ function flushIdleMessages(generation = runtimeGeneration) {
1375
+ if (pendingIdleMessages.length === 0)
1376
+ return;
1377
+ let ctx = getLiveContext(runtimeContext, generation);
1378
+ if (!ctx)
1379
+ return;
1380
+ let isIdle;
1381
+ try {
1382
+ isIdle = ctx.isIdle();
1383
+ } catch {
1384
+ return;
1385
+ }
1386
+ if (!isIdle) {
1387
+ scheduleInboundFlush(INBOUND_IDLE_RETRY_MS);
1388
+ return;
1389
+ }
1390
+ pendingIdleMessages.splice(0, pendingIdleMessages.length).forEach((entry, index) => {
1391
+ sendIncomingMessage(entry, index === 0 ? "trigger" : "followUp");
1392
+ });
1393
+ }
1394
+ function queueIdleMessage(entry) {
1395
+ pendingIdleMessages.push(entry), scheduleInboundFlush();
1396
+ }
1397
+ function handleIncomingMessage(ctx, from, message) {
1398
+ let messageGeneration = runtimeGeneration, liveContext = getLiveContext(ctx, messageGeneration);
1399
+ if (!liveContext)
1400
+ return;
1401
+ if (replyWaiter) {
1402
+ let fromMatches = (from.name || from.id).toLowerCase() === replyWaiter.from.toLowerCase() || from.id === replyWaiter.from, replyMatches = message.replyTo === replyWaiter.replyTo;
1403
+ if (fromMatches && replyMatches) {
1404
+ replyWaiter.resolve(message);
1405
+ return;
1406
+ }
1407
+ }
1408
+ let attachmentText = message.content.attachments?.length ? formatAttachments(message.content.attachments) : "", bodyText = `${message.content.text}${attachmentText}`, replyCommand = config.replyHint && message.expectsReply ? 'intercom({ action: "reply", message: "..." })' : void 0;
1409
+ replyTracker.recordIncomingMessage(from, message);
1410
+ let entry = { from, message, replyCommand, bodyText };
1411
+ (async () => {
1412
+ let activeContext = getLiveContext(liveContext, messageGeneration);
1413
+ if (activeContext) {
1414
+ if (!activeContext.isIdle()) {
1415
+ if (!activeContext.hasUI) {
1416
+ let activeClient = client;
1417
+ if (!message.replyTo && activeClient?.isConnected())
1418
+ try {
1419
+ (await activeClient.send(from.id, {
1420
+ text: "This agent is running in non-interactive mode and cannot respond to intercom messages while it is working. It will continue its current task and exit when done.",
1421
+ replyTo: message.id
1422
+ })).delivered && getLiveContext(liveContext, messageGeneration) && replyTracker.markReplied(message.id);
1423
+ } catch {
1424
+ }
1425
+ return;
1426
+ }
1427
+ queueIdleMessage(entry);
1428
+ return;
1429
+ }
1430
+ getLiveContext(liveContext, messageGeneration) && sendIncomingMessage(entry, "trigger", messageGeneration);
1431
+ }
1432
+ })();
1433
+ }
1434
+ function attachClientHandlers(nextClient) {
1435
+ nextClient.on("message", (from, message) => {
1436
+ let liveContext = getLiveContext();
1437
+ client !== nextClient || !liveContext || handleIncomingMessage(liveContext, from, message);
1438
+ }), nextClient.on("disconnected", (error) => {
1439
+ client === nextClient && (rejectReplyWaiter(new Error(`Disconnected while waiting for reply: ${error.message}`, { cause: error })), client = null, !shuttingDown && !disposed && (clearReconnectTimer(), scheduleReconnect()));
1440
+ }), nextClient.on("error", () => {
1441
+ });
1442
+ }
1443
+ function scheduleReconnect() {
1444
+ if (disposed || shuttingDown || reconnectTimer || reconnectPromise || !getLiveContext())
1445
+ return;
1446
+ let scheduledGeneration = runtimeGeneration;
1447
+ reconnectTimer = setTimeout(() => {
1448
+ reconnectTimer = null, !(scheduledGeneration !== runtimeGeneration || !getLiveContext()) && (reconnectAttempt += 1, ensureConnected("background").catch(() => {
1449
+ }));
1450
+ }, getReconnectDelayMs());
1451
+ }
1452
+ async function ensureConnected(reason) {
1453
+ if (!config.enabled)
1454
+ throw new Error("Intercom disabled");
1455
+ if (disposed || shuttingDown)
1456
+ throw new Error("Intercom shutting down");
1457
+ if (client && client.isConnected())
1458
+ return client;
1459
+ let contextAtStart = getLiveContext(), generationAtStart = runtimeGeneration;
1460
+ if (!contextAtStart || !currentSessionId || sessionStartedAt === null)
1461
+ throw new Error("Intercom runtime not initialized");
1462
+ if (clearReconnectTimer(), reconnectPromise && reconnectPromiseGeneration === generationAtStart)
1463
+ return reconnectPromise;
1464
+ let nextReconnectPromise = (async () => {
1465
+ let nextClient = new IntercomClient();
1466
+ client = nextClient, attachClientHandlers(nextClient);
1467
+ try {
1468
+ if (await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs), await nextClient.connect(buildRegistration(), currentSessionId), !getLiveContext(contextAtStart, generationAtStart))
1469
+ throw await nextClient.disconnect(), new Error("Intercom runtime no longer active");
1470
+ return client = nextClient, reconnectAttempt = 0, nextClient;
1471
+ } catch (error) {
1472
+ throw client === nextClient && (client = null), reason === "background" && getLiveContext(contextAtStart, generationAtStart) && scheduleReconnect(), toError3(error);
1473
+ } finally {
1474
+ reconnectPromise === nextReconnectPromise && (reconnectPromise = null, reconnectPromiseGeneration = null);
1475
+ }
1476
+ })();
1477
+ return reconnectPromise = nextReconnectPromise, reconnectPromiseGeneration = generationAtStart, nextReconnectPromise;
1478
+ }
1479
+ async function resolveSessionTarget(activeClient, nameOrId) {
1480
+ let sessions = await activeClient.listSessions(), byId = sessions.find((s) => s.id === nameOrId);
1481
+ if (byId)
1482
+ return byId.id;
1483
+ let lowerName = nameOrId.toLowerCase(), byName = sessions.filter((s) => s.name?.toLowerCase() === lowerName);
1484
+ if (byName.length > 1)
1485
+ throw new Error(`Multiple sessions named "${nameOrId}" are connected. Use the session ID instead.`);
1486
+ if (byName.length === 1)
1487
+ return byName[0].id;
1488
+ let byIdPrefix = sessions.filter((s) => s.id.startsWith(nameOrId));
1489
+ if (byIdPrefix.length === 1)
1490
+ return byIdPrefix[0].id;
1491
+ if (byIdPrefix.length > 1)
1492
+ throw new Error(`Multiple sessions match ID prefix "${nameOrId}". Use a longer session ID prefix.`);
1493
+ return null;
1494
+ }
1495
+ async function resolveSupervisorTarget(activeClient, metadata) {
1496
+ if (metadata.orchestratorSessionId) {
1497
+ let bySessionId = await resolveSessionTarget(activeClient, metadata.orchestratorSessionId);
1498
+ if (bySessionId)
1499
+ return bySessionId;
1500
+ }
1501
+ return await resolveSessionTarget(activeClient, metadata.orchestratorTarget) ?? metadata.orchestratorTarget;
1502
+ }
1503
+ function deliverLocalSubagentRelayMessage(sender, status, messageText) {
1504
+ let liveContext = getLiveContext(), now = Date.now();
1505
+ sendIncomingMessage({
1506
+ from: {
1507
+ id: sender,
1508
+ name: sender,
1509
+ cwd: liveContext?.cwd ?? "",
1510
+ model: sender,
1511
+ pid: process.pid,
1512
+ startedAt: now,
1513
+ lastActivity: now,
1514
+ status
1515
+ },
1516
+ message: {
1517
+ id: randomUUID3(),
1518
+ timestamp: now,
1519
+ content: { text: messageText }
1520
+ },
1521
+ bodyText: messageText
1522
+ }, "trigger", runtimeGeneration, !0);
1523
+ }
1524
+ function recordSubagentDeliveryError(entryType, to, message, error) {
1525
+ pi.appendEntry(entryType, {
1526
+ to,
1527
+ message,
1528
+ error: getErrorMessage(error),
1529
+ timestamp: Date.now()
1530
+ });
1531
+ }
1532
+ function startSessionRuntime(ctx) {
1533
+ let previousClient = client;
1534
+ previousClient && (client = null, previousClient.disconnect().catch(() => {
1535
+ })), shuttingDown = !1, disposed = !1, runtimeStarted = !0, runtimeGeneration += 1, reconnectAttempt = 0, clearReconnectTimer(), clearStartupConnectTimer(), clearNamePollTimer(), clearInboundFlushTimer(), rejectReplyWaiter(new Error("Session replaced")), replyTracker.reset(), pendingIdleMessages.length = 0, runtimeContext = ctx, currentSessionId = ctx.sessionManager.getSessionId(), publishIntercomSessionId(currentSessionId), currentModel = ctx.model?.id ?? "unknown", sessionStartedAt = Date.now(), lastPresenceName = buildPresenceIdentity(pi, currentSessionId).name, agentRunning = !1, activeTools.clear(), startNamePoll();
1536
+ let startupGeneration = runtimeGeneration;
1537
+ startupConnectTimer = setTimeout(() => {
1538
+ startupConnectTimer = null, getLiveContext(ctx, startupGeneration) && ensureConnected("startup").catch(() => {
1539
+ getLiveContext(ctx, startupGeneration) && (client = null, scheduleReconnect());
1540
+ });
1541
+ }, 0);
1542
+ }
1543
+ function emitResultDelivery(requestId, delivered, error) {
1544
+ requestId && pi.events.emit(SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT, {
1545
+ requestId,
1546
+ delivered,
1547
+ ...error ? { error: getErrorMessage(error) } : {}
1548
+ });
1549
+ }
1550
+ function relaySubagentIntercomPayload(payload, options) {
1551
+ let parsed = parseSubagentIntercomPayload(payload);
1552
+ if (!parsed)
1553
+ return;
1554
+ let relayGeneration = runtimeGeneration;
1555
+ (async () => {
1556
+ let relayStillLive = () => !runtimeStarted || !!getLiveContext(runtimeContext, relayGeneration);
1557
+ if (!relayStillLive())
1558
+ return;
1559
+ if (currentSessionTargetMatches(parsed.to)) {
1560
+ deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message), options.acknowledge && emitResultDelivery(parsed.requestId, !0);
1561
+ return;
1562
+ }
1563
+ let activeClient, target;
1564
+ try {
1565
+ activeClient = await ensureConnected("background"), target = await resolveSessionTarget(activeClient, parsed.to) ?? parsed.to;
1566
+ } catch (error) {
1567
+ if (!relayStillLive())
1568
+ return;
1569
+ recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error), options.acknowledge && emitResultDelivery(parsed.requestId, !1, error);
1570
+ return;
1571
+ }
1572
+ if (relayStillLive()) {
1573
+ if (currentSessionTargetMatches(parsed.to, target, activeClient)) {
1574
+ deliverLocalSubagentRelayMessage(options.sender, options.status, parsed.message), options.acknowledge && emitResultDelivery(parsed.requestId, !0);
1575
+ return;
1576
+ }
1577
+ try {
1578
+ let result = await activeClient.send(target, { text: parsed.message });
1579
+ if (!relayStillLive())
1580
+ return;
1581
+ if (!result.delivered) {
1582
+ let error = new Error(result.reason ?? "Session may not exist or has disconnected.");
1583
+ recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error), options.acknowledge && emitResultDelivery(parsed.requestId, !1, error);
1584
+ return;
1585
+ }
1586
+ options.acknowledge && emitResultDelivery(parsed.requestId, !0);
1587
+ } catch (error) {
1588
+ if (!relayStillLive())
1589
+ return;
1590
+ recordSubagentDeliveryError(options.errorEntryType, parsed.to, parsed.message, error), options.acknowledge && emitResultDelivery(parsed.requestId, !1, error);
1591
+ }
1592
+ }
1593
+ })();
1594
+ }
1595
+ let unsubscribeSubagentControlIntercom = pi.events.on(SUBAGENT_CONTROL_INTERCOM_EVENT, (payload) => {
1596
+ relaySubagentIntercomPayload(payload, {
1597
+ sender: "subagent-control",
1598
+ status: "needs_attention",
1599
+ errorEntryType: "intercom_control_error"
1600
+ });
1601
+ }), unsubscribeSubagentResultIntercom = pi.events.on(SUBAGENT_RESULT_INTERCOM_EVENT, (payload) => {
1602
+ relaySubagentIntercomPayload(payload, {
1603
+ sender: "subagent-result",
1604
+ status: "result",
1605
+ errorEntryType: "intercom_result_error",
1606
+ acknowledge: !0
1607
+ });
1608
+ });
1609
+ pi.on("session_start", (_event, ctx) => {
1610
+ config.enabled && startSessionRuntime(ctx);
1611
+ }), pi.on("session_shutdown", async () => {
1612
+ unsubscribeSubagentControlIntercom(), unsubscribeSubagentResultIntercom(), shuttingDown = !0, disposed = !0, runtimeGeneration += 1, clearStartupConnectTimer(), clearReconnectTimer(), clearNamePollTimer(), restoreIntercomSessionId(), rejectReplyWaiter(new Error("Session shutting down")), replyTracker.reset(), pendingIdleMessages.length = 0, clearInboundFlushTimer(), agentRunning = !1, activeTools.clear(), client && (await client.disconnect(), client = null), runtimeContext = null, currentSessionId = null, sessionStartedAt = null;
1613
+ }), pi.on("turn_end", () => {
1614
+ getLiveContext() && (replyTracker.endTurn(), scheduleInboundFlush(0));
1615
+ }), pi.on("agent_start", () => {
1616
+ getLiveContext() && (agentRunning = !0, activeTools.clear(), syncPresenceStatus());
1617
+ }), pi.on("tool_execution_start", (event) => {
1618
+ getLiveContext() && (activeTools.set(event.toolCallId, event.toolName), syncPresenceStatus());
1619
+ }), pi.on("tool_execution_end", (event) => {
1620
+ getLiveContext() && (activeTools.delete(event.toolCallId), syncPresenceStatus());
1621
+ }), pi.on("agent_end", () => {
1622
+ getLiveContext() && (agentRunning = !1, activeTools.clear(), syncPresenceStatus(), scheduleInboundFlush(0));
1623
+ }), pi.on("turn_start", (_event, ctx) => {
1624
+ let sessionId = ctx.sessionManager.getSessionId();
1625
+ if (!currentSessionId || sessionId !== currentSessionId) {
1626
+ if (!config.enabled)
1627
+ return;
1628
+ startSessionRuntime(ctx), replyTracker.beginTurn();
1629
+ return;
1630
+ }
1631
+ getLiveContext(ctx) && (syncPresenceIdentity(sessionId), replyTracker.beginTurn());
1632
+ }), pi.on("model_select", (event, ctx) => {
1633
+ getLiveContext(ctx) && (currentModel = event.model.id, client && client.updatePresence({
1634
+ ...buildPresenceIdentity(pi, ctx.sessionManager.getSessionId()),
1635
+ model: event.model.id,
1636
+ status: currentStatus()
1637
+ }));
1638
+ }), pi.registerMessageRenderer("intercom_message", (message, options, theme) => {
1639
+ let details = message.details;
1640
+ if (!details)
1641
+ return;
1642
+ let sender = details.from?.name || details.from?.id;
1643
+ return sender === "subagent-result" || sender === "subagent-control" ? { render: () => [], invalidate() {
1644
+ } } : new InlineMessageComponent(details.from, details.message, theme, details.replyCommand, details.bodyText, !options.expanded);
1645
+ }), pi.on("tool_result", (event) => {
1646
+ if (event.toolName !== "intercom" && event.toolName !== "contact_supervisor" || !event.details || typeof event.details != "object")
1647
+ return;
1648
+ let details = event.details;
1649
+ if (details.error === !0 || details.delivered === !1)
1650
+ return { isError: !0 };
1651
+ });
1652
+ let childOrchestratorMetadata = readChildOrchestratorMetadata();
1653
+ childOrchestratorMetadata && pi.registerTool({
1654
+ name: "contact_supervisor",
1655
+ label: "Contact Supervisor",
1656
+ description: "Subagent-only tool for contacting the supervisor agent that delegated this task. Use need_decision when blocked, uncertain, needing approval, or facing a product/API/scope decision before continuing; this waits for the supervisor's reply. Use interview_request when multiple structured questions need supervisor answers; this also waits for a reply. Use progress_update only for meaningful progress or unexpected discoveries that change the plan; this does not wait for a reply. Do not use for routine completion handoffs.",
1657
+ promptSnippet: "Subagent-only: contact the supervisor for decisions, structured interviews, or meaningful plan-changing updates. Do not use for routine completion handoffs.",
1658
+ promptGuidelines: [
1659
+ "Use contact_supervisor with reason='need_decision' when a subagent is blocked, uncertain, needs approval, or faces a product/API/scope decision before continuing.",
1660
+ "Use contact_supervisor with reason='interview_request' when the child needs multiple structured answers from the supervisor in one blocking exchange.",
1661
+ "Use contact_supervisor with reason='progress_update' only for meaningful progress or unexpected discoveries that change the plan.",
1662
+ "Do not use contact_supervisor for routine completion handoffs; return the final subagent result normally."
1663
+ ],
1664
+ parameters: Type.Object({
1665
+ reason: StringEnum(["need_decision", "progress_update", "interview_request"], {
1666
+ description: "Contact reason: 'need_decision' waits for a reply; 'interview_request' sends structured questions and waits for a reply; 'progress_update' sends a non-blocking update"
1667
+ }),
1668
+ message: Type.Optional(Type.String({
1669
+ description: "Decision request, optional interview note, or meaningful progress update for the supervisor"
1670
+ })),
1671
+ interview: Type.Optional(Type.Object({
1672
+ title: Type.Optional(Type.String()),
1673
+ description: Type.Optional(Type.String()),
1674
+ questions: Type.Array(Type.Object({
1675
+ id: Type.String(),
1676
+ type: StringEnum(["single", "multi", "text", "image", "info"], {
1677
+ description: "Question type: single, multi, text, image, or info"
1678
+ }),
1679
+ question: Type.String(),
1680
+ options: Type.Optional(Type.Array(Type.Any())),
1681
+ context: Type.Optional(Type.String())
1682
+ }))
1683
+ }, { description: "Structured interview request for reason='interview_request'" }))
1684
+ }),
1685
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
1686
+ let reason = params.reason;
1687
+ if (reason !== "need_decision" && reason !== "progress_update" && reason !== "interview_request")
1688
+ return {
1689
+ content: [{ type: "text", text: "Invalid reason. Use 'need_decision', 'interview_request', or 'progress_update'." }],
1690
+ details: { error: !0 }
1691
+ };
1692
+ if ((reason === "need_decision" || reason === "progress_update") && typeof params.message != "string")
1693
+ return {
1694
+ content: [{ type: "text", text: `Missing 'message' parameter for reason '${reason}'.` }],
1695
+ details: { error: !0 }
1696
+ };
1697
+ let interviewValidation = reason === "interview_request" ? validateSupervisorInterviewRequest(params.interview) : void 0;
1698
+ if (interviewValidation?.ok === !1)
1699
+ return {
1700
+ content: [{ type: "text", text: `Invalid interview request: ${interviewValidation.error}` }],
1701
+ details: { error: !0 }
1702
+ };
1703
+ let supervisorInterview = interviewValidation?.ok === !0 ? interviewValidation.interview : void 0, connectedClient;
1704
+ try {
1705
+ connectedClient = await ensureConnected("tool");
1706
+ } catch (error) {
1707
+ return {
1708
+ content: [{ type: "text", text: `Intercom not connected: ${getErrorMessage(error)}` }],
1709
+ details: { error: !0 }
1710
+ };
1711
+ }
1712
+ if (syncPresenceIdentity(ctx.sessionManager.getSessionId()), signal?.aborted)
1713
+ return {
1714
+ content: [{ type: "text", text: "Cancelled" }],
1715
+ details: { error: !0 }
1716
+ };
1717
+ let metadata = childOrchestratorMetadata, sendTo;
1718
+ try {
1719
+ sendTo = await resolveSupervisorTarget(connectedClient, metadata);
1720
+ } catch (error) {
1721
+ return {
1722
+ content: [{ type: "text", text: `Failed to resolve supervisor target: ${getErrorMessage(error)}` }],
1723
+ details: { error: !0 }
1724
+ };
1725
+ }
1726
+ if (signal?.aborted)
1727
+ return {
1728
+ content: [{ type: "text", text: "Cancelled" }],
1729
+ details: { error: !0 }
1730
+ };
1731
+ if (sendTo === connectedClient.sessionId)
1732
+ return {
1733
+ content: [{ type: "text", text: "Cannot message the current session" }],
1734
+ details: { error: !0 }
1735
+ };
1736
+ if (reason === "progress_update") {
1737
+ let message = params.message;
1738
+ try {
1739
+ let result = await connectedClient.send(sendTo, {
1740
+ text: formatChildOrchestratorMessage("update", metadata, message)
1741
+ });
1742
+ if (!result.delivered) {
1743
+ let errorText = result.reason ?? "Session may not exist or has disconnected.";
1744
+ return {
1745
+ content: [{ type: "text", text: `Message to "${metadata.orchestratorTarget}" was not delivered: ${errorText}` }],
1746
+ details: { messageId: result.id, delivered: !1, reason: result.reason }
1747
+ };
1748
+ }
1749
+ return pi.appendEntry("intercom_sent", {
1750
+ to: metadata.orchestratorTarget,
1751
+ message: { text: message, reason },
1752
+ messageId: result.id,
1753
+ timestamp: Date.now(),
1754
+ subagent: { runId: metadata.runId, agent: metadata.agent, index: metadata.index }
1755
+ }), {
1756
+ content: [{ type: "text", text: `Progress update sent to supervisor ${metadata.orchestratorTarget}` }],
1757
+ details: { messageId: result.id, delivered: !0 }
1758
+ };
1759
+ } catch (error) {
1760
+ return {
1761
+ content: [{ type: "text", text: `Failed to send progress update: ${getErrorMessage(error)}` }],
1762
+ details: { error: !0 }
1763
+ };
1764
+ }
1765
+ }
1766
+ if (replyWaiter)
1767
+ return {
1768
+ content: [{ type: "text", text: "Already waiting for a reply" }],
1769
+ details: { error: !0 }
1770
+ };
1771
+ let replyPromise = null;
1772
+ try {
1773
+ let questionId = randomUUID3();
1774
+ if (replyPromise = waitForReply(sendTo, questionId, signal, () => connectedClient.cancelAsk(questionId)), replyPromise.catch(() => {
1775
+ }), signal?.aborted) {
1776
+ rejectReplyWaiter(new Error("Cancelled"));
1777
+ try {
1778
+ await replyPromise;
1779
+ } catch {
1780
+ }
1781
+ return {
1782
+ content: [{ type: "text", text: "Cancelled" }],
1783
+ details: { error: !0 }
1784
+ };
1785
+ }
1786
+ let requestText = reason === "interview_request" ? formatChildOrchestratorMessage("interview", metadata, formatSupervisorInterviewRequest(supervisorInterview, typeof params.message == "string" ? params.message : void 0)) : formatChildOrchestratorMessage("ask", metadata, params.message), sendResult = await connectedClient.send(sendTo, {
1787
+ messageId: questionId,
1788
+ text: requestText,
1789
+ expectsReply: !0
1790
+ });
1791
+ if (!sendResult.delivered) {
1792
+ let errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
1793
+ if (rejectReplyWaiter(new Error(`Message to "${metadata.orchestratorTarget}" was not delivered: ${errorText}`)), replyPromise)
1794
+ try {
1795
+ await replyPromise;
1796
+ } catch {
1797
+ }
1798
+ return {
1799
+ content: [{ type: "text", text: `Message to "${metadata.orchestratorTarget}" was not delivered: ${errorText}` }],
1800
+ details: { error: !0 }
1801
+ };
1802
+ }
1803
+ pi.appendEntry("intercom_sent", {
1804
+ to: metadata.orchestratorTarget,
1805
+ message: {
1806
+ text: reason === "interview_request" ? requestText : params.message,
1807
+ reason,
1808
+ ...reason === "interview_request" ? { interview: supervisorInterview } : {}
1809
+ },
1810
+ messageId: sendResult.id,
1811
+ timestamp: Date.now(),
1812
+ subagent: { runId: metadata.runId, agent: metadata.agent, index: metadata.index }
1813
+ });
1814
+ let replyMessage = await replyPromise, replyText = replyMessage.content.text, replyAttachments = replyMessage.content.attachments?.length ? formatAttachments(replyMessage.content.attachments) : "", structuredReply = reason === "interview_request" ? parseStructuredSupervisorReply(replyText, supervisorInterview) : void 0;
1815
+ return pi.appendEntry("intercom_received", {
1816
+ from: metadata.orchestratorTarget,
1817
+ message: { text: replyText, attachments: replyMessage.content.attachments },
1818
+ messageId: replyMessage.id,
1819
+ timestamp: replyMessage.timestamp,
1820
+ subagent: { runId: metadata.runId, agent: metadata.agent, index: metadata.index }
1821
+ }), {
1822
+ content: [{ type: "text", text: `**Reply from supervisor:**
1823
+ ${replyText}${replyAttachments}` }],
1824
+ details: structuredReply ? structuredReply.value !== void 0 ? { structuredReply: structuredReply.value } : { structuredReplyParseError: structuredReply.error } : {}
1825
+ };
1826
+ } catch (error) {
1827
+ if (rejectReplyWaiter(toError3(error)), replyPromise)
1828
+ try {
1829
+ await replyPromise;
1830
+ } catch {
1831
+ }
1832
+ return {
1833
+ content: [{ type: "text", text: `Failed: ${getErrorMessage(error)}` }],
1834
+ details: { error: !0 }
1835
+ };
1836
+ }
1837
+ },
1838
+ renderCall(args, theme) {
1839
+ let reason = typeof args.reason == "string" ? args.reason : "contact", messagePreview = previewText(args.message, 96), interview = args.interview && typeof args.interview == "object" ? args.interview : void 0, text = theme.fg("toolTitle", theme.bold("contact_supervisor "));
1840
+ return text += theme.fg(reason === "need_decision" ? "warning" : reason === "progress_update" ? "muted" : "accent", reason), typeof interview?.title == "string" && interview.title.trim() && (text += " " + theme.fg("accent", interview.title.trim())), messagePreview && (text += `
1841
+ ` + theme.fg("dim", messagePreview)), new Text(text, 0, 0);
1842
+ },
1843
+ renderResult(result, { isPartial }, theme, context) {
1844
+ if (isPartial)
1845
+ return new Text(theme.fg("warning", "Waiting for supervisor..."), 0, 0);
1846
+ let details = result.details, textContent = firstTextContent(result), failed = !!(context.isError || details?.error === !0 || details?.delivered === !1), parseWarning = typeof details?.structuredReplyParseError == "string", text = failed ? theme.fg("error", "\u2717 ") : parseWarning ? theme.fg("warning", "\u26A0 ") : theme.fg("success", "\u2713 ");
1847
+ return text += theme.fg(failed ? "error" : "text", textContent), parseWarning && (text += `
1848
+ ` + theme.fg("warning", `Structured reply parse issue: ${details.structuredReplyParseError}`)), new Text(text, 0, 0);
1849
+ }
1850
+ }), pi.registerTool({
1851
+ name: "intercom",
1852
+ label: "Intercom",
1853
+ description: `Send a message to another pi session running on this machine.
1854
+ Use this to communicate findings, request help, or coordinate work with other sessions.
1855
+
1856
+ Usage:
1857
+ intercom({ action: "list" }) \u2192 List active sessions
1858
+ intercom({ action: "send", to: "session-name", message: "..." }) \u2192 Send message
1859
+ intercom({ action: "ask", to: "session-name", message: "..." }) \u2192 Ask and wait for reply
1860
+ intercom({ action: "reply", message: "..." }) \u2192 Reply to the active/single pending ask
1861
+ intercom({ action: "pending" }) \u2192 List unresolved inbound asks
1862
+ intercom({ action: "status" }) \u2192 Show connection status`,
1863
+ promptSnippet: "Use to coordinate with other local pi sessions: list peers, send updates, ask for help, or check intercom connectivity.",
1864
+ parameters: Type.Object({
1865
+ action: StringEnum(["list", "send", "ask", "reply", "pending", "status"], {
1866
+ description: "Action: 'list', 'send', 'ask', 'reply', 'pending', or 'status'"
1867
+ }),
1868
+ to: Type.Optional(Type.String({
1869
+ description: "Target session name or ID (for 'send', 'ask', or disambiguating 'reply')"
1870
+ })),
1871
+ message: Type.Optional(Type.String({
1872
+ description: "Message to send (for 'send', 'ask', or 'reply' action)"
1873
+ })),
1874
+ attachments: Type.Optional(Type.Array(Type.Object({
1875
+ type: StringEnum(["file", "snippet", "context"]),
1876
+ name: Type.String(),
1877
+ content: Type.String(),
1878
+ language: Type.Optional(Type.String())
1879
+ }))),
1880
+ replyTo: Type.Optional(Type.String({
1881
+ description: "Message ID to reply to (for threading or responding to an 'ask')"
1882
+ }))
1883
+ }),
1884
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
1885
+ let connectedClient;
1886
+ try {
1887
+ connectedClient = await ensureConnected("tool");
1888
+ } catch (error) {
1889
+ return {
1890
+ content: [{ type: "text", text: `Intercom not connected: ${getErrorMessage(error)}` }],
1891
+ details: { error: !0 }
1892
+ };
1893
+ }
1894
+ syncPresenceIdentity(ctx.sessionManager.getSessionId());
1895
+ let { action, to, message, attachments, replyTo } = params;
1896
+ switch (action) {
1897
+ case "list":
1898
+ try {
1899
+ let mySessionId = connectedClient.sessionId, sessions = await connectedClient.listSessions(), currentSession = sessions.find((s) => s.id === mySessionId), otherSessions = sessions.filter((s) => s.id !== mySessionId);
1900
+ if (!currentSession)
1901
+ return {
1902
+ content: [{ type: "text", text: "Current session is missing from intercom session list." }],
1903
+ details: { error: !0 }
1904
+ };
1905
+ let currentSection = `**Current session:**
1906
+ ${formatSessionListRow(currentSession, currentSession.cwd, !0)}`, otherSection = otherSessions.length === 0 ? `**Other sessions:**
1907
+ No other sessions connected.` : `**Other sessions:**
1908
+ ${otherSessions.map((s) => formatSessionListRow(s, currentSession.cwd, !1)).join(`
1909
+ `)}`;
1910
+ return {
1911
+ content: [{ type: "text", text: `${currentSection}
1912
+
1913
+ ${otherSection}` }],
1914
+ details: {}
1915
+ };
1916
+ } catch (error) {
1917
+ return {
1918
+ content: [{ type: "text", text: `Failed to list sessions: ${getErrorMessage(error)}` }],
1919
+ details: { error: !0 }
1920
+ };
1921
+ }
1922
+ case "send": {
1923
+ if (!to || !message)
1924
+ return {
1925
+ content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
1926
+ details: { error: !0 }
1927
+ };
1928
+ try {
1929
+ let sendTo = await resolveSessionTarget(connectedClient, to) ?? to;
1930
+ if (sendTo === connectedClient.sessionId)
1931
+ return {
1932
+ content: [{ type: "text", text: "Cannot message the current session" }],
1933
+ details: { error: !0 }
1934
+ };
1935
+ if (!replyTo && config.confirmSend && ctx.hasUI) {
1936
+ let attachmentText = attachments?.length ? formatAttachments(attachments) : "";
1937
+ if (!await ctx.ui.confirm("Send Message", `Send to "${to}":
1938
+
1939
+ ${message}${attachmentText}`))
1940
+ return {
1941
+ content: [{ type: "text", text: "Message cancelled by user" }],
1942
+ details: {}
1943
+ };
1944
+ }
1945
+ let result = await connectedClient.send(sendTo, {
1946
+ text: message,
1947
+ attachments,
1948
+ replyTo
1949
+ });
1950
+ if (!result.delivered) {
1951
+ let errorText = result.reason ?? "Session may not exist or has disconnected.";
1952
+ return {
1953
+ content: [{ type: "text", text: `Message to "${to}" was not delivered: ${errorText}` }],
1954
+ details: { messageId: result.id, delivered: !1, reason: result.reason }
1955
+ };
1956
+ }
1957
+ return pi.appendEntry("intercom_sent", {
1958
+ to,
1959
+ message: { text: message, attachments, replyTo },
1960
+ messageId: result.id,
1961
+ timestamp: Date.now()
1962
+ }), replyTo && replyTracker.markReplied(replyTo), {
1963
+ content: [{ type: "text", text: `Message sent to ${to}` }],
1964
+ details: { messageId: result.id, delivered: !0 }
1965
+ };
1966
+ } catch (error) {
1967
+ return {
1968
+ content: [{ type: "text", text: `Failed to send: ${getErrorMessage(error)}` }],
1969
+ details: { error: !0 }
1970
+ };
1971
+ }
1972
+ }
1973
+ case "ask": {
1974
+ if (!to || !message)
1975
+ return {
1976
+ content: [{ type: "text", text: "Missing 'to' or 'message' parameter" }],
1977
+ details: { error: !0 }
1978
+ };
1979
+ if (replyWaiter)
1980
+ return {
1981
+ content: [{ type: "text", text: "Already waiting for a reply" }],
1982
+ details: { error: !0 }
1983
+ };
1984
+ if (_signal?.aborted)
1985
+ return {
1986
+ content: [{ type: "text", text: "Cancelled" }],
1987
+ details: { error: !0 }
1988
+ };
1989
+ let replyPromise = null;
1990
+ try {
1991
+ let sendTo = await resolveSessionTarget(connectedClient, to) ?? to;
1992
+ if (_signal?.aborted)
1993
+ return {
1994
+ content: [{ type: "text", text: "Cancelled" }],
1995
+ details: { error: !0 }
1996
+ };
1997
+ if (sendTo === connectedClient.sessionId)
1998
+ return {
1999
+ content: [{ type: "text", text: "Cannot message the current session" }],
2000
+ details: { error: !0 }
2001
+ };
2002
+ if (replyWaiter)
2003
+ return {
2004
+ content: [{ type: "text", text: "Already waiting for a reply" }],
2005
+ details: { error: !0 }
2006
+ };
2007
+ let questionId = randomUUID3();
2008
+ replyPromise = waitForReply(sendTo, questionId, _signal, () => connectedClient.cancelAsk(questionId)), replyPromise.catch(() => {
2009
+ });
2010
+ let sendResult = await connectedClient.send(sendTo, {
2011
+ messageId: questionId,
2012
+ text: message,
2013
+ attachments,
2014
+ replyTo,
2015
+ expectsReply: !0
2016
+ });
2017
+ if (!sendResult.delivered) {
2018
+ let errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
2019
+ if (rejectReplyWaiter(new Error(`Message to "${to}" was not delivered: ${errorText}`)), replyPromise)
2020
+ try {
2021
+ await replyPromise;
2022
+ } catch {
2023
+ }
2024
+ return {
2025
+ content: [{ type: "text", text: `Message to "${to}" was not delivered: ${errorText}` }],
2026
+ details: { error: !0 }
2027
+ };
2028
+ }
2029
+ pi.appendEntry("intercom_sent", {
2030
+ to,
2031
+ message: { text: message, attachments, replyTo },
2032
+ messageId: sendResult.id,
2033
+ timestamp: Date.now()
2034
+ });
2035
+ let replyMessage = await replyPromise, replyText = replyMessage.content.text, replyAttachments = replyMessage.content.attachments?.length ? formatAttachments(replyMessage.content.attachments) : "";
2036
+ return pi.appendEntry("intercom_received", {
2037
+ from: to,
2038
+ message: { text: replyText, attachments: replyMessage.content.attachments },
2039
+ messageId: replyMessage.id,
2040
+ timestamp: replyMessage.timestamp
2041
+ }), {
2042
+ content: [{ type: "text", text: `**Reply from ${to}:**
2043
+ ${replyText}${replyAttachments}` }],
2044
+ details: {}
2045
+ };
2046
+ } catch (error) {
2047
+ if (rejectReplyWaiter(toError3(error)), replyPromise)
2048
+ try {
2049
+ await replyPromise;
2050
+ } catch {
2051
+ }
2052
+ return {
2053
+ content: [{ type: "text", text: `Failed: ${getErrorMessage(error)}` }],
2054
+ details: { error: !0 }
2055
+ };
2056
+ }
2057
+ }
2058
+ case "reply": {
2059
+ if (!message)
2060
+ return {
2061
+ content: [{ type: "text", text: "Missing 'message' parameter" }],
2062
+ details: { error: !0 }
2063
+ };
2064
+ try {
2065
+ let target = replyTracker.resolveReplyTarget({ to, replyTo });
2066
+ if (target.from.id === connectedClient.sessionId)
2067
+ return {
2068
+ content: [{ type: "text", text: "Cannot message the current session" }],
2069
+ details: { error: !0 }
2070
+ };
2071
+ let result = await connectedClient.send(target.from.id, {
2072
+ text: message,
2073
+ replyTo: target.message.id
2074
+ });
2075
+ if (!result.delivered) {
2076
+ let errorText = result.reason ?? "Session may not exist or has disconnected.";
2077
+ return result.reason === "Session not found" && replyTracker.dismissPendingAsk(target.message.id), {
2078
+ content: [{ type: "text", text: `Reply to "${target.from.name || target.from.id}" was not delivered: ${errorText}` }],
2079
+ details: { messageId: result.id, delivered: !1, reason: result.reason }
2080
+ };
2081
+ }
2082
+ return replyTracker.markReplied(target.message.id), pi.appendEntry("intercom_sent", {
2083
+ to: target.from.name || target.from.id,
2084
+ message: { text: message, replyTo: target.message.id },
2085
+ messageId: result.id,
2086
+ timestamp: Date.now()
2087
+ }), {
2088
+ content: [{ type: "text", text: `Reply sent to ${target.from.name || target.from.id}` }],
2089
+ details: { messageId: result.id, delivered: !0, replyTo: target.message.id }
2090
+ };
2091
+ } catch (error) {
2092
+ return {
2093
+ content: [{ type: "text", text: `Failed to reply: ${getErrorMessage(error)}` }],
2094
+ details: { error: !0 }
2095
+ };
2096
+ }
2097
+ }
2098
+ case "pending": {
2099
+ let pendingAsks = replyTracker.listPending();
2100
+ if (pendingAsks.length === 0)
2101
+ return {
2102
+ content: [{ type: "text", text: "No unresolved inbound asks." }],
2103
+ details: {}
2104
+ };
2105
+ let now = Date.now();
2106
+ return {
2107
+ content: [{ type: "text", text: `**Pending asks:**
2108
+ ${pendingAsks.map(({ from, message: message2, receivedAt }) => {
2109
+ let preview = message2.content.text.replace(/\s+/g, " ").slice(0, 80), elapsedSeconds = Math.max(0, Math.floor((now - receivedAt) / 1e3));
2110
+ return `- ${from.name || from.id} \xB7 ${message2.id} \xB7 ${elapsedSeconds}s ago \xB7 ${preview}`;
2111
+ }).join(`
2112
+ `)}` }],
2113
+ details: {}
2114
+ };
2115
+ }
2116
+ case "status":
2117
+ try {
2118
+ let mySessionId = connectedClient.sessionId, sessions = await connectedClient.listSessions();
2119
+ return {
2120
+ content: [{
2121
+ type: "text",
2122
+ text: `**Intercom Status:**
2123
+ Connected: Yes
2124
+ Session ID: ${mySessionId}
2125
+ Active sessions: ${sessions.length}`
2126
+ }],
2127
+ details: {}
2128
+ };
2129
+ } catch (error) {
2130
+ return {
2131
+ content: [{ type: "text", text: `Failed to get status: ${getErrorMessage(error)}` }],
2132
+ details: { error: !0 }
2133
+ };
2134
+ }
2135
+ default:
2136
+ return {
2137
+ content: [{ type: "text", text: `Unknown action: ${action}` }],
2138
+ details: { error: !0 }
2139
+ };
2140
+ }
2141
+ },
2142
+ renderCall(args, theme) {
2143
+ let action = typeof args.action == "string" ? args.action : "intercom", target = typeof args.to == "string" && args.to.trim() ? args.to.trim() : void 0, messagePreview = previewText(args.message, 96), attachmentCount = Array.isArray(args.attachments) ? args.attachments.length : 0, text = theme.fg("toolTitle", theme.bold("intercom "));
2144
+ return text += theme.fg(action === "ask" ? "warning" : action === "reply" ? "success" : "accent", action), target && (text += " " + theme.fg("muted", "\u2192") + " " + theme.fg("accent", target)), attachmentCount > 0 && (text += " " + theme.fg("dim", `(${attachmentCount} attachment${attachmentCount === 1 ? "" : "s"})`)), messagePreview && (text += `
2145
+ ` + theme.fg("dim", messagePreview)), new Text(text, 0, 0);
2146
+ },
2147
+ renderResult(result, { isPartial }, theme, context) {
2148
+ if (isPartial)
2149
+ return new Text(theme.fg("warning", "Intercom working..."), 0, 0);
2150
+ let details = result.details, failed = !!(context.isError || details?.error === !0 || details?.delivered === !1), text = failed ? theme.fg("error", "\u2717 ") : theme.fg("success", "\u2713 ");
2151
+ return text += theme.fg(failed ? "error" : "text", firstTextContent(result)), details?.messageId && !context.expanded && (text += theme.fg("dim", ` (${details.messageId.slice(0, 8)})`)), details?.reason && context.expanded && (text += `
2152
+ ` + theme.fg("dim", `Reason: ${details.reason}`)), new Text(text, 0, 0);
2153
+ }
2154
+ });
2155
+ async function openIntercomOverlay(ctx) {
2156
+ let overlayGeneration = runtimeGeneration, liveContext = getLiveContext(ctx, overlayGeneration);
2157
+ if (!liveContext?.hasUI || liveContext.mode !== "tui")
2158
+ return;
2159
+ let overlayClient;
2160
+ try {
2161
+ overlayClient = await ensureConnected("overlay");
2162
+ } catch (error) {
2163
+ notifyIfLive(ctx, `Intercom unavailable: ${getErrorMessage(error)}`, "error", overlayGeneration);
2164
+ return;
2165
+ }
2166
+ if (!getLiveContext(ctx, overlayGeneration))
2167
+ return;
2168
+ syncPresenceIdentity(ctx.sessionManager.getSessionId());
2169
+ let currentSession, sessions, duplicates;
2170
+ try {
2171
+ let mySessionId = overlayClient.sessionId, allSessions = await overlayClient.listSessions();
2172
+ if (!getLiveContext(ctx, overlayGeneration))
2173
+ return;
2174
+ let foundCurrentSession = allSessions.find((s) => s.id === mySessionId);
2175
+ if (!foundCurrentSession) {
2176
+ notifyIfLive(ctx, "Current session is missing from intercom session list", "error", overlayGeneration);
2177
+ return;
2178
+ }
2179
+ currentSession = foundCurrentSession, duplicates = duplicateSessionNames(allSessions), sessions = allSessions.filter((s) => s.id !== mySessionId);
2180
+ } catch (error) {
2181
+ notifyIfLive(ctx, `Failed to list sessions: ${getErrorMessage(error)}`, "error", overlayGeneration);
2182
+ return;
2183
+ }
2184
+ let selectedSession = await ctx.ui.custom((_tui, theme, keybindings, done) => new SessionListOverlay(theme, keybindings, currentSession, sessions, done), { overlay: !0, overlayOptions: { width: 88 } }).catch(() => {
2185
+ });
2186
+ if (!selectedSession || !getLiveContext(ctx, overlayGeneration))
2187
+ return;
2188
+ try {
2189
+ overlayClient = await ensureConnected("overlay");
2190
+ } catch (error) {
2191
+ notifyIfLive(ctx, `Intercom unavailable: ${getErrorMessage(error)}`, "error", overlayGeneration);
2192
+ return;
2193
+ }
2194
+ if (!getLiveContext(ctx, overlayGeneration))
2195
+ return;
2196
+ let targetLabel = formatSessionLabel(selectedSession, duplicates), result = await ctx.ui.custom((tui, theme, keybindings, done) => new ComposeOverlay(tui, theme, keybindings, selectedSession, targetLabel, overlayClient, done), { overlay: !0, overlayOptions: { width: 72 } }).catch(() => {
2197
+ });
2198
+ result?.sent && result.messageId && result.text && getLiveContext(ctx, overlayGeneration) && (pi.appendEntry("intercom_sent", {
2199
+ to: selectedSession.name || selectedSession.id,
2200
+ message: { text: result.text },
2201
+ messageId: result.messageId,
2202
+ timestamp: Date.now()
2203
+ }), notifyIfLive(ctx, `Message sent to ${targetLabel}`, "info", overlayGeneration));
2204
+ }
2205
+ pi.registerCommand("intercom", {
2206
+ description: "Open session intercom overlay",
2207
+ handler: async (_args, ctx) => openIntercomOverlay(ctx)
2208
+ }), pi.registerShortcut("alt+m", {
2209
+ description: "Open session intercom",
2210
+ handler: async (ctx) => openIntercomOverlay(ctx)
2211
+ });
2212
+ }
2213
+ export {
2214
+ piIntercomExtension as default
2215
+ };