@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,108 @@
1
+ /*
2
+ * 系统通知。
3
+ * Windows 走 PowerShell 的 WinRT toast,脚本内容经 -EncodedCommand 传递;
4
+ * WSL 下优先调用 powershell.exe,其余平台使用各自的通知命令。
5
+ */
6
+
7
+ import { describeError, powershellArgs, runCommand } from "./exec.ts"
8
+ import { isWsl, platform, type PlatformName } from "./os.ts"
9
+
10
+ export interface NotifyOptions {
11
+ readonly title: string
12
+ readonly body?: string
13
+ }
14
+
15
+ export interface NotifyCommand {
16
+ readonly command: string
17
+ readonly args: readonly string[]
18
+ readonly env?: Readonly<Record<string, string>>
19
+ }
20
+
21
+ const MACOS_SCRIPT =
22
+ 'display notification (system attribute "WELLSPRING_NOTIFY_BODY") with title (system attribute "WELLSPRING_NOTIFY_TITLE")'
23
+
24
+ /** PowerShell 单引号字符串,内部单引号翻倍 */
25
+ function psQuote(value: string): string {
26
+ return `'${value.replace(/'/g, "''")}'`
27
+ }
28
+
29
+ function powershellToast(title: string, body: string): string[] {
30
+ const script = [
31
+ "$ErrorActionPreference = 'Stop'",
32
+ "[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null",
33
+ "$template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)",
34
+ '$texts = $template.GetElementsByTagName("text")',
35
+ `$texts.Item(0).AppendChild($template.CreateTextNode(${psQuote(title)})) > $null`,
36
+ `$texts.Item(1).AppendChild($template.CreateTextNode(${psQuote(body)})) > $null`,
37
+ "$toast = [Windows.UI.Notifications.ToastNotification]::new($template)",
38
+ '[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Wellspring").Show($toast)',
39
+ ].join("\n")
40
+ return powershellArgs(script)
41
+ }
42
+
43
+ function normalize(options: NotifyOptions): { title: string; body: string } {
44
+ const title = options.title.trim()
45
+ if (title === "") {
46
+ throw new Error("通知标题为空")
47
+ }
48
+ return { title, body: options.body ?? "" }
49
+ }
50
+
51
+ /** 生成候选命令,按优先级排列。单独导出以便在任意平台测试 */
52
+ export function buildNotifyCommands(
53
+ options: NotifyOptions,
54
+ targetPlatform: PlatformName = platform,
55
+ inWsl: boolean = isWsl,
56
+ ): NotifyCommand[] {
57
+ const { title, body } = normalize(options)
58
+
59
+ if (targetPlatform === "windows") {
60
+ return [{ command: "powershell", args: powershellToast(title, body) }]
61
+ }
62
+
63
+ if (targetPlatform === "macos") {
64
+ return [
65
+ {
66
+ command: "osascript",
67
+ args: ["-e", MACOS_SCRIPT],
68
+ env: { WELLSPRING_NOTIFY_TITLE: title, WELLSPRING_NOTIFY_BODY: body },
69
+ },
70
+ ]
71
+ }
72
+
73
+ if (targetPlatform === "android") {
74
+ const args = ["--title", title]
75
+ if (body !== "") {
76
+ args.push("--content", body)
77
+ }
78
+ return [{ command: "termux-notification", args }]
79
+ }
80
+
81
+ const candidates: NotifyCommand[] = []
82
+ if (inWsl) {
83
+ // WSL 没有桌面通知守护进程,转到 Windows 侧显示
84
+ candidates.push({ command: "powershell.exe", args: powershellToast(title, body) })
85
+ }
86
+ const args = ["-a", "wellspring", "--", title]
87
+ if (body !== "") {
88
+ args.push(body)
89
+ }
90
+ candidates.push({ command: "notify-send", args })
91
+ return candidates
92
+ }
93
+
94
+ /** 发送系统通知。全部候选失败时抛出聚合错误 */
95
+ export async function notify(options: NotifyOptions): Promise<void> {
96
+ const failures: string[] = []
97
+ for (const candidate of buildNotifyCommands(options)) {
98
+ try {
99
+ const env =
100
+ candidate.env === undefined ? undefined : { ...process.env, ...candidate.env }
101
+ await runCommand(candidate.command, candidate.args, { env })
102
+ return
103
+ } catch (error) {
104
+ failures.push(`${candidate.command}: ${describeError(error)}`)
105
+ }
106
+ }
107
+ throw new Error(`通知发送失败:${failures.join(";")}`)
108
+ }
@@ -0,0 +1,132 @@
1
+ /*
2
+ * 用系统默认程序打开 URL 或本地路径。
3
+ * target 可能来自外部输入,须校验:以 "-" 开头会被 open / cmd start 视为参数,协议限定白名单。
4
+ */
5
+
6
+ import { spawn } from "node:child_process"
7
+ import { isAbsolute } from "node:path"
8
+
9
+ import { describeError } from "./exec.ts"
10
+ import { isTermux, isWsl, platform, type PlatformName } from "./os.ts"
11
+
12
+ /** 候选启动命令 */
13
+ export interface OpenCommand {
14
+ readonly command: string
15
+ readonly args: readonly string[]
16
+ }
17
+
18
+ /** 允许的协议 */
19
+ const ALLOWED_PROTOCOLS = new Set(["http:", "https:", "file:"])
20
+
21
+ interface NormalizedTarget {
22
+ readonly target: string
23
+ readonly isUrl: boolean
24
+ }
25
+
26
+ /** 绝对路径原样返回;其余须为白名单协议 URL。不合法时抛出异常 */
27
+ function normalizeTarget(input: string): NormalizedTarget {
28
+ const target = input.trim()
29
+ if (target === "") {
30
+ throw new Error("打开目标为空值")
31
+ }
32
+ // 控制字符(含换行)会破坏命令行语义
33
+ if (/[\u0000-\u001f\u007f]/.test(target)) {
34
+ throw new Error("打开目标包含控制字符")
35
+ }
36
+ if (target.startsWith("-")) {
37
+ throw new Error(`打开目标不能以 "-" 开头:${target}`)
38
+ }
39
+ // 本地路径;Windows 的 "C:\\..." 亦归此类
40
+ if (isAbsolute(target)) {
41
+ return { target, isUrl: false }
42
+ }
43
+
44
+ let parsed: URL
45
+ try {
46
+ parsed = new URL(target)
47
+ } catch {
48
+ throw new Error(`目标既非绝对路径也非合法 URL:${target}`)
49
+ }
50
+ if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) {
51
+ throw new Error(`不允许的协议:${parsed.protocol}`)
52
+ }
53
+ return { target: parsed.href, isUrl: true }
54
+ }
55
+
56
+ /** 生成候选命令,按优先级排列。单独导出以便在任意平台测试各系统的构造结果 */
57
+ export function buildOpenCommands(
58
+ rawTarget: string,
59
+ targetPlatform: PlatformName = platform,
60
+ inWsl: boolean = isWsl,
61
+ inTermux: boolean = isTermux,
62
+ ): OpenCommand[] {
63
+ const { target, isUrl } = normalizeTarget(rawTarget)
64
+
65
+ if (targetPlatform === "windows") {
66
+ // 第二个参数为 start 的窗口标题占位;缺失时带引号的路径会被当作标题
67
+ return [{ command: "cmd", args: ["/c", "start", "", target] }]
68
+ }
69
+
70
+ if (targetPlatform === "macos") {
71
+ return [{ command: "open", args: [target] }]
72
+ }
73
+
74
+ if (targetPlatform === "android") {
75
+ const candidates: OpenCommand[] = []
76
+ if (inTermux) {
77
+ candidates.push({ command: "termux-open", args: [target] })
78
+ }
79
+ candidates.push({ command: "xdg-open", args: [target] })
80
+ // am 只能打开 URI,本地路径没有对应的 content:// 地址
81
+ if (isUrl) {
82
+ candidates.push({
83
+ command: "am",
84
+ args: ["start", "-a", "android.intent.action.VIEW", "-d", target],
85
+ })
86
+ }
87
+ return candidates
88
+ }
89
+
90
+ const candidates: OpenCommand[] = []
91
+ if (inWsl) {
92
+ // WSL 下 xdg-open 常无效,优先 wslview(wslu),其次 explorer.exe
93
+ candidates.push({ command: "wslview", args: [target] })
94
+ candidates.push({ command: "explorer.exe", args: [target] })
95
+ }
96
+ candidates.push({ command: "xdg-open", args: [target] })
97
+ candidates.push({ command: "gio", args: ["open", target] })
98
+ return candidates
99
+ }
100
+
101
+ function spawnDetached(command: string, args: readonly string[]): Promise<void> {
102
+ return new Promise<void>((resolve, reject) => {
103
+ const child = spawn(command, [...args], {
104
+ detached: true,
105
+ stdio: "ignore",
106
+ windowsHide: true,
107
+ })
108
+ child.once("error", reject)
109
+ child.once("spawn", () => {
110
+ // 不等待退出:浏览器与文件管理器均为长驻进程
111
+ child.unref()
112
+ resolve()
113
+ })
114
+ })
115
+ }
116
+
117
+ /** 依次尝试候选命令,全部失败时抛出聚合错误 */
118
+ export async function openExternal(rawTarget: string): Promise<void> {
119
+ const { target } = normalizeTarget(rawTarget)
120
+ const failures: string[] = []
121
+
122
+ for (const candidate of buildOpenCommands(target)) {
123
+ try {
124
+ await spawnDetached(candidate.command, candidate.args)
125
+ return
126
+ } catch (error) {
127
+ failures.push(`${candidate.command}: ${describeError(error)}`)
128
+ }
129
+ }
130
+
131
+ throw new Error(`无法打开 ${target}:已尝试 ${failures.join(";")}`)
132
+ }
@@ -0,0 +1,101 @@
1
+ /*
2
+ * 平台识别。
3
+ * 本模块是唯一读取 process.platform 的位置。
4
+ */
5
+
6
+ import { homedir } from "node:os"
7
+
8
+ /** 业务侧平台名,不使用 Node 的 win32 / darwin / linux 原始值 */
9
+ export type PlatformName = "windows" | "macos" | "linux" | "android"
10
+
11
+ /** Termux 等 Android 用户态 Node 报告 linux,用 Android 环境变量识别 */
12
+ function isAndroidEnv(env: NodeJS.ProcessEnv): boolean {
13
+ const has = (name: string): boolean => {
14
+ const value = env[name]
15
+ return value !== undefined && value.trim() !== ""
16
+ }
17
+ return has("ANDROID_ROOT") || has("ANDROID_DATA") || has("TERMUX_VERSION")
18
+ }
19
+
20
+ /** 平台归一化。参数可注入,供测试覆盖各平台 */
21
+ export function detectPlatform(
22
+ nodePlatform: NodeJS.Platform = process.platform,
23
+ env: NodeJS.ProcessEnv = process.env,
24
+ ): PlatformName {
25
+ switch (nodePlatform) {
26
+ case "win32":
27
+ return "windows"
28
+ case "darwin":
29
+ return "macos"
30
+ case "android":
31
+ return "android"
32
+ default:
33
+ return isAndroidEnv(env) ? "android" : "linux"
34
+ }
35
+ }
36
+
37
+ export const platform: PlatformName = detectPlatform()
38
+ export const isWindows: boolean = platform === "windows"
39
+ export const isMacOS: boolean = platform === "macos"
40
+ export const isLinux: boolean = platform === "linux"
41
+ export const isAndroid: boolean = platform === "android"
42
+ /** POSIX 权限与路径语义可用的平台,含 Android */
43
+ export const isPosix: boolean = platform !== "windows"
44
+
45
+ function detectWsl(): boolean {
46
+ if (platform !== "linux") {
47
+ return false
48
+ }
49
+ // WSL 会注入 WSL_DISTRO_NAME / WSL_INTEROP,该环境下调用外部程序的行为与原生 Linux 不同
50
+ return process.env["WSL_DISTRO_NAME"] !== undefined || process.env["WSL_INTEROP"] !== undefined
51
+ }
52
+
53
+ export const isWsl: boolean = detectWsl()
54
+
55
+ /** Android 上的 Termux 用户态 */
56
+ export const isTermux: boolean =
57
+ isAndroid &&
58
+ (readEnv("TERMUX_VERSION") !== undefined ||
59
+ (readEnv("PREFIX")?.includes("com.termux") ?? false))
60
+
61
+ /** 读取环境变量,空串按未设置处理。Windows 下变量名大小写不敏感 */
62
+ export function readEnv(name: string, env: NodeJS.ProcessEnv = process.env): string | undefined {
63
+ const direct = env[name]
64
+ if (direct !== undefined) {
65
+ const value = direct.trim()
66
+ return value === "" ? undefined : value
67
+ }
68
+ if (!isWindows) {
69
+ return undefined
70
+ }
71
+ // Windows 环境变量名不区分大小写
72
+ const lower = name.toLowerCase()
73
+ const key = Object.keys(env).find((item) => item.toLowerCase() === lower)
74
+ const value = key === undefined ? undefined : env[key]?.trim()
75
+ return value === undefined || value === "" ? undefined : value
76
+ }
77
+
78
+ /** HOME 优先,其次 USERPROFILE 与系统用户目录;Android 沙箱可能三者皆无 */
79
+ export function homeDir(env: NodeJS.ProcessEnv = process.env): string {
80
+ const fromEnv = readEnv("HOME", env) ?? readEnv("USERPROFILE", env)
81
+ if (fromEnv !== undefined) {
82
+ return fromEnv
83
+ }
84
+ try {
85
+ const home = homedir()
86
+ if (home !== "") {
87
+ return home
88
+ }
89
+ } catch {
90
+ // 无 passwd 条目时回落
91
+ }
92
+ return process.cwd()
93
+ }
94
+
95
+ /** Windows 可执行文件带 .exe 后缀 */
96
+ export function executableName(name: string): string {
97
+ if (!isWindows || name.toLowerCase().endsWith(".exe")) {
98
+ return name
99
+ }
100
+ return `${name}.exe`
101
+ }
@@ -0,0 +1,214 @@
1
+ /*
2
+ * 目录解析。
3
+ * 根目录:config(配置与凭据)、data(持久数据)、cache(可再生成)、log(日志)。
4
+ * 优先级:initPaths 显式覆盖 > WELLSPRING_*_DIR > WELLSPRING_HOME 便携模式 > 平台默认。
5
+ * 仅解析路径,不创建目录;创建见 file.ts 的 ensureDirs。
6
+ */
7
+
8
+ import { isAbsolute, join, normalize } from "node:path"
9
+
10
+ import { homeDir, platform, readEnv, type PlatformName } from "./os.ts"
11
+
12
+ /** 各平台统一使用的目录名 */
13
+ export const APP_DIR_NAME = "wellspring"
14
+
15
+ /** 四个根目录 */
16
+ export interface PathRoots {
17
+ readonly configDir: string
18
+ readonly dataDir: string
19
+ readonly cacheDir: string
20
+ readonly logDir: string
21
+ }
22
+
23
+ /** 显式覆盖,通常来自 CLI 参数。相对路径按当前工作目录解析 */
24
+ export interface PathOverrides {
25
+ readonly configDir?: string
26
+ readonly dataDir?: string
27
+ readonly cacheDir?: string
28
+ readonly logDir?: string
29
+ }
30
+
31
+ /** 取值来源,用于诊断 */
32
+ export type PathSource = "override" | "env" | "portable-home" | "os-default"
33
+
34
+ export interface ResolvedPaths extends PathRoots {
35
+ readonly sources: Readonly<Record<keyof PathRoots, PathSource>>
36
+ }
37
+
38
+ const ROOT_KEYS = ["configDir", "dataDir", "cacheDir", "logDir"] as const
39
+ type RootKey = (typeof ROOT_KEYS)[number]
40
+
41
+ const ENV_NAMES: Readonly<Record<RootKey, string>> = {
42
+ configDir: "WELLSPRING_CONFIG_DIR",
43
+ dataDir: "WELLSPRING_DATA_DIR",
44
+ cacheDir: "WELLSPRING_CACHE_DIR",
45
+ logDir: "WELLSPRING_LOG_DIR",
46
+ }
47
+
48
+ const ROOT_LABELS: Readonly<Record<RootKey, string>> = {
49
+ configDir: "config",
50
+ dataDir: "data",
51
+ cacheDir: "cache",
52
+ logDir: "log",
53
+ }
54
+
55
+ /** 是否 Termux 用户态:目录沿用 XDG,HOME 可用 */
56
+ function isTermuxEnv(env: NodeJS.ProcessEnv): boolean {
57
+ return (
58
+ readEnv("TERMUX_VERSION", env) !== undefined ||
59
+ (readEnv("PREFIX", env)?.includes("com.termux") ?? false)
60
+ )
61
+ }
62
+
63
+ function xdgRoots(env: NodeJS.ProcessEnv, home: string): PathRoots {
64
+ return {
65
+ configDir: join(readEnv("XDG_CONFIG_HOME", env) ?? join(home, ".config"), APP_DIR_NAME),
66
+ dataDir: join(readEnv("XDG_DATA_HOME", env) ?? join(home, ".local", "share"), APP_DIR_NAME),
67
+ cacheDir: join(readEnv("XDG_CACHE_HOME", env) ?? join(home, ".cache"), APP_DIR_NAME),
68
+ logDir: join(
69
+ readEnv("XDG_STATE_HOME", env) ?? join(home, ".local", "state"),
70
+ APP_DIR_NAME,
71
+ "logs",
72
+ ),
73
+ }
74
+ }
75
+
76
+ /*
77
+ * Android 应用沙箱:HOME 通常指向应用私有 files 目录。
78
+ * 未设置 HOME 时依赖 WELLSPRING_HOME;两者皆无则使用系统用户目录。
79
+ */
80
+ function androidAppRoots(env: NodeJS.ProcessEnv, home: string): PathRoots {
81
+ const base = readEnv("HOME", env) ?? home
82
+ return {
83
+ configDir: join(base, "config"),
84
+ dataDir: join(base, "data"),
85
+ cacheDir: join(base, "cache"),
86
+ logDir: join(base, "logs"),
87
+ }
88
+ }
89
+
90
+ /** 平台默认根目录。参数可注入,供测试覆盖各平台 */
91
+ export function defaultRoots(
92
+ platformName: PlatformName,
93
+ env: NodeJS.ProcessEnv,
94
+ home: string,
95
+ ): PathRoots {
96
+ switch (platformName) {
97
+ case "windows": {
98
+ const roaming = readEnv("APPDATA", env) ?? join(home, "AppData", "Roaming")
99
+ const local = readEnv("LOCALAPPDATA", env) ?? join(home, "AppData", "Local")
100
+ return {
101
+ configDir: join(roaming, APP_DIR_NAME),
102
+ dataDir: join(local, APP_DIR_NAME),
103
+ // Windows 无独立缓存目录约定,缓存与日志置于 data 下
104
+ cacheDir: join(local, APP_DIR_NAME, "cache"),
105
+ logDir: join(local, APP_DIR_NAME, "logs"),
106
+ }
107
+ }
108
+ case "macos": {
109
+ // macOS 惯例:配置与数据同放 Application Support,缓存与日志各自独立
110
+ const support = join(home, "Library", "Application Support", APP_DIR_NAME)
111
+ return {
112
+ configDir: support,
113
+ dataDir: support,
114
+ cacheDir: join(home, "Library", "Caches", APP_DIR_NAME),
115
+ logDir: join(home, "Library", "Logs", APP_DIR_NAME),
116
+ }
117
+ }
118
+ case "android":
119
+ return isTermuxEnv(env) ? xdgRoots(env, home) : androidAppRoots(env, home)
120
+ default:
121
+ return xdgRoots(env, home)
122
+ }
123
+ }
124
+
125
+ /** 便携模式:所有数据落在同一个根下 */
126
+ function portableRoots(home: string): PathRoots {
127
+ return {
128
+ configDir: join(home, "config"),
129
+ dataDir: join(home, "data"),
130
+ cacheDir: join(home, "cache"),
131
+ logDir: join(home, "logs"),
132
+ }
133
+ }
134
+
135
+ function expandTilde(input: string, env: NodeJS.ProcessEnv): string {
136
+ if (input === "~") {
137
+ return homeDir(env)
138
+ }
139
+ if (input.startsWith("~/") || input.startsWith("~\\")) {
140
+ return join(homeDir(env), input.slice(2))
141
+ }
142
+ return input
143
+ }
144
+
145
+ function toAbsolute(input: string, env: NodeJS.ProcessEnv): string {
146
+ const expanded = expandTilde(input, env)
147
+ return normalize(isAbsolute(expanded) ? expanded : join(process.cwd(), expanded))
148
+ }
149
+
150
+ let cached: ResolvedPaths | null = null
151
+
152
+ /** 解析并缓存。重复调用会按最新参数与环境变量重新解析 */
153
+ export function initPaths(
154
+ overrides: PathOverrides = {},
155
+ env: NodeJS.ProcessEnv = process.env,
156
+ ): ResolvedPaths {
157
+ const home = homeDir(env)
158
+ const portableHome = readEnv("WELLSPRING_HOME", env)
159
+ const defaults =
160
+ portableHome === undefined
161
+ ? defaultRoots(platform, env, home)
162
+ : portableRoots(toAbsolute(portableHome, env))
163
+ const baseSource: PathSource = portableHome === undefined ? "os-default" : "portable-home"
164
+
165
+ const roots: Record<RootKey, string> = {
166
+ configDir: "",
167
+ dataDir: "",
168
+ cacheDir: "",
169
+ logDir: "",
170
+ }
171
+ const sources: Record<RootKey, PathSource> = {
172
+ configDir: baseSource,
173
+ dataDir: baseSource,
174
+ cacheDir: baseSource,
175
+ logDir: baseSource,
176
+ }
177
+
178
+ for (const key of ROOT_KEYS) {
179
+ const override = overrides[key]
180
+ if (override !== undefined && override.trim() !== "") {
181
+ roots[key] = toAbsolute(override, env)
182
+ sources[key] = "override"
183
+ continue
184
+ }
185
+ const fromEnv = readEnv(ENV_NAMES[key], env)
186
+ if (fromEnv !== undefined) {
187
+ roots[key] = toAbsolute(fromEnv, env)
188
+ sources[key] = "env"
189
+ continue
190
+ }
191
+ roots[key] = defaults[key]
192
+ }
193
+
194
+ const resolved: ResolvedPaths = { ...roots, sources }
195
+ cached = resolved
196
+ return resolved
197
+ }
198
+
199
+ /** 取缓存结果,未解析时先解析一次 */
200
+ export function getPaths(): ResolvedPaths {
201
+ return cached ?? initPaths()
202
+ }
203
+
204
+ /** 清空缓存,供测试使用。下次 getPaths 重新读取环境变量 */
205
+ export function resetPaths(): void {
206
+ cached = null
207
+ }
208
+
209
+ /** 打印四个根目录及其来源,用于诊断 */
210
+ export function describePaths(roots: ResolvedPaths = getPaths()): string {
211
+ return ROOT_KEYS.map(
212
+ (key) => `${ROOT_LABELS[key].padEnd(7)} ${roots[key]} (${roots.sources[key]})`,
213
+ ).join("\n")
214
+ }
@@ -0,0 +1,46 @@
1
+ /*
2
+ * 插件访问守卫:插件加载/执行期间禁止直接 import 文件、进程等模块,
3
+ * 统一走宿主 API(api.fs / ctx.fs、api.logger 等)。
4
+ * 这是软隔离,无法阻止 plugin 通过 process.getBuiltinModule 等宿主逃逸。
5
+ */
6
+
7
+ import { registerHooks } from "node:module"
8
+
9
+ import { getHookOwner } from "../api/host/hooks.ts"
10
+
11
+ const BLOCKED = new Set([
12
+ "fs",
13
+ "node:fs",
14
+ "fs/promises",
15
+ "node:fs/promises",
16
+ "child_process",
17
+ "node:child_process",
18
+ "worker_threads",
19
+ "node:worker_threads",
20
+ "vm",
21
+ "node:vm",
22
+ "module",
23
+ "node:module",
24
+ "inspector",
25
+ "node:inspector",
26
+ ])
27
+
28
+ let installed = false
29
+
30
+ export function ensureAccessGuard(): void {
31
+ if (installed) {
32
+ return
33
+ }
34
+ installed = true
35
+ registerHooks({
36
+ resolve(specifier, context, nextResolve) {
37
+ const owner = getHookOwner()
38
+ if (owner !== null && BLOCKED.has(specifier)) {
39
+ throw new Error(
40
+ `插件 ${owner} 禁止直接访问 ${specifier},请使用 api.fs / ctx.fs 等宿主 API`,
41
+ )
42
+ }
43
+ return nextResolve(specifier, context)
44
+ },
45
+ })
46
+ }