@astralyn/pi 0.84.15 → 0.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (437) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/bun/cli.js +10 -7
  3. package/dist/bun/cli.js.map +1 -1
  4. package/dist/bun/runtime-setup.d.ts +2 -0
  5. package/dist/bun/runtime-setup.d.ts.map +1 -0
  6. package/dist/bun/runtime-setup.js +9 -0
  7. package/dist/bun/runtime-setup.js.map +1 -0
  8. package/dist/cli/args.d.ts.map +1 -1
  9. package/dist/cli/args.js +2 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/config-selector.d.ts.map +1 -1
  12. package/dist/cli/config-selector.js +2 -1
  13. package/dist/cli/config-selector.js.map +1 -1
  14. package/dist/cli/experimental/cli.d.ts +7 -3
  15. package/dist/cli/experimental/cli.d.ts.map +1 -1
  16. package/dist/cli/experimental/cli.js +6 -2
  17. package/dist/cli/experimental/cli.js.map +1 -1
  18. package/dist/cli/experimental/command-options.d.ts +23 -12
  19. package/dist/cli/experimental/command-options.d.ts.map +1 -1
  20. package/dist/cli/experimental/command-options.js +69 -20
  21. package/dist/cli/experimental/command-options.js.map +1 -1
  22. package/dist/cli/experimental/command.d.ts +10 -3
  23. package/dist/cli/experimental/command.d.ts.map +1 -1
  24. package/dist/cli/experimental/command.js +28 -14
  25. package/dist/cli/experimental/command.js.map +1 -1
  26. package/dist/cli/experimental/commands/client.d.ts +8 -2
  27. package/dist/cli/experimental/commands/client.d.ts.map +1 -1
  28. package/dist/cli/experimental/commands/client.js +43 -5
  29. package/dist/cli/experimental/commands/client.js.map +1 -1
  30. package/dist/cli/experimental/commands/server.d.ts +7 -3
  31. package/dist/cli/experimental/commands/server.d.ts.map +1 -1
  32. package/dist/cli/experimental/commands/server.js +27 -8
  33. package/dist/cli/experimental/commands/server.js.map +1 -1
  34. package/dist/cli.js +2541 -18
  35. package/dist/cli.js.map +1 -1
  36. package/dist/client/index.d.ts +1 -2
  37. package/dist/client/index.d.ts.map +1 -1
  38. package/dist/client/index.js +1 -2
  39. package/dist/client/index.js.map +1 -1
  40. package/dist/config.d.ts +1 -0
  41. package/dist/config.d.ts.map +1 -1
  42. package/dist/config.js +1 -0
  43. package/dist/config.js.map +1 -1
  44. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  45. package/dist/core/agent-session-runtime.js +15 -7
  46. package/dist/core/agent-session-runtime.js.map +1 -1
  47. package/dist/core/agent-session.d.ts +2 -6
  48. package/dist/core/agent-session.d.ts.map +1 -1
  49. package/dist/core/agent-session.js +14 -6
  50. package/dist/core/agent-session.js.map +1 -1
  51. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  52. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  53. package/dist/core/compaction/branch-summarization.js +2 -1
  54. package/dist/core/compaction/branch-summarization.js.map +1 -1
  55. package/dist/core/extensions/loader.d.ts.map +1 -1
  56. package/dist/core/extensions/loader.js +1 -2
  57. package/dist/core/extensions/loader.js.map +1 -1
  58. package/dist/core/extensions/types.d.ts +8 -2
  59. package/dist/core/extensions/types.d.ts.map +1 -1
  60. package/dist/core/extensions/types.js.map +1 -1
  61. package/dist/core/http-dispatcher.d.ts.map +1 -1
  62. package/dist/core/http-dispatcher.js +2 -0
  63. package/dist/core/http-dispatcher.js.map +1 -1
  64. package/dist/core/messages.d.ts +1 -1
  65. package/dist/core/messages.d.ts.map +1 -1
  66. package/dist/core/messages.js.map +1 -1
  67. package/dist/core/model-config.d.ts +15 -0
  68. package/dist/core/model-config.d.ts.map +1 -1
  69. package/dist/core/model-config.js +3 -0
  70. package/dist/core/model-config.js.map +1 -1
  71. package/dist/core/model-runtime.d.ts +1 -0
  72. package/dist/core/model-runtime.d.ts.map +1 -1
  73. package/dist/core/model-runtime.js +5 -2
  74. package/dist/core/model-runtime.js.map +1 -1
  75. package/dist/core/provider-composer.d.ts.map +1 -1
  76. package/dist/core/provider-composer.js +8 -2
  77. package/dist/core/provider-composer.js.map +1 -1
  78. package/dist/core/session-manager.d.ts +3 -2
  79. package/dist/core/session-manager.d.ts.map +1 -1
  80. package/dist/core/session-manager.js +40 -13
  81. package/dist/core/session-manager.js.map +1 -1
  82. package/dist/core/settings-manager.js.map +1 -1
  83. package/dist/core/skills.d.ts +1 -1
  84. package/dist/core/skills.d.ts.map +1 -1
  85. package/dist/core/skills.js +4 -2
  86. package/dist/core/skills.js.map +1 -1
  87. package/dist/core/system-prompt.d.ts.map +1 -1
  88. package/dist/core/system-prompt.js +8 -9
  89. package/dist/core/system-prompt.js.map +1 -1
  90. package/dist/core/tools/bash.d.ts.map +1 -1
  91. package/dist/core/tools/bash.js +3 -161
  92. package/dist/core/tools/bash.js.map +1 -1
  93. package/dist/core/tools/edit.d.ts +1 -11
  94. package/dist/core/tools/edit.d.ts.map +1 -1
  95. package/dist/core/tools/edit.js +5 -173
  96. package/dist/core/tools/edit.js.map +1 -1
  97. package/dist/core/tools/find.d.ts.map +1 -1
  98. package/dist/core/tools/find.js +4 -54
  99. package/dist/core/tools/find.js.map +1 -1
  100. package/dist/core/tools/grep.d.ts.map +1 -1
  101. package/dist/core/tools/grep.js +4 -68
  102. package/dist/core/tools/grep.js.map +1 -1
  103. package/dist/core/tools/ls.d.ts.map +1 -1
  104. package/dist/core/tools/ls.js +4 -48
  105. package/dist/core/tools/ls.js.map +1 -1
  106. package/dist/core/tools/read.d.ts.map +1 -1
  107. package/dist/core/tools/read.js +5 -121
  108. package/dist/core/tools/read.js.map +1 -1
  109. package/dist/core/tools/renderers/bash.d.ts +13 -0
  110. package/dist/core/tools/renderers/bash.d.ts.map +1 -0
  111. package/dist/core/tools/renderers/bash.js +174 -0
  112. package/dist/core/tools/renderers/bash.js.map +1 -0
  113. package/dist/core/tools/renderers/edit.d.ts +22 -0
  114. package/dist/core/tools/renderers/edit.d.ts.map +1 -0
  115. package/dist/core/tools/renderers/edit.js +177 -0
  116. package/dist/core/tools/renderers/edit.js.map +1 -0
  117. package/dist/core/tools/renderers/find.d.ts +10 -0
  118. package/dist/core/tools/renderers/find.d.ts.map +1 -0
  119. package/dist/core/tools/renderers/find.js +63 -0
  120. package/dist/core/tools/renderers/find.js.map +1 -0
  121. package/dist/core/tools/renderers/grep.d.ts +10 -0
  122. package/dist/core/tools/renderers/grep.d.ts.map +1 -0
  123. package/dist/core/tools/renderers/grep.js +77 -0
  124. package/dist/core/tools/renderers/grep.js.map +1 -0
  125. package/dist/core/tools/renderers/index.d.ts +28 -0
  126. package/dist/core/tools/renderers/index.d.ts.map +1 -0
  127. package/dist/core/tools/renderers/index.js +47 -0
  128. package/dist/core/tools/renderers/index.js.map +1 -0
  129. package/dist/core/tools/renderers/ls.d.ts +10 -0
  130. package/dist/core/tools/renderers/ls.d.ts.map +1 -0
  131. package/dist/core/tools/renderers/ls.js +57 -0
  132. package/dist/core/tools/renderers/ls.js.map +1 -0
  133. package/dist/core/tools/renderers/read.d.ts +11 -0
  134. package/dist/core/tools/renderers/read.d.ts.map +1 -0
  135. package/dist/core/tools/renderers/read.js +131 -0
  136. package/dist/core/tools/renderers/read.js.map +1 -0
  137. package/dist/core/tools/renderers/write.d.ts +10 -0
  138. package/dist/core/tools/renderers/write.d.ts.map +1 -0
  139. package/dist/core/tools/renderers/write.js +151 -0
  140. package/dist/core/tools/renderers/write.js.map +1 -0
  141. package/dist/core/tools/write.d.ts.map +1 -1
  142. package/dist/core/tools/write.js +5 -144
  143. package/dist/core/tools/write.js.map +1 -1
  144. package/dist/experimental/client-runtime.d.ts +43 -0
  145. package/dist/experimental/client-runtime.d.ts.map +1 -0
  146. package/dist/experimental/client-runtime.js +183 -0
  147. package/dist/experimental/client-runtime.js.map +1 -0
  148. package/dist/experimental/client-tui-chat.d.ts +14 -0
  149. package/dist/experimental/client-tui-chat.d.ts.map +1 -0
  150. package/dist/experimental/client-tui-chat.js +176 -0
  151. package/dist/experimental/client-tui-chat.js.map +1 -0
  152. package/dist/experimental/client-tui.d.ts +37 -0
  153. package/dist/experimental/client-tui.d.ts.map +1 -0
  154. package/dist/experimental/client-tui.js +702 -0
  155. package/dist/experimental/client-tui.js.map +1 -0
  156. package/dist/experimental/client.d.ts +25 -0
  157. package/dist/experimental/client.d.ts.map +1 -0
  158. package/dist/experimental/client.js +99 -0
  159. package/dist/experimental/client.js.map +1 -0
  160. package/dist/experimental/coordinator-entry.d.ts +3 -0
  161. package/dist/experimental/coordinator-entry.d.ts.map +1 -0
  162. package/dist/experimental/coordinator-entry.js +11 -0
  163. package/dist/experimental/coordinator-entry.js.map +1 -0
  164. package/dist/experimental/coordinator.d.ts +38 -0
  165. package/dist/experimental/coordinator.d.ts.map +1 -0
  166. package/dist/experimental/coordinator.js +572 -0
  167. package/dist/experimental/coordinator.js.map +1 -0
  168. package/dist/experimental/mini/main.d.ts +7 -0
  169. package/dist/experimental/mini/main.d.ts.map +1 -0
  170. package/dist/experimental/mini/main.js +21 -0
  171. package/dist/experimental/mini/main.js.map +1 -0
  172. package/dist/experimental/mini/server/entry.d.ts +3 -0
  173. package/dist/experimental/mini/server/entry.d.ts.map +1 -0
  174. package/dist/experimental/mini/server/entry.js +11 -0
  175. package/dist/experimental/mini/server/entry.js.map +1 -0
  176. package/dist/experimental/mini/server/run.d.ts +13 -0
  177. package/dist/experimental/mini/server/run.d.ts.map +1 -0
  178. package/dist/experimental/mini/server/run.js +150 -0
  179. package/dist/experimental/mini/server/run.js.map +1 -0
  180. package/dist/experimental/mini/shared/protocol.d.ts +127 -0
  181. package/dist/experimental/mini/shared/protocol.d.ts.map +1 -0
  182. package/dist/experimental/mini/shared/protocol.js +13 -0
  183. package/dist/experimental/mini/shared/protocol.js.map +1 -0
  184. package/dist/experimental/mini/shared/rpc.d.ts +49 -0
  185. package/dist/experimental/mini/shared/rpc.d.ts.map +1 -0
  186. package/dist/experimental/mini/shared/rpc.js +171 -0
  187. package/dist/experimental/mini/shared/rpc.js.map +1 -0
  188. package/dist/experimental/mini/shared/transport.d.ts +35 -0
  189. package/dist/experimental/mini/shared/transport.d.ts.map +1 -0
  190. package/dist/experimental/mini/shared/transport.js +94 -0
  191. package/dist/experimental/mini/shared/transport.js.map +1 -0
  192. package/dist/experimental/mini/tui/run.d.ts +9 -0
  193. package/dist/experimental/mini/tui/run.d.ts.map +1 -0
  194. package/dist/experimental/mini/tui/run.js +62 -0
  195. package/dist/experimental/mini/tui/run.js.map +1 -0
  196. package/dist/experimental/mini/tui/session.d.ts +26 -0
  197. package/dist/experimental/mini/tui/session.d.ts.map +1 -0
  198. package/dist/experimental/mini/tui/session.js +94 -0
  199. package/dist/experimental/mini/tui/session.js.map +1 -0
  200. package/dist/experimental/mini/tui/view.d.ts +10 -0
  201. package/dist/experimental/mini/tui/view.d.ts.map +1 -0
  202. package/dist/experimental/mini/tui/view.js +461 -0
  203. package/dist/experimental/mini/tui/view.js.map +1 -0
  204. package/dist/experimental/mini/worker/entry.d.ts +3 -0
  205. package/dist/experimental/mini/worker/entry.d.ts.map +1 -0
  206. package/dist/experimental/mini/worker/entry.js +10 -0
  207. package/dist/experimental/mini/worker/entry.js.map +1 -0
  208. package/dist/experimental/mini/worker/lane-service.d.ts +44 -0
  209. package/dist/experimental/mini/worker/lane-service.d.ts.map +1 -0
  210. package/dist/experimental/mini/worker/lane-service.js +97 -0
  211. package/dist/experimental/mini/worker/lane-service.js.map +1 -0
  212. package/dist/experimental/mini/worker/models-service.d.ts +19 -0
  213. package/dist/experimental/mini/worker/models-service.d.ts.map +1 -0
  214. package/dist/experimental/mini/worker/models-service.js +136 -0
  215. package/dist/experimental/mini/worker/models-service.js.map +1 -0
  216. package/dist/experimental/mini/worker/run.d.ts +14 -0
  217. package/dist/experimental/mini/worker/run.d.ts.map +1 -0
  218. package/dist/experimental/mini/worker/run.js +88 -0
  219. package/dist/experimental/mini/worker/run.js.map +1 -0
  220. package/dist/experimental/plugin.d.ts +4 -0
  221. package/dist/experimental/plugin.d.ts.map +1 -0
  222. package/dist/experimental/plugin.js +4 -0
  223. package/dist/experimental/plugin.js.map +1 -0
  224. package/dist/experimental/plugins/bundled.d.ts +7 -0
  225. package/dist/experimental/plugins/bundled.d.ts.map +1 -0
  226. package/dist/experimental/plugins/bundled.js +51 -0
  227. package/dist/experimental/plugins/bundled.js.map +1 -0
  228. package/dist/experimental/plugins/package.d.ts +18 -0
  229. package/dist/experimental/plugins/package.d.ts.map +1 -0
  230. package/dist/experimental/plugins/package.js +113 -0
  231. package/dist/experimental/plugins/package.js.map +1 -0
  232. package/dist/experimental/process.d.ts +20 -0
  233. package/dist/experimental/process.d.ts.map +1 -0
  234. package/dist/experimental/process.js +85 -0
  235. package/dist/experimental/process.js.map +1 -0
  236. package/dist/experimental/radius-auth.d.ts +17 -0
  237. package/dist/experimental/radius-auth.d.ts.map +1 -0
  238. package/dist/experimental/radius-auth.js +52 -0
  239. package/dist/experimental/radius-auth.js.map +1 -0
  240. package/dist/experimental/radius-relay.d.ts +90 -0
  241. package/dist/experimental/radius-relay.d.ts.map +1 -0
  242. package/dist/experimental/radius-relay.js +582 -0
  243. package/dist/experimental/radius-relay.js.map +1 -0
  244. package/dist/experimental/server.d.ts +75 -0
  245. package/dist/experimental/server.d.ts.map +1 -0
  246. package/dist/experimental/server.js +682 -0
  247. package/dist/experimental/server.js.map +1 -0
  248. package/dist/experimental/services/agent-controller-provider.d.ts +4 -0
  249. package/dist/experimental/services/agent-controller-provider.d.ts.map +1 -0
  250. package/dist/experimental/services/agent-controller-provider.js +84 -0
  251. package/dist/experimental/services/agent-controller-provider.js.map +1 -0
  252. package/dist/experimental/services/agent-controller.d.ts +57 -0
  253. package/dist/experimental/services/agent-controller.d.ts.map +1 -0
  254. package/dist/experimental/services/agent-controller.js +3 -0
  255. package/dist/experimental/services/agent-controller.js.map +1 -0
  256. package/dist/experimental/services/connection.d.ts +40 -0
  257. package/dist/experimental/services/connection.d.ts.map +1 -0
  258. package/dist/experimental/services/connection.js +301 -0
  259. package/dist/experimental/services/connection.js.map +1 -0
  260. package/dist/experimental/services/models-provider.d.ts +16 -0
  261. package/dist/experimental/services/models-provider.d.ts.map +1 -0
  262. package/dist/experimental/services/models-provider.js +116 -0
  263. package/dist/experimental/services/models-provider.js.map +1 -0
  264. package/dist/experimental/services/models.d.ts +36 -0
  265. package/dist/experimental/services/models.d.ts.map +1 -0
  266. package/dist/experimental/services/models.js +3 -0
  267. package/dist/experimental/services/models.js.map +1 -0
  268. package/dist/experimental/services/plugins.d.ts +16 -0
  269. package/dist/experimental/services/plugins.d.ts.map +1 -0
  270. package/dist/experimental/services/plugins.js +4 -0
  271. package/dist/experimental/services/plugins.js.map +1 -0
  272. package/dist/experimental/services/presentation-ui.d.ts +13 -0
  273. package/dist/experimental/services/presentation-ui.d.ts.map +1 -0
  274. package/dist/experimental/services/presentation-ui.js +3 -0
  275. package/dist/experimental/services/presentation-ui.js.map +1 -0
  276. package/dist/experimental/services/server.d.ts +19 -0
  277. package/dist/experimental/services/server.d.ts.map +1 -0
  278. package/dist/experimental/services/server.js +104 -0
  279. package/dist/experimental/services/server.js.map +1 -0
  280. package/dist/experimental/services/sessions.d.ts +28 -0
  281. package/dist/experimental/services/sessions.d.ts.map +1 -0
  282. package/dist/experimental/services/sessions.js +4 -0
  283. package/dist/experimental/services/sessions.js.map +1 -0
  284. package/dist/experimental/services/slash-commands-provider.d.ts +14 -0
  285. package/dist/experimental/services/slash-commands-provider.d.ts.map +1 -0
  286. package/dist/experimental/services/slash-commands-provider.js +200 -0
  287. package/dist/experimental/services/slash-commands-provider.js.map +1 -0
  288. package/dist/experimental/services/slash-commands.d.ts +24 -0
  289. package/dist/experimental/services/slash-commands.d.ts.map +1 -0
  290. package/dist/experimental/services/slash-commands.js +3 -0
  291. package/dist/experimental/services/slash-commands.js.map +1 -0
  292. package/dist/experimental/services/transcript-provider.d.ts +12 -0
  293. package/dist/experimental/services/transcript-provider.d.ts.map +1 -0
  294. package/dist/experimental/services/transcript-provider.js +109 -0
  295. package/dist/experimental/services/transcript-provider.js.map +1 -0
  296. package/dist/experimental/services/transcript.d.ts +13 -0
  297. package/dist/experimental/services/transcript.d.ts.map +1 -0
  298. package/dist/experimental/services/transcript.js +3 -0
  299. package/dist/experimental/services/transcript.js.map +1 -0
  300. package/dist/experimental/services/worker.d.ts +28 -0
  301. package/dist/experimental/services/worker.d.ts.map +1 -0
  302. package/dist/experimental/services/worker.js +107 -0
  303. package/dist/experimental/services/worker.js.map +1 -0
  304. package/dist/experimental/session-worker-manager.d.ts +24 -0
  305. package/dist/experimental/session-worker-manager.d.ts.map +1 -0
  306. package/dist/experimental/session-worker-manager.js +699 -0
  307. package/dist/experimental/session-worker-manager.js.map +1 -0
  308. package/dist/experimental/session-worker.d.ts +188 -0
  309. package/dist/experimental/session-worker.d.ts.map +1 -0
  310. package/dist/experimental/session-worker.js +785 -0
  311. package/dist/experimental/session-worker.js.map +1 -0
  312. package/dist/experimental/source-resolver.d.ts +2 -0
  313. package/dist/experimental/source-resolver.d.ts.map +1 -0
  314. package/dist/experimental/source-resolver.js +71 -0
  315. package/dist/experimental/source-resolver.js.map +1 -0
  316. package/dist/extensions/background/index.d.ts +5 -4
  317. package/dist/extensions/background/index.d.ts.map +1 -1
  318. package/dist/extensions/background/index.js +9 -5
  319. package/dist/extensions/background/index.js.map +1 -1
  320. package/dist/extensions/subagent/render.d.ts.map +1 -1
  321. package/dist/extensions/subagent/render.js +9 -2
  322. package/dist/extensions/subagent/render.js.map +1 -1
  323. package/dist/image-resize-worker.js +2 -0
  324. package/dist/index.d.ts +1 -1
  325. package/dist/index.d.ts.map +1 -1
  326. package/dist/index.js.map +1 -1
  327. package/dist/main.d.ts.map +1 -1
  328. package/dist/main.js +126 -1
  329. package/dist/main.js.map +1 -1
  330. package/dist/modes/interactive/chat-viewport.d.ts +20 -0
  331. package/dist/modes/interactive/chat-viewport.d.ts.map +1 -0
  332. package/dist/modes/interactive/chat-viewport.js +28 -0
  333. package/dist/modes/interactive/chat-viewport.js.map +1 -0
  334. package/dist/modes/interactive/components/assistant-message.d.ts +1 -0
  335. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  336. package/dist/modes/interactive/components/assistant-message.js +18 -10
  337. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  338. package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
  339. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  340. package/dist/modes/interactive/components/custom-editor.js +37 -1
  341. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  342. package/dist/modes/interactive/components/index.d.ts +1 -1
  343. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  344. package/dist/modes/interactive/components/index.js.map +1 -1
  345. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  346. package/dist/modes/interactive/components/model-selector.js +5 -14
  347. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  348. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  349. package/dist/modes/interactive/components/scoped-models-selector.js +13 -15
  350. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  351. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  352. package/dist/modes/interactive/components/settings-selector.js +14 -10
  353. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  354. package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
  355. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  356. package/dist/modes/interactive/components/status-indicator.js +10 -3
  357. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  358. package/dist/modes/interactive/components/thinking-selector.js +2 -2
  359. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  360. package/dist/modes/interactive/components/tool-execution.d.ts +22 -4
  361. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  362. package/dist/modes/interactive/components/tool-execution.js +31 -30
  363. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  364. package/dist/modes/interactive/components/trust-selector.js +2 -2
  365. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  366. package/dist/modes/interactive/interactive-mode.d.ts +8 -15
  367. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  368. package/dist/modes/interactive/interactive-mode.js +95 -80
  369. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  370. package/dist/modes/interactive/session-share.d.ts.map +1 -1
  371. package/dist/modes/interactive/session-share.js +8 -12
  372. package/dist/modes/interactive/session-share.js.map +1 -1
  373. package/dist/modes/interactive/theme/dark.json +2 -1
  374. package/dist/modes/interactive/theme/light.json +2 -1
  375. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
  376. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  377. package/dist/modes/interactive/theme/theme-controller.js +5 -0
  378. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  379. package/dist/modes/interactive/theme/theme-json.d.ts +84 -0
  380. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -0
  381. package/dist/modes/interactive/theme/theme-json.js +130 -0
  382. package/dist/modes/interactive/theme/theme-json.js.map +1 -0
  383. package/dist/modes/interactive/theme/theme-schema.json +6 -2
  384. package/dist/modes/interactive/theme/theme.d.ts +14 -5
  385. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  386. package/dist/modes/interactive/theme/theme.js +18 -119
  387. package/dist/modes/interactive/theme/theme.js.map +1 -1
  388. package/dist/modes/interactive/tui-renderer.d.ts +21 -0
  389. package/dist/modes/interactive/tui-renderer.d.ts.map +1 -0
  390. package/dist/modes/interactive/tui-renderer.js +66 -0
  391. package/dist/modes/interactive/tui-renderer.js.map +1 -0
  392. package/dist/rpc-entry.js +2541 -10
  393. package/dist/utils/exif-orientation.d.ts.map +1 -1
  394. package/dist/utils/exif-orientation.js +2 -3
  395. package/dist/utils/exif-orientation.js.map +1 -1
  396. package/dist/utils/tools-manager.d.ts +1 -0
  397. package/dist/utils/tools-manager.d.ts.map +1 -1
  398. package/dist/utils/tools-manager.js +41 -19
  399. package/dist/utils/tools-manager.js.map +1 -1
  400. package/docs/bundled/extensions/background.md +2 -2
  401. package/docs/bundled/extensions/subagent.md +1 -1
  402. package/docs/development.md +1 -1
  403. package/examples/plugins/pi-example-plugin/README.md +38 -0
  404. package/examples/plugins/pi-example-plugin/package.json +10 -0
  405. package/examples/plugins/pi-example-plugin/src/contract.ts +13 -0
  406. package/examples/plugins/pi-example-plugin/src/session.ts +23 -0
  407. package/examples/plugins/pi-example-plugin/src/tui.ts +31 -0
  408. package/npm-shrinkwrap.json +724 -212
  409. package/package.json +15 -7
  410. package/dist/bun/register-bedrock.d.ts +0 -2
  411. package/dist/bun/register-bedrock.d.ts.map +0 -1
  412. package/dist/bun/register-bedrock.js +0 -4
  413. package/dist/bun/register-bedrock.js.map +0 -1
  414. package/dist/cli/experimental/auth.d.ts +0 -16
  415. package/dist/cli/experimental/auth.d.ts.map +0 -1
  416. package/dist/cli/experimental/auth.js +0 -13
  417. package/dist/cli/experimental/auth.js.map +0 -1
  418. package/dist/cli/experimental/commands/pi.d.ts +0 -15
  419. package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
  420. package/dist/cli/experimental/commands/pi.js +0 -28
  421. package/dist/cli/experimental/commands/pi.js.map +0 -1
  422. package/dist/cli/experimental/transport-address.d.ts +0 -10
  423. package/dist/cli/experimental/transport-address.d.ts.map +0 -1
  424. package/dist/cli/experimental/transport-address.js +0 -38
  425. package/dist/cli/experimental/transport-address.js.map +0 -1
  426. package/dist/client/remote-session.d.ts +0 -53
  427. package/dist/client/remote-session.d.ts.map +0 -1
  428. package/dist/client/remote-session.js +0 -340
  429. package/dist/client/remote-session.js.map +0 -1
  430. package/dist/client/transcript.d.ts +0 -12
  431. package/dist/client/transcript.d.ts.map +0 -1
  432. package/dist/client/transcript.js +0 -98
  433. package/dist/client/transcript.js.map +0 -1
  434. package/dist/server/create-harness.d.ts +0 -26
  435. package/dist/server/create-harness.d.ts.map +0 -1
  436. package/dist/server/create-harness.js +0 -106
  437. package/dist/server/create-harness.js.map +0 -1
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The `mini` command. Runs the presentation host.
3
+ *
4
+ * Run: node packages/coding-agent/src/experimental/mini/main.ts [--continue]
5
+ */
6
+ import { runTui } from "./tui/run.js";
7
+ function parseArgs(argv) {
8
+ const options = {};
9
+ for (const arg of argv) {
10
+ if (arg === "--continue" || arg === "-c")
11
+ options.continueSession = true;
12
+ else
13
+ throw new Error(`Unknown argument: ${arg}`);
14
+ }
15
+ return options;
16
+ }
17
+ runTui(parseArgs(process.argv.slice(2))).then(() => process.exit(0), (error) => {
18
+ console.error(error);
19
+ process.exit(1);
20
+ });
21
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../src/experimental/mini/main.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAmB,MAAM,cAAc,CAAC;AAEvD,SAAS,SAAS,CAAC,IAAuB;IACzC,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;;YACpE,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC5C,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EACrB,CAAC,KAAc,EAAE,EAAE;IAClB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CACD,CAAC","sourcesContent":["/**\n * The `mini` command. Runs the presentation host.\n *\n * Run: node packages/coding-agent/src/experimental/mini/main.ts [--continue]\n */\n\nimport { runTui, type TuiOptions } from \"./tui/run.ts\";\n\nfunction parseArgs(argv: readonly string[]): TuiOptions {\n\tconst options: TuiOptions = {};\n\tfor (const arg of argv) {\n\t\tif (arg === \"--continue\" || arg === \"-c\") options.continueSession = true;\n\t\telse throw new Error(`Unknown argument: ${arg}`);\n\t}\n\treturn options;\n}\n\nrunTui(parseArgs(process.argv.slice(2))).then(\n\t() => process.exit(0),\n\t(error: unknown) => {\n\t\tconsole.error(error);\n\t\tprocess.exit(1);\n\t},\n);\n"]}
@@ -0,0 +1,3 @@
1
+ /** Server process entry: `node server/entry.ts <socketPath> <sessionsRoot>`. Spawned detached by the CLI. */
2
+ export {};
3
+ //# sourceMappingURL=entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../../../src/experimental/mini/server/entry.ts"],"names":[],"mappings":"AAAA,6GAA6G"}
@@ -0,0 +1,11 @@
1
+ /** Server process entry: `node server/entry.ts <socketPath> <sessionsRoot>`. Spawned detached by the CLI. */
2
+ import { socketTransport } from "../shared/transport.js";
3
+ import { runServer } from "./run.js";
4
+ const [socketPath, sessionsRoot] = process.argv.slice(2);
5
+ if (!socketPath || !sessionsRoot)
6
+ throw new Error("Server requires <socketPath> <sessionsRoot>");
7
+ void runServer({ transport: socketTransport(socketPath), sessionsRoot }).catch((error) => {
8
+ console.error(error);
9
+ process.exit(1);
10
+ });
11
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../../src/experimental/mini/server/entry.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAE7G,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,MAAM,CAAC,UAAU,EAAE,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzD,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY;IAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AAEjG,KAAK,SAAS,CAAC,EAAE,SAAS,EAAE,eAAe,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IACjG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC","sourcesContent":["/** Server process entry: `node server/entry.ts <socketPath> <sessionsRoot>`. Spawned detached by the CLI. */\n\nimport { socketTransport } from \"../shared/transport.ts\";\nimport { runServer } from \"./run.ts\";\n\nconst [socketPath, sessionsRoot] = process.argv.slice(2);\nif (!socketPath || !sessionsRoot) throw new Error(\"Server requires <socketPath> <sessionsRoot>\");\n\nvoid runServer({ transport: socketTransport(socketPath), sessionsRoot }).catch((error: unknown) => {\n\tconsole.error(error);\n\tprocess.exit(1);\n});\n"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Session server: accepts client connections, spawns one worker process per session, routes.
3
+ *
4
+ * It provides `Sessions` and holds no agent state. Any other service name is forwarded to the worker
5
+ * the calling client is attached to, and every worker event is pushed back to that worker's clients.
6
+ * Workers reach `Sessions` over the same peer, because the routing rule is symmetric.
7
+ */
8
+ import { type Transport } from "../shared/transport.ts";
9
+ export declare function runServer(options: {
10
+ transport: Transport;
11
+ sessionsRoot: string;
12
+ }): Promise<void>;
13
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../../src/experimental/mini/server/run.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAkCzE,wBAAsB,SAAS,CAAC,OAAO,EAAE;IAAE,SAAS,EAAE,SAAS,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4GtG"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Session server: accepts client connections, spawns one worker process per session, routes.
3
+ *
4
+ * It provides `Sessions` and holds no agent state. Any other service name is forwarded to the worker
5
+ * the calling client is attached to, and every worker event is pushed back to that worker's clients.
6
+ * Workers reach `Sessions` over the same peer, because the routing rule is symmetric.
7
+ */
8
+ import { spawn } from "node:child_process";
9
+ import { extname } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ // Narrow entries: the server routes and lists sessions, it never runs an agent.
12
+ import { BACKGROUND_CONTEXT } from "@earendil-works/pi-agent-core/harness/context";
13
+ import { NodeExecutionEnv } from "@earendil-works/pi-agent-core/harness/env/nodejs";
14
+ import { JsonlSessionRepo } from "@earendil-works/pi-agent-core/harness/session";
15
+ import { Sessions, Worker } from "../shared/protocol.js";
16
+ import { createPeer } from "../shared/rpc.js";
17
+ import { childConnection } from "../shared/transport.js";
18
+ const SELF_EXTENSION = extname(fileURLToPath(import.meta.url));
19
+ const WORKER_ENTRY = fileURLToPath(new URL(`../worker/entry${SELF_EXTENSION}`, import.meta.url));
20
+ const WORKER_START_TIMEOUT_MS = 30_000;
21
+ /** Grace period before an idle server retires, so a reconnecting presentation does not race it. */
22
+ const IDLE_SHUTDOWN_MS = 10_000;
23
+ async function listSessions(sessionsRoot) {
24
+ const executionEnv = new NodeExecutionEnv({ cwd: process.cwd() });
25
+ const repo = new JsonlSessionRepo({ fileSystem: executionEnv, sessionsRoot });
26
+ try {
27
+ return (await repo.list(undefined, BACKGROUND_CONTEXT)).map((metadata) => ({
28
+ id: metadata.id,
29
+ path: metadata.path,
30
+ cwd: metadata.cwd,
31
+ createdAt: metadata.createdAt,
32
+ }));
33
+ }
34
+ finally {
35
+ await repo.close(BACKGROUND_CONTEXT);
36
+ await executionEnv.cleanup(BACKGROUND_CONTEXT);
37
+ }
38
+ }
39
+ export async function runServer(options) {
40
+ const routes = new Map();
41
+ let presentations = 0;
42
+ let retire = () => { };
43
+ const retired = new Promise((resolve) => {
44
+ retire = resolve;
45
+ });
46
+ let idleTimer;
47
+ /** Nothing to serve and nothing running: leave, so the next start always gets current code. */
48
+ const considerRetiring = () => {
49
+ if (idleTimer)
50
+ clearTimeout(idleTimer);
51
+ if (presentations > 0 || routes.size > 0)
52
+ return;
53
+ idleTimer = setTimeout(() => {
54
+ if (presentations === 0 && routes.size === 0)
55
+ retire();
56
+ }, IDLE_SHUTDOWN_MS);
57
+ idleTimer.unref();
58
+ };
59
+ /** Concurrent attaches to one session must share a worker: two writers would corrupt the session. */
60
+ const spawning = new Map();
61
+ const spawnWorker = async (sessionId, cwd) => {
62
+ const args = [...process.execArgv, WORKER_ENTRY, options.sessionsRoot, cwd, ...(sessionId ? [sessionId] : [])];
63
+ const child = spawn(process.execPath, args, { stdio: ["pipe", "pipe", "inherit"] });
64
+ const connection = childConnection(child);
65
+ const peer = createPeer(connection);
66
+ // Workers consume `Sessions` through this same peer.
67
+ peer.provide(Sessions, { list, attach: attachUnsupported });
68
+ // A worker that never answers must not wedge the attach that spawned it.
69
+ const described = await peer.use(Worker, { timeoutMs: WORKER_START_TIMEOUT_MS }).describe();
70
+ const route = {
71
+ sessionId: described.sessionId,
72
+ worker: peer,
73
+ subscribers: new Map(),
74
+ stop: () => child.kill(),
75
+ };
76
+ // Routing is the server's job. An addressed event reaches one presentation; the rest are shared.
77
+ peer.onEvent((service, payload, to) => {
78
+ if (to !== undefined) {
79
+ route.subscribers.get(to)?.emitRaw(service, payload);
80
+ return;
81
+ }
82
+ for (const subscriber of route.subscribers.values())
83
+ subscriber.emitRaw(service, payload);
84
+ });
85
+ peer.onClose(() => {
86
+ routes.delete(route.sessionId);
87
+ considerRetiring();
88
+ });
89
+ routes.set(route.sessionId, route);
90
+ return route;
91
+ };
92
+ const ensureRoute = (sessionId, cwd) => {
93
+ if (sessionId === null)
94
+ return spawnWorker(undefined, cwd);
95
+ const existing = routes.get(sessionId);
96
+ if (existing)
97
+ return Promise.resolve(existing);
98
+ const pending = spawning.get(sessionId);
99
+ if (pending)
100
+ return pending;
101
+ const started = spawnWorker(sessionId, cwd).finally(() => spawning.delete(sessionId));
102
+ spawning.set(sessionId, started);
103
+ return started;
104
+ };
105
+ const list = () => listSessions(options.sessionsRoot);
106
+ const attachUnsupported = async () => {
107
+ throw new Error("Only presentations attach to sessions");
108
+ };
109
+ const listener = await options.transport.listen((connection) => {
110
+ presentations += 1;
111
+ let route;
112
+ let attachedAs;
113
+ const sessions = {
114
+ list,
115
+ attach: async (sessionId, cwd, presentationId) => {
116
+ route?.subscribers.delete(attachedAs ?? "");
117
+ attachedAs = presentationId;
118
+ route = await ensureRoute(sessionId, cwd);
119
+ route.subscribers.set(presentationId, presentation);
120
+ return route.sessionId;
121
+ },
122
+ };
123
+ const presentation = createPeer(connection, {
124
+ forward: (method, args) => {
125
+ if (!route)
126
+ throw new Error("Not attached to a session");
127
+ const service = method.slice(0, method.indexOf("."));
128
+ if (!route.worker.announced.has(service)) {
129
+ throw new Error(`No host provides ${service}: server has [${[...presentation.provided]}], worker has [${[...route.worker.announced]}]`);
130
+ }
131
+ return route.worker.call(method, ...args);
132
+ },
133
+ });
134
+ presentation.provide(Sessions, sessions);
135
+ connection.onClose(() => {
136
+ presentations -= 1;
137
+ if (route && attachedAs !== undefined) {
138
+ route.subscribers.delete(attachedAs);
139
+ // One worker per session, kept alive only while someone is looking at it.
140
+ if (route.subscribers.size === 0)
141
+ route.stop();
142
+ }
143
+ considerRetiring();
144
+ });
145
+ });
146
+ considerRetiring();
147
+ await retired;
148
+ await listener.close();
149
+ }
150
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../../src/experimental/mini/server/run.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Session server: accepts client connections, spawns one worker process per session, routes.\n *\n * It provides `Sessions` and holds no agent state. Any other service name is forwarded to the worker\n * the calling client is attached to, and every worker event is pushed back to that worker's clients.\n * Workers reach `Sessions` over the same peer, because the routing rule is symmetric.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { extname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n// Narrow entries: the server routes and lists sessions, it never runs an agent.\nimport { BACKGROUND_CONTEXT } from \"@earendil-works/pi-agent-core/harness/context\";\nimport { NodeExecutionEnv } from \"@earendil-works/pi-agent-core/harness/env/nodejs\";\nimport { JsonlSessionRepo } from \"@earendil-works/pi-agent-core/harness/session\";\nimport { type SessionSummary, Sessions, type SessionsServiceApi, Worker } from \"../shared/protocol.ts\";\nimport { createPeer, type RpcPeer } from \"../shared/rpc.ts\";\nimport { childConnection, type Transport } from \"../shared/transport.ts\";\n\nconst SELF_EXTENSION = extname(fileURLToPath(import.meta.url));\nconst WORKER_ENTRY = fileURLToPath(new URL(`../worker/entry${SELF_EXTENSION}`, import.meta.url));\nconst WORKER_START_TIMEOUT_MS = 30_000;\n/** Grace period before an idle server retires, so a reconnecting presentation does not race it. */\nconst IDLE_SHUTDOWN_MS = 10_000;\n\n/** The server's routing entry for one session worker process. The worker knows none of this. */\ninterface Route {\n\tsessionId: string;\n\t/** Peer to the worker process. */\n\tworker: RpcPeer;\n\t/** Attached presentations by id, so an addressed event goes to exactly one of them. */\n\tsubscribers: Map<string, RpcPeer>;\n\tstop(): void;\n}\n\nasync function listSessions(sessionsRoot: string): Promise<SessionSummary[]> {\n\tconst executionEnv = new NodeExecutionEnv({ cwd: process.cwd() });\n\tconst repo = new JsonlSessionRepo({ fileSystem: executionEnv, sessionsRoot });\n\ttry {\n\t\treturn (await repo.list(undefined, BACKGROUND_CONTEXT)).map((metadata) => ({\n\t\t\tid: metadata.id,\n\t\t\tpath: metadata.path,\n\t\t\tcwd: metadata.cwd,\n\t\t\tcreatedAt: metadata.createdAt,\n\t\t}));\n\t} finally {\n\t\tawait repo.close(BACKGROUND_CONTEXT);\n\t\tawait executionEnv.cleanup(BACKGROUND_CONTEXT);\n\t}\n}\n\nexport async function runServer(options: { transport: Transport; sessionsRoot: string }): Promise<void> {\n\tconst routes = new Map<string, Route>();\n\tlet presentations = 0;\n\tlet retire = (): void => {};\n\tconst retired = new Promise<void>((resolve) => {\n\t\tretire = resolve;\n\t});\n\tlet idleTimer: NodeJS.Timeout | undefined;\n\t/** Nothing to serve and nothing running: leave, so the next start always gets current code. */\n\tconst considerRetiring = (): void => {\n\t\tif (idleTimer) clearTimeout(idleTimer);\n\t\tif (presentations > 0 || routes.size > 0) return;\n\t\tidleTimer = setTimeout(() => {\n\t\t\tif (presentations === 0 && routes.size === 0) retire();\n\t\t}, IDLE_SHUTDOWN_MS);\n\t\tidleTimer.unref();\n\t};\n\t/** Concurrent attaches to one session must share a worker: two writers would corrupt the session. */\n\tconst spawning = new Map<string, Promise<Route>>();\n\n\tconst spawnWorker = async (sessionId: string | undefined, cwd: string): Promise<Route> => {\n\t\tconst args = [...process.execArgv, WORKER_ENTRY, options.sessionsRoot, cwd, ...(sessionId ? [sessionId] : [])];\n\t\tconst child = spawn(process.execPath, args, { stdio: [\"pipe\", \"pipe\", \"inherit\"] });\n\t\tconst connection = childConnection(child);\n\t\tconst peer = createPeer(connection);\n\t\t// Workers consume `Sessions` through this same peer.\n\t\tpeer.provide(Sessions, { list, attach: attachUnsupported });\n\t\t// A worker that never answers must not wedge the attach that spawned it.\n\t\tconst described = await peer.use(Worker, { timeoutMs: WORKER_START_TIMEOUT_MS }).describe();\n\t\tconst route: Route = {\n\t\t\tsessionId: described.sessionId,\n\t\t\tworker: peer,\n\t\t\tsubscribers: new Map(),\n\t\t\tstop: () => child.kill(),\n\t\t};\n\t\t// Routing is the server's job. An addressed event reaches one presentation; the rest are shared.\n\t\tpeer.onEvent((service, payload, to) => {\n\t\t\tif (to !== undefined) {\n\t\t\t\troute.subscribers.get(to)?.emitRaw(service, payload);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const subscriber of route.subscribers.values()) subscriber.emitRaw(service, payload);\n\t\t});\n\t\tpeer.onClose(() => {\n\t\t\troutes.delete(route.sessionId);\n\t\t\tconsiderRetiring();\n\t\t});\n\t\troutes.set(route.sessionId, route);\n\t\treturn route;\n\t};\n\n\tconst ensureRoute = (sessionId: string | null, cwd: string): Promise<Route> => {\n\t\tif (sessionId === null) return spawnWorker(undefined, cwd);\n\t\tconst existing = routes.get(sessionId);\n\t\tif (existing) return Promise.resolve(existing);\n\t\tconst pending = spawning.get(sessionId);\n\t\tif (pending) return pending;\n\t\tconst started = spawnWorker(sessionId, cwd).finally(() => spawning.delete(sessionId));\n\t\tspawning.set(sessionId, started);\n\t\treturn started;\n\t};\n\n\tconst list = (): Promise<SessionSummary[]> => listSessions(options.sessionsRoot);\n\tconst attachUnsupported = async (): Promise<string> => {\n\t\tthrow new Error(\"Only presentations attach to sessions\");\n\t};\n\n\tconst listener = await options.transport.listen((connection) => {\n\t\tpresentations += 1;\n\t\tlet route: Route | undefined;\n\t\tlet attachedAs: string | undefined;\n\t\tconst sessions: SessionsServiceApi = {\n\t\t\tlist,\n\t\t\tattach: async (sessionId, cwd, presentationId) => {\n\t\t\t\troute?.subscribers.delete(attachedAs ?? \"\");\n\t\t\t\tattachedAs = presentationId;\n\t\t\t\troute = await ensureRoute(sessionId, cwd);\n\t\t\t\troute.subscribers.set(presentationId, presentation);\n\t\t\t\treturn route.sessionId;\n\t\t\t},\n\t\t};\n\t\tconst presentation: RpcPeer = createPeer(connection, {\n\t\t\tforward: (method, args) => {\n\t\t\t\tif (!route) throw new Error(\"Not attached to a session\");\n\t\t\t\tconst service = method.slice(0, method.indexOf(\".\"));\n\t\t\t\tif (!route.worker.announced.has(service)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`No host provides ${service}: server has [${[...presentation.provided]}], worker has [${[...route.worker.announced]}]`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn route.worker.call(method, ...args);\n\t\t\t},\n\t\t});\n\t\tpresentation.provide(Sessions, sessions);\n\t\tconnection.onClose(() => {\n\t\t\tpresentations -= 1;\n\t\t\tif (route && attachedAs !== undefined) {\n\t\t\t\troute.subscribers.delete(attachedAs);\n\t\t\t\t// One worker per session, kept alive only while someone is looking at it.\n\t\t\t\tif (route.subscribers.size === 0) route.stop();\n\t\t\t}\n\t\t\tconsiderRetiring();\n\t\t});\n\t});\n\n\tconsiderRetiring();\n\tawait retired;\n\tawait listener.close();\n}\n"]}
@@ -0,0 +1,127 @@
1
+ /** Service contracts and everything that crosses the wire. */
2
+ import type { HarnessEvent, LaneSnapshot } from "@earendil-works/pi-agent-core";
3
+ import type { AuthEvent, AuthPrompt } from "@earendil-works/pi-ai";
4
+ /** Commands answer with data, never exceptions, exactly like a remote call would. */
5
+ export type CommandResult = {
6
+ ok: true;
7
+ } | {
8
+ ok: false;
9
+ error: string;
10
+ };
11
+ /** Durable model identity. Nothing outside a worker holds a `Model` object. */
12
+ export interface ModelRef {
13
+ provider: string;
14
+ modelId: string;
15
+ }
16
+ export interface ModelSummary extends ModelRef {
17
+ name: string;
18
+ }
19
+ export interface ProviderAccount {
20
+ id: string;
21
+ name: string;
22
+ authType: "oauth" | "api_key";
23
+ configured: boolean;
24
+ /** Where the credential came from, for display: "stored", "environment", an env var name. */
25
+ source?: string;
26
+ /** False for ambient credentials pi cannot collect itself, such as AWS profiles or env vars. */
27
+ interactive: boolean;
28
+ methodName?: string;
29
+ }
30
+ export interface ModelsState {
31
+ readonly models: readonly ModelSummary[];
32
+ readonly accounts: readonly ProviderAccount[];
33
+ readonly refreshing: boolean;
34
+ }
35
+ /** An auth prompt without its `AbortSignal`: the part that can cross a transport. */
36
+ export type AuthPromptRequest = AuthPrompt extends infer Prompt ? Prompt extends unknown ? Omit<Prompt, "signal"> : never : never;
37
+ /** A service seen from the other side of a connection: every method returns a promise. */
38
+ export type Remote<T> = {
39
+ [K in keyof T]: T[K] extends (...args: infer A) => infer R ? (...args: A) => Promise<Awaited<R>> : never;
40
+ };
41
+ /** Names one service and carries its call and event types. Names are globally unique. */
42
+ export interface ServiceToken<TApi extends object, TEvent = never> {
43
+ readonly name: string;
44
+ /** Phantom, never read: keeps the types attached to the token. */
45
+ readonly types?: (api: TApi, event: TEvent) => void;
46
+ }
47
+ export declare function defineService<TApi extends object, TEvent = never>(name: string): ServiceToken<TApi, TEvent>;
48
+ export interface SessionSummary {
49
+ id: string;
50
+ path: string;
51
+ cwd: string;
52
+ createdAt: number;
53
+ }
54
+ export interface SessionSnapshot {
55
+ sessionId: string;
56
+ cwd: string;
57
+ sessionPath: string;
58
+ /** Carries the lane configuration, queues, and stats: no side-channel replication. */
59
+ lane: LaneSnapshot;
60
+ models: ModelsState;
61
+ }
62
+ /** Everything the `Models` service publishes. */
63
+ export type ModelsEvent = {
64
+ type: "state";
65
+ state: ModelsState;
66
+ } | {
67
+ type: "prompt";
68
+ requestId: string;
69
+ request: AuthPromptRequest;
70
+ } | {
71
+ type: "notice";
72
+ notice: AuthEvent;
73
+ };
74
+ /** The login half, for whatever drives the dialog. */
75
+ export type AuthEventPayload = Exclude<ModelsEvent, {
76
+ type: "state";
77
+ }>;
78
+ /** One presentation's subscription: a `lane.watch()` in the worker, named so its events can be filtered. */
79
+ export interface LaneSubscription {
80
+ subscriptionId: string;
81
+ snapshot: SessionSnapshot;
82
+ }
83
+ /** Lane events are addressed to the subscription whose watch produced them. */
84
+ export interface LaneEvent {
85
+ subscriptionId: string;
86
+ event: HarnessEvent;
87
+ }
88
+ export interface LaneServiceApi {
89
+ /**
90
+ * Capture a snapshot and open a subscription for one presentation. Its events are addressed to
91
+ * `presentationId`, so the server routes them instead of broadcasting. Buffered until `start`.
92
+ */
93
+ watch(presentationId: string): Promise<LaneSubscription>;
94
+ /** Begin delivery, draining everything buffered since the snapshot. */
95
+ start(subscriptionId: string): Promise<void>;
96
+ unwatch(subscriptionId: string): Promise<void>;
97
+ prompt(text: string): Promise<CommandResult>;
98
+ steer(text: string): Promise<CommandResult>;
99
+ followUp(text: string): Promise<CommandResult>;
100
+ compact(): Promise<CommandResult>;
101
+ abort(): Promise<CommandResult>;
102
+ setModel(ref: ModelRef): Promise<CommandResult>;
103
+ }
104
+ export interface ModelsServiceApi {
105
+ refresh(): Promise<CommandResult>;
106
+ login(providerId: string, authType: "oauth" | "api_key"): Promise<CommandResult>;
107
+ authReply(requestId: string, answer: string | null): Promise<void>;
108
+ }
109
+ /** Provided by a worker so the server can identify the session it opened, without naming lane methods. */
110
+ export interface WorkerServiceApi {
111
+ describe(): Promise<{
112
+ sessionId: string;
113
+ }>;
114
+ }
115
+ export interface SessionsServiceApi {
116
+ list(): Promise<SessionSummary[]>;
117
+ attach(sessionId: string | null, cwd: string, presentationId: string): Promise<string>;
118
+ }
119
+ /** Provided by the worker. One subscription per presentation; `watch` again to rebase. */
120
+ export declare const Lane: ServiceToken<LaneServiceApi, LaneEvent>;
121
+ /** Provided by the worker. Small enough to publish whole. */
122
+ export declare const Models: ServiceToken<ModelsServiceApi, ModelsEvent>;
123
+ /** Provided by the worker, consumed only by the server. */
124
+ export declare const Worker: ServiceToken<WorkerServiceApi, never>;
125
+ /** Provided by the server. */
126
+ export declare const Sessions: ServiceToken<SessionsServiceApi, never>;
127
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../../src/experimental/mini/shared/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /** Service contracts and everything that crosses the wire. */
2
+ export function defineService(name) {
3
+ return { name };
4
+ }
5
+ /** Provided by the worker. One subscription per presentation; `watch` again to rebase. */
6
+ export const Lane = defineService("lane");
7
+ /** Provided by the worker. Small enough to publish whole. */
8
+ export const Models = defineService("models");
9
+ /** Provided by the worker, consumed only by the server. */
10
+ export const Worker = defineService("worker");
11
+ /** Provided by the server. */
12
+ export const Sessions = defineService("sessions");
13
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../../src/experimental/mini/shared/protocol.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAuD9D,MAAM,UAAU,aAAa,CAAsC,IAAY;IAC9E,OAAO,EAAE,IAAI,EAAE,CAAC;AACjB,CAAC;AAyED,0FAA0F;AAC1F,MAAM,CAAC,MAAM,IAAI,GAAG,aAAa,CAA4B,MAAM,CAAC,CAAC;AACrE,6DAA6D;AAC7D,MAAM,CAAC,MAAM,MAAM,GAAG,aAAa,CAAgC,QAAQ,CAAC,CAAC;AAC7E,2DAA2D;AAC3D,MAAM,CAAC,MAAM,MAAM,GAAG,aAAa,CAAmB,QAAQ,CAAC,CAAC;AAChE,8BAA8B;AAC9B,MAAM,CAAC,MAAM,QAAQ,GAAG,aAAa,CAAqB,UAAU,CAAC,CAAC","sourcesContent":["/** Service contracts and everything that crosses the wire. */\n\nimport type { HarnessEvent, LaneSnapshot } from \"@earendil-works/pi-agent-core\";\nimport type { AuthEvent, AuthPrompt } from \"@earendil-works/pi-ai\";\n\n/** Commands answer with data, never exceptions, exactly like a remote call would. */\nexport type CommandResult = { ok: true } | { ok: false; error: string };\n\n/** Durable model identity. Nothing outside a worker holds a `Model` object. */\nexport interface ModelRef {\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface ModelSummary extends ModelRef {\n\tname: string;\n}\n\nexport interface ProviderAccount {\n\tid: string;\n\tname: string;\n\tauthType: \"oauth\" | \"api_key\";\n\tconfigured: boolean;\n\t/** Where the credential came from, for display: \"stored\", \"environment\", an env var name. */\n\tsource?: string;\n\t/** False for ambient credentials pi cannot collect itself, such as AWS profiles or env vars. */\n\tinteractive: boolean;\n\tmethodName?: string;\n}\n\nexport interface ModelsState {\n\treadonly models: readonly ModelSummary[];\n\treadonly accounts: readonly ProviderAccount[];\n\treadonly refreshing: boolean;\n}\n\n/** An auth prompt without its `AbortSignal`: the part that can cross a transport. */\nexport type AuthPromptRequest = AuthPrompt extends infer Prompt\n\t? Prompt extends unknown\n\t\t? Omit<Prompt, \"signal\">\n\t\t: never\n\t: never;\n\n/** A service seen from the other side of a connection: every method returns a promise. */\nexport type Remote<T> = {\n\t[K in keyof T]: T[K] extends (...args: infer A) => infer R ? (...args: A) => Promise<Awaited<R>> : never;\n};\n\n/** Names one service and carries its call and event types. Names are globally unique. */\nexport interface ServiceToken<TApi extends object, TEvent = never> {\n\treadonly name: string;\n\t/** Phantom, never read: keeps the types attached to the token. */\n\treadonly types?: (api: TApi, event: TEvent) => void;\n}\n\nexport function defineService<TApi extends object, TEvent = never>(name: string): ServiceToken<TApi, TEvent> {\n\treturn { name };\n}\n\nexport interface SessionSummary {\n\tid: string;\n\tpath: string;\n\tcwd: string;\n\tcreatedAt: number;\n}\n\nexport interface SessionSnapshot {\n\tsessionId: string;\n\tcwd: string;\n\tsessionPath: string;\n\t/** Carries the lane configuration, queues, and stats: no side-channel replication. */\n\tlane: LaneSnapshot;\n\tmodels: ModelsState;\n}\n\n/** Everything the `Models` service publishes. */\nexport type ModelsEvent =\n\t| { type: \"state\"; state: ModelsState }\n\t// Login runs the wrong way round: the request is an event, the answer is an ordinary call.\n\t| { type: \"prompt\"; requestId: string; request: AuthPromptRequest }\n\t| { type: \"notice\"; notice: AuthEvent };\n\n/** The login half, for whatever drives the dialog. */\nexport type AuthEventPayload = Exclude<ModelsEvent, { type: \"state\" }>;\n\n/** One presentation's subscription: a `lane.watch()` in the worker, named so its events can be filtered. */\nexport interface LaneSubscription {\n\tsubscriptionId: string;\n\tsnapshot: SessionSnapshot;\n}\n\n/** Lane events are addressed to the subscription whose watch produced them. */\nexport interface LaneEvent {\n\tsubscriptionId: string;\n\tevent: HarnessEvent;\n}\n\nexport interface LaneServiceApi {\n\t/**\n\t * Capture a snapshot and open a subscription for one presentation. Its events are addressed to\n\t * `presentationId`, so the server routes them instead of broadcasting. Buffered until `start`.\n\t */\n\twatch(presentationId: string): Promise<LaneSubscription>;\n\t/** Begin delivery, draining everything buffered since the snapshot. */\n\tstart(subscriptionId: string): Promise<void>;\n\tunwatch(subscriptionId: string): Promise<void>;\n\tprompt(text: string): Promise<CommandResult>;\n\tsteer(text: string): Promise<CommandResult>;\n\tfollowUp(text: string): Promise<CommandResult>;\n\tcompact(): Promise<CommandResult>;\n\tabort(): Promise<CommandResult>;\n\tsetModel(ref: ModelRef): Promise<CommandResult>;\n}\n\nexport interface ModelsServiceApi {\n\trefresh(): Promise<CommandResult>;\n\tlogin(providerId: string, authType: \"oauth\" | \"api_key\"): Promise<CommandResult>;\n\tauthReply(requestId: string, answer: string | null): Promise<void>;\n}\n\n/** Provided by a worker so the server can identify the session it opened, without naming lane methods. */\nexport interface WorkerServiceApi {\n\tdescribe(): Promise<{ sessionId: string }>;\n}\n\nexport interface SessionsServiceApi {\n\tlist(): Promise<SessionSummary[]>;\n\tattach(sessionId: string | null, cwd: string, presentationId: string): Promise<string>;\n}\n\n/** Provided by the worker. One subscription per presentation; `watch` again to rebase. */\nexport const Lane = defineService<LaneServiceApi, LaneEvent>(\"lane\");\n/** Provided by the worker. Small enough to publish whole. */\nexport const Models = defineService<ModelsServiceApi, ModelsEvent>(\"models\");\n/** Provided by the worker, consumed only by the server. */\nexport const Worker = defineService<WorkerServiceApi>(\"worker\");\n/** Provided by the server. */\nexport const Sessions = defineService<SessionsServiceApi>(\"sessions\");\n"]}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The whole protocol: call, result, error, cancel, event, ping. Plus named services and one routing
3
+ * rule.
4
+ *
5
+ * A peer provides any number of services and uses the other side's. A call for a service this peer
6
+ * does not provide goes to `forward`, which is what makes the server transparent: a TUI uses
7
+ * `lane.prompt`, the server does not provide `lane`, so it hands the call to the attached worker.
8
+ * The same rule lets a worker use `sessions.list` back through the server.
9
+ */
10
+ import type { Remote, ServiceToken } from "./protocol.ts";
11
+ import type { Connection } from "./transport.ts";
12
+ export type Forward = (method: string, args: unknown[]) => Promise<unknown>;
13
+ export interface CallOptions {
14
+ /** Abandon the call and tell the peer to stop. */
15
+ signal?: AbortSignal;
16
+ /** Reject if the peer has not answered in time. Omit for calls with no bounded duration. */
17
+ timeoutMs?: number;
18
+ }
19
+ export interface PeerOptions {
20
+ /** Handles calls for services this peer does not provide. */
21
+ forward?: Forward;
22
+ /** Silence tolerated before the peer is declared gone. Default 15s; 0 disables liveness. */
23
+ deadMs?: number;
24
+ }
25
+ export interface RpcPeer {
26
+ /** Register an implementation and announce the name to the other side. */
27
+ provide<TApi extends object, TEvent>(token: ServiceToken<TApi, TEvent>, implementation: TApi): void;
28
+ /** Services this peer provides. */
29
+ readonly provided: ReadonlySet<string>;
30
+ /** Services the other side announced. */
31
+ readonly announced: ReadonlySet<string>;
32
+ /** Use a service, wherever it is provided: this peer's other side, or its next hop. */
33
+ use<TApi extends object, TEvent>(token: ServiceToken<TApi, TEvent>, options?: CallOptions): Remote<TApi>;
34
+ /** Publish to everyone listening on the other side. */
35
+ emit<TApi extends object, TEvent>(token: ServiceToken<TApi, TEvent>, event: TEvent): void;
36
+ /** Publish for one destination. A router delivers it there instead of broadcasting. */
37
+ emitTo<TApi extends object, TEvent>(token: ServiceToken<TApi, TEvent>, event: TEvent, to: string): void;
38
+ on<TApi extends object, TEvent>(token: ServiceToken<TApi, TEvent>, handler: (event: TEvent) => void): void;
39
+ /** Router half of the event channel: observe and republish without knowing the service. */
40
+ onEvent(handler: (service: string, payload: unknown, to: string | undefined) => void): void;
41
+ emitRaw(service: string, payload: unknown, to?: string): void;
42
+ call(method: string, ...args: unknown[]): Promise<unknown>;
43
+ callWith(options: CallOptions, method: string, ...args: unknown[]): Promise<unknown>;
44
+ onClose(handler: () => void): void;
45
+ close(): void;
46
+ }
47
+ /** A bidirectional peer on one connection. */
48
+ export declare function createPeer(connection: Connection, options?: PeerOptions): RpcPeer;
49
+ //# sourceMappingURL=rpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../../../src/experimental/mini/shared/rpc.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAWjD,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE5E,MAAM,WAAW,WAAW;IAC3B,kDAAkD;IAClD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC3B,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,MAAM,WAAW,OAAO;IACvB,0EAA0E;IAC1E,OAAO,CAAC,IAAI,SAAS,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,cAAc,EAAE,IAAI,GAAG,IAAI,CAAC;IACpG,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACxC,uFAAuF;IACvF,GAAG,CAAC,IAAI,SAAS,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACzG,uDAAuD;IACvD,IAAI,CAAC,IAAI,SAAS,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1F,uFAAuF;IACvF,MAAM,CAAC,IAAI,SAAS,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACxG,EAAE,CAAC,IAAI,SAAS,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3G,2FAA2F;IAC3F,OAAO,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI,CAAC;IAC5F,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9D,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrF,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACnC,KAAK,IAAI,IAAI,CAAC;CACd;AAED,8CAA8C;AAC9C,wBAAgB,UAAU,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAoKrF"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * The whole protocol: call, result, error, cancel, event, ping. Plus named services and one routing
3
+ * rule.
4
+ *
5
+ * A peer provides any number of services and uses the other side's. A call for a service this peer
6
+ * does not provide goes to `forward`, which is what makes the server transparent: a TUI uses
7
+ * `lane.prompt`, the server does not provide `lane`, so it hands the call to the attached worker.
8
+ * The same rule lets a worker use `sessions.list` back through the server.
9
+ */
10
+ const DEFAULT_DEAD_MS = 15_000;
11
+ /** A bidirectional peer on one connection. */
12
+ export function createPeer(connection, options = {}) {
13
+ const services = new Map();
14
+ const provided = new Set();
15
+ /** What the other side told us it provides, so routing is a lookup rather than a guess. */
16
+ const announced = new Set();
17
+ const pending = new Map();
18
+ /** Controllers for calls this peer is currently answering, so a `cancel` frame can stop them. */
19
+ const inflight = new Map();
20
+ const eventHandlers = [];
21
+ let nextId = 1;
22
+ let lastFrameAt = Date.now();
23
+ // The signal is appended to every handler call: services that care declare a trailing
24
+ // `AbortSignal` parameter, the rest ignore an extra argument.
25
+ const dispatch = async (method, args, signal) => {
26
+ const dot = method.indexOf(".");
27
+ const local = dot === -1 ? undefined : services.get(method.slice(0, dot));
28
+ if (!local) {
29
+ if (!options.forward)
30
+ throw new Error(`No service provides ${method}`);
31
+ return options.forward(method, args);
32
+ }
33
+ const handler = local[method.slice(dot + 1)];
34
+ if (typeof handler !== "function")
35
+ throw new Error(`Unknown method: ${method}`);
36
+ return handler.apply(local, [...args, signal]);
37
+ };
38
+ connection.onMessage((frameValue) => {
39
+ const frame = frameValue;
40
+ lastFrameAt = Date.now();
41
+ switch (frame.kind) {
42
+ case "event": {
43
+ for (const handler of eventHandlers)
44
+ handler(frame.service, frame.payload, frame.to);
45
+ return;
46
+ }
47
+ case "call": {
48
+ const controller = new AbortController();
49
+ inflight.set(frame.id, controller);
50
+ void dispatch(frame.method, frame.args, controller.signal)
51
+ .then(
52
+ // `undefined` vanishes through JSON, so an absent result is sent as null.
53
+ (result) => connection.send({ kind: "result", id: frame.id, result: result ?? null }), (error) => connection.send({ kind: "error", id: frame.id, error: message(error) }))
54
+ .finally(() => inflight.delete(frame.id));
55
+ return;
56
+ }
57
+ case "cancel": {
58
+ inflight.get(frame.id)?.abort(new Error("Cancelled by caller"));
59
+ inflight.delete(frame.id);
60
+ return;
61
+ }
62
+ case "result":
63
+ case "error": {
64
+ const waiter = pending.get(frame.id);
65
+ pending.delete(frame.id);
66
+ if (frame.kind === "error")
67
+ waiter?.reject(new Error(frame.error));
68
+ else
69
+ waiter?.resolve(frame.result);
70
+ return;
71
+ }
72
+ case "announce": {
73
+ announced.clear();
74
+ for (const service of frame.services)
75
+ announced.add(service);
76
+ return;
77
+ }
78
+ case "ping":
79
+ return;
80
+ default: {
81
+ const unknownFrame = frame;
82
+ throw new Error(`Unknown frame: ${JSON.stringify(unknownFrame)}`);
83
+ }
84
+ }
85
+ });
86
+ connection.onClose(() => {
87
+ if (liveness)
88
+ clearInterval(liveness);
89
+ for (const waiter of pending.values())
90
+ waiter.reject(new Error("Connection closed"));
91
+ pending.clear();
92
+ for (const controller of inflight.values())
93
+ controller.abort(new Error("Connection closed"));
94
+ inflight.clear();
95
+ });
96
+ /**
97
+ * A peer can vanish without closing: a killed machine, a wedged event loop. Any frame counts as
98
+ * proof of life, and pings keep an idle connection proving it.
99
+ */
100
+ const deadMs = options.deadMs ?? DEFAULT_DEAD_MS;
101
+ const liveness = deadMs > 0
102
+ ? setInterval(() => {
103
+ if (Date.now() - lastFrameAt > deadMs)
104
+ connection.close();
105
+ else
106
+ connection.send({ kind: "ping" });
107
+ }, Math.floor(deadMs / 3))
108
+ : undefined;
109
+ liveness?.unref();
110
+ const callWith = (callOptions, method, ...args) => new Promise((resolve, reject) => {
111
+ const id = nextId++;
112
+ let timer;
113
+ const abandon = (error) => {
114
+ if (!pending.delete(id))
115
+ return;
116
+ if (timer)
117
+ clearTimeout(timer);
118
+ callOptions.signal?.removeEventListener("abort", onAbort);
119
+ // Tell the peer to stop; it may already be gone, in which case this is a no-op.
120
+ connection.send({ kind: "cancel", id });
121
+ reject(error);
122
+ };
123
+ const onAbort = () => abandon(new Error("Call cancelled"));
124
+ const settle = (handler) => (value) => {
125
+ if (timer)
126
+ clearTimeout(timer);
127
+ callOptions.signal?.removeEventListener("abort", onAbort);
128
+ handler(value);
129
+ };
130
+ if (callOptions.signal?.aborted) {
131
+ reject(new Error("Call cancelled"));
132
+ return;
133
+ }
134
+ pending.set(id, { resolve: settle(resolve), reject: settle(reject) });
135
+ callOptions.signal?.addEventListener("abort", onAbort, { once: true });
136
+ if (callOptions.timeoutMs !== undefined) {
137
+ timer = setTimeout(() => abandon(new Error(`${method} timed out after ${callOptions.timeoutMs}ms`)), callOptions.timeoutMs);
138
+ timer.unref();
139
+ }
140
+ connection.send({ kind: "call", id, method, args });
141
+ });
142
+ const peer = {
143
+ provide: (token, implementation) => {
144
+ services.set(token.name, implementation);
145
+ provided.add(token.name);
146
+ connection.send({ kind: "announce", services: [...provided] });
147
+ },
148
+ provided,
149
+ announced,
150
+ use: (token, callOptions = {}) => new Proxy({}, {
151
+ get: (_target, method) => (...args) => callWith(callOptions, `${token.name}.${String(method)}`, ...args),
152
+ }),
153
+ emit: (token, event) => connection.send({ kind: "event", service: token.name, payload: event }),
154
+ emitTo: (token, event, to) => connection.send({ kind: "event", service: token.name, payload: event, to }),
155
+ emitRaw: (service, payload, to) => connection.send({ kind: "event", service, payload, ...(to === undefined ? {} : { to }) }),
156
+ on: (token, handler) => eventHandlers.push((name, payload) => {
157
+ if (name === token.name)
158
+ handler(payload);
159
+ }),
160
+ onEvent: (handler) => eventHandlers.push(handler),
161
+ call: (method, ...args) => callWith({}, method, ...args),
162
+ callWith,
163
+ onClose: (handler) => connection.onClose(handler),
164
+ close: () => connection.close(),
165
+ };
166
+ return peer;
167
+ }
168
+ function message(error) {
169
+ return error instanceof Error ? error.message : String(error);
170
+ }
171
+ //# sourceMappingURL=rpc.js.map