@xyit/wellspring 0.0.0-stage → 1.1.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 (464) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +853 -2
  3. package/dist/agent/pending-asks.d.ts +20 -0
  4. package/dist/agent/pending-asks.js +70 -0
  5. package/dist/agent/pending-asks.js.map +1 -0
  6. package/dist/agent/task-registry.d.ts +14 -0
  7. package/dist/agent/task-registry.js +80 -0
  8. package/dist/agent/task-registry.js.map +1 -0
  9. package/dist/agent/tool-context.d.ts +30 -0
  10. package/dist/agent/tool-context.js +10 -0
  11. package/dist/agent/tool-context.js.map +1 -0
  12. package/dist/agent/usage.d.ts +40 -0
  13. package/dist/agent/usage.js +122 -0
  14. package/dist/agent/usage.js.map +1 -0
  15. package/dist/api/host/agent.d.ts +165 -0
  16. package/dist/api/host/agent.js +5 -0
  17. package/dist/api/host/agent.js.map +1 -0
  18. package/dist/api/host/events.d.ts +2 -0
  19. package/dist/api/host/events.js +6 -0
  20. package/dist/api/host/events.js.map +1 -0
  21. package/dist/api/host/exec.d.ts +36 -0
  22. package/dist/api/host/exec.js +10 -0
  23. package/dist/api/host/exec.js.map +1 -0
  24. package/dist/api/host/fs.d.ts +24 -0
  25. package/dist/api/host/fs.js +7 -0
  26. package/dist/api/host/fs.js.map +1 -0
  27. package/dist/api/host/hooks.d.ts +210 -0
  28. package/dist/api/host/hooks.js +401 -0
  29. package/dist/api/host/hooks.js.map +1 -0
  30. package/dist/api/host/host.d.ts +36 -0
  31. package/dist/api/host/host.js +53 -0
  32. package/dist/api/host/host.js.map +1 -0
  33. package/dist/api/host/http.d.ts +58 -0
  34. package/dist/api/host/http.js +6 -0
  35. package/dist/api/host/http.js.map +1 -0
  36. package/dist/api/host/index.d.ts +15 -0
  37. package/dist/api/host/index.js +20 -0
  38. package/dist/api/host/index.js.map +1 -0
  39. package/dist/api/host/models.d.ts +65 -0
  40. package/dist/api/host/models.js +8 -0
  41. package/dist/api/host/models.js.map +1 -0
  42. package/dist/api/host/network.d.ts +22 -0
  43. package/dist/api/host/network.js +7 -0
  44. package/dist/api/host/network.js.map +1 -0
  45. package/dist/api/host/plugin.d.ts +138 -0
  46. package/dist/api/host/plugin.js +6 -0
  47. package/dist/api/host/plugin.js.map +1 -0
  48. package/dist/api/host/plugins.d.ts +49 -0
  49. package/dist/api/host/plugins.js +6 -0
  50. package/dist/api/host/plugins.js.map +1 -0
  51. package/dist/api/host/pty.d.ts +55 -0
  52. package/dist/api/host/pty.js +21 -0
  53. package/dist/api/host/pty.js.map +1 -0
  54. package/dist/api/host/session.d.ts +5 -0
  55. package/dist/api/host/session.js +52 -0
  56. package/dist/api/host/session.js.map +1 -0
  57. package/dist/api/host/version.d.ts +2 -0
  58. package/dist/api/host/version.js +3 -0
  59. package/dist/api/host/version.js.map +1 -0
  60. package/dist/api/host/workspace.d.ts +38 -0
  61. package/dist/api/host/workspace.js +9 -0
  62. package/dist/api/host/workspace.js.map +1 -0
  63. package/dist/api/plugin/http-client.d.ts +42 -0
  64. package/dist/api/plugin/http-client.js +364 -0
  65. package/dist/api/plugin/http-client.js.map +1 -0
  66. package/dist/api/plugin/http-protocol.d.ts +152 -0
  67. package/dist/api/plugin/http-protocol.js +49 -0
  68. package/dist/api/plugin/http-protocol.js.map +1 -0
  69. package/dist/api/result/result.d.ts +16 -0
  70. package/dist/api/result/result.js +43 -0
  71. package/dist/api/result/result.js.map +1 -0
  72. package/dist/commands/agent-turn.d.ts +63 -0
  73. package/dist/commands/agent-turn.js +687 -0
  74. package/dist/commands/agent-turn.js.map +1 -0
  75. package/dist/commands/ask-prompt.d.ts +6 -0
  76. package/dist/commands/ask-prompt.js +49 -0
  77. package/dist/commands/ask-prompt.js.map +1 -0
  78. package/dist/commands/config.d.ts +2 -0
  79. package/dist/commands/config.js +283 -0
  80. package/dist/commands/config.js.map +1 -0
  81. package/dist/commands/conversation.d.ts +51 -0
  82. package/dist/commands/conversation.js +630 -0
  83. package/dist/commands/conversation.js.map +1 -0
  84. package/dist/commands/doctor.d.ts +2 -0
  85. package/dist/commands/doctor.js +77 -0
  86. package/dist/commands/doctor.js.map +1 -0
  87. package/dist/commands/exec-approval.d.ts +3 -0
  88. package/dist/commands/exec-approval.js +80 -0
  89. package/dist/commands/exec-approval.js.map +1 -0
  90. package/dist/commands/help.d.ts +2 -0
  91. package/dist/commands/help.js +35 -0
  92. package/dist/commands/help.js.map +1 -0
  93. package/dist/commands/key.d.ts +2 -0
  94. package/dist/commands/key.js +226 -0
  95. package/dist/commands/key.js.map +1 -0
  96. package/dist/commands/plugin.d.ts +2 -0
  97. package/dist/commands/plugin.js +190 -0
  98. package/dist/commands/plugin.js.map +1 -0
  99. package/dist/commands/session.d.ts +2 -0
  100. package/dist/commands/session.js +167 -0
  101. package/dist/commands/session.js.map +1 -0
  102. package/dist/commands/shared.d.ts +35 -0
  103. package/dist/commands/shared.js +66 -0
  104. package/dist/commands/shared.js.map +1 -0
  105. package/dist/commands/start.d.ts +2 -0
  106. package/dist/commands/start.js +75 -0
  107. package/dist/commands/start.js.map +1 -0
  108. package/dist/commands/stop.d.ts +2 -0
  109. package/dist/commands/stop.js +24 -0
  110. package/dist/commands/stop.js.map +1 -0
  111. package/dist/commands/version.d.ts +2 -0
  112. package/dist/commands/version.js +33 -0
  113. package/dist/commands/version.js.map +1 -0
  114. package/dist/config/codes.d.ts +13 -0
  115. package/dist/config/codes.js +15 -0
  116. package/dist/config/codes.js.map +1 -0
  117. package/dist/config/credentials.d.ts +67 -0
  118. package/dist/config/credentials.js +214 -0
  119. package/dist/config/credentials.js.map +1 -0
  120. package/dist/config/defaults.d.ts +5 -0
  121. package/dist/config/defaults.js +31 -0
  122. package/dist/config/defaults.js.map +1 -0
  123. package/dist/config/index.d.ts +5 -0
  124. package/dist/config/index.js +10 -0
  125. package/dist/config/index.js.map +1 -0
  126. package/dist/config/loader.d.ts +10 -0
  127. package/dist/config/loader.js +68 -0
  128. package/dist/config/loader.js.map +1 -0
  129. package/dist/config/providers.d.ts +30 -0
  130. package/dist/config/providers.js +97 -0
  131. package/dist/config/providers.js.map +1 -0
  132. package/dist/config/types.d.ts +75 -0
  133. package/dist/config/types.js +4 -0
  134. package/dist/config/types.js.map +1 -0
  135. package/dist/config/validate.d.ts +4 -0
  136. package/dist/config/validate.js +391 -0
  137. package/dist/config/validate.js.map +1 -0
  138. package/dist/display/markdown.d.ts +7 -0
  139. package/dist/display/markdown.js +116 -0
  140. package/dist/display/markdown.js.map +1 -0
  141. package/dist/display/tool-label.d.ts +6 -0
  142. package/dist/display/tool-label.js +81 -0
  143. package/dist/display/tool-label.js.map +1 -0
  144. package/dist/event/event.d.ts +27 -0
  145. package/dist/event/event.js +152 -0
  146. package/dist/event/event.js.map +1 -0
  147. package/dist/index.d.ts +2 -0
  148. package/dist/index.js +308 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/input/codes.d.ts +15 -0
  151. package/dist/input/codes.js +20 -0
  152. package/dist/input/codes.js.map +1 -0
  153. package/dist/input/commands.d.ts +10 -0
  154. package/dist/input/commands.js +65 -0
  155. package/dist/input/commands.js.map +1 -0
  156. package/dist/input/help.d.ts +8 -0
  157. package/dist/input/help.js +51 -0
  158. package/dist/input/help.js.map +1 -0
  159. package/dist/input/index.d.ts +6 -0
  160. package/dist/input/index.js +10 -0
  161. package/dist/input/index.js.map +1 -0
  162. package/dist/input/parse-options.d.ts +11 -0
  163. package/dist/input/parse-options.js +51 -0
  164. package/dist/input/parse-options.js.map +1 -0
  165. package/dist/input/parse.d.ts +3 -0
  166. package/dist/input/parse.js +119 -0
  167. package/dist/input/parse.js.map +1 -0
  168. package/dist/input/types.d.ts +17 -0
  169. package/dist/input/types.js +2 -0
  170. package/dist/input/types.js.map +1 -0
  171. package/dist/logger/elog4js.d.ts +65 -0
  172. package/dist/logger/elog4js.js +305 -0
  173. package/dist/logger/elog4js.js.map +1 -0
  174. package/dist/logger/logger.d.ts +37 -0
  175. package/dist/logger/logger.js +196 -0
  176. package/dist/logger/logger.js.map +1 -0
  177. package/dist/network/index.d.ts +2 -0
  178. package/dist/network/index.js +6 -0
  179. package/dist/network/index.js.map +1 -0
  180. package/dist/network/openai.d.ts +117 -0
  181. package/dist/network/openai.js +443 -0
  182. package/dist/network/openai.js.map +1 -0
  183. package/dist/network/proxy.d.ts +9 -0
  184. package/dist/network/proxy.js +72 -0
  185. package/dist/network/proxy.js.map +1 -0
  186. package/dist/network/web.d.ts +34 -0
  187. package/dist/network/web.js +152 -0
  188. package/dist/network/web.js.map +1 -0
  189. package/dist/platform/clipboard.d.ts +15 -0
  190. package/dist/platform/clipboard.js +82 -0
  191. package/dist/platform/clipboard.js.map +1 -0
  192. package/dist/platform/exec.d.ts +28 -0
  193. package/dist/platform/exec.js +95 -0
  194. package/dist/platform/exec.js.map +1 -0
  195. package/dist/platform/file.d.ts +38 -0
  196. package/dist/platform/file.js +197 -0
  197. package/dist/platform/file.js.map +1 -0
  198. package/dist/platform/index.d.ts +7 -0
  199. package/dist/platform/index.js +12 -0
  200. package/dist/platform/index.js.map +1 -0
  201. package/dist/platform/notification.d.ts +14 -0
  202. package/dist/platform/notification.js +82 -0
  203. package/dist/platform/notification.js.map +1 -0
  204. package/dist/platform/open-external.d.ts +10 -0
  205. package/dist/platform/open-external.js +105 -0
  206. package/dist/platform/open-external.js.map +1 -0
  207. package/dist/platform/os.d.ts +20 -0
  208. package/dist/platform/os.js +86 -0
  209. package/dist/platform/os.js.map +1 -0
  210. package/dist/platform/path.d.ts +32 -0
  211. package/dist/platform/path.js +154 -0
  212. package/dist/platform/path.js.map +1 -0
  213. package/dist/plugin/access-guard.d.ts +1 -0
  214. package/dist/plugin/access-guard.js +40 -0
  215. package/dist/plugin/access-guard.js.map +1 -0
  216. package/dist/plugin/agent-service.d.ts +25 -0
  217. package/dist/plugin/agent-service.js +809 -0
  218. package/dist/plugin/agent-service.js.map +1 -0
  219. package/dist/plugin/agent-tools.d.ts +12 -0
  220. package/dist/plugin/agent-tools.js +31 -0
  221. package/dist/plugin/agent-tools.js.map +1 -0
  222. package/dist/plugin/capabilities.d.ts +26 -0
  223. package/dist/plugin/capabilities.js +192 -0
  224. package/dist/plugin/capabilities.js.map +1 -0
  225. package/dist/plugin/console-guard.d.ts +2 -0
  226. package/dist/plugin/console-guard.js +52 -0
  227. package/dist/plugin/console-guard.js.map +1 -0
  228. package/dist/plugin/data-access.d.ts +15 -0
  229. package/dist/plugin/data-access.js +57 -0
  230. package/dist/plugin/data-access.js.map +1 -0
  231. package/dist/plugin/fs.d.ts +3 -0
  232. package/dist/plugin/fs.js +93 -0
  233. package/dist/plugin/fs.js.map +1 -0
  234. package/dist/plugin/host-alias.d.ts +2 -0
  235. package/dist/plugin/host-alias.js +57 -0
  236. package/dist/plugin/host-alias.js.map +1 -0
  237. package/dist/plugin/index.d.ts +7 -0
  238. package/dist/plugin/index.js +11 -0
  239. package/dist/plugin/index.js.map +1 -0
  240. package/dist/plugin/install.d.ts +17 -0
  241. package/dist/plugin/install.js +163 -0
  242. package/dist/plugin/install.js.map +1 -0
  243. package/dist/plugin/loader.d.ts +45 -0
  244. package/dist/plugin/loader.js +739 -0
  245. package/dist/plugin/loader.js.map +1 -0
  246. package/dist/plugin/manage.d.ts +31 -0
  247. package/dist/plugin/manage.js +271 -0
  248. package/dist/plugin/manage.js.map +1 -0
  249. package/dist/plugin/models-service.d.ts +15 -0
  250. package/dist/plugin/models-service.js +317 -0
  251. package/dist/plugin/models-service.js.map +1 -0
  252. package/dist/plugin/network-service.d.ts +10 -0
  253. package/dist/plugin/network-service.js +87 -0
  254. package/dist/plugin/network-service.js.map +1 -0
  255. package/dist/plugin/package-manager.d.ts +46 -0
  256. package/dist/plugin/package-manager.js +148 -0
  257. package/dist/plugin/package-manager.js.map +1 -0
  258. package/dist/plugin/paths.d.ts +6 -0
  259. package/dist/plugin/paths.js +15 -0
  260. package/dist/plugin/paths.js.map +1 -0
  261. package/dist/plugin/registry.d.ts +17 -0
  262. package/dist/plugin/registry.js +82 -0
  263. package/dist/plugin/registry.js.map +1 -0
  264. package/dist/plugin/runtime.d.ts +9 -0
  265. package/dist/plugin/runtime.js +43 -0
  266. package/dist/plugin/runtime.js.map +1 -0
  267. package/dist/plugin/scaffold.d.ts +13 -0
  268. package/dist/plugin/scaffold.js +132 -0
  269. package/dist/plugin/scaffold.js.map +1 -0
  270. package/dist/plugin/state.d.ts +6 -0
  271. package/dist/plugin/state.js +38 -0
  272. package/dist/plugin/state.js.map +1 -0
  273. package/dist/plugin/zip.d.ts +7 -0
  274. package/dist/plugin/zip.js +138 -0
  275. package/dist/plugin/zip.js.map +1 -0
  276. package/dist/sandbox/audit.d.ts +12 -0
  277. package/dist/sandbox/audit.js +20 -0
  278. package/dist/sandbox/audit.js.map +1 -0
  279. package/dist/sandbox/backends/bwrap.d.ts +28 -0
  280. package/dist/sandbox/backends/bwrap.js +197 -0
  281. package/dist/sandbox/backends/bwrap.js.map +1 -0
  282. package/dist/sandbox/backends/direct.d.ts +7 -0
  283. package/dist/sandbox/backends/direct.js +32 -0
  284. package/dist/sandbox/backends/direct.js.map +1 -0
  285. package/dist/sandbox/bridge-state.d.ts +13 -0
  286. package/dist/sandbox/bridge-state.js +12 -0
  287. package/dist/sandbox/bridge-state.js.map +1 -0
  288. package/dist/sandbox/index.d.ts +5 -0
  289. package/dist/sandbox/index.js +6 -0
  290. package/dist/sandbox/index.js.map +1 -0
  291. package/dist/sandbox/manager.d.ts +8 -0
  292. package/dist/sandbox/manager.js +325 -0
  293. package/dist/sandbox/manager.js.map +1 -0
  294. package/dist/sandbox/memory-limit.d.ts +44 -0
  295. package/dist/sandbox/memory-limit.js +193 -0
  296. package/dist/sandbox/memory-limit.js.map +1 -0
  297. package/dist/sandbox/plugin-client.d.ts +80 -0
  298. package/dist/sandbox/plugin-client.js +1601 -0
  299. package/dist/sandbox/plugin-client.js.map +1 -0
  300. package/dist/sandbox/plugin-host.d.ts +1 -0
  301. package/dist/sandbox/plugin-host.js +1001 -0
  302. package/dist/sandbox/plugin-host.js.map +1 -0
  303. package/dist/sandbox/protocol.d.ts +43 -0
  304. package/dist/sandbox/protocol.js +96 -0
  305. package/dist/sandbox/protocol.js.map +1 -0
  306. package/dist/sandbox/rpc-timeouts.d.ts +28 -0
  307. package/dist/sandbox/rpc-timeouts.js +15 -0
  308. package/dist/sandbox/rpc-timeouts.js.map +1 -0
  309. package/dist/sandbox/supervisor.d.ts +31 -0
  310. package/dist/sandbox/supervisor.js +114 -0
  311. package/dist/sandbox/supervisor.js.map +1 -0
  312. package/dist/sandbox/types.d.ts +124 -0
  313. package/dist/sandbox/types.js +17 -0
  314. package/dist/sandbox/types.js.map +1 -0
  315. package/dist/service/control.d.ts +32 -0
  316. package/dist/service/control.js +117 -0
  317. package/dist/service/control.js.map +1 -0
  318. package/dist/session/compress.d.ts +3 -0
  319. package/dist/session/compress.js +42 -0
  320. package/dist/session/compress.js.map +1 -0
  321. package/dist/session/index.d.ts +4 -0
  322. package/dist/session/index.js +8 -0
  323. package/dist/session/index.js.map +1 -0
  324. package/dist/session/registry.d.ts +4 -0
  325. package/dist/session/registry.js +12 -0
  326. package/dist/session/registry.js.map +1 -0
  327. package/dist/session/replay.d.ts +10 -0
  328. package/dist/session/replay.js +109 -0
  329. package/dist/session/replay.js.map +1 -0
  330. package/dist/session/session.d.ts +40 -0
  331. package/dist/session/session.js +108 -0
  332. package/dist/session/session.js.map +1 -0
  333. package/dist/session/store.d.ts +58 -0
  334. package/dist/session/store.js +382 -0
  335. package/dist/session/store.js.map +1 -0
  336. package/dist/session/types.d.ts +56 -0
  337. package/dist/session/types.js +3 -0
  338. package/dist/session/types.js.map +1 -0
  339. package/dist/workspace/index.d.ts +7 -0
  340. package/dist/workspace/index.js +17 -0
  341. package/dist/workspace/index.js.map +1 -0
  342. package/dist/workspace/registry.d.ts +25 -0
  343. package/dist/workspace/registry.js +293 -0
  344. package/dist/workspace/registry.js.map +1 -0
  345. package/package.json +73 -5
  346. package/scripts/build-node-pty.mjs +55 -0
  347. package/scripts/rewrite-dts.mjs +36 -0
  348. package/scripts/run-tests.mjs +41 -0
  349. package/scripts/verify-sandbox.ts +98 -0
  350. package/src/agent/pending-asks.ts +88 -0
  351. package/src/agent/task-registry.ts +108 -0
  352. package/src/agent/tool-context.ts +47 -0
  353. package/src/agent/usage.ts +170 -0
  354. package/src/api/host/agent.ts +162 -0
  355. package/src/api/host/events.ts +7 -0
  356. package/src/api/host/exec.ts +47 -0
  357. package/src/api/host/fs.ts +33 -0
  358. package/src/api/host/hooks.ts +635 -0
  359. package/src/api/host/host.ts +99 -0
  360. package/src/api/host/http.ts +79 -0
  361. package/src/api/host/index.ts +20 -0
  362. package/src/api/host/models.ts +81 -0
  363. package/src/api/host/network.ts +32 -0
  364. package/src/api/host/plugin.ts +158 -0
  365. package/src/api/host/plugins.ts +59 -0
  366. package/src/api/host/pty.ts +73 -0
  367. package/src/api/host/session.ts +61 -0
  368. package/src/api/host/version.ts +2 -0
  369. package/src/api/host/workspace.ts +51 -0
  370. package/src/api/plugin/http-client.ts +492 -0
  371. package/src/api/plugin/http-protocol.ts +231 -0
  372. package/src/api/result/result.ts +52 -0
  373. package/src/commands/agent-turn.ts +817 -0
  374. package/src/commands/ask-prompt.ts +52 -0
  375. package/src/commands/config.ts +306 -0
  376. package/src/commands/conversation.ts +777 -0
  377. package/src/commands/doctor.ts +92 -0
  378. package/src/commands/exec-approval.ts +91 -0
  379. package/src/commands/help.ts +41 -0
  380. package/src/commands/key.ts +281 -0
  381. package/src/commands/plugin.ts +222 -0
  382. package/src/commands/session.ts +179 -0
  383. package/src/commands/shared.ts +103 -0
  384. package/src/commands/start.ts +88 -0
  385. package/src/commands/stop.ts +24 -0
  386. package/src/commands/version.ts +40 -0
  387. package/src/config/codes.ts +17 -0
  388. package/src/config/credentials.ts +302 -0
  389. package/src/config/defaults.ts +32 -0
  390. package/src/config/index.ts +10 -0
  391. package/src/config/loader.ts +80 -0
  392. package/src/config/providers.ts +133 -0
  393. package/src/config/types.ts +88 -0
  394. package/src/config/validate.ts +458 -0
  395. package/src/display/markdown.ts +137 -0
  396. package/src/display/tool-label.ts +87 -0
  397. package/src/event/event.ts +171 -0
  398. package/src/index.ts +344 -0
  399. package/src/input/codes.ts +21 -0
  400. package/src/input/commands.ts +76 -0
  401. package/src/input/help.ts +60 -0
  402. package/src/input/index.ts +10 -0
  403. package/src/input/parse-options.ts +66 -0
  404. package/src/input/parse.ts +138 -0
  405. package/src/input/types.ts +19 -0
  406. package/src/logger/elog4js.ts +366 -0
  407. package/src/logger/logger.ts +251 -0
  408. package/src/network/index.ts +6 -0
  409. package/src/network/openai.ts +571 -0
  410. package/src/network/proxy.ts +80 -0
  411. package/src/network/web.ts +206 -0
  412. package/src/platform/clipboard.ts +107 -0
  413. package/src/platform/exec.ts +128 -0
  414. package/src/platform/file.ts +235 -0
  415. package/src/platform/index.ts +12 -0
  416. package/src/platform/notification.ts +108 -0
  417. package/src/platform/open-external.ts +132 -0
  418. package/src/platform/os.ts +101 -0
  419. package/src/platform/path.ts +214 -0
  420. package/src/plugin/access-guard.ts +46 -0
  421. package/src/plugin/agent-service.ts +969 -0
  422. package/src/plugin/agent-tools.ts +43 -0
  423. package/src/plugin/capabilities.ts +240 -0
  424. package/src/plugin/console-guard.ts +66 -0
  425. package/src/plugin/data-access.ts +70 -0
  426. package/src/plugin/fs.ts +109 -0
  427. package/src/plugin/host-alias.ts +61 -0
  428. package/src/plugin/index.ts +11 -0
  429. package/src/plugin/install.ts +213 -0
  430. package/src/plugin/loader.ts +952 -0
  431. package/src/plugin/manage.ts +338 -0
  432. package/src/plugin/models-service.ts +383 -0
  433. package/src/plugin/network-service.ts +102 -0
  434. package/src/plugin/package-manager.ts +214 -0
  435. package/src/plugin/paths.ts +19 -0
  436. package/src/plugin/registry.ts +103 -0
  437. package/src/plugin/runtime.ts +57 -0
  438. package/src/plugin/scaffold.ts +158 -0
  439. package/src/plugin/state.ts +52 -0
  440. package/src/plugin/zip.ts +156 -0
  441. package/src/sandbox/audit.ts +38 -0
  442. package/src/sandbox/backends/bwrap.ts +251 -0
  443. package/src/sandbox/backends/direct.ts +43 -0
  444. package/src/sandbox/bridge-state.ts +29 -0
  445. package/src/sandbox/index.ts +5 -0
  446. package/src/sandbox/manager.ts +406 -0
  447. package/src/sandbox/memory-limit.ts +245 -0
  448. package/src/sandbox/plugin-client.ts +1881 -0
  449. package/src/sandbox/plugin-host.ts +1282 -0
  450. package/src/sandbox/protocol.ts +142 -0
  451. package/src/sandbox/pty-bridge.py +154 -0
  452. package/src/sandbox/rpc-timeouts.ts +43 -0
  453. package/src/sandbox/supervisor.ts +172 -0
  454. package/src/sandbox/types.ts +149 -0
  455. package/src/service/control.ts +155 -0
  456. package/src/session/compress.ts +47 -0
  457. package/src/session/index.ts +8 -0
  458. package/src/session/registry.ts +17 -0
  459. package/src/session/replay.ts +132 -0
  460. package/src/session/session.ts +134 -0
  461. package/src/session/store.ts +468 -0
  462. package/src/session/types.ts +61 -0
  463. package/src/workspace/index.ts +21 -0
  464. package/src/workspace/registry.ts +356 -0
@@ -0,0 +1,1282 @@
1
+ /*
2
+ * sandbox 插件进程入口。
3
+ * 由宿主通过 bwrap/direct backend 启动;stdio 上跑 frame 协议,插件代码只通过 bridge 访问宿主。
4
+ */
5
+
6
+ import { Readable } from "node:stream"
7
+ import { pathToFileURL } from "node:url"
8
+
9
+ import type { Logger } from "pino"
10
+
11
+ import type { Host, HostOSInfo, HostPluginStatus, HostStatus } from "../api/host/host.ts"
12
+ import type { HostFileApi, HostFileEntry, HostFileStat } from "../api/host/fs.ts"
13
+ import type {
14
+ HostExecApi,
15
+ HostExecChunk,
16
+ HostExecRunOptions,
17
+ HostExecSession,
18
+ } from "../api/host/exec.ts"
19
+ import type {
20
+ HostModelProviderInput,
21
+ HostModelsApi,
22
+ HostModelsFetchResult,
23
+ HostModelsState,
24
+ HostModelsStateResult,
25
+ } from "../api/host/models.ts"
26
+ import type {
27
+ HostNetworkApi,
28
+ HostNetworkProxyInput,
29
+ HostNetworkResult,
30
+ HostNetworkState,
31
+ } from "../api/host/network.ts"
32
+ import type {
33
+ HostPluginInstallInput,
34
+ HostPluginsApi,
35
+ HostPluginListResult,
36
+ HostPluginMutationResult,
37
+ } from "../api/host/plugins.ts"
38
+ import type {
39
+ HostWorkspaceAddInput,
40
+ HostWorkspaceAddResult,
41
+ HostWorkspaceEntry,
42
+ HostWorkspaceListResult,
43
+ HostWorkspaceRemoveResult,
44
+ HostWorkspacesApi,
45
+ } from "../api/host/workspace.ts"
46
+ import type {
47
+ HostPtyApi,
48
+ HostPtyAvailability,
49
+ HostPtyChunk,
50
+ HostPtySession,
51
+ HostPtySpawnOptions,
52
+ } from "../api/host/pty.ts"
53
+ import type {
54
+ HostAgentApi,
55
+ HostAgentChatInput,
56
+ HostAgentStreamEvent,
57
+ HostWorkspaceCheck,
58
+ HostWorkspaceFilesResult,
59
+ } from "../api/host/agent.ts"
60
+ import type {
61
+ HostHttpApi,
62
+ HttpHandler,
63
+ HttpRequest,
64
+ HttpResponse,
65
+ PluginWebSocket,
66
+ WebSocketHandler,
67
+ } from "../api/host/http.ts"
68
+ import {
69
+ emitAfterStep,
70
+ emitAfterTurn,
71
+ emitAgentAsyncTaskComplete,
72
+ emitAgentAsk,
73
+ emitAgentCallTool,
74
+ emitAgentQueryTask,
75
+ emitAgentRead,
76
+ emitAgentRequestPermission,
77
+ emitAgentRunAsync,
78
+ emitAgentRunSync,
79
+ emitAgentSetGoal,
80
+ emitAgentSetTasks,
81
+ emitAgentSubmit,
82
+ emitBeforeStep,
83
+ emitBeforeTurn,
84
+ emitInitHooks,
85
+ emitOnMessage,
86
+ emitSessionStart,
87
+ emitShutdownHooks,
88
+ emitUserAnswer,
89
+ listHookKinds,
90
+ withHookOwner,
91
+ type HookKind,
92
+ } from "../api/host/hooks.ts"
93
+ import type {
94
+ AgentCallToolResult,
95
+ AgentTool,
96
+ HostOutput,
97
+ PluginApi,
98
+ PluginCommand,
99
+ PluginCommandContext,
100
+ PluginConfig,
101
+ PluginStatus,
102
+ WellspringPlugin,
103
+ } from "../api/host/plugin.ts"
104
+ import { eventBus } from "../event/event.ts"
105
+ import type { ResolvedPaths } from "../platform/path.ts"
106
+ import type { AppSetting } from "../config/types.ts"
107
+ import { ensureAccessGuard } from "../plugin/access-guard.ts"
108
+ import { ensureHostAlias } from "../plugin/host-alias.ts"
109
+ import { setHostBridge, type HostBridge } from "./bridge-state.ts"
110
+ import {
111
+ FrameDecoder,
112
+ encodeMessage,
113
+ nextRequestId,
114
+ type RpcMessage,
115
+ type RpcRequest,
116
+ } from "./protocol.ts"
117
+ import { RPC_TIMEOUT_MS } from "./rpc-timeouts.ts"
118
+
119
+ interface HostSnapshotData {
120
+ readonly status: HostStatus
121
+ readonly os: HostOSInfo
122
+ readonly paths: ResolvedPaths
123
+ readonly plugins: ReadonlyArray<{
124
+ readonly id: string
125
+ readonly name: string
126
+ readonly version: string
127
+ readonly deps: readonly string[]
128
+ readonly commands: readonly string[]
129
+ readonly status: HostPluginStatus
130
+ }>
131
+ }
132
+
133
+ interface ConfigurePayload {
134
+ readonly pluginId: string
135
+ readonly pluginName: string
136
+ readonly pluginVersion: string
137
+ readonly pluginEntry: string
138
+ readonly pluginDataDir: string
139
+ readonly pluginConfig: PluginConfig
140
+ readonly paths: ResolvedPaths
141
+ readonly config: AppSetting
142
+ readonly host: HostSnapshotData | null
143
+ readonly deferInit?: boolean
144
+ }
145
+
146
+ interface HostRequest {
147
+ readonly method: string
148
+ readonly params: Record<string, unknown>
149
+ readonly id: string
150
+ }
151
+
152
+ const rawStdoutWrite = process.stdout.write.bind(process.stdout)
153
+ const rawStderrWrite = process.stderr.write.bind(process.stderr)
154
+
155
+ function writeFrame(message: RpcMessage): void {
156
+ rawStdoutWrite(encodeMessage(message))
157
+ }
158
+
159
+ const pending = new Map<
160
+ string,
161
+ {
162
+ resolve: (value: unknown) => void
163
+ reject: (error: Error) => void
164
+ timer: NodeJS.Timeout | null
165
+ }
166
+ >()
167
+
168
+ function bridgeRequest(
169
+ method: string,
170
+ params: unknown,
171
+ timeoutMs: number | null = RPC_TIMEOUT_MS.default,
172
+ ): Promise<unknown> {
173
+ const id = nextRequestId("child")
174
+ return new Promise<unknown>((resolveRequest, rejectRequest) => {
175
+ // timeoutMs 为 null 时不挂定时器:长任务 RPC(例如 agent.stream)由运行过程自身结束
176
+ const timer =
177
+ timeoutMs === null
178
+ ? null
179
+ : setTimeout(() => {
180
+ pending.delete(id)
181
+ rejectRequest(new Error(`host RPC 超时:${method}`))
182
+ }, timeoutMs)
183
+ timer?.unref()
184
+ const clearTimer = (): void => {
185
+ if (timer !== null) {
186
+ clearTimeout(timer)
187
+ }
188
+ }
189
+ pending.set(id, {
190
+ resolve: (value) => {
191
+ clearTimer()
192
+ resolveRequest(value)
193
+ },
194
+ reject: (error) => {
195
+ clearTimer()
196
+ rejectRequest(error)
197
+ },
198
+ timer,
199
+ })
200
+ writeFrame({
201
+ v: 1,
202
+ type: "request",
203
+ id,
204
+ method,
205
+ params,
206
+ ...(timeoutMs === null ? {} : { timeoutMs }),
207
+ })
208
+ })
209
+ }
210
+
211
+ function bridgeNotify(method: string, params: unknown): void {
212
+ writeFrame({ v: 1, type: "event", method, params })
213
+ }
214
+
215
+ let hostSnapshot: Host | null = null
216
+
217
+ const bridge: HostBridge = {
218
+ request: bridgeRequest,
219
+ notify: bridgeNotify,
220
+ getHostSnapshot: () => {
221
+ if (hostSnapshot === null) {
222
+ throw new Error("插件未获得 getHost 权限")
223
+ }
224
+ return hostSnapshot
225
+ },
226
+ shutdown: () => {
227
+ void bridgeRequest("host.shutdown", {}).catch(() => undefined)
228
+ },
229
+ }
230
+
231
+ setHostBridge(bridge)
232
+ ensureHostAlias()
233
+ ensureAccessGuard()
234
+
235
+ interface PluginRuntime {
236
+ readonly owner: string
237
+ readonly plugin: WellspringPlugin
238
+ readonly commands: PluginCommand[]
239
+ readonly agentTools: AgentTool[]
240
+ hooks: readonly HookKind[]
241
+ readonly api: PluginApi
242
+ initialized: boolean
243
+ }
244
+
245
+ const HOOK_API_NAME: Readonly<Record<HookKind, string>> = {
246
+ message: "onMessage",
247
+ sessionStart: "onSessionStart",
248
+ beforeTurn: "beforeTurn",
249
+ beforeStep: "beforeStep",
250
+ afterStep: "afterStep",
251
+ afterTurn: "afterTurn",
252
+ agentRunSync: "onAgentRunSync",
253
+ agentRunAsync: "onAgentRunAsync",
254
+ agentAsyncTaskComplete: "onAgentAsyncTaskComplete",
255
+ agentCallTool: "onAgentCallTool",
256
+ agentAsk: "onAgentAsk",
257
+ agentRead: "onAgentRead",
258
+ agentQueryTask: "onAgentQueryTask",
259
+ agentSubmit: "onAgentSubmit",
260
+ agentSetTasks: "onAgentSetTasks",
261
+ agentSetGoal: "onAgentSetGoal",
262
+ agentRequestPermission: "onAgentRequestPermission",
263
+ userAnswer: "onUserAnswer",
264
+ init: "onInit",
265
+ shutdown: "onShutdown",
266
+ }
267
+
268
+ let runtime: PluginRuntime | null = null
269
+
270
+ const httpHandlers = new Map<string, HttpHandler>()
271
+ const agentStreamHandlers = new Map<string, (event: HostAgentStreamEvent) => void>()
272
+ const websocketHandlers = new Map<string, WebSocketHandler>()
273
+ const wsMessages = new Map<string, Array<(data: string) => void>>()
274
+ const wsCloses = new Map<string, Array<(code: number, reason: string) => void>>()
275
+
276
+ function remoteExec(): HostExecApi {
277
+ return {
278
+ async run(options: HostExecRunOptions): Promise<HostExecSession> {
279
+ return (await bridgeRequest("host.exec.run", {
280
+ command: options.command,
281
+ cwd: options.cwd,
282
+ env: options.env ?? {},
283
+ timeoutMs: options.timeoutMs,
284
+ })) as HostExecSession
285
+ },
286
+ async poll(sessionId: string): Promise<HostExecChunk> {
287
+ return (await bridgeRequest("host.exec.poll", { sessionId })) as HostExecChunk
288
+ },
289
+ async stop(sessionId: string): Promise<void> {
290
+ await bridgeRequest("host.exec.stop", { sessionId })
291
+ },
292
+ }
293
+ }
294
+
295
+ function remotePty(): HostPtyApi {
296
+ return {
297
+ async available(): Promise<HostPtyAvailability> {
298
+ const result = (await bridgeRequest("host.pty.available", {})) as {
299
+ available?: boolean
300
+ backend?: string
301
+ reason?: string
302
+ }
303
+ const backend =
304
+ result.backend === "node-pty" || result.backend === "python-pty"
305
+ ? result.backend
306
+ : undefined
307
+ return {
308
+ available: result.available === true,
309
+ backend,
310
+ reason: typeof result.reason === "string" ? result.reason : undefined,
311
+ }
312
+ },
313
+ async spawn(options: HostPtySpawnOptions): Promise<HostPtySession> {
314
+ return (await bridgeRequest("host.pty.spawn", {
315
+ file: options.file ?? "",
316
+ args: options.args ?? [],
317
+ cwd: options.cwd,
318
+ env: options.env ?? {},
319
+ cols: options.cols,
320
+ rows: options.rows,
321
+ })) as HostPtySession
322
+ },
323
+ async poll(sessionId: string): Promise<HostPtyChunk> {
324
+ return (await bridgeRequest("host.pty.poll", { sessionId })) as HostPtyChunk
325
+ },
326
+ async write(sessionId: string, data: string): Promise<void> {
327
+ await bridgeRequest("host.pty.write", { sessionId, data })
328
+ },
329
+ async resize(sessionId: string, cols: number, rows: number): Promise<void> {
330
+ await bridgeRequest("host.pty.resize", { sessionId, cols, rows })
331
+ },
332
+ async kill(sessionId: string): Promise<void> {
333
+ await bridgeRequest("host.pty.kill", { sessionId })
334
+ },
335
+ }
336
+ }
337
+
338
+ function remoteAgent(): HostAgentApi {
339
+ return {
340
+ async chat(input: HostAgentChatInput) {
341
+ return await bridgeRequest(
342
+ "host.agent.chat",
343
+ input as unknown as Record<string, unknown>,
344
+ RPC_TIMEOUT_MS.agentChat,
345
+ )
346
+ },
347
+ async stream(input: HostAgentChatInput, onEvent: (event: HostAgentStreamEvent) => void) {
348
+ const streamId = nextRequestId("agent-stream")
349
+ agentStreamHandlers.set(streamId, onEvent)
350
+ try {
351
+ // 一轮 Agent 可能跑很久(多步工具调用),不设 RPC 上限
352
+ return await bridgeRequest(
353
+ "host.agent.stream",
354
+ { streamId, input },
355
+ RPC_TIMEOUT_MS.agentStream,
356
+ )
357
+ } finally {
358
+ agentStreamHandlers.delete(streamId)
359
+ }
360
+ },
361
+ async validateWorkspace(path: string) {
362
+ return (await bridgeRequest("host.agent.validateWorkspace", {
363
+ path,
364
+ })) as HostWorkspaceCheck
365
+ },
366
+ async pickDirectory() {
367
+ return (await bridgeRequest("host.agent.pickDirectory", {})) as HostWorkspaceCheck
368
+ },
369
+ async searchWorkspaceFiles(root: string, query: string) {
370
+ return (await bridgeRequest("host.agent.searchWorkspaceFiles", {
371
+ root,
372
+ query,
373
+ })) as HostWorkspaceFilesResult
374
+ },
375
+ async interject(sessionId: string, message: string) {
376
+ return (await bridgeRequest("host.agent.interject", {
377
+ sessionId,
378
+ message,
379
+ })) as boolean
380
+ },
381
+ async stop(sessionId: string) {
382
+ return (await bridgeRequest("host.agent.stop", { sessionId })) as boolean
383
+ },
384
+ async respondApproval(approvalId: string, approved: boolean) {
385
+ return (await bridgeRequest("host.agent.respondApproval", {
386
+ approvalId,
387
+ approved,
388
+ })) as boolean
389
+ },
390
+ async respondAsk(askId: string, answer: string) {
391
+ return (await bridgeRequest("host.agent.respondAsk", {
392
+ askId,
393
+ answer,
394
+ })) as boolean
395
+ },
396
+ } as HostAgentApi
397
+ }
398
+
399
+ function remoteModels(): HostModelsApi {
400
+ return {
401
+ async state(): Promise<HostModelsState> {
402
+ return (await bridgeRequest("host.models.state", {})) as HostModelsState
403
+ },
404
+ async setActive(
405
+ providerId: string,
406
+ model: string | null,
407
+ reasoning?: string | null,
408
+ ): Promise<HostModelsState> {
409
+ return (await bridgeRequest("host.models.setActive", {
410
+ providerId,
411
+ model,
412
+ reasoning,
413
+ })) as HostModelsState
414
+ },
415
+ async saveProvider(input: HostModelProviderInput): Promise<HostModelsStateResult> {
416
+ return (await bridgeRequest(
417
+ "host.models.saveProvider",
418
+ input as unknown as Record<string, unknown>,
419
+ )) as HostModelsStateResult
420
+ },
421
+ async removeProvider(id: string): Promise<HostModelsStateResult> {
422
+ return (await bridgeRequest("host.models.removeProvider", {
423
+ id,
424
+ })) as HostModelsStateResult
425
+ },
426
+ async fetchModels(id: string, apiKey?: string): Promise<HostModelsFetchResult> {
427
+ const payload: Record<string, unknown> = { id }
428
+ if (apiKey !== undefined) {
429
+ payload["apiKey"] = apiKey
430
+ }
431
+ return (await bridgeRequest(
432
+ "host.models.fetchModels",
433
+ payload,
434
+ RPC_TIMEOUT_MS.modelsFetch,
435
+ )) as HostModelsFetchResult
436
+ },
437
+ async saveKey(id: string, apiKey: string): Promise<HostModelsStateResult> {
438
+ return (await bridgeRequest("host.models.saveKey", {
439
+ id,
440
+ apiKey,
441
+ })) as HostModelsStateResult
442
+ },
443
+ async clearKey(id: string): Promise<HostModelsState> {
444
+ return (await bridgeRequest("host.models.clearKey", { id })) as HostModelsState
445
+ },
446
+ }
447
+ }
448
+
449
+ function remoteNetwork(): HostNetworkApi {
450
+ return {
451
+ async state(): Promise<HostNetworkState> {
452
+ return (await bridgeRequest("host.network.state", {})) as HostNetworkState
453
+ },
454
+ async saveProxy(input: HostNetworkProxyInput): Promise<HostNetworkResult> {
455
+ return (await bridgeRequest(
456
+ "host.network.saveProxy",
457
+ input as unknown as Record<string, unknown>,
458
+ )) as HostNetworkResult
459
+ },
460
+ }
461
+ }
462
+
463
+ function remotePlugins(): HostPluginsApi {
464
+ return {
465
+ async list(): Promise<HostPluginListResult> {
466
+ return (await bridgeRequest("host.plugins.list", {})) as HostPluginListResult
467
+ },
468
+ async install(input: HostPluginInstallInput): Promise<HostPluginMutationResult> {
469
+ return (await bridgeRequest(
470
+ "host.plugins.install",
471
+ input as unknown as Record<string, unknown>,
472
+ RPC_TIMEOUT_MS.pluginsInstall,
473
+ )) as HostPluginMutationResult
474
+ },
475
+ async remove(id: string): Promise<HostPluginMutationResult> {
476
+ return (await bridgeRequest("host.plugins.remove", { id })) as HostPluginMutationResult
477
+ },
478
+ async enable(id: string): Promise<HostPluginMutationResult> {
479
+ return (await bridgeRequest("host.plugins.enable", { id })) as HostPluginMutationResult
480
+ },
481
+ async disable(id: string): Promise<HostPluginMutationResult> {
482
+ return (await bridgeRequest("host.plugins.disable", { id })) as HostPluginMutationResult
483
+ },
484
+ }
485
+ }
486
+
487
+ function remoteWorkspaces(): HostWorkspacesApi {
488
+ return {
489
+ async list(): Promise<HostWorkspaceListResult> {
490
+ return (await bridgeRequest("host.workspaces.list", {})) as HostWorkspaceListResult
491
+ },
492
+ async add(input: HostWorkspaceAddInput): Promise<HostWorkspaceAddResult> {
493
+ return (await bridgeRequest(
494
+ "host.workspaces.add",
495
+ input as unknown as Record<string, unknown>,
496
+ )) as HostWorkspaceAddResult
497
+ },
498
+ async remove(id: string): Promise<HostWorkspaceRemoveResult> {
499
+ return (await bridgeRequest("host.workspaces.remove", {
500
+ id,
501
+ })) as HostWorkspaceRemoveResult
502
+ },
503
+ async rename(id: string, name: string): Promise<HostWorkspaceEntry | null> {
504
+ return (await bridgeRequest("host.workspaces.rename", {
505
+ id,
506
+ name,
507
+ })) as HostWorkspaceEntry | null
508
+ },
509
+ async touch(id: string): Promise<HostWorkspaceEntry | null> {
510
+ return (await bridgeRequest("host.workspaces.touch", {
511
+ id,
512
+ })) as HostWorkspaceEntry | null
513
+ },
514
+ }
515
+ }
516
+
517
+ function remoteHttp(): HostHttpApi {
518
+ return {
519
+ async createServer(options, handler) {
520
+ const serverId = nextRequestId("http")
521
+ httpHandlers.set(serverId, handler)
522
+ if (typeof options.websocket === "function") {
523
+ websocketHandlers.set(serverId, options.websocket)
524
+ }
525
+ try {
526
+ const ready = (await bridgeRequest("host.http.createServer", {
527
+ serverId,
528
+ host: options.host,
529
+ port: options.port,
530
+ tls: options.tls,
531
+ websocket: typeof options.websocket === "function",
532
+ })) as { serverId: string; host: string; port: number }
533
+ return {
534
+ serverId: ready.serverId,
535
+ host: ready.host,
536
+ port: ready.port,
537
+ async close() {
538
+ httpHandlers.delete(serverId)
539
+ await bridgeRequest("host.http.closeServer", { serverId })
540
+ },
541
+ }
542
+ } catch (error) {
543
+ httpHandlers.delete(serverId)
544
+ throw error
545
+ }
546
+ },
547
+ }
548
+ }
549
+
550
+ function isObject(value: unknown): value is Record<string, unknown> {
551
+ return typeof value === "object" && value !== null && !Array.isArray(value)
552
+ }
553
+
554
+ function validatePlugin(value: unknown): WellspringPlugin {
555
+ if (!isObject(value)) {
556
+ throw new Error("setup() 必须返回 WellspringPlugin 对象")
557
+ }
558
+ const id = value["id"]
559
+ const name = value["name"]
560
+ const version = value["version"]
561
+ const status = value["status"]
562
+ if (typeof id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(id)) {
563
+ throw new Error(`插件 id 不合法:${String(id)}`)
564
+ }
565
+ if (typeof name !== "string" || name.trim() === "") {
566
+ throw new Error(`插件 name 不合法:${String(name)}`)
567
+ }
568
+ if (typeof version !== "string" || version.trim() === "") {
569
+ throw new Error(`插件 version 不合法:${String(version)}`)
570
+ }
571
+ if (status !== "ok" && status !== "failed") {
572
+ throw new Error(`插件 status 必须是 ok / failed:${String(status)}`)
573
+ }
574
+ return value as unknown as WellspringPlugin
575
+ }
576
+
577
+ function createLogger(): Logger {
578
+ const make = (bindings: Record<string, unknown> = {}): Record<string, unknown> => {
579
+ const log =
580
+ (level: string) =>
581
+ (first: unknown, second?: unknown): void => {
582
+ const fields = isObject(first) ? first : bindings
583
+ const message = isObject(first) ? String(second ?? "") : String(first ?? "")
584
+ bridgeNotify("host.log", { level, message, fields })
585
+ }
586
+ const logger: Record<string, unknown> = {
587
+ trace: log("trace"),
588
+ debug: log("debug"),
589
+ info: log("info"),
590
+ warn: log("warn"),
591
+ error: log("error"),
592
+ fatal: log("fatal"),
593
+ child: (childBindings: Record<string, unknown>) =>
594
+ make({ ...bindings, ...childBindings }),
595
+ }
596
+ return logger
597
+ }
598
+ return make() as unknown as Logger
599
+ }
600
+
601
+ const logger = createLogger()
602
+
603
+ const output: HostOutput = {
604
+ info: (text) => bridgeNotify("host.output", { kind: "info", text }),
605
+ warn: (text) => bridgeNotify("host.output", { kind: "warn", text }),
606
+ error: (text) => bridgeNotify("host.output", { kind: "error", text }),
607
+ print: (text = "") => bridgeNotify("host.output", { kind: "print", text }),
608
+ }
609
+
610
+ function createFileApi(scope: "fs" | "workspaceFs"): HostFileApi {
611
+ const call = (method: string, params: Record<string, unknown> = {}) =>
612
+ bridgeRequest(`host.${scope}.${method}`, params)
613
+ return {
614
+ root: scope,
615
+ async readText(path) {
616
+ const result = (await call("readText", { path })) as { text: string | null }
617
+ return result.text
618
+ },
619
+ async readBytes(path) {
620
+ const result = (await call("readBytes", { path })) as { data: string | null }
621
+ if (result.data === null) {
622
+ return null
623
+ }
624
+ return new Uint8Array(Buffer.from(result.data, "base64"))
625
+ },
626
+ async readJson<T = unknown>(path: string) {
627
+ const result = (await call("readJson", { path })) as { value: T | null }
628
+ return result.value
629
+ },
630
+ async writeText(path, text) {
631
+ await call("writeText", { path, text })
632
+ },
633
+ async writeBytes(path, bytes) {
634
+ await call("writeBytes", {
635
+ path,
636
+ data: Buffer.from(bytes).toString("base64"),
637
+ })
638
+ },
639
+ async writeJson(path, value) {
640
+ await call("writeJson", { path, value })
641
+ },
642
+ async list(path = "") {
643
+ const result = (await call("list", { path })) as { entries: HostFileEntry[] }
644
+ return result.entries
645
+ },
646
+ async stat(path) {
647
+ const result = (await call("stat", { path })) as { stat: HostFileStat | null }
648
+ return result.stat
649
+ },
650
+ async mkdir(path) {
651
+ await call("mkdir", { path })
652
+ },
653
+ async remove(path) {
654
+ await call("remove", { path })
655
+ },
656
+ async exists(path) {
657
+ const result = (await call("exists", { path })) as { exists: boolean }
658
+ return result.exists
659
+ },
660
+ }
661
+ }
662
+
663
+ function patchConsole(): void {
664
+ const methods: Array<[string, string]> = [
665
+ ["log", "info"],
666
+ ["info", "info"],
667
+ ["debug", "debug"],
668
+ ["warn", "warn"],
669
+ ["error", "error"],
670
+ ["trace", "trace"],
671
+ ["dir", "info"],
672
+ ["table", "info"],
673
+ ]
674
+ for (const [method, level] of methods) {
675
+ ;(console as unknown as Record<string, (...args: unknown[]) => void>)[method] = (
676
+ ...args: unknown[]
677
+ ): void => {
678
+ bridgeNotify("host.console", { level, args: args.map((item) => String(item)) })
679
+ }
680
+ }
681
+ console.assert = (condition: unknown, ...args: unknown[]): void => {
682
+ if (!condition) {
683
+ bridgeNotify("host.console", { level: "error", args: args.map(String) })
684
+ }
685
+ }
686
+ }
687
+
688
+ function patchProcessStreams(): void {
689
+ process.stdout.write = ((chunk: unknown): boolean => {
690
+ bridgeNotify("host.log", { level: "info", message: String(chunk), fields: {} })
691
+ return true
692
+ }) as typeof process.stdout.write
693
+ process.stderr.write = ((chunk: unknown): boolean => {
694
+ bridgeNotify("host.log", { level: "error", message: String(chunk), fields: {} })
695
+ return true
696
+ }) as typeof process.stderr.write
697
+ }
698
+
699
+ function remotePluginData(targetId: string): HostFileApi {
700
+ const call = async (method: string, args: unknown[]): Promise<unknown> =>
701
+ await bridgeRequest("host.pluginData", { targetId, method, args })
702
+ return {
703
+ root: "",
704
+ async readText(path) {
705
+ return (await call("readText", [path])) as string | null
706
+ },
707
+ async readBytes(path) {
708
+ const value = (await call("readBytes", [path])) as number[] | null
709
+ return value === null ? null : Uint8Array.from(value)
710
+ },
711
+ async readJson<T = unknown>(path: string) {
712
+ return (await call("readJson", [path])) as T | null
713
+ },
714
+ async writeText(path, text) {
715
+ await call("writeText", [path, text])
716
+ },
717
+ async writeBytes(path, bytes) {
718
+ await call("writeBytes", [path, [...bytes]])
719
+ },
720
+ async writeJson(path, value) {
721
+ await call("writeJson", [path, value])
722
+ },
723
+ async list(path = "") {
724
+ return (await call("list", [path])) as HostFileEntry[]
725
+ },
726
+ async stat(path) {
727
+ return (await call("stat", [path])) as HostFileStat | null
728
+ },
729
+ async mkdir(path) {
730
+ await call("mkdir", [path])
731
+ },
732
+ async remove(path) {
733
+ await call("remove", [path])
734
+ },
735
+ async exists(path) {
736
+ return (await call("exists", [path])) as boolean
737
+ },
738
+ }
739
+ }
740
+
741
+ async function bootstrap(params: ConfigurePayload): Promise<{
742
+ plugin: { id: string; name: string; version: string; status: PluginStatus; deps: string[] }
743
+ commands: Array<{
744
+ name: string
745
+ summary: string
746
+ usage?: string
747
+ aliases?: readonly string[]
748
+ }>
749
+ agentTools: Array<{
750
+ name: string
751
+ introduction: { params: Record<string, unknown>; content: string }
752
+ }>
753
+ hooks: string[]
754
+ }> {
755
+ const hostData = params.host
756
+ hostSnapshot =
757
+ hostData === null
758
+ ? null
759
+ : {
760
+ getStatus: () => hostData.status,
761
+ getOS: () => hostData.os,
762
+ getPaths: () => hostData.paths,
763
+ getPlugins: () =>
764
+ hostData.plugins.map((plugin) => ({
765
+ id: plugin.id,
766
+ name: plugin.name,
767
+ version: plugin.version,
768
+ deps: plugin.deps,
769
+ commands: plugin.commands,
770
+ getStatus: () => plugin.status,
771
+ })),
772
+ }
773
+ const pluginId = params.pluginId
774
+ const commands: PluginCommand[] = []
775
+ const agentTools: AgentTool[] = []
776
+
777
+ const api: PluginApi = {
778
+ apiVersion: 1,
779
+ plugin: { id: pluginId, name: params.pluginName, version: params.pluginVersion },
780
+ paths: params.paths,
781
+ config: params.config,
782
+ logger,
783
+ output,
784
+ pluginDataDir: params.pluginDataDir,
785
+ pluginConfig: params.pluginConfig,
786
+ fs: createFileApi("fs"),
787
+ workspaceFs: createFileApi("workspaceFs"),
788
+ registerCommand: (command: PluginCommand): void => {
789
+ commands.push(command)
790
+ },
791
+ registerAgentTool: (tool: AgentTool): void => {
792
+ agentTools.push(tool)
793
+ },
794
+ pluginData: async (targetId: string): Promise<HostFileApi | null> => {
795
+ return remotePluginData(targetId)
796
+ },
797
+ capabilities: {
798
+ async executeCode(input: unknown) {
799
+ // 沙箱自己的命令超时最长 600s,RPC 用更长的上限,避免宿主先放弃等待
800
+ return await bridgeRequest(
801
+ "host.capabilities.executeCode",
802
+ input as Record<string, unknown>,
803
+ RPC_TIMEOUT_MS.sandboxExec,
804
+ )
805
+ },
806
+ async startBackgroundCode(input: unknown) {
807
+ return await bridgeRequest(
808
+ "host.capabilities.startBackgroundCode",
809
+ input as Record<string, unknown>,
810
+ )
811
+ },
812
+ async queryTask(taskId?: string) {
813
+ return await bridgeRequest("host.capabilities.queryTask", { taskId })
814
+ },
815
+ async stopTask(taskId: string | undefined, mode: string) {
816
+ return await bridgeRequest("host.capabilities.stopTask", { taskId, mode })
817
+ },
818
+ async webSearch(query: string, count?: number) {
819
+ return await bridgeRequest("host.capabilities.webSearch", { query, count })
820
+ },
821
+ async webFetch(url: string) {
822
+ return await bridgeRequest("host.capabilities.webFetch", { url })
823
+ },
824
+ } as never,
825
+ http: remoteHttp(),
826
+ agent: remoteAgent(),
827
+ models: remoteModels(),
828
+ network: remoteNetwork(),
829
+ plugins: remotePlugins(),
830
+ workspaces: remoteWorkspaces(),
831
+ exec: remoteExec(),
832
+ pty: remotePty(),
833
+ }
834
+
835
+ const module = (await withHookOwner(pluginId, async () => {
836
+ return (await import(pathToFileURL(params.pluginEntry).href)) as { setup?: unknown }
837
+ })) as { setup?: unknown }
838
+
839
+ if (typeof module.setup !== "function") {
840
+ throw new Error("入口需要导出 setup() 函数")
841
+ }
842
+
843
+ let created: WellspringPlugin | null = null
844
+ await withHookOwner(pluginId, async () => {
845
+ created = validatePlugin(await (module.setup as () => unknown)())
846
+ if (created.status !== "ok") {
847
+ throw new Error(`插件自报状态:${created.status}`)
848
+ }
849
+ commands.push(...(created.commands ?? []))
850
+ agentTools.push(...(created.agentTools ?? []))
851
+ })
852
+ if (created === null) {
853
+ throw new Error("插件未初始化")
854
+ }
855
+ const plugin: WellspringPlugin = created
856
+ const current: PluginRuntime = {
857
+ owner: pluginId,
858
+ plugin,
859
+ commands,
860
+ agentTools,
861
+ hooks: listHookKinds(pluginId),
862
+ api,
863
+ initialized: false,
864
+ }
865
+ runtime = current
866
+ if (params.deferInit !== true) {
867
+ await initializeRuntime(current)
868
+ }
869
+ return readyOf(current)
870
+ }
871
+
872
+ async function initializeRuntime(current: PluginRuntime): Promise<void> {
873
+ if (current.initialized) {
874
+ return
875
+ }
876
+ await withHookOwner(current.owner, async () => {
877
+ await current.plugin.init?.(current.api)
878
+ })
879
+ for (const tool of current.agentTools) {
880
+ if (typeof tool.name !== "string" || typeof tool.call !== "function") {
881
+ throw new Error("Agent 工具缺少 name / call")
882
+ }
883
+ }
884
+ current.initialized = true
885
+ current.hooks = listHookKinds(current.owner)
886
+ }
887
+
888
+ function readyOf(current: PluginRuntime): {
889
+ plugin: { id: string; name: string; version: string; status: PluginStatus; deps: string[] }
890
+ commands: Array<{
891
+ name: string
892
+ summary: string
893
+ usage?: string
894
+ aliases?: readonly string[]
895
+ }>
896
+ agentTools: Array<{
897
+ name: string
898
+ introduction: { params: Record<string, unknown>; content: string }
899
+ }>
900
+ hooks: string[]
901
+ } {
902
+ return {
903
+ plugin: {
904
+ id: current.plugin.id,
905
+ name: current.plugin.name,
906
+ version: current.plugin.version,
907
+ status: current.plugin.status,
908
+ deps: [...(current.plugin.deps ?? [])],
909
+ },
910
+ commands: current.commands.map((command) => ({
911
+ name: command.name,
912
+ summary: command.summary,
913
+ usage: command.usage,
914
+ aliases: command.aliases,
915
+ })),
916
+ agentTools: current.agentTools.map((tool) => ({
917
+ name: tool.name,
918
+ introduction: {
919
+ params: { ...tool.introduction.params },
920
+ content: tool.introduction.content,
921
+ },
922
+ })),
923
+ hooks: current.hooks.map((kind) => HOOK_API_NAME[kind]),
924
+ }
925
+ }
926
+
927
+ async function dispatchHook(name: string, payload: Record<string, unknown>): Promise<unknown> {
928
+ switch (name) {
929
+ case "onMessage":
930
+ await emitOnMessage(payload as never)
931
+ return { prompt: (payload["prompt"] as string[] | undefined) ?? [] }
932
+ case "onSessionStart":
933
+ await emitSessionStart(payload as never)
934
+ return { prompt: (payload["prompt"] as string[] | undefined) ?? [] }
935
+ case "beforeTurn":
936
+ await emitBeforeTurn(payload as never)
937
+ return {}
938
+ case "beforeStep":
939
+ await emitBeforeStep(payload as never)
940
+ return {}
941
+ case "afterStep":
942
+ await emitAfterStep(payload as never)
943
+ return {}
944
+ case "afterTurn":
945
+ await emitAfterTurn(payload as never)
946
+ return {}
947
+ case "onAgentRunSync":
948
+ await emitAgentRunSync(payload as never)
949
+ return {}
950
+ case "onAgentRunAsync":
951
+ await emitAgentRunAsync(payload as never)
952
+ return {}
953
+ case "onAgentAsyncTaskComplete":
954
+ await emitAgentAsyncTaskComplete(payload as never)
955
+ return {}
956
+ case "onAgentCallTool":
957
+ await emitAgentCallTool(payload as never)
958
+ return {}
959
+ case "onAgentAsk":
960
+ await emitAgentAsk(payload as never)
961
+ return {}
962
+ case "onAgentRead":
963
+ await emitAgentRead(payload as never)
964
+ return {}
965
+ case "onAgentQueryTask":
966
+ await emitAgentQueryTask(payload as never)
967
+ return {}
968
+ case "onAgentSubmit":
969
+ await emitAgentSubmit(payload as never)
970
+ return {}
971
+ case "onAgentSetTasks":
972
+ await emitAgentSetTasks(payload as never)
973
+ return {}
974
+ case "onAgentSetGoal":
975
+ await emitAgentSetGoal(payload as never)
976
+ return {}
977
+ case "onAgentRequestPermission":
978
+ await emitAgentRequestPermission(payload as never)
979
+ return {}
980
+ case "onUserAnswer":
981
+ await emitUserAnswer(payload as never)
982
+ return {}
983
+ case "onInit":
984
+ await emitInitHooks()
985
+ return {}
986
+ case "onShutdown":
987
+ await emitShutdownHooks()
988
+ return {}
989
+ default:
990
+ throw new Error(`未知钩子:${name}`)
991
+ }
992
+ }
993
+
994
+ async function runCommand(request: RpcRequest): Promise<unknown> {
995
+ if (runtime === null) {
996
+ throw new Error("插件尚未初始化")
997
+ }
998
+ const params = request.params as {
999
+ name: string
1000
+ argv: string[]
1001
+ cwd: string
1002
+ json: boolean
1003
+ stdin?: string
1004
+ }
1005
+ const command = runtime.commands.find((item) => item.name === params.name)
1006
+ if (command === undefined) {
1007
+ throw new Error(`命令不存在:${params.name}`)
1008
+ }
1009
+ const context: PluginCommandContext = {
1010
+ argv: params.argv,
1011
+ env: {},
1012
+ paths: runtime.api.paths,
1013
+ config: runtime.api.config,
1014
+ logger,
1015
+ output,
1016
+ pluginDataDir: runtime.api.pluginDataDir,
1017
+ pluginConfig: runtime.api.pluginConfig,
1018
+ fs: runtime.api.fs,
1019
+ workspaceFs: runtime.api.workspaceFs,
1020
+ cwd: params.cwd,
1021
+ json: params.json,
1022
+ stdin: Readable.from([params.stdin ?? ""]),
1023
+ stdout: process.stdout,
1024
+ stderr: process.stderr,
1025
+ }
1026
+ const code = await withHookOwner(runtime.owner, async () => await command.run(context))
1027
+ return { exitCode: typeof code === "number" ? code : 0 }
1028
+ }
1029
+
1030
+ async function handleHostRequest(request: RpcRequest): Promise<void> {
1031
+ try {
1032
+ let result: unknown
1033
+ if (request.method === "plugin.command") {
1034
+ result = await runCommand(request)
1035
+ } else if (request.method === "plugin.agentTool") {
1036
+ if (runtime === null) {
1037
+ throw new Error("插件尚未初始化")
1038
+ }
1039
+ const params = request.params as { name: string; args: unknown }
1040
+ const tool = runtime.agentTools.find((item) => item.name === params.name)
1041
+ if (tool === undefined) {
1042
+ throw new Error(`Agent 工具不存在:${params.name}`)
1043
+ }
1044
+ result = await withHookOwner(
1045
+ runtime.owner,
1046
+ async () => (await tool.call(params.args)) as AgentCallToolResult,
1047
+ )
1048
+ } else if (request.method === "plugin.init") {
1049
+ if (runtime === null) {
1050
+ throw new Error("插件尚未初始化")
1051
+ }
1052
+ await initializeRuntime(runtime)
1053
+ result = readyOf(runtime)
1054
+ } else if (request.method === "plugin.websocket.connect") {
1055
+ if (runtime === null) {
1056
+ throw new Error("插件尚未初始化")
1057
+ }
1058
+ const params = request.params as {
1059
+ serverId: string
1060
+ connectionId: string
1061
+ request: HttpRequest
1062
+ }
1063
+ const handler = websocketHandlers.get(params.serverId)
1064
+ if (handler === undefined) {
1065
+ throw new Error("WebSocket handler 不存在")
1066
+ }
1067
+ const connectionId = params.connectionId
1068
+ const socket: PluginWebSocket = {
1069
+ connectionId,
1070
+ async send(data: string) {
1071
+ await bridgeRequest("host.websocket.send", { connectionId, data })
1072
+ },
1073
+ async close(code = 1000, reason = "") {
1074
+ await bridgeRequest("host.websocket.close", {
1075
+ connectionId,
1076
+ code,
1077
+ reason,
1078
+ })
1079
+ },
1080
+ onMessage(handler) {
1081
+ const list = wsMessages.get(connectionId) ?? []
1082
+ list.push(handler)
1083
+ wsMessages.set(connectionId, list)
1084
+ },
1085
+ onClose(handler) {
1086
+ const list = wsCloses.get(connectionId) ?? []
1087
+ list.push(handler)
1088
+ wsCloses.set(connectionId, list)
1089
+ },
1090
+ }
1091
+ await withHookOwner(runtime.owner, async () => handler(socket, params.request))
1092
+ result = {}
1093
+ } else if (request.method === "plugin.websocket.message") {
1094
+ const params = request.params as {
1095
+ connectionId: string
1096
+ data: string
1097
+ binary: boolean
1098
+ }
1099
+ const text = params.binary
1100
+ ? Buffer.from(params.data, "base64").toString("utf8")
1101
+ : Buffer.from(params.data, "base64").toString("utf8")
1102
+ for (const handler of wsMessages.get(params.connectionId) ?? []) {
1103
+ handler(text)
1104
+ }
1105
+ result = {}
1106
+ } else if (request.method === "plugin.websocket.close") {
1107
+ const params = request.params as {
1108
+ connectionId: string
1109
+ code: number
1110
+ reason: string
1111
+ }
1112
+ for (const handler of wsCloses.get(params.connectionId) ?? []) {
1113
+ handler(params.code, params.reason)
1114
+ }
1115
+ wsMessages.delete(params.connectionId)
1116
+ wsCloses.delete(params.connectionId)
1117
+ result = {}
1118
+ } else if (request.method === "plugin.http") {
1119
+ if (runtime === null) {
1120
+ throw new Error("插件尚未初始化")
1121
+ }
1122
+ const params = request.params as {
1123
+ serverId: string
1124
+ requestId: string
1125
+ request: HttpRequest
1126
+ }
1127
+ const handler = httpHandlers.get(params.serverId)
1128
+ if (handler === undefined) {
1129
+ throw new Error(`HTTP handler 不存在:${params.serverId}`)
1130
+ }
1131
+ const requestId = params.requestId
1132
+ let flushed = false
1133
+ let ended = false
1134
+ const buffered: string[] = []
1135
+ const flush = (): void => {
1136
+ if (flushed) {
1137
+ return
1138
+ }
1139
+ flushed = true
1140
+ for (const chunk of buffered) {
1141
+ bridgeNotify("host.http.stream", { requestId, chunk })
1142
+ }
1143
+ buffered.length = 0
1144
+ if (ended) {
1145
+ bridgeNotify("host.http.stream", { requestId, end: true })
1146
+ }
1147
+ }
1148
+ const stream = {
1149
+ write(chunk: string) {
1150
+ if (flushed) {
1151
+ bridgeNotify("host.http.stream", { requestId, chunk })
1152
+ } else {
1153
+ buffered.push(chunk)
1154
+ }
1155
+ },
1156
+ end() {
1157
+ if (flushed) {
1158
+ bridgeNotify("host.http.stream", { requestId, end: true })
1159
+ } else {
1160
+ ended = true
1161
+ }
1162
+ },
1163
+ }
1164
+ const response = (await withHookOwner(runtime.owner, async () =>
1165
+ handler(params.request, stream),
1166
+ )) as HttpResponse
1167
+ if (response.stream === true) {
1168
+ setImmediate(flush)
1169
+ }
1170
+ result = response
1171
+ } else if (request.method === "plugin.hook") {
1172
+ const params = request.params as { hook: string; payload: Record<string, unknown> }
1173
+ if (runtime === null) {
1174
+ throw new Error("插件尚未初始化")
1175
+ }
1176
+ result = await withHookOwner(runtime.owner, async () =>
1177
+ dispatchHook(params.hook, params.payload),
1178
+ )
1179
+ } else if (request.method === "sandbox.ping") {
1180
+ result = { time: Date.now() }
1181
+ } else if (request.method === "sandbox.shutdown") {
1182
+ await emitShutdownHooks()
1183
+ result = {}
1184
+ writeFrame({ v: 1, type: "response", id: request.id, ok: true, result })
1185
+ setTimeout(() => process.exit(0), 10)
1186
+ return
1187
+ } else {
1188
+ throw new Error(`未知方法:${request.method}`)
1189
+ }
1190
+ writeFrame({ v: 1, type: "response", id: request.id, ok: true, result })
1191
+ } catch (error) {
1192
+ writeFrame({
1193
+ v: 1,
1194
+ type: "response",
1195
+ id: request.id,
1196
+ ok: false,
1197
+ error: {
1198
+ code:
1199
+ request.method === "plugin.hook"
1200
+ ? "plugin.hook-failed"
1201
+ : "plugin.command-failed",
1202
+ message: error instanceof Error ? error.message : String(error),
1203
+ },
1204
+ })
1205
+ }
1206
+ }
1207
+
1208
+ const configureResolvers: Array<(params: ConfigurePayload) => void> = []
1209
+
1210
+ async function main(): Promise<void> {
1211
+ const decoder = new FrameDecoder()
1212
+ process.stdin.on("data", async (chunk: Buffer) => {
1213
+ for (const message of decoder.push(chunk)) {
1214
+ if (message.type === "response") {
1215
+ const entry = pending.get(message.id)
1216
+ if (entry !== undefined) {
1217
+ pending.delete(message.id)
1218
+ if (message.ok) {
1219
+ entry.resolve(message.result)
1220
+ } else {
1221
+ entry.reject(new Error(message.error?.message ?? "host RPC 失败"))
1222
+ }
1223
+ }
1224
+ continue
1225
+ }
1226
+ if (message.type === "event") {
1227
+ /*
1228
+ * 事件回调出错不能拖垮 stdin 读取
1229
+ *
1230
+ * 这里在 data 监听里同步执行插件侧回调;一旦抛出就是未捕获异常,
1231
+ * 插件可能直接挂掉或丢掉这一帧里剩下的事件——宿主还在跑、界面却再也
1232
+ * 收不到任何事件,表现就是「服务端一直有日志、页面卡住不动」。
1233
+ */
1234
+ try {
1235
+ if (message.method === "sandbox.event") {
1236
+ const params = message.params as { name: string; data: unknown }
1237
+ eventBus.receive(params.name, params.data)
1238
+ } else if (message.method === "sandbox.agent.stream") {
1239
+ const params = message.params as {
1240
+ streamId: string
1241
+ event: HostAgentStreamEvent
1242
+ }
1243
+ agentStreamHandlers.get(params.streamId)?.(params.event)
1244
+ }
1245
+ } catch (error) {
1246
+ process.stderr.write(
1247
+ `事件处理失败(${message.method}):${error instanceof Error ? error.message : String(error)}\n`,
1248
+ )
1249
+ }
1250
+ continue
1251
+ }
1252
+ const request = message
1253
+ if (request.method === "sandbox.configure") {
1254
+ const params = request.params as ConfigurePayload
1255
+ try {
1256
+ patchConsole()
1257
+ patchProcessStreams()
1258
+ const ready = await bootstrap(params)
1259
+ writeFrame({ v: 1, type: "response", id: request.id, ok: true, result: ready })
1260
+ } catch (error) {
1261
+ writeFrame({
1262
+ v: 1,
1263
+ type: "response",
1264
+ id: request.id,
1265
+ ok: false,
1266
+ error: {
1267
+ code: "plugin.init-failed",
1268
+ message: error instanceof Error ? error.message : String(error),
1269
+ },
1270
+ })
1271
+ setTimeout(() => process.exit(1), 10)
1272
+ }
1273
+ continue
1274
+ }
1275
+ void handleHostRequest(request)
1276
+ }
1277
+ })
1278
+ process.stdin.resume()
1279
+ await new Promise<void>(() => undefined)
1280
+ }
1281
+
1282
+ await main()