@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,739 @@
1
+ /*
2
+ * 插件加载。
3
+ * 先 import + setup() 收集元数据,再按 deps 拓扑排序,最后注册命令并执行 init(api)。
4
+ * 支持 plugins-state.json 禁用插件;坏插件只记录失败,不影响其他插件。
5
+ */
6
+ import { cp, readdir, rm, stat, symlink } from "node:fs/promises";
7
+ import { basename, join, resolve } from "node:path";
8
+ import { pathToFileURL } from "node:url";
9
+ import { configureHost, setHostPlugins, } from "../api/host/host.js";
10
+ import { emitInitHooksForOwner, emitShutdownHooksForOwner, removeHooksByOwner, withHookOwner, } from "../api/host/hooks.js";
11
+ import { HOST_API_VERSION } from "../api/host/version.js";
12
+ import { DEFAULT_SETTINGS } from "../config/defaults.js";
13
+ import { SETTING_FILE_NAME } from "../config/loader.js";
14
+ import { getElog } from "../logger/elog4js.js";
15
+ import { ensureDir, readJsonIfExists } from "../platform/file.js";
16
+ import { getPaths } from "../platform/path.js";
17
+ import { BwrapBackend } from "../sandbox/backends/bwrap.js";
18
+ import { PluginSandboxClient } from "../sandbox/plugin-client.js";
19
+ import { AgentToolRegistry } from "./agent-tools.js";
20
+ import { createHostCapabilities } from "./capabilities.js";
21
+ import { PluginDataService } from "./data-access.js";
22
+ import { ensureAccessGuard } from "./access-guard.js";
23
+ import { ensureHostAlias } from "./host-alias.js";
24
+ import { PLUGIN_NAME, pluginsRoot } from "./paths.js";
25
+ import { PluginRegistry } from "./registry.js";
26
+ import { createHostAgentService } from "./agent-service.js";
27
+ import { createHostModelsService } from "./models-service.js";
28
+ import { createHostNetworkService } from "./network-service.js";
29
+ import { loadPluginConfig } from "./runtime.js";
30
+ import { readPluginState, setPluginEnabled } from "./state.js";
31
+ import { createHostPluginManager, } from "./manage.js";
32
+ const runtimes = new Map();
33
+ const ENTRY_CANDIDATES = ["index.ts", "index.js", "index.mjs", "index.mts"];
34
+ function errorText(error) {
35
+ if (error instanceof Error) {
36
+ const cause = error.cause;
37
+ return cause instanceof Error ? `${error.message}(${cause.message})` : error.message;
38
+ }
39
+ return String(error);
40
+ }
41
+ function isObject(value) {
42
+ return typeof value === "object" && value !== null && !Array.isArray(value);
43
+ }
44
+ async function resolveEntry(dir, pkg) {
45
+ const candidates = [];
46
+ if (pkg?.wellspring?.entry !== undefined) {
47
+ candidates.push(pkg.wellspring.entry);
48
+ }
49
+ if (pkg?.main !== undefined) {
50
+ candidates.push(pkg.main);
51
+ }
52
+ candidates.push(...ENTRY_CANDIDATES);
53
+ for (const candidate of candidates) {
54
+ const file = resolve(dir, candidate);
55
+ try {
56
+ const info = await stat(file);
57
+ if (info.isFile()) {
58
+ return file;
59
+ }
60
+ }
61
+ catch {
62
+ // 尝试下一个候选
63
+ }
64
+ }
65
+ return null;
66
+ }
67
+ function validatePlugin(value) {
68
+ if (!isObject(value)) {
69
+ throw new Error("setup() 必须返回 WellspringPlugin 对象");
70
+ }
71
+ const id = value["id"];
72
+ const name = value["name"];
73
+ const version = value["version"];
74
+ if (typeof id !== "string" || !PLUGIN_NAME.test(id)) {
75
+ throw new Error(`插件 id 不合法:${String(id)}`);
76
+ }
77
+ if (typeof name !== "string" || name.trim() === "") {
78
+ throw new Error(`插件 name 不合法:${String(name)}`);
79
+ }
80
+ if (typeof version !== "string" || version.trim() === "") {
81
+ throw new Error(`插件 version 不合法:${String(version)}`);
82
+ }
83
+ const status = value["status"];
84
+ if (status !== "ok" && status !== "failed") {
85
+ throw new Error(`插件 status 必须是 ok / failed:${String(status)}`);
86
+ }
87
+ const deps = value["deps"];
88
+ if (deps !== undefined) {
89
+ if (!Array.isArray(deps) || deps.some((item) => typeof item !== "string")) {
90
+ throw new Error("插件 deps 必须是字符串数组");
91
+ }
92
+ }
93
+ const commands = value["commands"];
94
+ if (commands !== undefined && !Array.isArray(commands)) {
95
+ throw new Error("插件 commands 必须是数组");
96
+ }
97
+ const agentTools = value["agentTools"];
98
+ if (agentTools !== undefined) {
99
+ if (!Array.isArray(agentTools)) {
100
+ throw new Error("插件 agentTools 必须是数组");
101
+ }
102
+ for (const tool of agentTools) {
103
+ if (!isObject(tool) || typeof tool["name"] !== "string") {
104
+ throw new Error("Agent 工具缺少 name");
105
+ }
106
+ if (!isObject(tool["introduction"]) || typeof tool["call"] !== "function") {
107
+ throw new Error(`Agent 工具缺少 introduction / call:${tool["name"]}`);
108
+ }
109
+ }
110
+ }
111
+ const init = value["init"];
112
+ if (init !== undefined && typeof init !== "function") {
113
+ throw new Error("插件 init 必须是函数");
114
+ }
115
+ return value;
116
+ }
117
+ function ownerOf(dirName, pkg) {
118
+ if (typeof pkg?.name === "string" && PLUGIN_NAME.test(pkg.name)) {
119
+ return pkg.name;
120
+ }
121
+ return dirName;
122
+ }
123
+ function sandboxPermissions(pkg) {
124
+ const raw = pkg?.wellspring?.sandbox;
125
+ const manifest = typeof raw === "object" && raw !== null && !Array.isArray(raw)
126
+ ? raw
127
+ : {};
128
+ const rawHostApi = manifest["hostApi"];
129
+ const hostApi = Array.isArray(rawHostApi)
130
+ ? rawHostApi.filter((item) => typeof item === "string")
131
+ : ["logger", "fs", "event", "getHost", "shutdown", "agent"];
132
+ const rawFs = manifest["fs"];
133
+ const fs = typeof rawFs === "object" && rawFs !== null && !Array.isArray(rawFs)
134
+ ? rawFs
135
+ : {};
136
+ const read = Array.isArray(fs["read"])
137
+ ? fs["read"].filter((item) => typeof item === "string")
138
+ : [];
139
+ const write = Array.isArray(fs["write"])
140
+ ? fs["write"].filter((item) => typeof item === "string")
141
+ : [];
142
+ return {
143
+ hostApi,
144
+ workspaceRead: read.includes("${workspace}") || write.includes("${workspace}"),
145
+ workspaceWrite: write.includes("${workspace}"),
146
+ };
147
+ }
148
+ async function loadEntry(dirName, dir, index, options, disabled, sandboxBackend, dataAccess, sandboxSetting, agentService, modelsService, networkService, pluginManager) {
149
+ let pkg = null;
150
+ try {
151
+ pkg = await readJsonIfExists(join(dir, "package.json"));
152
+ }
153
+ catch (error) {
154
+ return {
155
+ dirName,
156
+ dir,
157
+ owner: dirName,
158
+ pkg: null,
159
+ index,
160
+ plugin: null,
161
+ error: `package.json 无法解析:${errorText(error)}`,
162
+ disabled: false,
163
+ sandboxClient: null,
164
+ };
165
+ }
166
+ const owner = ownerOf(dirName, pkg);
167
+ const entry = {
168
+ dirName,
169
+ dir,
170
+ owner,
171
+ pkg,
172
+ index,
173
+ plugin: null,
174
+ error: null,
175
+ disabled: disabled.has(dirName),
176
+ sandboxClient: null,
177
+ };
178
+ if (entry.disabled) {
179
+ return entry;
180
+ }
181
+ const apiVersion = pkg?.wellspring?.apiVersion ?? HOST_API_VERSION;
182
+ if (apiVersion !== HOST_API_VERSION) {
183
+ entry.error = `不支持的 apiVersion:${apiVersion}`;
184
+ return entry;
185
+ }
186
+ const entryFile = await resolveEntry(dir, pkg);
187
+ if (entryFile === null) {
188
+ entry.error = "找不到插件入口";
189
+ return entry;
190
+ }
191
+ if (sandboxSetting.mode === "off") {
192
+ entry.error = "sandbox.mode = off,插件禁止在宿主进程内运行";
193
+ return entry;
194
+ }
195
+ if (sandboxBackend === null) {
196
+ entry.error = "sandbox backend 不可用(插件必须运行在 sandbox 内)";
197
+ return entry;
198
+ }
199
+ {
200
+ let client = null;
201
+ try {
202
+ const paths = options.paths ?? getPaths();
203
+ const pluginConfig = await loadPluginConfig(owner, paths);
204
+ client = new PluginSandboxClient({
205
+ pluginId: owner,
206
+ pluginName: typeof pkg?.name === "string" ? pkg.name : owner,
207
+ pluginVersion: typeof pkg?.version === "string" ? pkg.version : "0.0.0",
208
+ pluginDir: dir,
209
+ pluginEntry: entryFile,
210
+ paths,
211
+ config: options.config,
212
+ pluginConfig,
213
+ backend: sandboxBackend,
214
+ limits: {
215
+ timeoutMs: sandboxSetting.defaultTimeoutMs,
216
+ memoryMB: sandboxSetting.defaultMemoryMB,
217
+ pids: 64,
218
+ outputLimitBytes: sandboxSetting.outputLimitBytes,
219
+ },
220
+ logger: options.logger,
221
+ permissions: sandboxPermissions(pkg),
222
+ dataAccess,
223
+ capabilities: createHostCapabilities({
224
+ config: options.config,
225
+ paths,
226
+ logger: options.logger,
227
+ settingsFile: join(paths.configDir, SETTING_FILE_NAME),
228
+ }),
229
+ agent: agentService,
230
+ models: modelsService,
231
+ network: networkService,
232
+ plugins: pluginManager,
233
+ });
234
+ const ready = await client.start({ deferInit: true });
235
+ entry.sandboxClient = client;
236
+ entry.plugin = {
237
+ id: ready.plugin.id,
238
+ name: ready.plugin.name,
239
+ version: ready.plugin.version,
240
+ status: ready.plugin.status,
241
+ deps: ready.plugin.deps,
242
+ commands: [],
243
+ };
244
+ }
245
+ catch (error) {
246
+ await client?.close().catch(() => undefined);
247
+ entry.error = errorText(error);
248
+ entry.plugin = null;
249
+ removeHooksByOwner(owner);
250
+ }
251
+ return entry;
252
+ }
253
+ }
254
+ async function cleanupEntry(entry, options) {
255
+ if (entry.sandboxClient !== null) {
256
+ await entry.sandboxClient.close().catch(() => undefined);
257
+ }
258
+ if (entry.plugin !== null) {
259
+ options.registry.removePlugin(entry.plugin.id);
260
+ }
261
+ options.agentTools?.removePlugin(entry.plugin?.id ?? entry.owner);
262
+ removeHooksByOwner(entry.owner);
263
+ }
264
+ /** 按 deps 做稳定拓扑排序;循环依赖 / 缺失依赖的节点会写入 error */
265
+ function sortByDeps(entries) {
266
+ const byId = new Map();
267
+ for (const entry of entries) {
268
+ const id = entry.plugin?.id ?? entry.owner;
269
+ if (!byId.has(id)) {
270
+ byId.set(id, entry);
271
+ }
272
+ }
273
+ const active = entries.filter((entry) => entry.plugin !== null && entry.error === null);
274
+ const indegree = new Map();
275
+ const dependents = new Map();
276
+ for (const entry of active) {
277
+ const deps = entry.plugin?.deps ?? [];
278
+ let count = 0;
279
+ for (const dep of deps) {
280
+ const target = byId.get(dep);
281
+ if (target === undefined) {
282
+ entry.error = `依赖不存在:${dep}`;
283
+ break;
284
+ }
285
+ if (target === entry) {
286
+ entry.error = `循环依赖:${dep}`;
287
+ break;
288
+ }
289
+ if (target.disabled) {
290
+ entry.error = `依赖被禁用:${dep}`;
291
+ break;
292
+ }
293
+ if (target.error !== null || target.plugin === null) {
294
+ entry.error = `依赖不可用:${dep}`;
295
+ break;
296
+ }
297
+ count += 1;
298
+ const list = dependents.get(target) ?? [];
299
+ list.push(entry);
300
+ dependents.set(target, list);
301
+ }
302
+ if (entry.error === null) {
303
+ indegree.set(entry, count);
304
+ }
305
+ }
306
+ const ready = active
307
+ .filter((entry) => entry.error === null && (indegree.get(entry) ?? 0) === 0)
308
+ .sort((left, right) => left.index - right.index);
309
+ const sorted = [];
310
+ while (ready.length > 0) {
311
+ const current = ready.shift();
312
+ if (current === undefined) {
313
+ break;
314
+ }
315
+ sorted.push(current);
316
+ for (const dependent of dependents.get(current) ?? []) {
317
+ const remaining = (indegree.get(dependent) ?? 0) - 1;
318
+ indegree.set(dependent, remaining);
319
+ if (remaining === 0) {
320
+ ready.push(dependent);
321
+ ready.sort((left, right) => left.index - right.index);
322
+ }
323
+ }
324
+ }
325
+ for (const entry of active) {
326
+ if (entry.error === null && !sorted.includes(entry)) {
327
+ entry.error = "循环依赖";
328
+ }
329
+ }
330
+ return sorted;
331
+ }
332
+ /** 加载全部插件。坏插件记录失败状态,不影响其他插件 */
333
+ function pluginIdOf(entry) {
334
+ return entry.plugin?.id ?? entry.owner;
335
+ }
336
+ /** 把当前 entries 写回宿主快照;热变更后管理页与 /api/host 立即反映 */
337
+ function publishHostPlugins(entries, registry) {
338
+ setHostPlugins(entries.map((entry) => {
339
+ const plugin = entry.plugin;
340
+ const id = pluginIdOf(entry);
341
+ const commands = plugin === null || entry.error !== null || entry.disabled
342
+ ? []
343
+ : registry
344
+ .list()
345
+ .filter((record) => record.pluginName === id)
346
+ .map((record) => record.command.name);
347
+ return {
348
+ id,
349
+ name: plugin?.name ??
350
+ (typeof entry.pkg?.name === "string" ? entry.pkg.name : entry.owner),
351
+ version: plugin?.version ??
352
+ (typeof entry.pkg?.version === "string" ? entry.pkg.version : "0.0.0"),
353
+ deps: plugin?.deps ?? [],
354
+ commands,
355
+ getStatus: () => entry.disabled ? "disabled" : entry.error ? "failed" : "ok",
356
+ };
357
+ }));
358
+ }
359
+ /** 依赖数据访问按运行中的插件刷新 */
360
+ function refreshDataAccess(state) {
361
+ state.dataAccess.setPlugins(state.entries.map((entry) => ({
362
+ id: pluginIdOf(entry),
363
+ deps: entry.plugin?.deps ?? [],
364
+ })));
365
+ }
366
+ function runExclusive(state, task) {
367
+ const next = state.queueHost.current.then(task, task);
368
+ state.queueHost.current = next.then(() => undefined, () => undefined);
369
+ return next;
370
+ }
371
+ async function hotEnableEntry(state, idOrDir) {
372
+ const existing = state.entries.find((entry) => entry.dirName === idOrDir || pluginIdOf(entry) === idOrDir || entry.owner === idOrDir);
373
+ if (existing !== undefined &&
374
+ existing.plugin !== null &&
375
+ existing.error === null &&
376
+ existing.sandboxClient !== null) {
377
+ return { ok: true, id: existing.plugin.id, changed: false };
378
+ }
379
+ const dirName = existing?.dirName ?? idOrDir;
380
+ if (!PLUGIN_NAME.test(dirName)) {
381
+ return { ok: false, id: dirName, error: "插件名不合法" };
382
+ }
383
+ const dir = join(state.root, dirName);
384
+ const info = await stat(dir).catch(() => null);
385
+ if (info === null || !info.isDirectory()) {
386
+ return { ok: false, id: dirName, error: "plugin.not-found" };
387
+ }
388
+ if (existing !== undefined) {
389
+ state.entries = state.entries.filter((entry) => entry !== existing);
390
+ }
391
+ const disabled = new Set(await readPluginState(state.paths));
392
+ disabled.delete(dirName);
393
+ const entry = await loadEntry(dirName, dir, state.entries.length, state.options, disabled, state.sandboxBackend, state.dataAccess, state.sandboxSetting, state.agentService, state.modelsService, state.networkService, state.pluginManager);
394
+ if (entry.plugin === null || entry.error !== null) {
395
+ state.entries.push(entry);
396
+ publishHostPlugins(state.entries, state.options.registry);
397
+ return { ok: false, id: pluginIdOf(entry), error: entry.error ?? "插件加载失败" };
398
+ }
399
+ const plugin = entry.plugin;
400
+ for (const dep of plugin.deps ?? []) {
401
+ const target = state.entries.find((candidate) => pluginIdOf(candidate) === dep &&
402
+ candidate.plugin !== null &&
403
+ candidate.error === null &&
404
+ candidate.sandboxClient !== null);
405
+ if (target === undefined) {
406
+ await cleanupEntry(entry, state.options);
407
+ entry.error = `依赖未启动:${dep}`;
408
+ state.entries.push(entry);
409
+ publishHostPlugins(state.entries, state.options.registry);
410
+ return { ok: false, id: plugin.id, error: entry.error };
411
+ }
412
+ }
413
+ if (entry.sandboxClient === null) {
414
+ entry.error = "插件未运行在 sandbox 内";
415
+ state.entries.push(entry);
416
+ publishHostPlugins(state.entries, state.options.registry);
417
+ return { ok: false, id: plugin.id, error: entry.error };
418
+ }
419
+ // 先恢复依赖图再执行 init:插件 init 里可能通过 api.pluginData 读取依赖插件的数据
420
+ state.entries.push(entry);
421
+ refreshDataAccess(state);
422
+ publishHostPlugins(state.entries, state.options.registry);
423
+ try {
424
+ const ready = await entry.sandboxClient.initialize();
425
+ for (const command of entry.sandboxClient.commandStubs()) {
426
+ state.options.registry.register(ready.plugin.id, command);
427
+ }
428
+ for (const tool of entry.sandboxClient.agentToolStubs()) {
429
+ state.options.agentTools?.register(ready.plugin.id, tool);
430
+ }
431
+ await setPluginEnabled(dirName, true, state.paths);
432
+ await emitInitHooksForOwner(ready.plugin.id);
433
+ refreshDataAccess(state);
434
+ publishHostPlugins(state.entries, state.options.registry);
435
+ return { ok: true, id: ready.plugin.id, changed: true };
436
+ }
437
+ catch (error) {
438
+ entry.error = errorText(error);
439
+ await cleanupEntry(entry, state.options);
440
+ refreshDataAccess(state);
441
+ publishHostPlugins(state.entries, state.options.registry);
442
+ return { ok: false, id: plugin.id, error: entry.error };
443
+ }
444
+ }
445
+ async function hotDisableEntry(state, idOrDir) {
446
+ const entry = state.entries.find((candidate) => candidate.dirName === idOrDir ||
447
+ pluginIdOf(candidate) === idOrDir ||
448
+ candidate.owner === idOrDir);
449
+ if (entry === undefined) {
450
+ return { ok: false, id: idOrDir, error: "plugin.not-found" };
451
+ }
452
+ const id = pluginIdOf(entry);
453
+ if (id === "wellspring-web" || entry.dirName === "wellspring-web") {
454
+ return {
455
+ ok: false,
456
+ id,
457
+ error: "wellspring-web 不支持热禁用,请走重启流程",
458
+ };
459
+ }
460
+ const dependents = state.entries
461
+ .filter((candidate) => {
462
+ if (candidate === entry)
463
+ return false;
464
+ if (candidate.plugin === null || candidate.error !== null)
465
+ return false;
466
+ return (candidate.plugin.deps ?? []).includes(id);
467
+ })
468
+ .map(pluginIdOf);
469
+ if (dependents.length > 0) {
470
+ return {
471
+ ok: false,
472
+ id,
473
+ dependents,
474
+ error: `插件被依赖:${dependents.join(", ")}`,
475
+ };
476
+ }
477
+ try {
478
+ await emitShutdownHooksForOwner(entry.owner);
479
+ }
480
+ catch {
481
+ // 关闭钩子的错误不阻止停用
482
+ }
483
+ await cleanupEntry(entry, state.options);
484
+ // 留一个禁用占位,宿主快照与管理页仍能看到它
485
+ entry.disabled = true;
486
+ entry.plugin = null;
487
+ entry.error = null;
488
+ entry.sandboxClient = null;
489
+ await setPluginEnabled(entry.dirName, false, state.paths);
490
+ refreshDataAccess(state);
491
+ publishHostPlugins(state.entries, state.options.registry);
492
+ return { ok: true, id, changed: true };
493
+ }
494
+ async function hotForgetEntry(state, idOrDir) {
495
+ const entry = state.entries.find((candidate) => candidate.dirName === idOrDir ||
496
+ pluginIdOf(candidate) === idOrDir ||
497
+ candidate.owner === idOrDir);
498
+ if (entry === undefined) {
499
+ return;
500
+ }
501
+ state.entries = state.entries.filter((candidate) => candidate !== entry);
502
+ refreshDataAccess(state);
503
+ publishHostPlugins(state.entries, state.options.registry);
504
+ }
505
+ function controllerOf(state) {
506
+ return {
507
+ hotEnable: (id) => runExclusive(state, () => hotEnableEntry(state, id)),
508
+ hotDisable: (id) => runExclusive(state, () => hotDisableEntry(state, id)),
509
+ hotForget: (id) => runExclusive(state, () => hotForgetEntry(state, id)),
510
+ };
511
+ }
512
+ /** 取当前进程的插件热加载控制器;未经过 loadPlugins 时返回 null */
513
+ export function getPluginRuntime(paths = getPaths()) {
514
+ const state = runtimes.get(paths.dataDir);
515
+ if (state === undefined) {
516
+ return null;
517
+ }
518
+ return controllerOf(state);
519
+ }
520
+ export async function hotEnablePlugin(id, paths = getPaths()) {
521
+ const runtime = getPluginRuntime(paths);
522
+ if (runtime === null) {
523
+ return { ok: false, id, error: "插件运行时未初始化" };
524
+ }
525
+ return await runtime.hotEnable(id);
526
+ }
527
+ export async function hotDisablePlugin(id, paths = getPaths()) {
528
+ const runtime = getPluginRuntime(paths);
529
+ if (runtime === null) {
530
+ return { ok: false, id, error: "插件运行时未初始化" };
531
+ }
532
+ return await runtime.hotDisable(id);
533
+ }
534
+ export async function loadPlugins(options) {
535
+ ensureHostAlias();
536
+ ensureAccessGuard();
537
+ const resolvedPaths = options.paths ?? getPaths();
538
+ configureHost({ paths: resolvedPaths });
539
+ const dataAccess = options.dataAccess ?? new PluginDataService(resolvedPaths);
540
+ const root = pluginsRoot(options.paths);
541
+ await ensureDir(root);
542
+ let names;
543
+ try {
544
+ names = (await readdir(root)).sort();
545
+ }
546
+ catch {
547
+ return [];
548
+ }
549
+ const sandboxSetting = options.sandbox ?? {
550
+ ...DEFAULT_SETTINGS.sandbox,
551
+ mode: "best-effort",
552
+ };
553
+ let sandboxBackend = null;
554
+ if (sandboxSetting.mode !== "off") {
555
+ if (options.sandboxBackend !== undefined) {
556
+ sandboxBackend = options.sandboxBackend;
557
+ }
558
+ else if (sandboxSetting.backend === "auto" || sandboxSetting.backend === "bwrap") {
559
+ const bwrap = new BwrapBackend();
560
+ const status = await bwrap.probe();
561
+ // 插件不做 direct 降级:没有 OS 后端就拒绝加载
562
+ sandboxBackend = status.available ? bwrap : null;
563
+ }
564
+ }
565
+ const agentService = options.agent ??
566
+ createHostAgentService({
567
+ settings: options.config,
568
+ paths: resolvedPaths,
569
+ logger: options.logger,
570
+ registry: options.registry,
571
+ agentTools: options.agentTools ?? new AgentToolRegistry(),
572
+ });
573
+ // 自定义供应商与模型切换:直接读写 app-setting.json,改完下一轮对话生效
574
+ const modelsService = createHostModelsService({
575
+ settings: options.config,
576
+ settingsFile: join(resolvedPaths.configDir, SETTING_FILE_NAME),
577
+ configDir: resolvedPaths.configDir,
578
+ logger: options.logger,
579
+ });
580
+ const networkService = createHostNetworkService({
581
+ settings: options.config,
582
+ settingsFile: join(resolvedPaths.configDir, SETTING_FILE_NAME),
583
+ logger: options.logger,
584
+ });
585
+ const state = {
586
+ options,
587
+ paths: resolvedPaths,
588
+ root,
589
+ sandboxSetting,
590
+ sandboxBackend,
591
+ dataAccess,
592
+ agentService,
593
+ modelsService,
594
+ networkService,
595
+ pluginManager: null,
596
+ queueHost: { current: Promise.resolve() },
597
+ entries: [],
598
+ };
599
+ const pluginManager = createHostPluginManager({
600
+ paths: resolvedPaths,
601
+ logger: options.logger,
602
+ runtime: controllerOf(state),
603
+ });
604
+ state.pluginManager = pluginManager;
605
+ runtimes.set(resolvedPaths.dataDir, state);
606
+ const disabled = await readPluginState(options.paths ?? getPaths());
607
+ const entries = [];
608
+ let index = 0;
609
+ for (const dirName of names) {
610
+ if (!PLUGIN_NAME.test(dirName) || dirName.startsWith(".")) {
611
+ continue;
612
+ }
613
+ const dir = join(root, dirName);
614
+ try {
615
+ const info = await stat(dir);
616
+ if (!info.isDirectory()) {
617
+ continue;
618
+ }
619
+ }
620
+ catch {
621
+ continue;
622
+ }
623
+ entries.push(await loadEntry(dirName, dir, index, options, disabled, sandboxBackend, dataAccess, sandboxSetting, agentService, modelsService, networkService, pluginManager));
624
+ index += 1;
625
+ }
626
+ state.entries = entries;
627
+ refreshDataAccess(state);
628
+ const sorted = sortByDeps(entries);
629
+ // 让 init/hook 期间也能看到宿主插件列表(命令列表在 finalize 后补全)
630
+ publishHostPlugins(entries, options.registry);
631
+ const finished = new Set();
632
+ for (const entry of sorted) {
633
+ const plugin = entry.plugin;
634
+ if (plugin === null || entry.error !== null) {
635
+ continue;
636
+ }
637
+ const deps = plugin.deps ?? [];
638
+ let blocked = false;
639
+ for (const dep of deps) {
640
+ const target = entries.find((candidate) => (candidate.plugin?.id ?? candidate.owner) === dep);
641
+ if (target === undefined || !finished.has(target)) {
642
+ entry.error = `依赖未就绪:${dep}`;
643
+ blocked = true;
644
+ break;
645
+ }
646
+ }
647
+ if (blocked) {
648
+ await cleanupEntry(entry, options);
649
+ continue;
650
+ }
651
+ if (entry.sandboxClient !== null) {
652
+ try {
653
+ const ready = await entry.sandboxClient.initialize();
654
+ for (const command of entry.sandboxClient.commandStubs()) {
655
+ options.registry.register(ready.plugin.id, command);
656
+ }
657
+ for (const tool of entry.sandboxClient.agentToolStubs()) {
658
+ options.agentTools?.register(ready.plugin.id, tool);
659
+ }
660
+ finished.add(entry);
661
+ }
662
+ catch (error) {
663
+ entry.error = errorText(error);
664
+ await cleanupEntry(entry, options);
665
+ }
666
+ continue;
667
+ }
668
+ entry.error = "插件未运行在 sandbox 内";
669
+ await cleanupEntry(entry, options);
670
+ }
671
+ for (const entry of entries) {
672
+ if ((entry.plugin !== null || entry.sandboxClient !== null) &&
673
+ entry.error !== null &&
674
+ !finished.has(entry)) {
675
+ await cleanupEntry(entry, options);
676
+ }
677
+ }
678
+ const loaded = entries.map((entry) => {
679
+ const plugin = entry.plugin;
680
+ const base = {
681
+ id: plugin?.id ?? entry.owner,
682
+ name: plugin?.name ??
683
+ (typeof entry.pkg?.name === "string" ? entry.pkg.name : entry.owner),
684
+ version: plugin?.version ??
685
+ (typeof entry.pkg?.version === "string" ? entry.pkg.version : "0.0.0"),
686
+ deps: plugin?.deps ?? [],
687
+ dir: entry.dir,
688
+ };
689
+ if (entry.disabled) {
690
+ return { ...base, status: "disabled", commands: [], error: null };
691
+ }
692
+ if (plugin === null || entry.error !== null) {
693
+ return {
694
+ ...base,
695
+ status: "failed",
696
+ commands: [],
697
+ error: entry.error ?? "插件加载失败",
698
+ };
699
+ }
700
+ const commands = options.registry
701
+ .list()
702
+ .filter((record) => record.pluginName === plugin.id)
703
+ .map((record) => record.command.name);
704
+ return { ...base, status: "ok", commands, error: null };
705
+ });
706
+ state.entries = entries;
707
+ publishHostPlugins(entries, options.registry);
708
+ return loaded;
709
+ }
710
+ /** 把本地插件目录链接进插件根目录,开发用;没有符号链接权限时退化为复制 */
711
+ export async function linkPlugin(sourcePath, paths = getPaths()) {
712
+ const source = resolve(sourcePath);
713
+ const name = basename(source);
714
+ if (!PLUGIN_NAME.test(name)) {
715
+ throw new Error(`插件目录名不合法:${name}`);
716
+ }
717
+ const root = pluginsRoot(paths);
718
+ await ensureDir(root);
719
+ const target = join(root, name);
720
+ const existing = await stat(target).catch(() => null);
721
+ if (existing !== null) {
722
+ throw new Error(`插件已存在:${name}`);
723
+ }
724
+ try {
725
+ await symlink(source, target, "dir");
726
+ }
727
+ catch {
728
+ await cp(source, target, { recursive: true });
729
+ }
730
+ return name;
731
+ }
732
+ /** 删除插件目录 */
733
+ export async function removePlugin(name, paths = getPaths()) {
734
+ if (!PLUGIN_NAME.test(name)) {
735
+ throw new Error(`插件名不合法:${name}`);
736
+ }
737
+ await rm(join(pluginsRoot(paths), name), { recursive: true, force: true });
738
+ }
739
+ //# sourceMappingURL=loader.js.map