@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,43 @@
1
+ // 插件 Agent 工具注册表
2
+
3
+ import type { AgentTool } from "../api/host/plugin.ts"
4
+
5
+ const TOOL_NAME = /^[a-z][a-z0-9_-]{1,63}$/
6
+
7
+ export interface RegisteredAgentTool {
8
+ readonly pluginId: string
9
+ readonly tool: AgentTool
10
+ }
11
+
12
+ export class AgentToolRegistry {
13
+ readonly #tools = new Map<string, RegisteredAgentTool>()
14
+
15
+ register(pluginId: string, tool: AgentTool): void {
16
+ if (!TOOL_NAME.test(tool.name)) {
17
+ throw new Error(`Agent 工具名不合法:${tool.name}`)
18
+ }
19
+ if (this.#tools.has(tool.name)) {
20
+ throw new Error(`Agent 工具重名:${tool.name}`)
21
+ }
22
+ if (typeof tool.call !== "function") {
23
+ throw new Error(`Agent 工具缺少 call:${tool.name}`)
24
+ }
25
+ this.#tools.set(tool.name, { pluginId, tool })
26
+ }
27
+
28
+ list(): readonly RegisteredAgentTool[] {
29
+ return [...this.#tools.values()]
30
+ }
31
+
32
+ get(name: string): RegisteredAgentTool | undefined {
33
+ return this.#tools.get(name)
34
+ }
35
+
36
+ removePlugin(pluginId: string): void {
37
+ for (const [name, record] of this.#tools) {
38
+ if (record.pluginId === pluginId) {
39
+ this.#tools.delete(name)
40
+ }
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,240 @@
1
+ // 插件可用的宿主能力:sandbox 代码执行与网络工具
2
+
3
+ import type { Logger } from "pino"
4
+
5
+ import { loadSettings } from "../config/loader.ts"
6
+ import type { AppSetting } from "../config/types.ts"
7
+ import { credentialsFile, resolveApiKeySync } from "../config/credentials.ts"
8
+ import {
9
+ WEB_CODES,
10
+ createDeepSeekWebClient,
11
+ type WebFetchResult,
12
+ type WebSearchResult,
13
+ } from "../network/web.ts"
14
+ import { createProxyFetch } from "../network/proxy.ts"
15
+ import type { ResolvedPaths } from "../platform/path.ts"
16
+ import { SandboxManager } from "../sandbox/manager.ts"
17
+ import type { AgentCodeRequest, AgentCodeResult, StopMode } from "../sandbox/types.ts"
18
+ import { getAgentToolContext, type AgentToolContext } from "../agent/tool-context.ts"
19
+ import {
20
+ queryTask,
21
+ registerBackgroundTask,
22
+ stopTask,
23
+ type AgentTaskInfo,
24
+ } from "../agent/task-registry.ts"
25
+
26
+ export interface HostCapabilities {
27
+ executeCode(
28
+ input: Omit<AgentCodeRequest, "workspaceDir">,
29
+ context?: AgentToolContext,
30
+ ): Promise<AgentCodeResult>
31
+ startBackgroundCode(
32
+ input: Omit<AgentCodeRequest, "workspaceDir">,
33
+ context?: AgentToolContext,
34
+ ): Promise<{ taskId: string; sandboxId: string }>
35
+ queryTask(taskId?: string): AgentTaskInfo | null
36
+ stopTask(taskId: string | undefined, mode: StopMode): boolean
37
+ webSearch(query: string, count?: number): Promise<readonly WebSearchResult[]>
38
+ webFetch(url: string): Promise<WebFetchResult>
39
+ }
40
+
41
+ export interface HostCapabilitiesOptions {
42
+ readonly config: AppSetting
43
+ readonly paths: ResolvedPaths
44
+ readonly logger: Logger
45
+ /** 配置文件路径;提供时每次联网工具调用都重读,网页里改的代理不需要重启 */
46
+ readonly settingsFile?: string
47
+ }
48
+
49
+ const ACCESS_RANK: Readonly<Record<string, number>> = {
50
+ "read-only": 0,
51
+ "workspace-write": 1,
52
+ "danger-full-access": 2,
53
+ }
54
+
55
+ export function createHostCapabilities(options: HostCapabilitiesOptions): HostCapabilities {
56
+ let manager: SandboxManager | null = null
57
+ let web: ReturnType<typeof createDeepSeekWebClient> | null = null
58
+ let webCacheKey: string | null = null
59
+
60
+ /** 联网工具用默认供应商(OpenAI/DeepSeek)的 Key:环境变量 > credentials.json */
61
+ const resolveWebApiKey = (): string | null =>
62
+ resolveApiKeySync(credentialsFile(options.paths.configDir))?.apiKey ?? null
63
+
64
+ /** 配置文件可能存在网页/CLI 运行中修改(Key、Base URL、代理):每次调用重读 */
65
+ const currentConfig = async (): Promise<AppSetting> => {
66
+ if (options.settingsFile === undefined) return options.config
67
+ try {
68
+ const loaded = await loadSettings(options.settingsFile)
69
+ return loaded.getData() ?? options.config
70
+ } catch {
71
+ return options.config
72
+ }
73
+ }
74
+
75
+ /** Key / 代理 / Base URL 都可能在运行中变化,缓存按这些字段失效 */
76
+ const webClient = async (): Promise<ReturnType<typeof createDeepSeekWebClient>> => {
77
+ const config = await currentConfig()
78
+ const apiKey = resolveWebApiKey()
79
+ const proxy = config.network.proxy
80
+ const cacheKey = [
81
+ apiKey ?? "",
82
+ config.openai.baseUrl ?? "",
83
+ String(config.openai.timeoutMs),
84
+ proxy?.url ?? "",
85
+ (proxy?.noProxy ?? []).join(","),
86
+ ].join("|")
87
+ if (web === null || webCacheKey !== cacheKey) {
88
+ webCacheKey = cacheKey
89
+ web = createDeepSeekWebClient({
90
+ baseUrl: config.openai.baseUrl,
91
+ timeoutMs: config.openai.timeoutMs,
92
+ fetch: createProxyFetch(proxy) as typeof fetch | undefined,
93
+ ...(apiKey === null ? {} : { apiKey }),
94
+ })
95
+ }
96
+ return web
97
+ }
98
+
99
+ const webError = (code: string | null, action: string): Error => {
100
+ if (code === WEB_CODES.missingApiKey) {
101
+ return new Error(
102
+ "web.missing-api-key:联网工具缺少 API Key。设置环境变量 OPENAI_API_KEY,或运行 wellspring key set(网页:左下角「供应商」里填写该供应商的 Key)",
103
+ )
104
+ }
105
+ return new Error(code ?? `web.${action}-failed`)
106
+ }
107
+ const sandbox = (): SandboxManager => {
108
+ manager ??= new SandboxManager({
109
+ settings: options.config.sandbox,
110
+ paths: options.paths,
111
+ logger: options.logger,
112
+ })
113
+ return manager
114
+ }
115
+ const approve = async (
116
+ input: Omit<AgentCodeRequest, "workspaceDir">,
117
+ context: AgentToolContext,
118
+ /** 调用方是 startAgentCode(后台任务)而不是 runAgentCode */
119
+ background = false,
120
+ ): Promise<{ access: NonNullable<AgentCodeRequest["access"]>; cwd: string }> => {
121
+ const current = context.permission
122
+ const requested = input.access ?? current
123
+ const cwd = input.cwd ?? context.workspaceDir
124
+ if ((ACCESS_RANK[requested] ?? 0) > (ACCESS_RANK[current] ?? 0)) {
125
+ const argv = input.argv ?? []
126
+ const stdin = typeof input.stdin === "string" ? input.stdin.trim() : ""
127
+ /*
128
+ * 参数逐个列出,而不是把 command 和 argv 拼成一行:
129
+ * 「bash -lc 'curl … | sh'」里危险的是参数边界,拼行会看不出引号归属。
130
+ */
131
+ context.elog.action("请求执行命令", [
132
+ { label: "command", value: input.command, code: true },
133
+ ...argv.map((arg, index) => ({
134
+ label: `参数 ${index + 1}`,
135
+ value: arg,
136
+ code: true,
137
+ })),
138
+ { label: "工作目录", value: cwd },
139
+ { label: "权限", value: `${current} → ${requested}` },
140
+ ...(input.network === true ? [{ label: "网络", value: "请求联网" }] : []),
141
+ ...(background ? [{ label: "运行方式", value: "后台执行" }] : []),
142
+ ...(typeof input.timeoutMs === "number"
143
+ ? [{ label: "超时", value: `${Math.round(input.timeoutMs / 1000)} 秒` }]
144
+ : []),
145
+ ...(stdin === ""
146
+ ? []
147
+ : [
148
+ {
149
+ label: "标准输入",
150
+ value: stdin.length > 200 ? `${stdin.slice(0, 200)}…` : stdin,
151
+ code: true,
152
+ },
153
+ ]),
154
+ ])
155
+ let allowed = context.allowExec
156
+ if (!allowed && context.approveExec !== undefined) {
157
+ allowed = await context.approveExec({
158
+ command: input.command,
159
+ argv: input.argv ?? [],
160
+ cwd,
161
+ currentPermission: current,
162
+ requestedPermission: requested,
163
+ justification: input.justification,
164
+ ...(input.network === true ? { network: true } : {}),
165
+ ...(background ? { background: true } : {}),
166
+ ...(typeof input.stdin === "string" && input.stdin !== ""
167
+ ? { stdin: input.stdin }
168
+ : {}),
169
+ ...(typeof input.timeoutMs === "number" ? { timeoutMs: input.timeoutMs } : {}),
170
+ })
171
+ }
172
+ if (!allowed) {
173
+ throw new Error("工具执行被拒绝")
174
+ }
175
+ context.elog.toolResult("已允许提权")
176
+ }
177
+ return { access: requested, cwd }
178
+ }
179
+ return {
180
+ async executeCode(input, explicitContext) {
181
+ const context = explicitContext ?? getAgentToolContext()
182
+ if (context === null) {
183
+ throw new Error("executeCode 只能在 Agent 工具调用中使用")
184
+ }
185
+ const { access, cwd } = await approve(input, context)
186
+ const result = await sandbox().runAgentCode({
187
+ ...input,
188
+ cwd,
189
+ workspaceDir: context.workspaceDir,
190
+ access,
191
+ })
192
+ if (result.exitCode !== 0) {
193
+ context.elog.toolResult(`exit=${String(result.exitCode)}`)
194
+ }
195
+ return result
196
+ },
197
+ async startBackgroundCode(input, explicitContext) {
198
+ const context = explicitContext ?? getAgentToolContext()
199
+ if (context === null) {
200
+ throw new Error("startBackgroundCode 只能在 Agent 工具调用中使用")
201
+ }
202
+ const { access, cwd } = await approve(input, context, true)
203
+ const handle = await sandbox().startAgentCode({
204
+ ...input,
205
+ cwd,
206
+ workspaceDir: context.workspaceDir,
207
+ access,
208
+ })
209
+ const info = registerBackgroundTask(handle)
210
+ context.elog.toolResult(`后台任务 ${info.taskId}`)
211
+ return { taskId: info.taskId, sandboxId: info.sandboxId }
212
+ },
213
+ queryTask(taskId?: string) {
214
+ return queryTask(taskId)
215
+ },
216
+ stopTask(taskId: string | undefined, mode: StopMode) {
217
+ return stopTask(taskId, mode)
218
+ },
219
+ async webSearch(query, count) {
220
+ const client = await webClient()
221
+ const result = await client.search(query, count)
222
+ if (!result.isSuccess()) {
223
+ throw webError(result.getCode(), "search")
224
+ }
225
+ return result.getData() ?? []
226
+ },
227
+ async webFetch(url) {
228
+ const client = await webClient()
229
+ const result = await client.fetch(url)
230
+ if (!result.isSuccess()) {
231
+ throw webError(result.getCode(), "fetch")
232
+ }
233
+ const page = result.getData()
234
+ if (page === null) {
235
+ throw webError(null, "fetch")
236
+ }
237
+ return page
238
+ },
239
+ }
240
+ }
@@ -0,0 +1,66 @@
1
+ /*
2
+ * 插件 console 拦截。
3
+ * 插件内 console.* 不直接写终端:先记录一条 error,再按原方法级别输出原始消息。
4
+ * 拦截只覆盖插件 import / register / run 期间,结束后恢复。
5
+ */
6
+
7
+ import { format } from "node:util"
8
+
9
+ import type { Logger } from "pino"
10
+
11
+ const METHODS = ["log", "info", "debug", "warn", "error", "trace", "dir", "table"] as const
12
+
13
+ type GuardedMethod = (typeof METHODS)[number]
14
+
15
+ const LEVEL_OF: Readonly<Record<GuardedMethod, "info" | "debug" | "warn" | "error" | "trace">> = {
16
+ log: "info",
17
+ info: "info",
18
+ debug: "debug",
19
+ warn: "warn",
20
+ error: "error",
21
+ trace: "trace",
22
+ dir: "info",
23
+ table: "info",
24
+ }
25
+
26
+ export async function withConsoleGuard<T>(
27
+ pluginName: string,
28
+ logger: Logger,
29
+ task: () => T | Promise<T>,
30
+ ): Promise<T> {
31
+ const target = console as unknown as Record<string, (...args: unknown[]) => void>
32
+ const originals = new Map<string, (...args: unknown[]) => void>()
33
+
34
+ const emit = (level: "info" | "debug" | "warn" | "error" | "trace", args: unknown[]): void => {
35
+ logger.error(`插件 [${pluginName}] 使用了不推荐的 console logger !`)
36
+ const text = `${pluginName} ${format(...args)}`
37
+ logger[level](text)
38
+ }
39
+
40
+ for (const method of METHODS) {
41
+ const original = target[method]
42
+ if (typeof original !== "function") {
43
+ continue
44
+ }
45
+ originals.set(method, original)
46
+ target[method] = (...args: unknown[]): void => {
47
+ emit(LEVEL_OF[method], args)
48
+ }
49
+ }
50
+
51
+ const originalAssert = console.assert
52
+ console.assert = (condition: unknown, ...args: unknown[]): void => {
53
+ if (!condition) {
54
+ emit("error", args)
55
+ }
56
+ }
57
+
58
+ try {
59
+ return await task()
60
+ } finally {
61
+ for (const [method, original] of originals) {
62
+ target[method] = original
63
+ }
64
+ console.assert = originalAssert
65
+ }
66
+ }
@@ -0,0 +1,70 @@
1
+ // 插件数据访问:依赖关系链上的插件可互访 data 目录
2
+
3
+ import type { HostFileApi } from "../api/host/fs.ts"
4
+ import type { ResolvedPaths } from "../platform/path.ts"
5
+ import { createPluginFileApi } from "./fs.ts"
6
+ import { ensurePluginDataDir } from "./runtime.ts"
7
+
8
+ interface PluginNode {
9
+ readonly id: string
10
+ readonly deps: readonly string[]
11
+ }
12
+
13
+ export class PluginDataService {
14
+ readonly #paths: ResolvedPaths
15
+ readonly #edges = new Map<string, Set<string>>()
16
+
17
+ constructor(paths: ResolvedPaths) {
18
+ this.#paths = paths
19
+ }
20
+
21
+ /** 建立无向依赖图;A 依赖 B 后双方都可访问对方 data */
22
+ setPlugins(plugins: readonly PluginNode[]): void {
23
+ this.#edges.clear()
24
+ for (const plugin of plugins) {
25
+ this.#edges.set(plugin.id, this.#edges.get(plugin.id) ?? new Set())
26
+ for (const dep of plugin.deps) {
27
+ this.#link(plugin.id, dep)
28
+ this.#link(dep, plugin.id)
29
+ }
30
+ }
31
+ }
32
+
33
+ #link(left: string, right: string): void {
34
+ const set = this.#edges.get(left) ?? new Set<string>()
35
+ set.add(right)
36
+ this.#edges.set(left, set)
37
+ }
38
+
39
+ canAccess(from: string, to: string): boolean {
40
+ if (from === to) {
41
+ return true
42
+ }
43
+ const seen = new Set<string>([from])
44
+ const queue = [from]
45
+ while (queue.length > 0) {
46
+ const current = queue.shift()
47
+ if (current === undefined) {
48
+ break
49
+ }
50
+ for (const next of this.#edges.get(current) ?? []) {
51
+ if (next === to) {
52
+ return true
53
+ }
54
+ if (!seen.has(next)) {
55
+ seen.add(next)
56
+ queue.push(next)
57
+ }
58
+ }
59
+ }
60
+ return false
61
+ }
62
+
63
+ async open(from: string, to: string): Promise<HostFileApi | null> {
64
+ if (!this.canAccess(from, to)) {
65
+ return null
66
+ }
67
+ const root = await ensurePluginDataDir(to, this.#paths)
68
+ return createPluginFileApi(root)
69
+ }
70
+ }
@@ -0,0 +1,109 @@
1
+ /*
2
+ * HostFileApi 实现:根目录内的相对路径访问。
3
+ */
4
+
5
+ import { readdir } from "node:fs/promises"
6
+ import { isAbsolute, resolve, sep } from "node:path"
7
+
8
+ import type { HostFileApi, HostFileEntry, HostFileStat, HostFileType } from "../api/host/fs.ts"
9
+ import {
10
+ ensureDir,
11
+ readBytesIfExists,
12
+ readJsonIfExists,
13
+ readTextIfExists,
14
+ removePath,
15
+ statIfExists,
16
+ writeBytesAtomic,
17
+ writeJsonAtomic,
18
+ writeTextAtomic,
19
+ } from "../platform/file.ts"
20
+
21
+ function safePath(root: string, relative: string): string {
22
+ if (typeof relative !== "string" || relative.includes("\0")) {
23
+ throw new Error("文件路径不合法")
24
+ }
25
+ if (isAbsolute(relative)) {
26
+ throw new Error(`不允许绝对路径:${relative}`)
27
+ }
28
+ const target = resolve(root, relative)
29
+ if (target !== root && !target.startsWith(`${root}${sep}`)) {
30
+ throw new Error(`路径越界:${relative}`)
31
+ }
32
+ return target
33
+ }
34
+
35
+ function fileTypeOf(isFile: boolean, isDirectory: boolean): HostFileType {
36
+ if (isFile) {
37
+ return "file"
38
+ }
39
+ if (isDirectory) {
40
+ return "directory"
41
+ }
42
+ return "other"
43
+ }
44
+
45
+ /** 为某个根目录创建 HostFileApi;root 需已存在或首次写入时自动创建 */
46
+ export function createPluginFileApi(root: string): HostFileApi {
47
+ const base = resolve(root)
48
+
49
+ const api: HostFileApi = {
50
+ root: base,
51
+ async readText(path) {
52
+ return await readTextIfExists(safePath(base, path))
53
+ },
54
+ async readBytes(path) {
55
+ const bytes = await readBytesIfExists(safePath(base, path))
56
+ return bytes === null ? null : new Uint8Array(bytes)
57
+ },
58
+ async readJson<T = unknown>(path: string) {
59
+ return await readJsonIfExists<T>(safePath(base, path))
60
+ },
61
+ async writeText(path, text) {
62
+ await writeTextAtomic(safePath(base, path), text)
63
+ },
64
+ async writeBytes(path, bytes) {
65
+ await writeBytesAtomic(safePath(base, path), bytes)
66
+ },
67
+ async writeJson(path, value) {
68
+ await writeJsonAtomic(safePath(base, path), value)
69
+ },
70
+ async list(path = "") {
71
+ const dir = safePath(base, path)
72
+ const entries = await readdir(dir, { withFileTypes: true })
73
+ const result: HostFileEntry[] = []
74
+ for (const entry of entries) {
75
+ const info = await statIfExists(resolve(dir, entry.name))
76
+ result.push({
77
+ name: entry.name,
78
+ type: fileTypeOf(entry.isFile(), entry.isDirectory()),
79
+ size: info?.size ?? 0,
80
+ mtimeMs: info?.mtimeMs ?? 0,
81
+ })
82
+ }
83
+ result.sort((left, right) => left.name.localeCompare(right.name))
84
+ return result
85
+ },
86
+ async stat(path) {
87
+ const info = await statIfExists(safePath(base, path))
88
+ if (info === null) {
89
+ return null
90
+ }
91
+ const stat: HostFileStat = {
92
+ type: fileTypeOf(info.isFile(), info.isDirectory()),
93
+ size: info.size,
94
+ mtimeMs: info.mtimeMs,
95
+ }
96
+ return stat
97
+ },
98
+ async mkdir(path) {
99
+ await ensureDir(safePath(base, path))
100
+ },
101
+ async remove(path) {
102
+ await removePath(safePath(base, path))
103
+ },
104
+ async exists(path) {
105
+ return (await statIfExists(safePath(base, path))) !== null
106
+ },
107
+ }
108
+ return api
109
+ }
@@ -0,0 +1,61 @@
1
+ /*
2
+ * 插件侧模块别名。
3
+ * 插件不在 wellspring 包的解析路径内,用 Node 的 resolve hook 把
4
+ * "wellspring" / "wellspring/..." 映射到本仓库的 src 目录,
5
+ * 这样插件可以 import { onMessage, getHost } from "wellspring/api/host/index.ts"。
6
+ */
7
+
8
+ import { statSync } from "node:fs"
9
+ import { registerHooks } from "node:module"
10
+ import { join, resolve } from "node:path"
11
+ import { pathToFileURL } from "node:url"
12
+
13
+ const PROJECT_ROOT = resolve(import.meta.dirname, "../..")
14
+ const SOURCE_ROOT = join(PROJECT_ROOT, "src")
15
+ const PREFIX = "wellspring/"
16
+
17
+ let installed = false
18
+
19
+ function existingFile(path: string): string | null {
20
+ try {
21
+ const info = statSync(path)
22
+ return info.isFile() ? path : null
23
+ } catch {
24
+ return null
25
+ }
26
+ }
27
+
28
+ function resolveHostTarget(specifier: string): string | null {
29
+ if (specifier === "wellspring") {
30
+ return existingFile(join(SOURCE_ROOT, "api", "host", "index.ts"))
31
+ }
32
+ if (!specifier.startsWith(PREFIX)) {
33
+ return null
34
+ }
35
+ const rest = specifier.slice(PREFIX.length)
36
+ if (rest === "" || rest.startsWith("..") || rest.startsWith("/") || rest.includes("\\")) {
37
+ return null
38
+ }
39
+ const direct = existingFile(join(SOURCE_ROOT, rest))
40
+ if (direct !== null) {
41
+ return direct
42
+ }
43
+ return existingFile(join(SOURCE_ROOT, rest, "index.ts"))
44
+ }
45
+
46
+ /** 注册一次即可;在加载插件前调用 */
47
+ export function ensureHostAlias(): void {
48
+ if (installed) {
49
+ return
50
+ }
51
+ installed = true
52
+ registerHooks({
53
+ resolve(specifier, context, nextResolve) {
54
+ const target = resolveHostTarget(specifier)
55
+ if (target !== null) {
56
+ return { url: pathToFileURL(target).href, shortCircuit: true }
57
+ }
58
+ return nextResolve(specifier, context)
59
+ },
60
+ })
61
+ }
@@ -0,0 +1,11 @@
1
+ /*
2
+ * 插件层入口。
3
+ */
4
+
5
+ export * from "./console-guard.ts"
6
+ export * from "./host-alias.ts"
7
+ export * from "./install.ts"
8
+ export * from "./loader.ts"
9
+ export * from "./paths.ts"
10
+ export * from "./registry.ts"
11
+ export * from "./zip.ts"