@clinebot/core 0.0.33 → 0.0.35

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 (412) hide show
  1. package/README.md +12 -8
  2. package/dist/ClineCore.d.ts +48 -29
  3. package/dist/ClineCore.d.ts.map +1 -1
  4. package/dist/auth/client.d.ts +19 -0
  5. package/dist/auth/client.d.ts.map +1 -1
  6. package/dist/auth/cline.d.ts.map +1 -1
  7. package/dist/auth/oca.d.ts.map +1 -1
  8. package/dist/auth/server.d.ts +32 -0
  9. package/dist/auth/server.d.ts.map +1 -1
  10. package/dist/auth/types.d.ts +29 -0
  11. package/dist/auth/types.d.ts.map +1 -1
  12. package/dist/extensions/config/agent-config-loader.d.ts +2 -2
  13. package/dist/extensions/config/agent-config-loader.d.ts.map +1 -1
  14. package/dist/extensions/config/agent-config-parser.d.ts +1 -1
  15. package/dist/extensions/config/agent-config-parser.d.ts.map +1 -1
  16. package/dist/extensions/config/hooks-config-loader.d.ts +2 -2
  17. package/dist/extensions/config/hooks-config-loader.d.ts.map +1 -1
  18. package/dist/extensions/config/index.d.ts +3 -3
  19. package/dist/extensions/config/index.d.ts.map +1 -1
  20. package/dist/extensions/config/user-instruction-config-loader.d.ts +2 -2
  21. package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -1
  22. package/dist/extensions/index.d.ts +2 -1
  23. package/dist/extensions/index.d.ts.map +1 -1
  24. package/dist/extensions/plugin/plugin-config-loader.d.ts +2 -1
  25. package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -1
  26. package/dist/extensions/plugin/plugin-load-report.d.ts +19 -0
  27. package/dist/extensions/plugin/plugin-load-report.d.ts.map +1 -0
  28. package/dist/extensions/plugin/plugin-loader.d.ts +6 -0
  29. package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -1
  30. package/dist/extensions/plugin/plugin-sandbox.d.ts +2 -1
  31. package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -1
  32. package/dist/extensions/plugin-sandbox-bootstrap.js +242 -242
  33. package/dist/extensions/tools/constants.d.ts.map +1 -0
  34. package/dist/extensions/tools/definitions.d.ts.map +1 -0
  35. package/dist/extensions/tools/executors/apply-patch-parser.d.ts.map +1 -0
  36. package/dist/extensions/tools/executors/apply-patch.d.ts.map +1 -0
  37. package/dist/extensions/tools/executors/bash.d.ts.map +1 -0
  38. package/dist/extensions/tools/executors/editor.d.ts.map +1 -0
  39. package/dist/extensions/tools/executors/file-read.d.ts.map +1 -0
  40. package/dist/extensions/tools/executors/index.d.ts.map +1 -0
  41. package/dist/extensions/tools/executors/search.d.ts.map +1 -0
  42. package/dist/extensions/tools/executors/web-fetch.d.ts.map +1 -0
  43. package/dist/extensions/tools/helpers.d.ts.map +1 -0
  44. package/dist/extensions/tools/index.d.ts.map +1 -0
  45. package/dist/{tools → extensions/tools}/model-tool-routing.d.ts +1 -1
  46. package/dist/extensions/tools/model-tool-routing.d.ts.map +1 -0
  47. package/dist/{tools → extensions/tools}/presets.d.ts +1 -2
  48. package/dist/extensions/tools/presets.d.ts.map +1 -0
  49. package/dist/extensions/tools/schemas.d.ts.map +1 -0
  50. package/dist/extensions/tools/team/delegated-agent.d.ts.map +1 -0
  51. package/dist/extensions/tools/team/index.d.ts.map +1 -0
  52. package/dist/{team → extensions/tools/team}/multi-agent.d.ts +1 -3
  53. package/dist/extensions/tools/team/multi-agent.d.ts.map +1 -0
  54. package/dist/extensions/tools/team/projections.d.ts.map +1 -0
  55. package/dist/extensions/tools/team/runtime.d.ts.map +1 -0
  56. package/dist/{team → extensions/tools/team}/spawn-agent-tool.d.ts +0 -1
  57. package/dist/extensions/tools/team/spawn-agent-tool.d.ts.map +1 -0
  58. package/dist/extensions/tools/team/subagent-prompts.d.ts.map +1 -0
  59. package/dist/extensions/tools/team/team-tools.d.ts.map +1 -0
  60. package/dist/{tools → extensions/tools}/types.d.ts +4 -3
  61. package/dist/extensions/tools/types.d.ts.map +1 -0
  62. package/dist/{runtime → hooks}/checkpoint-hooks.d.ts +7 -0
  63. package/dist/hooks/checkpoint-hooks.d.ts.map +1 -0
  64. package/dist/{runtime → hooks}/hook-file-hooks.d.ts +0 -2
  65. package/dist/hooks/hook-file-hooks.d.ts.map +1 -0
  66. package/dist/hooks/subprocess.d.ts +3 -130
  67. package/dist/hooks/subprocess.d.ts.map +1 -1
  68. package/dist/index.d.ts +38 -35
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +386 -384
  71. package/dist/runtime/history.d.ts +4 -0
  72. package/dist/runtime/history.d.ts.map +1 -0
  73. package/dist/runtime/host.d.ts +9 -0
  74. package/dist/runtime/host.d.ts.map +1 -0
  75. package/dist/{session → runtime}/rpc-runtime-ensure.d.ts +13 -1
  76. package/dist/{session → runtime}/rpc-runtime-ensure.d.ts.map +1 -1
  77. package/dist/{session → runtime}/rpc-spawn-lease.d.ts.map +1 -1
  78. package/dist/runtime/runtime-builder.d.ts +1 -1
  79. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  80. package/dist/{session/session-manager.d.ts → runtime/runtime-host.d.ts} +55 -12
  81. package/dist/runtime/runtime-host.d.ts.map +1 -0
  82. package/dist/{session → runtime}/runtime-oauth-token-manager.d.ts +1 -1
  83. package/dist/{session → runtime}/runtime-oauth-token-manager.d.ts.map +1 -1
  84. package/dist/runtime/session-runtime.d.ts +2 -2
  85. package/dist/runtime/session-runtime.d.ts.map +1 -1
  86. package/dist/runtime/subprocess-sandbox.d.ts +2 -0
  87. package/dist/runtime/subprocess-sandbox.d.ts.map +1 -1
  88. package/dist/runtime/tool-approval.d.ts.map +1 -1
  89. package/dist/{session/session-agent-events.d.ts → services/agent-events.d.ts} +4 -4
  90. package/dist/services/agent-events.d.ts.map +1 -0
  91. package/dist/services/config.d.ts +3 -0
  92. package/dist/services/config.d.ts.map +1 -0
  93. package/dist/services/local-runtime-bootstrap.d.ts +41 -0
  94. package/dist/services/local-runtime-bootstrap.d.ts.map +1 -0
  95. package/dist/services/providers/local-provider-registry.d.ts.map +1 -0
  96. package/dist/services/providers/local-provider-service.d.ts.map +1 -0
  97. package/dist/{session → services}/session-artifacts.d.ts +2 -4
  98. package/dist/services/session-artifacts.d.ts.map +1 -0
  99. package/dist/{session/utils/helpers.d.ts → services/session-data.d.ts} +19 -27
  100. package/dist/services/session-data.d.ts.map +1 -0
  101. package/dist/{session → services}/session-telemetry.d.ts +2 -2
  102. package/dist/services/session-telemetry.d.ts.map +1 -0
  103. package/dist/{storage → services/storage}/file-team-store.d.ts +2 -2
  104. package/dist/services/storage/file-team-store.d.ts.map +1 -0
  105. package/dist/{storage → services/storage}/provider-settings-legacy-migration.d.ts +1 -1
  106. package/dist/services/storage/provider-settings-legacy-migration.d.ts.map +1 -0
  107. package/dist/{storage → services/storage}/provider-settings-manager.d.ts +1 -1
  108. package/dist/services/storage/provider-settings-manager.d.ts.map +1 -0
  109. package/dist/{storage → services/storage}/sqlite-session-store.d.ts +3 -3
  110. package/dist/services/storage/sqlite-session-store.d.ts.map +1 -0
  111. package/dist/{storage → services/storage}/sqlite-team-store.d.ts +2 -2
  112. package/dist/services/storage/sqlite-team-store.d.ts.map +1 -0
  113. package/dist/{storage → services/storage}/team-store.d.ts +1 -1
  114. package/dist/services/storage/team-store.d.ts.map +1 -0
  115. package/dist/services/telemetry/ITelemetryAdapter.d.ts.map +1 -0
  116. package/dist/services/telemetry/OpenTelemetryAdapter.d.ts.map +1 -0
  117. package/dist/services/telemetry/OpenTelemetryProvider.d.ts.map +1 -0
  118. package/dist/services/telemetry/TelemetryLoggerSink.d.ts.map +1 -0
  119. package/dist/services/telemetry/TelemetryService.d.ts.map +1 -0
  120. package/dist/services/telemetry/core-events.d.ts.map +1 -0
  121. package/dist/services/telemetry/distinct-id.d.ts.map +1 -0
  122. package/dist/services/telemetry/index.d.ts.map +1 -0
  123. package/dist/{telemetry → services/telemetry}/index.js +6 -6
  124. package/dist/{session/utils → services}/usage.d.ts +1 -1
  125. package/dist/services/usage.d.ts.map +1 -0
  126. package/dist/services/workspace/file-indexer.d.ts.map +1 -0
  127. package/dist/services/workspace/index.d.ts.map +1 -0
  128. package/dist/services/workspace/mention-enricher.d.ts.map +1 -0
  129. package/dist/services/workspace-manifest.d.ts.map +1 -0
  130. package/dist/session/file-session-service.d.ts +4 -1
  131. package/dist/session/file-session-service.d.ts.map +1 -1
  132. package/dist/session/persistence-service.d.ts +8 -6
  133. package/dist/session/persistence-service.d.ts.map +1 -1
  134. package/dist/session/rpc-session-service.d.ts +3 -0
  135. package/dist/session/rpc-session-service.d.ts.map +1 -1
  136. package/dist/session/session-service.d.ts +8 -9
  137. package/dist/session/session-service.d.ts.map +1 -1
  138. package/dist/session/session-team-coordination.d.ts +4 -4
  139. package/dist/session/session-team-coordination.d.ts.map +1 -1
  140. package/dist/session/sqlite-rpc-session-backend.d.ts.map +1 -1
  141. package/dist/{session/default-session-manager.d.ts → transports/local.d.ts} +24 -14
  142. package/dist/transports/local.d.ts.map +1 -0
  143. package/dist/transports/rpc.d.ts +51 -0
  144. package/dist/transports/rpc.d.ts.map +1 -0
  145. package/dist/transports/runtime-host-support.d.ts +21 -0
  146. package/dist/transports/runtime-host-support.d.ts.map +1 -0
  147. package/dist/types/chat-schema.d.ts.map +1 -0
  148. package/dist/types/config.d.ts +3 -2
  149. package/dist/types/config.d.ts.map +1 -1
  150. package/dist/{session/utils/types.d.ts → types/session.d.ts} +15 -6
  151. package/dist/types/session.d.ts.map +1 -0
  152. package/dist/types/sessions.d.ts +19 -0
  153. package/dist/types/sessions.d.ts.map +1 -1
  154. package/dist/types/storage.d.ts +1 -3
  155. package/dist/types/storage.d.ts.map +1 -1
  156. package/dist/types.d.ts +7 -6
  157. package/dist/types.d.ts.map +1 -1
  158. package/package.json +7 -12
  159. package/src/ClineCore.test.ts +95 -19
  160. package/src/ClineCore.ts +120 -50
  161. package/src/auth/client.test.ts +29 -0
  162. package/src/auth/client.ts +21 -0
  163. package/src/auth/cline.ts +3 -1
  164. package/src/auth/codex.ts +1 -1
  165. package/src/auth/oca.ts +3 -1
  166. package/src/auth/server.test.ts +287 -0
  167. package/src/auth/server.ts +50 -1
  168. package/src/auth/types.ts +29 -0
  169. package/src/extensions/config/agent-config-loader.test.ts +3 -3
  170. package/src/extensions/config/agent-config-loader.ts +1 -5
  171. package/src/extensions/config/agent-config-parser.ts +1 -1
  172. package/src/extensions/config/hooks-config-loader.ts +1 -2
  173. package/src/extensions/config/index.ts +0 -4
  174. package/src/extensions/config/user-instruction-config-loader.ts +0 -4
  175. package/src/extensions/index.ts +6 -0
  176. package/src/extensions/plugin/plugin-config-loader.test.ts +39 -0
  177. package/src/extensions/plugin/plugin-config-loader.ts +18 -10
  178. package/src/extensions/plugin/plugin-load-report.ts +20 -0
  179. package/src/extensions/plugin/plugin-loader.test.ts +45 -0
  180. package/src/extensions/plugin/plugin-loader.ts +57 -3
  181. package/src/extensions/plugin/plugin-sandbox-bootstrap.ts +158 -86
  182. package/src/extensions/plugin/plugin-sandbox.test.ts +70 -0
  183. package/src/extensions/plugin/plugin-sandbox.ts +17 -6
  184. package/src/{tools → extensions/tools}/definitions.ts +1 -1
  185. package/src/extensions/tools/executors/file-read.test.ts +125 -0
  186. package/src/{tools → extensions/tools}/executors/file-read.ts +29 -4
  187. package/src/{tools → extensions/tools}/executors/search.ts +1 -1
  188. package/src/{tools → extensions/tools}/model-tool-routing.ts +1 -1
  189. package/src/{tools → extensions/tools}/presets.ts +2 -3
  190. package/src/extensions/tools/team/multi-agent.lifecycle.test.ts +455 -0
  191. package/src/{team → extensions/tools/team}/multi-agent.ts +80 -17
  192. package/src/{team → extensions/tools/team}/spawn-agent-tool.test.ts +0 -6
  193. package/src/{team → extensions/tools/team}/spawn-agent-tool.ts +1 -7
  194. package/src/{team → extensions/tools/team}/subagent-prompts.ts +2 -2
  195. package/src/{team → extensions/tools/team}/team-tools.test.ts +146 -30
  196. package/src/{team → extensions/tools/team}/team-tools.ts +98 -69
  197. package/src/{tools → extensions/tools}/types.ts +5 -3
  198. package/src/{runtime → hooks}/checkpoint-hooks.ts +27 -0
  199. package/src/{runtime → hooks}/hook-file-hooks.test.ts +42 -7
  200. package/src/{runtime → hooks}/hook-file-hooks.ts +6 -11
  201. package/src/hooks/subprocess.ts +48 -257
  202. package/src/index.ts +178 -158
  203. package/src/runtime/history.test.ts +114 -0
  204. package/src/runtime/history.ts +237 -0
  205. package/src/runtime/host.test.ts +230 -0
  206. package/src/runtime/host.ts +362 -0
  207. package/src/runtime/rpc-runtime-ensure.test.ts +123 -0
  208. package/src/{session → runtime}/rpc-runtime-ensure.ts +165 -27
  209. package/src/{session → runtime}/rpc-spawn-lease.test.ts +33 -1
  210. package/src/{session → runtime}/rpc-spawn-lease.ts +54 -20
  211. package/src/runtime/runtime-builder.team-persistence.test.ts +6 -3
  212. package/src/runtime/runtime-builder.test.ts +101 -4
  213. package/src/runtime/runtime-builder.ts +125 -86
  214. package/src/runtime/runtime-host.ts +178 -0
  215. package/src/{session → runtime}/runtime-oauth-token-manager.ts +1 -1
  216. package/src/runtime/runtime-parity.test.ts +1 -1
  217. package/src/runtime/session-runtime.ts +2 -2
  218. package/src/runtime/subprocess-sandbox.ts +26 -23
  219. package/src/runtime/tool-approval.ts +13 -15
  220. package/src/{session/session-agent-events.ts → services/agent-events.ts} +7 -7
  221. package/src/services/config.ts +5 -0
  222. package/src/services/local-runtime-bootstrap.ts +280 -0
  223. package/src/{providers → services/providers}/local-provider-service.ts +4 -4
  224. package/src/{session → services}/session-artifacts.ts +23 -19
  225. package/src/{session/utils/helpers.test.ts → services/session-data.test.ts} +1 -1
  226. package/src/{session/utils/helpers.ts → services/session-data.ts} +76 -72
  227. package/src/{session → services}/session-telemetry.ts +7 -9
  228. package/src/services/storage/artifact-store.ts +1 -0
  229. package/src/{storage → services/storage}/file-team-store.ts +2 -2
  230. package/src/{storage → services/storage}/provider-settings-legacy-migration.test.ts +1 -1
  231. package/src/{storage → services/storage}/provider-settings-legacy-migration.ts +2 -2
  232. package/src/{storage → services/storage}/provider-settings-manager.ts +2 -2
  233. package/src/services/storage/session-store.ts +1 -0
  234. package/src/{storage → services/storage}/sqlite-session-store.ts +7 -12
  235. package/src/{storage → services/storage}/sqlite-team-store.ts +4 -4
  236. package/src/{storage → services/storage}/team-store.ts +1 -1
  237. package/src/{session/utils → services}/usage.ts +1 -1
  238. package/src/{input → services/workspace}/file-indexer.test.ts +30 -1
  239. package/src/{input → services/workspace}/file-indexer.ts +26 -2
  240. package/src/{input → services/workspace}/mention-enricher.test.ts +21 -0
  241. package/src/{input → services/workspace}/mention-enricher.ts +1 -1
  242. package/src/session/file-session-service.ts +9 -7
  243. package/src/session/index.ts +25 -17
  244. package/src/session/persistence-service.test.ts +121 -24
  245. package/src/session/persistence-service.ts +118 -102
  246. package/src/session/rpc-session-service.ts +9 -2
  247. package/src/session/session-service.team-persistence.test.ts +1 -1
  248. package/src/session/session-service.ts +32 -19
  249. package/src/session/session-team-coordination.ts +13 -6
  250. package/src/session/sqlite-rpc-session-backend.ts +4 -6
  251. package/src/session/workspace-manager.ts +1 -1
  252. package/src/{session/default-session-manager.e2e.test.ts → transports/local.e2e.test.ts} +13 -17
  253. package/src/{session/default-session-manager.test.ts → transports/local.test.ts} +316 -230
  254. package/src/{session/default-session-manager.ts → transports/local.ts} +138 -172
  255. package/src/transports/rpc.test.ts +82 -0
  256. package/src/transports/rpc.ts +665 -0
  257. package/src/transports/runtime-host-support.ts +86 -0
  258. package/src/types/config.ts +3 -2
  259. package/src/{session/utils/types.ts → types/session.ts} +18 -5
  260. package/src/types/sessions.ts +21 -0
  261. package/src/types/storage.ts +1 -6
  262. package/src/types.ts +25 -18
  263. package/dist/chat/chat-schema.d.ts.map +0 -1
  264. package/dist/input/file-indexer.d.ts.map +0 -1
  265. package/dist/input/index.d.ts.map +0 -1
  266. package/dist/input/mention-enricher.d.ts.map +0 -1
  267. package/dist/prompt/default-system.d.ts +0 -2
  268. package/dist/prompt/default-system.d.ts.map +0 -1
  269. package/dist/providers/local-provider-registry.d.ts.map +0 -1
  270. package/dist/providers/local-provider-service.d.ts.map +0 -1
  271. package/dist/runtime/checkpoint-hooks.d.ts.map +0 -1
  272. package/dist/runtime/hook-file-hooks.d.ts.map +0 -1
  273. package/dist/runtime/team-runtime-registry.d.ts +0 -13
  274. package/dist/runtime/team-runtime-registry.d.ts.map +0 -1
  275. package/dist/session/default-session-manager.d.ts.map +0 -1
  276. package/dist/session/session-agent-events.d.ts.map +0 -1
  277. package/dist/session/session-artifacts.d.ts.map +0 -1
  278. package/dist/session/session-config-builder.d.ts +0 -16
  279. package/dist/session/session-config-builder.d.ts.map +0 -1
  280. package/dist/session/session-host.d.ts +0 -15
  281. package/dist/session/session-host.d.ts.map +0 -1
  282. package/dist/session/session-manager.d.ts.map +0 -1
  283. package/dist/session/session-telemetry.d.ts.map +0 -1
  284. package/dist/session/utils/helpers.d.ts.map +0 -1
  285. package/dist/session/utils/types.d.ts.map +0 -1
  286. package/dist/session/utils/usage.d.ts.map +0 -1
  287. package/dist/session/workspace-manifest.d.ts.map +0 -1
  288. package/dist/storage/file-team-store.d.ts.map +0 -1
  289. package/dist/storage/provider-settings-legacy-migration.d.ts.map +0 -1
  290. package/dist/storage/provider-settings-manager.d.ts.map +0 -1
  291. package/dist/storage/sqlite-session-store.d.ts.map +0 -1
  292. package/dist/storage/sqlite-team-store.d.ts.map +0 -1
  293. package/dist/storage/team-store.d.ts.map +0 -1
  294. package/dist/team/delegated-agent.d.ts.map +0 -1
  295. package/dist/team/index.d.ts.map +0 -1
  296. package/dist/team/multi-agent.d.ts.map +0 -1
  297. package/dist/team/projections.d.ts.map +0 -1
  298. package/dist/team/runtime.d.ts.map +0 -1
  299. package/dist/team/spawn-agent-tool.d.ts.map +0 -1
  300. package/dist/team/subagent-prompts.d.ts.map +0 -1
  301. package/dist/team/team-tools.d.ts.map +0 -1
  302. package/dist/telemetry/ITelemetryAdapter.d.ts.map +0 -1
  303. package/dist/telemetry/OpenTelemetryAdapter.d.ts.map +0 -1
  304. package/dist/telemetry/OpenTelemetryProvider.d.ts.map +0 -1
  305. package/dist/telemetry/TelemetryLoggerSink.d.ts.map +0 -1
  306. package/dist/telemetry/TelemetryService.d.ts.map +0 -1
  307. package/dist/telemetry/core-events.d.ts.map +0 -1
  308. package/dist/telemetry/distinct-id.d.ts.map +0 -1
  309. package/dist/telemetry/index.d.ts.map +0 -1
  310. package/dist/tools/constants.d.ts.map +0 -1
  311. package/dist/tools/definitions.d.ts.map +0 -1
  312. package/dist/tools/executors/apply-patch-parser.d.ts.map +0 -1
  313. package/dist/tools/executors/apply-patch.d.ts.map +0 -1
  314. package/dist/tools/executors/bash.d.ts.map +0 -1
  315. package/dist/tools/executors/editor.d.ts.map +0 -1
  316. package/dist/tools/executors/file-read.d.ts.map +0 -1
  317. package/dist/tools/executors/index.d.ts.map +0 -1
  318. package/dist/tools/executors/search.d.ts.map +0 -1
  319. package/dist/tools/executors/web-fetch.d.ts.map +0 -1
  320. package/dist/tools/helpers.d.ts.map +0 -1
  321. package/dist/tools/index.d.ts.map +0 -1
  322. package/dist/tools/model-tool-routing.d.ts.map +0 -1
  323. package/dist/tools/presets.d.ts.map +0 -1
  324. package/dist/tools/schemas.d.ts.map +0 -1
  325. package/dist/tools/types.d.ts.map +0 -1
  326. package/src/prompt/default-system.ts +0 -21
  327. package/src/runtime/team-runtime-registry.ts +0 -43
  328. package/src/session/session-config-builder.ts +0 -126
  329. package/src/session/session-host.test.ts +0 -89
  330. package/src/session/session-host.ts +0 -213
  331. package/src/session/session-manager.ts +0 -74
  332. package/src/storage/artifact-store.ts +0 -1
  333. package/src/storage/session-store.ts +0 -1
  334. package/src/team/multi-agent.lifecycle.test.ts +0 -201
  335. package/src/tools/executors/file-read.test.ts +0 -49
  336. /package/dist/{tools → extensions/tools}/constants.d.ts +0 -0
  337. /package/dist/{tools → extensions/tools}/definitions.d.ts +0 -0
  338. /package/dist/{tools → extensions/tools}/executors/apply-patch-parser.d.ts +0 -0
  339. /package/dist/{tools → extensions/tools}/executors/apply-patch.d.ts +0 -0
  340. /package/dist/{tools → extensions/tools}/executors/bash.d.ts +0 -0
  341. /package/dist/{tools → extensions/tools}/executors/editor.d.ts +0 -0
  342. /package/dist/{tools → extensions/tools}/executors/file-read.d.ts +0 -0
  343. /package/dist/{tools → extensions/tools}/executors/index.d.ts +0 -0
  344. /package/dist/{tools → extensions/tools}/executors/search.d.ts +0 -0
  345. /package/dist/{tools → extensions/tools}/executors/web-fetch.d.ts +0 -0
  346. /package/dist/{tools → extensions/tools}/helpers.d.ts +0 -0
  347. /package/dist/{tools → extensions/tools}/index.d.ts +0 -0
  348. /package/dist/{tools → extensions/tools}/schemas.d.ts +0 -0
  349. /package/dist/{team → extensions/tools/team}/delegated-agent.d.ts +0 -0
  350. /package/dist/{team → extensions/tools/team}/index.d.ts +0 -0
  351. /package/dist/{team → extensions/tools/team}/projections.d.ts +0 -0
  352. /package/dist/{team → extensions/tools/team}/runtime.d.ts +0 -0
  353. /package/dist/{team → extensions/tools/team}/subagent-prompts.d.ts +0 -0
  354. /package/dist/{team → extensions/tools/team}/team-tools.d.ts +0 -0
  355. /package/dist/{session → runtime}/rpc-spawn-lease.d.ts +0 -0
  356. /package/dist/{providers → services/providers}/local-provider-registry.d.ts +0 -0
  357. /package/dist/{providers → services/providers}/local-provider-service.d.ts +0 -0
  358. /package/dist/{telemetry → services/telemetry}/ITelemetryAdapter.d.ts +0 -0
  359. /package/dist/{telemetry → services/telemetry}/OpenTelemetryAdapter.d.ts +0 -0
  360. /package/dist/{telemetry → services/telemetry}/OpenTelemetryProvider.d.ts +0 -0
  361. /package/dist/{telemetry → services/telemetry}/TelemetryLoggerSink.d.ts +0 -0
  362. /package/dist/{telemetry → services/telemetry}/TelemetryService.d.ts +0 -0
  363. /package/dist/{telemetry → services/telemetry}/core-events.d.ts +0 -0
  364. /package/dist/{telemetry → services/telemetry}/distinct-id.d.ts +0 -0
  365. /package/dist/{telemetry → services/telemetry}/index.d.ts +0 -0
  366. /package/dist/{input → services/workspace}/file-indexer.d.ts +0 -0
  367. /package/dist/{input → services/workspace}/index.d.ts +0 -0
  368. /package/dist/{input → services/workspace}/mention-enricher.d.ts +0 -0
  369. /package/dist/{session → services}/workspace-manifest.d.ts +0 -0
  370. /package/dist/{chat → types}/chat-schema.d.ts +0 -0
  371. /package/src/{tools → extensions/tools}/constants.ts +0 -0
  372. /package/src/{tools → extensions/tools}/definitions.test.ts +0 -0
  373. /package/src/{tools → extensions/tools}/executors/apply-patch-parser.ts +0 -0
  374. /package/src/{tools → extensions/tools}/executors/apply-patch.ts +0 -0
  375. /package/src/{tools → extensions/tools}/executors/bash.test.ts +0 -0
  376. /package/src/{tools → extensions/tools}/executors/bash.ts +0 -0
  377. /package/src/{tools → extensions/tools}/executors/editor.test.ts +0 -0
  378. /package/src/{tools → extensions/tools}/executors/editor.ts +0 -0
  379. /package/src/{tools → extensions/tools}/executors/index.ts +0 -0
  380. /package/src/{tools → extensions/tools}/executors/web-fetch.ts +0 -0
  381. /package/src/{tools → extensions/tools}/helpers.ts +0 -0
  382. /package/src/{tools → extensions/tools}/index.ts +0 -0
  383. /package/src/{tools → extensions/tools}/model-tool-routing.test.ts +0 -0
  384. /package/src/{tools → extensions/tools}/presets.test.ts +0 -0
  385. /package/src/{tools → extensions/tools}/schemas.ts +0 -0
  386. /package/src/{team → extensions/tools/team}/delegated-agent.ts +0 -0
  387. /package/src/{team → extensions/tools/team}/index.ts +0 -0
  388. /package/src/{team → extensions/tools/team}/projections.ts +0 -0
  389. /package/src/{team → extensions/tools/team}/runtime.ts +0 -0
  390. /package/src/{runtime → hooks}/checkpoint-hooks.test.ts +0 -0
  391. /package/src/{session → runtime}/runtime-oauth-token-manager.test.ts +0 -0
  392. /package/src/{providers → services/providers}/local-provider-registry.ts +0 -0
  393. /package/src/{providers → services/providers}/local-provider-service.test.ts +0 -0
  394. /package/src/{storage → services/storage}/index.ts +0 -0
  395. /package/src/{storage → services/storage}/provider-settings-manager.test.ts +0 -0
  396. /package/src/{telemetry → services/telemetry}/ITelemetryAdapter.ts +0 -0
  397. /package/src/{telemetry → services/telemetry}/OpenTelemetryAdapter.test.ts +0 -0
  398. /package/src/{telemetry → services/telemetry}/OpenTelemetryAdapter.ts +0 -0
  399. /package/src/{telemetry → services/telemetry}/OpenTelemetryProvider.test.ts +0 -0
  400. /package/src/{telemetry → services/telemetry}/OpenTelemetryProvider.ts +0 -0
  401. /package/src/{telemetry → services/telemetry}/TelemetryLoggerSink.test.ts +0 -0
  402. /package/src/{telemetry → services/telemetry}/TelemetryLoggerSink.ts +0 -0
  403. /package/src/{telemetry → services/telemetry}/TelemetryService.test.ts +0 -0
  404. /package/src/{telemetry → services/telemetry}/TelemetryService.ts +0 -0
  405. /package/src/{telemetry → services/telemetry}/core-events.ts +0 -0
  406. /package/src/{telemetry → services/telemetry}/distinct-id.test.ts +0 -0
  407. /package/src/{telemetry → services/telemetry}/distinct-id.ts +0 -0
  408. /package/src/{telemetry → services/telemetry}/index.ts +0 -0
  409. /package/src/{input → services/workspace}/file-indexer.d.ts +0 -0
  410. /package/src/{input → services/workspace}/index.ts +0 -0
  411. /package/src/{session → services}/workspace-manifest.ts +0 -0
  412. /package/src/{chat → types}/chat-schema.ts +0 -0
@@ -5,7 +5,8 @@ import {
5
5
  resolveConfiguredPluginModulePaths,
6
6
  resolvePluginConfigSearchPaths as resolvePluginConfigSearchPathsFromShared,
7
7
  } from "@clinebot/shared/storage";
8
- import { loadAgentPluginsFromPaths } from "./plugin-loader";
8
+ import type { PluginLoadDiagnostics } from "./plugin-load-report";
9
+ import { loadAgentPluginsFromPathsWithDiagnostics } from "./plugin-loader";
9
10
  import { loadSandboxedPlugins } from "./plugin-sandbox";
10
11
 
11
12
  type AgentPlugin = NonNullable<AgentConfig["extensions"]>[number];
@@ -64,21 +65,26 @@ export interface ResolveAndLoadAgentPluginsOptions
64
65
 
65
66
  export async function resolveAndLoadAgentPlugins(
66
67
  options: ResolveAndLoadAgentPluginsOptions = {},
67
- ): Promise<{
68
- extensions: AgentPlugin[];
69
- shutdown?: () => Promise<void>;
70
- }> {
68
+ ): Promise<
69
+ {
70
+ extensions: AgentPlugin[];
71
+ shutdown?: () => Promise<void>;
72
+ } & PluginLoadDiagnostics
73
+ > {
71
74
  const paths = resolveAgentPluginPaths(options);
72
75
  if (paths.length === 0) {
73
- return { extensions: [] };
76
+ return { extensions: [], failures: [], warnings: [] };
74
77
  }
75
78
 
76
79
  if (options.mode === "in_process") {
80
+ const report = await loadAgentPluginsFromPathsWithDiagnostics(paths, {
81
+ cwd: options.cwd,
82
+ exportName: options.exportName,
83
+ });
77
84
  return {
78
- extensions: await loadAgentPluginsFromPaths(paths, {
79
- cwd: options.cwd,
80
- exportName: options.exportName,
81
- }),
85
+ extensions: report.plugins,
86
+ failures: report.failures,
87
+ warnings: report.warnings,
82
88
  };
83
89
  }
84
90
 
@@ -93,5 +99,7 @@ export async function resolveAndLoadAgentPlugins(
93
99
  return {
94
100
  extensions: sandboxed.extensions ?? [],
95
101
  shutdown: sandboxed.shutdown,
102
+ failures: sandboxed.failures,
103
+ warnings: sandboxed.warnings,
96
104
  };
97
105
  }
@@ -0,0 +1,20 @@
1
+ export interface PluginInitializationFailure {
2
+ pluginPath: string;
3
+ pluginName?: string;
4
+ phase: "load" | "setup";
5
+ message: string;
6
+ stack?: string;
7
+ }
8
+
9
+ export interface PluginInitializationWarning {
10
+ type: "duplicate_plugin_override";
11
+ pluginPath: string;
12
+ pluginName: string;
13
+ overriddenPluginPath: string;
14
+ message: string;
15
+ }
16
+
17
+ export interface PluginLoadDiagnostics {
18
+ failures: PluginInitializationFailure[];
19
+ warnings: PluginInitializationWarning[];
20
+ }
@@ -5,6 +5,7 @@ import { afterAll, beforeAll, describe, expect, it } from "vitest";
5
5
  import {
6
6
  loadAgentPluginFromPath,
7
7
  loadAgentPluginsFromPaths,
8
+ loadAgentPluginsFromPathsWithDiagnostics,
8
9
  } from "./plugin-loader";
9
10
 
10
11
  describe("plugin-loader", () => {
@@ -158,6 +159,17 @@ describe("plugin-loader", () => {
158
159
  "export default { name: 'invalid-plugin' };",
159
160
  "utf8",
160
161
  );
162
+
163
+ await writeFile(
164
+ join(dir, "duplicate-one.mjs"),
165
+ "export default { name: 'duplicate-plugin', manifest: { capabilities: ['tools'] } };",
166
+ "utf8",
167
+ );
168
+ await writeFile(
169
+ join(dir, "duplicate-two.mjs"),
170
+ "export default { name: 'duplicate-plugin', manifest: { capabilities: ['commands'] } };",
171
+ "utf8",
172
+ );
161
173
  });
162
174
 
163
175
  afterAll(async () => {
@@ -244,4 +256,37 @@ describe("plugin-loader", () => {
244
256
  loadAgentPluginFromPath(join(dir, "invalid-plugin.mjs")),
245
257
  ).rejects.toThrow(/missing required "manifest"/i);
246
258
  });
259
+
260
+ it("continues loading valid plugins when one plugin fails", async () => {
261
+ const report = await loadAgentPluginsFromPathsWithDiagnostics([
262
+ join(dir, "plugin-a.mjs"),
263
+ join(dir, "invalid-plugin.mjs"),
264
+ join(dir, "plugin-b.mjs"),
265
+ ]);
266
+
267
+ expect(report.plugins.map((plugin) => plugin.name)).toEqual([
268
+ "plugin-a",
269
+ "plugin-b",
270
+ ]);
271
+ expect(report.failures).toHaveLength(1);
272
+ expect(report.failures[0]?.pluginPath).toBe(
273
+ join(dir, "invalid-plugin.mjs"),
274
+ );
275
+ expect(report.warnings).toEqual([]);
276
+ });
277
+
278
+ it("keeps the later duplicate plugin and reports the override", async () => {
279
+ const report = await loadAgentPluginsFromPathsWithDiagnostics([
280
+ join(dir, "duplicate-one.mjs"),
281
+ join(dir, "duplicate-two.mjs"),
282
+ ]);
283
+
284
+ expect(report.plugins).toHaveLength(1);
285
+ expect(report.plugins[0]?.name).toBe("duplicate-plugin");
286
+ expect(report.plugins[0]?.manifest.capabilities).toEqual(["commands"]);
287
+ expect(report.warnings).toHaveLength(1);
288
+ expect(report.warnings[0]?.overriddenPluginPath).toBe(
289
+ join(dir, "duplicate-one.mjs"),
290
+ );
291
+ });
247
292
  });
@@ -1,5 +1,9 @@
1
1
  import { resolve } from "node:path";
2
2
  import type { AgentConfig } from "@clinebot/shared";
3
+ import type {
4
+ PluginInitializationFailure,
5
+ PluginInitializationWarning,
6
+ } from "./plugin-load-report";
3
7
  import { importPluginModule } from "./plugin-module-import";
4
8
 
5
9
  type AgentPlugin = NonNullable<AgentConfig["extensions"]>[number];
@@ -98,9 +102,59 @@ export async function loadAgentPluginsFromPaths(
98
102
  pluginPaths: string[],
99
103
  options: LoadAgentPluginFromPathOptions = {},
100
104
  ): Promise<AgentPlugin[]> {
101
- const loaded: AgentPlugin[] = [];
105
+ const report = await loadAgentPluginsFromPathsWithDiagnostics(
106
+ pluginPaths,
107
+ options,
108
+ );
109
+ return report.plugins;
110
+ }
111
+
112
+ export async function loadAgentPluginsFromPathsWithDiagnostics(
113
+ pluginPaths: string[],
114
+ options: LoadAgentPluginFromPathOptions = {},
115
+ ): Promise<{
116
+ plugins: AgentPlugin[];
117
+ failures: PluginInitializationFailure[];
118
+ warnings: PluginInitializationWarning[];
119
+ }> {
120
+ const failures: PluginInitializationFailure[] = [];
121
+ const warnings: PluginInitializationWarning[] = [];
122
+ const loadedByName = new Map<
123
+ string,
124
+ { plugin: AgentPlugin; pluginPath: string; order: number }
125
+ >();
126
+ let order = 0;
127
+
102
128
  for (const pluginPath of pluginPaths) {
103
- loaded.push(await loadAgentPluginFromPath(pluginPath, options));
129
+ try {
130
+ const plugin = await loadAgentPluginFromPath(pluginPath, options);
131
+ const existing = loadedByName.get(plugin.name);
132
+ if (existing) {
133
+ warnings.push({
134
+ type: "duplicate_plugin_override",
135
+ pluginName: plugin.name,
136
+ pluginPath,
137
+ overriddenPluginPath: existing.pluginPath,
138
+ message: `Plugin "${plugin.name}" from ${pluginPath} overrides ${existing.pluginPath}`,
139
+ });
140
+ }
141
+ loadedByName.set(plugin.name, { plugin, pluginPath, order: order++ });
142
+ } catch (error) {
143
+ const message = error instanceof Error ? error.message : String(error);
144
+ failures.push({
145
+ pluginPath,
146
+ phase: "load",
147
+ message,
148
+ stack: error instanceof Error ? error.stack : undefined,
149
+ });
150
+ }
104
151
  }
105
- return loaded;
152
+
153
+ return {
154
+ plugins: [...loadedByName.values()]
155
+ .sort((left, right) => left.order - right.order)
156
+ .map((entry) => entry.plugin),
157
+ failures,
158
+ warnings,
159
+ };
106
160
  }
@@ -84,6 +84,7 @@ interface ContributionDescriptor {
84
84
 
85
85
  interface PluginDescriptor {
86
86
  pluginId: string;
87
+ pluginPath: string;
87
88
  name: string;
88
89
  manifest: Record<string, unknown>;
89
90
  contributions: {
@@ -96,6 +97,28 @@ interface PluginDescriptor {
96
97
  };
97
98
  }
98
99
 
100
+ interface PluginInitializationFailure {
101
+ pluginPath: string;
102
+ pluginName?: string;
103
+ phase: "load" | "setup";
104
+ message: string;
105
+ stack?: string;
106
+ }
107
+
108
+ interface PluginInitializationWarning {
109
+ type: "duplicate_plugin_override";
110
+ pluginPath: string;
111
+ pluginName: string;
112
+ overriddenPluginPath: string;
113
+ message: string;
114
+ }
115
+
116
+ interface InitializeResult {
117
+ plugins: PluginDescriptor[];
118
+ failures: PluginInitializationFailure[];
119
+ warnings: PluginInitializationWarning[];
120
+ }
121
+
99
122
  interface PluginState {
100
123
  plugin: PluginModule;
101
124
  handlers: {
@@ -191,104 +214,153 @@ function getPlugin(pluginId: string): PluginState {
191
214
  async function initialize(args: {
192
215
  pluginPaths?: string[];
193
216
  exportName?: string;
194
- }): Promise<PluginDescriptor[]> {
217
+ }): Promise<InitializeResult> {
195
218
  pluginState.clear();
196
219
  pluginCounter = 0;
197
220
  contributionCounters.clear();
198
221
 
199
222
  const descriptors: PluginDescriptor[] = [];
223
+ const failures: PluginInitializationFailure[] = [];
224
+ const warnings: PluginInitializationWarning[] = [];
200
225
  const exportName = args.exportName || "plugin";
226
+ const pluginIndexByName = new Map<string, number>();
201
227
 
202
228
  for (const pluginPath of args.pluginPaths || []) {
203
- const moduleExports = await importPluginModule(pluginPath);
204
- const plugin = (moduleExports.default ??
205
- moduleExports[exportName]) as unknown;
206
- assertValidPluginModule(plugin, pluginPath);
207
-
208
- const pluginId = `plugin_${++pluginCounter}`;
209
- const contributions: PluginDescriptor["contributions"] = {
210
- tools: [],
211
- commands: [],
212
- shortcuts: [],
213
- flags: [],
214
- messageBuilders: [],
215
- providers: [],
216
- };
217
- const handlers: PluginState["handlers"] = {
218
- tools: new Map(),
219
- commands: new Map(),
220
- messageBuilders: new Map(),
221
- };
222
-
223
- const api: PluginApi = {
224
- registerTool: (tool) => {
225
- const id = makeId(pluginId, "tool");
226
- handlers.tools.set(id, tool.execute);
227
- contributions.tools.push({
228
- id,
229
- name: tool.name,
230
- description: tool.description,
231
- inputSchema: tool.inputSchema,
232
- timeoutMs: tool.timeoutMs,
233
- retryable: tool.retryable,
234
- });
235
- },
236
- registerCommand: (command) => {
237
- const id = makeId(pluginId, "command");
238
- if (typeof command.handler === "function") {
239
- handlers.commands.set(id, command.handler);
229
+ let plugin: PluginModule | undefined;
230
+ try {
231
+ const moduleExports = await importPluginModule(pluginPath);
232
+ plugin = (moduleExports.default ??
233
+ moduleExports[exportName]) as unknown as PluginModule;
234
+ assertValidPluginModule(plugin, pluginPath);
235
+
236
+ const pluginId = `plugin_${++pluginCounter}`;
237
+ const contributions: PluginDescriptor["contributions"] = {
238
+ tools: [],
239
+ commands: [],
240
+ shortcuts: [],
241
+ flags: [],
242
+ messageBuilders: [],
243
+ providers: [],
244
+ };
245
+ const handlers: PluginState["handlers"] = {
246
+ tools: new Map(),
247
+ commands: new Map(),
248
+ messageBuilders: new Map(),
249
+ };
250
+
251
+ const api: PluginApi = {
252
+ registerTool: (tool) => {
253
+ const id = makeId(pluginId, "tool");
254
+ handlers.tools.set(id, tool.execute);
255
+ contributions.tools.push({
256
+ id,
257
+ name: tool.name,
258
+ description: tool.description,
259
+ inputSchema: tool.inputSchema,
260
+ timeoutMs: tool.timeoutMs,
261
+ retryable: tool.retryable,
262
+ });
263
+ },
264
+ registerCommand: (command) => {
265
+ const id = makeId(pluginId, "command");
266
+ if (typeof command.handler === "function") {
267
+ handlers.commands.set(id, command.handler);
268
+ }
269
+ contributions.commands.push({
270
+ id,
271
+ name: command.name,
272
+ description: command.description,
273
+ });
274
+ },
275
+ registerShortcut: (shortcut) => {
276
+ contributions.shortcuts.push({
277
+ id: makeId(pluginId, "shortcut"),
278
+ name: shortcut.name,
279
+ value: shortcut.value,
280
+ description: shortcut.description,
281
+ });
282
+ },
283
+ registerFlag: (flag) => {
284
+ contributions.flags.push({
285
+ id: makeId(pluginId, "flag"),
286
+ name: flag.name,
287
+ description: flag.description,
288
+ defaultValue: flag.defaultValue,
289
+ });
290
+ },
291
+ registerMessageBuilder: (builder) => {
292
+ const id = makeId(pluginId, "builder");
293
+ handlers.messageBuilders.set(id, builder.build);
294
+ contributions.messageBuilders.push({ id, name: builder.name });
295
+ },
296
+ registerProvider: (provider) => {
297
+ contributions.providers.push({
298
+ id: makeId(pluginId, "provider"),
299
+ name: provider.name,
300
+ description: provider.description,
301
+ metadata: sanitizeObject(provider.metadata),
302
+ });
303
+ },
304
+ };
305
+
306
+ if (typeof plugin.setup === "function") {
307
+ try {
308
+ await plugin.setup(api);
309
+ } catch (error) {
310
+ failures.push({
311
+ pluginPath,
312
+ pluginName: plugin.name,
313
+ phase: "setup",
314
+ message: error instanceof Error ? error.message : String(error),
315
+ stack: error instanceof Error ? error.stack : undefined,
316
+ });
317
+ continue;
318
+ }
319
+ }
320
+
321
+ const previousIndex = pluginIndexByName.get(plugin.name);
322
+ if (previousIndex !== undefined) {
323
+ const previous = descriptors[previousIndex];
324
+ if (!previous) {
325
+ pluginIndexByName.delete(plugin.name);
326
+ } else {
327
+ warnings.push({
328
+ type: "duplicate_plugin_override",
329
+ pluginName: plugin.name,
330
+ pluginPath,
331
+ overriddenPluginPath: previous.pluginPath,
332
+ message: `Plugin "${plugin.name}" from ${pluginPath} overrides ${previous.pluginPath}`,
333
+ });
334
+ pluginState.delete(previous.pluginId);
335
+ descriptors.splice(previousIndex, 1);
336
+ pluginIndexByName.clear();
337
+ for (const [index, descriptor] of descriptors.entries()) {
338
+ pluginIndexByName.set(descriptor.name, index);
339
+ }
240
340
  }
241
- contributions.commands.push({
242
- id,
243
- name: command.name,
244
- description: command.description,
245
- });
246
- },
247
- registerShortcut: (shortcut) => {
248
- contributions.shortcuts.push({
249
- id: makeId(pluginId, "shortcut"),
250
- name: shortcut.name,
251
- value: shortcut.value,
252
- description: shortcut.description,
253
- });
254
- },
255
- registerFlag: (flag) => {
256
- contributions.flags.push({
257
- id: makeId(pluginId, "flag"),
258
- name: flag.name,
259
- description: flag.description,
260
- defaultValue: flag.defaultValue,
261
- });
262
- },
263
- registerMessageBuilder: (builder) => {
264
- const id = makeId(pluginId, "builder");
265
- handlers.messageBuilders.set(id, builder.build);
266
- contributions.messageBuilders.push({ id, name: builder.name });
267
- },
268
- registerProvider: (provider) => {
269
- contributions.providers.push({
270
- id: makeId(pluginId, "provider"),
271
- name: provider.name,
272
- description: provider.description,
273
- metadata: sanitizeObject(provider.metadata),
274
- });
275
- },
276
- };
277
-
278
- if (typeof plugin.setup === "function") {
279
- await plugin.setup(api);
341
+ }
342
+
343
+ pluginState.set(pluginId, { plugin, handlers });
344
+ pluginIndexByName.set(plugin.name, descriptors.length);
345
+ descriptors.push({
346
+ pluginId,
347
+ pluginPath,
348
+ name: plugin.name,
349
+ manifest: plugin.manifest,
350
+ contributions,
351
+ });
352
+ } catch (error) {
353
+ failures.push({
354
+ pluginPath,
355
+ pluginName: plugin?.name,
356
+ phase: "load",
357
+ message: error instanceof Error ? error.message : String(error),
358
+ stack: error instanceof Error ? error.stack : undefined,
359
+ });
280
360
  }
281
-
282
- pluginState.set(pluginId, { plugin, handlers });
283
- descriptors.push({
284
- pluginId,
285
- name: plugin.name,
286
- manifest: plugin.manifest,
287
- contributions,
288
- });
289
361
  }
290
362
 
291
- return descriptors;
363
+ return { plugins: descriptors, failures, warnings };
292
364
  }
293
365
 
294
366
  async function invokeHook(args: {
@@ -184,6 +184,31 @@ describe("plugin-sandbox", () => {
184
184
  "utf8",
185
185
  );
186
186
 
187
+ await writeFile(
188
+ join(dir, "plugin-broken-setup.mjs"),
189
+ [
190
+ "export default {",
191
+ " name: 'sandbox-broken-setup',",
192
+ " manifest: { capabilities: ['tools'] },",
193
+ " async setup() {",
194
+ " throw new Error('broken setup');",
195
+ " },",
196
+ "};",
197
+ ].join("\n"),
198
+ "utf8",
199
+ );
200
+
201
+ await writeFile(
202
+ join(dir, "plugin-duplicate-a.mjs"),
203
+ "export default { name: 'sandbox-duplicate', manifest: { capabilities: ['tools'] } };",
204
+ "utf8",
205
+ );
206
+ await writeFile(
207
+ join(dir, "plugin-duplicate-b.mjs"),
208
+ "export default { name: 'sandbox-duplicate', manifest: { capabilities: ['commands'] } };",
209
+ "utf8",
210
+ );
211
+
187
212
  sharedSandbox = await loadSandboxedPlugins({
188
213
  pluginPaths: [
189
214
  join(dir, "plugin.mjs"),
@@ -321,6 +346,51 @@ describe("plugin-sandbox", () => {
321
346
  expect(result).toEqual({ echoed: "ok" });
322
347
  });
323
348
 
349
+ it("continues loading remaining sandbox plugins when one setup fails", async () => {
350
+ const sandboxed = await loadSandboxedPlugins({
351
+ pluginPaths: [
352
+ join(dir, "plugin.mjs"),
353
+ join(dir, "plugin-broken-setup.mjs"),
354
+ join(dir, "plugin-events.mjs"),
355
+ ],
356
+ });
357
+
358
+ try {
359
+ expect(sandboxed.extensions?.map((extension) => extension.name)).toEqual([
360
+ "sandbox-test",
361
+ "sandbox-events",
362
+ ]);
363
+ expect(sandboxed.failures).toHaveLength(1);
364
+ expect(sandboxed.failures[0]?.pluginName).toBe("sandbox-broken-setup");
365
+ expect(sandboxed.failures[0]?.phase).toBe("setup");
366
+ } finally {
367
+ await sandboxed.shutdown();
368
+ }
369
+ });
370
+
371
+ it("keeps the later duplicate sandbox plugin and reports the override", async () => {
372
+ const sandboxed = await loadSandboxedPlugins({
373
+ pluginPaths: [
374
+ join(dir, "plugin-duplicate-a.mjs"),
375
+ join(dir, "plugin-duplicate-b.mjs"),
376
+ ],
377
+ });
378
+
379
+ try {
380
+ expect(sandboxed.extensions).toHaveLength(1);
381
+ expect(sandboxed.extensions?.[0]?.name).toBe("sandbox-duplicate");
382
+ expect(sandboxed.extensions?.[0]?.manifest.capabilities).toEqual([
383
+ "commands",
384
+ ]);
385
+ expect(sandboxed.warnings).toHaveLength(1);
386
+ expect(sandboxed.warnings[0]?.overriddenPluginPath).toBe(
387
+ join(dir, "plugin-duplicate-a.mjs"),
388
+ );
389
+ } finally {
390
+ await sandboxed.shutdown();
391
+ }
392
+ });
393
+
324
394
  it("resolves plugin-local dependencies in the sandbox process", async () => {
325
395
  expect(sharedExtensions.get("sandbox-local-dep")?.name).toBe(
326
396
  "sandbox-local-dep",
@@ -4,6 +4,7 @@ import { dirname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import type { AgentConfig, HookStage, Tool } from "@clinebot/shared";
6
6
  import { SubprocessSandbox } from "../../runtime/subprocess-sandbox";
7
+ import type { PluginLoadDiagnostics } from "./plugin-load-report";
7
8
 
8
9
  export interface PluginSandboxOptions {
9
10
  pluginPaths: string[];
@@ -31,6 +32,7 @@ type SandboxedContributionDescriptor = {
31
32
 
32
33
  type SandboxedPluginDescriptor = {
33
34
  pluginId: string;
35
+ pluginPath: string;
34
36
  name: string;
35
37
  manifest: AgentExtension["manifest"];
36
38
  contributions: {
@@ -43,6 +45,10 @@ type SandboxedPluginDescriptor = {
43
45
  };
44
46
  };
45
47
 
48
+ type SandboxedInitializeResult = {
49
+ plugins: SandboxedPluginDescriptor[];
50
+ } & PluginLoadDiagnostics;
51
+
46
52
  function isUnknownPluginIdError(error: unknown): boolean {
47
53
  const message = error instanceof Error ? error.message : String(error);
48
54
  return message.includes("Unknown sandbox plugin id:");
@@ -153,10 +159,12 @@ function withTimeoutFallback(
153
159
 
154
160
  export async function loadSandboxedPlugins(
155
161
  options: PluginSandboxOptions,
156
- ): Promise<{
157
- extensions: AgentConfig["extensions"];
158
- shutdown: () => Promise<void>;
159
- }> {
162
+ ): Promise<
163
+ {
164
+ extensions: AgentConfig["extensions"];
165
+ shutdown: () => Promise<void>;
166
+ } & PluginLoadDiagnostics
167
+ > {
160
168
  const sandbox = new SubprocessSandbox({
161
169
  name: "plugin-sandbox",
162
170
  ...("file" in BOOTSTRAP
@@ -187,9 +195,9 @@ export async function loadSandboxedPlugins(
187
195
  return reinitPromise;
188
196
  };
189
197
 
190
- let descriptors: SandboxedPluginDescriptor[];
198
+ let initialized: SandboxedInitializeResult;
191
199
  try {
192
- descriptors = await sandbox.call<SandboxedPluginDescriptor[]>(
200
+ initialized = await sandbox.call<SandboxedInitializeResult>(
193
201
  "initialize",
194
202
  initArgs,
195
203
  { timeoutMs: importTimeoutMs },
@@ -200,6 +208,7 @@ export async function loadSandboxedPlugins(
200
208
  });
201
209
  throw error;
202
210
  }
211
+ const descriptors = initialized.plugins;
203
212
 
204
213
  const extensions: NonNullable<AgentConfig["extensions"]> = descriptors.map(
205
214
  (descriptor) => {
@@ -239,9 +248,11 @@ export async function loadSandboxedPlugins(
239
248
 
240
249
  return {
241
250
  extensions,
251
+ failures: initialized.failures,
242
252
  shutdown: async () => {
243
253
  await sandbox.shutdown();
244
254
  },
255
+ warnings: initialized.warnings,
245
256
  };
246
257
  }
247
258
 
@@ -81,7 +81,7 @@ export function createReadFilesTool(
81
81
  return createTool<ReadFilesInput, ToolOperationResult[]>({
82
82
  name: "read_files",
83
83
  description:
84
- "Read the full content of text files at the provided absolute paths, or return only an inclusive one-based line range when start_line/end_line are provided. " +
84
+ "Read the full content of text or image files at the provided absolute paths, or return only an inclusive one-based line range when start_line/end_line are provided. " +
85
85
  "Returns file contents or error messages for each path.",
86
86
  inputSchema: zodToJsonSchema(ReadFilesInputSchema),
87
87
  timeoutMs: timeoutMs * 2, // Account for multiple files