@clinebot/core 0.0.27 → 0.0.29

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 (339) hide show
  1. package/README.md +7 -0
  2. package/dist/ClineCore.d.ts +28 -2
  3. package/dist/ClineCore.d.ts.map +1 -1
  4. package/dist/account/cline-account-service.d.ts +1 -1
  5. package/dist/account/cline-account-service.d.ts.map +1 -1
  6. package/dist/account/index.d.ts +1 -1
  7. package/dist/account/index.d.ts.map +1 -1
  8. package/dist/account/types.d.ts +5 -0
  9. package/dist/account/types.d.ts.map +1 -1
  10. package/dist/auth/bounded-ttl-cache.d.ts +14 -0
  11. package/dist/auth/bounded-ttl-cache.d.ts.map +1 -0
  12. package/dist/auth/cline.d.ts +27 -2
  13. package/dist/auth/cline.d.ts.map +1 -1
  14. package/dist/auth/oca.d.ts.map +1 -1
  15. package/dist/chat/chat-schema.d.ts +8 -8
  16. package/dist/extensions/config/agent-config-loader.d.ts.map +1 -0
  17. package/dist/{agents → extensions/config}/agent-config-parser.d.ts +2 -2
  18. package/dist/extensions/config/agent-config-parser.d.ts.map +1 -0
  19. package/dist/{agents → extensions/config}/hooks-config-loader.d.ts +1 -1
  20. package/dist/extensions/config/hooks-config-loader.d.ts.map +1 -0
  21. package/dist/{agents → extensions/config}/index.d.ts +2 -4
  22. package/dist/extensions/config/index.d.ts.map +1 -0
  23. package/dist/{runtime/commands.d.ts → extensions/config/runtime-commands.d.ts} +2 -3
  24. package/dist/extensions/config/runtime-commands.d.ts.map +1 -0
  25. package/dist/extensions/config/unified-config-file-watcher.d.ts.map +1 -0
  26. package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -0
  27. package/dist/extensions/context/agentic-compaction.d.ts +13 -0
  28. package/dist/extensions/context/agentic-compaction.d.ts.map +1 -0
  29. package/dist/extensions/context/basic-compaction.d.ts +9 -0
  30. package/dist/extensions/context/basic-compaction.d.ts.map +1 -0
  31. package/dist/extensions/context/compaction-shared.d.ts +60 -0
  32. package/dist/extensions/context/compaction-shared.d.ts.map +1 -0
  33. package/dist/extensions/context/compaction.d.ts +20 -0
  34. package/dist/extensions/context/compaction.d.ts.map +1 -0
  35. package/dist/extensions/index.d.ts +5 -0
  36. package/dist/extensions/index.d.ts.map +1 -0
  37. package/dist/extensions/mcp/client.d.ts +3 -0
  38. package/dist/extensions/mcp/client.d.ts.map +1 -0
  39. package/dist/extensions/mcp/config-loader.d.ts.map +1 -0
  40. package/dist/extensions/mcp/index.d.ts +9 -0
  41. package/dist/extensions/mcp/index.d.ts.map +1 -0
  42. package/dist/{mcp → extensions/mcp}/manager.d.ts +1 -2
  43. package/dist/extensions/mcp/manager.d.ts.map +1 -0
  44. package/dist/extensions/mcp/name-transform.d.ts +3 -0
  45. package/dist/extensions/mcp/name-transform.d.ts.map +1 -0
  46. package/dist/extensions/mcp/policies.d.ts +15 -0
  47. package/dist/extensions/mcp/policies.d.ts.map +1 -0
  48. package/dist/extensions/mcp/tools.d.ts +4 -0
  49. package/dist/extensions/mcp/tools.d.ts.map +1 -0
  50. package/dist/{mcp → extensions/mcp}/types.d.ts +29 -1
  51. package/dist/extensions/mcp/types.d.ts.map +1 -0
  52. package/dist/{agents → extensions/plugin}/plugin-config-loader.d.ts +1 -1
  53. package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -0
  54. package/dist/{agents → extensions/plugin}/plugin-loader.d.ts +1 -1
  55. package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -0
  56. package/dist/extensions/plugin/plugin-module-import.d.ts +5 -0
  57. package/dist/extensions/plugin/plugin-module-import.d.ts.map +1 -0
  58. package/dist/{agents → extensions/plugin}/plugin-sandbox.d.ts +1 -1
  59. package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -0
  60. package/dist/extensions/plugin-sandbox-bootstrap.js +485 -0
  61. package/dist/hooks/index.d.ts +4 -0
  62. package/dist/hooks/index.d.ts.map +1 -0
  63. package/dist/hooks/persistent.d.ts +64 -0
  64. package/dist/hooks/persistent.d.ts.map +1 -0
  65. package/dist/hooks/subprocess-runner.d.ts +22 -0
  66. package/dist/hooks/subprocess-runner.d.ts.map +1 -0
  67. package/dist/hooks/subprocess.d.ts +189 -0
  68. package/dist/hooks/subprocess.d.ts.map +1 -0
  69. package/dist/index.d.ts +22 -25
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +560 -447
  72. package/dist/prompt/default-system.d.ts +2 -0
  73. package/dist/prompt/default-system.d.ts.map +1 -0
  74. package/dist/providers/local-provider-service.d.ts +1 -1
  75. package/dist/providers/local-provider-service.d.ts.map +1 -1
  76. package/dist/runtime/checkpoint-hooks.d.ts +21 -0
  77. package/dist/runtime/checkpoint-hooks.d.ts.map +1 -0
  78. package/dist/runtime/hook-file-hooks.d.ts +1 -1
  79. package/dist/runtime/hook-file-hooks.d.ts.map +1 -1
  80. package/dist/runtime/rules.d.ts +1 -1
  81. package/dist/runtime/rules.d.ts.map +1 -1
  82. package/dist/runtime/runtime-builder.d.ts +1 -1
  83. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  84. package/dist/runtime/session-runtime.d.ts +25 -5
  85. package/dist/runtime/session-runtime.d.ts.map +1 -1
  86. package/dist/runtime/subprocess-sandbox.d.ts.map +1 -0
  87. package/dist/runtime/team-runtime-registry.d.ts +1 -1
  88. package/dist/runtime/team-runtime-registry.d.ts.map +1 -1
  89. package/dist/runtime/tool-approval.d.ts +1 -1
  90. package/dist/session/default-session-manager.d.ts +4 -3
  91. package/dist/session/default-session-manager.d.ts.map +1 -1
  92. package/dist/session/file-session-service.d.ts +1 -1
  93. package/dist/session/file-session-service.d.ts.map +1 -1
  94. package/dist/session/{unified-session-persistence-service.d.ts → persistence-service.d.ts} +11 -42
  95. package/dist/session/persistence-service.d.ts.map +1 -0
  96. package/dist/session/rpc-session-service.d.ts +1 -1
  97. package/dist/session/rpc-session-service.d.ts.map +1 -1
  98. package/dist/session/session-agent-events.d.ts +1 -1
  99. package/dist/session/session-artifacts.d.ts.map +1 -1
  100. package/dist/session/session-config-builder.d.ts.map +1 -1
  101. package/dist/session/session-graph.d.ts +1 -1
  102. package/dist/session/session-graph.d.ts.map +1 -1
  103. package/dist/session/session-host.d.ts.map +1 -1
  104. package/dist/session/session-manager.d.ts +6 -5
  105. package/dist/session/session-manager.d.ts.map +1 -1
  106. package/dist/session/session-manifest.d.ts +1 -1
  107. package/dist/session/session-service.d.ts +3 -2
  108. package/dist/session/session-service.d.ts.map +1 -1
  109. package/dist/session/session-team-coordination.d.ts +2 -1
  110. package/dist/session/session-team-coordination.d.ts.map +1 -1
  111. package/dist/session/utils/helpers.d.ts +51 -3
  112. package/dist/session/utils/helpers.d.ts.map +1 -1
  113. package/dist/session/utils/types.d.ts +41 -7
  114. package/dist/session/utils/types.d.ts.map +1 -1
  115. package/dist/session/workspace-manager.d.ts +1 -2
  116. package/dist/session/workspace-manager.d.ts.map +1 -1
  117. package/dist/session/workspace-manifest.d.ts +1 -22
  118. package/dist/session/workspace-manifest.d.ts.map +1 -1
  119. package/dist/storage/file-team-store.d.ts +2 -1
  120. package/dist/storage/file-team-store.d.ts.map +1 -1
  121. package/dist/storage/sqlite-team-store.d.ts +4 -1
  122. package/dist/storage/sqlite-team-store.d.ts.map +1 -1
  123. package/dist/storage/team-store.d.ts.map +1 -1
  124. package/dist/team/delegated-agent.d.ts +44 -0
  125. package/dist/team/delegated-agent.d.ts.map +1 -0
  126. package/dist/team/index.d.ts +1 -0
  127. package/dist/team/index.d.ts.map +1 -1
  128. package/dist/team/multi-agent.d.ts +229 -0
  129. package/dist/team/multi-agent.d.ts.map +1 -0
  130. package/dist/team/projections.d.ts +2 -2
  131. package/dist/team/projections.d.ts.map +1 -1
  132. package/dist/team/runtime.d.ts +5 -0
  133. package/dist/team/runtime.d.ts.map +1 -0
  134. package/dist/team/spawn-agent-tool.d.ts +85 -0
  135. package/dist/team/spawn-agent-tool.d.ts.map +1 -0
  136. package/dist/team/subagent-prompts.d.ts +4 -0
  137. package/dist/team/subagent-prompts.d.ts.map +1 -0
  138. package/dist/team/team-tools.d.ts +35 -0
  139. package/dist/team/team-tools.d.ts.map +1 -0
  140. package/dist/telemetry/OpenTelemetryProvider.d.ts +11 -1
  141. package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
  142. package/dist/telemetry/{LoggerTelemetryAdapter.d.ts → TelemetryLoggerSink.d.ts} +10 -4
  143. package/dist/telemetry/TelemetryLoggerSink.d.ts.map +1 -0
  144. package/dist/telemetry/TelemetryService.d.ts.map +1 -1
  145. package/dist/telemetry/index.js +15 -28
  146. package/dist/tools/definitions.d.ts +4 -3
  147. package/dist/tools/definitions.d.ts.map +1 -1
  148. package/dist/tools/index.d.ts +5 -5
  149. package/dist/tools/index.d.ts.map +1 -1
  150. package/dist/tools/model-tool-routing.d.ts.map +1 -1
  151. package/dist/tools/presets.d.ts +26 -0
  152. package/dist/tools/presets.d.ts.map +1 -1
  153. package/dist/tools/schemas.d.ts +8 -0
  154. package/dist/tools/schemas.d.ts.map +1 -1
  155. package/dist/tools/types.d.ts +23 -2
  156. package/dist/tools/types.d.ts.map +1 -1
  157. package/dist/types/config.d.ts +47 -3
  158. package/dist/types/config.d.ts.map +1 -1
  159. package/dist/types/events.d.ts +1 -1
  160. package/dist/types/provider-settings.d.ts +1 -1
  161. package/dist/types/provider-settings.d.ts.map +1 -1
  162. package/dist/types/storage.d.ts +2 -1
  163. package/dist/types/storage.d.ts.map +1 -1
  164. package/dist/types.d.ts +7 -16
  165. package/dist/types.d.ts.map +1 -1
  166. package/package.json +16 -13
  167. package/src/ClineCore.test.ts +150 -0
  168. package/src/ClineCore.ts +114 -8
  169. package/src/account/cline-account-service.test.ts +84 -0
  170. package/src/account/cline-account-service.ts +2 -2
  171. package/src/account/index.ts +1 -0
  172. package/src/account/types.ts +6 -0
  173. package/src/auth/bounded-ttl-cache.test.ts +38 -0
  174. package/src/auth/bounded-ttl-cache.ts +53 -0
  175. package/src/auth/cline.test.ts +173 -36
  176. package/src/auth/cline.ts +395 -93
  177. package/src/auth/oca.test.ts +125 -0
  178. package/src/auth/oca.ts +17 -4
  179. package/src/{agents → extensions/config}/agent-config-loader.test.ts +1 -1
  180. package/src/{agents → extensions/config}/agent-config-parser.ts +2 -2
  181. package/src/{agents → extensions/config}/hooks-config-loader.ts +1 -1
  182. package/src/{agents → extensions/config}/index.ts +7 -11
  183. package/src/{runtime/commands.test.ts → extensions/config/runtime-commands.test.ts} +20 -3
  184. package/src/{runtime/commands.ts → extensions/config/runtime-commands.ts} +1 -8
  185. package/src/{agents → extensions/config}/unified-config-file-watcher.ts +15 -2
  186. package/src/{agents → extensions/config}/user-instruction-config-loader.test.ts +90 -2
  187. package/src/{agents → extensions/config}/user-instruction-config-loader.ts +126 -12
  188. package/src/extensions/context/agentic-compaction.ts +119 -0
  189. package/src/extensions/context/basic-compaction.ts +275 -0
  190. package/src/extensions/context/compaction-shared.ts +458 -0
  191. package/src/extensions/context/compaction.test.ts +477 -0
  192. package/src/extensions/context/compaction.ts +203 -0
  193. package/src/extensions/index.ts +12 -0
  194. package/src/extensions/mcp/client.ts +420 -0
  195. package/src/{mcp → extensions/mcp}/index.ts +16 -0
  196. package/src/{mcp → extensions/mcp}/manager.test.ts +1 -2
  197. package/src/{mcp → extensions/mcp}/manager.ts +3 -5
  198. package/src/extensions/mcp/name-transform.ts +33 -0
  199. package/src/extensions/mcp/policies.ts +47 -0
  200. package/src/extensions/mcp/tools.ts +47 -0
  201. package/src/{mcp → extensions/mcp}/types.ts +35 -7
  202. package/src/{agents → extensions/plugin}/plugin-config-loader.test.ts +18 -13
  203. package/src/{agents → extensions/plugin}/plugin-config-loader.ts +1 -1
  204. package/src/{agents → extensions/plugin}/plugin-loader.test.ts +41 -4
  205. package/src/extensions/plugin/plugin-loader.ts +106 -0
  206. package/src/extensions/plugin/plugin-module-import.ts +278 -0
  207. package/src/{agents → extensions/plugin}/plugin-sandbox-bootstrap.ts +30 -92
  208. package/src/{agents → extensions/plugin}/plugin-sandbox.test.ts +60 -3
  209. package/src/{agents → extensions/plugin}/plugin-sandbox.ts +146 -56
  210. package/src/hooks/index.ts +25 -0
  211. package/src/hooks/persistent.ts +661 -0
  212. package/src/hooks/subprocess-runner.ts +196 -0
  213. package/src/hooks/subprocess.ts +669 -0
  214. package/src/index.ts +200 -118
  215. package/src/prompt/default-system.ts +21 -0
  216. package/src/providers/local-provider-registry.ts +1 -1
  217. package/src/providers/local-provider-service.test.ts +23 -2
  218. package/src/providers/local-provider-service.ts +2 -2
  219. package/src/runtime/checkpoint-hooks.test.ts +167 -0
  220. package/src/runtime/checkpoint-hooks.ts +186 -0
  221. package/src/runtime/hook-file-hooks.test.ts +40 -1
  222. package/src/runtime/hook-file-hooks.ts +35 -16
  223. package/src/runtime/index.ts +4 -19
  224. package/src/runtime/rules.ts +4 -1
  225. package/src/runtime/runtime-builder.team-persistence.test.ts +3 -6
  226. package/src/runtime/runtime-builder.test.ts +266 -160
  227. package/src/runtime/runtime-builder.ts +120 -47
  228. package/src/runtime/runtime-parity.test.ts +22 -22
  229. package/src/runtime/session-runtime.ts +36 -6
  230. package/src/runtime/{sandbox/subprocess-sandbox.ts → subprocess-sandbox.ts} +24 -3
  231. package/src/runtime/team-runtime-registry.ts +1 -4
  232. package/src/runtime/tool-approval.ts +1 -1
  233. package/src/session/default-session-manager.e2e.test.ts +2 -2
  234. package/src/session/default-session-manager.test.ts +553 -9
  235. package/src/session/default-session-manager.ts +140 -46
  236. package/src/session/file-session-service.ts +3 -3
  237. package/src/session/index.ts +6 -6
  238. package/src/session/persistence-service.test.ts +212 -0
  239. package/src/session/{unified-session-persistence-service.ts → persistence-service.ts} +106 -172
  240. package/src/session/rpc-session-service.ts +3 -3
  241. package/src/session/runtime-oauth-token-manager.ts +1 -1
  242. package/src/session/session-agent-events.ts +1 -1
  243. package/src/session/session-artifacts.ts +32 -4
  244. package/src/session/session-config-builder.ts +22 -9
  245. package/src/session/session-graph.ts +1 -1
  246. package/src/session/session-host.ts +19 -11
  247. package/src/session/session-manager.ts +11 -6
  248. package/src/session/session-service.team-persistence.test.ts +1 -1
  249. package/src/session/session-service.ts +6 -9
  250. package/src/session/session-team-coordination.ts +7 -3
  251. package/src/session/session-telemetry.ts +1 -1
  252. package/src/session/utils/helpers.test.ts +160 -0
  253. package/src/session/utils/helpers.ts +289 -42
  254. package/src/session/utils/types.ts +47 -7
  255. package/src/session/workspace-manager.ts +5 -3
  256. package/src/session/workspace-manifest.ts +3 -49
  257. package/src/storage/file-team-store.ts +2 -5
  258. package/src/storage/provider-settings-legacy-migration.ts +2 -2
  259. package/src/storage/provider-settings-manager.test.ts +1 -1
  260. package/src/storage/sqlite-team-store.ts +212 -125
  261. package/src/storage/team-store.ts +1 -5
  262. package/src/team/delegated-agent.ts +131 -0
  263. package/src/team/index.ts +1 -0
  264. package/src/team/multi-agent.lifecycle.test.ts +201 -0
  265. package/src/team/multi-agent.ts +1666 -0
  266. package/src/team/projections.ts +2 -4
  267. package/src/team/runtime.ts +54 -0
  268. package/src/team/spawn-agent-tool.test.ts +387 -0
  269. package/src/team/spawn-agent-tool.ts +207 -0
  270. package/src/team/subagent-prompts.ts +41 -0
  271. package/src/team/team-tools.test.ts +802 -0
  272. package/src/team/team-tools.ts +792 -0
  273. package/src/telemetry/OpenTelemetryProvider.test.ts +25 -3
  274. package/src/telemetry/OpenTelemetryProvider.ts +108 -18
  275. package/src/telemetry/TelemetryLoggerSink.test.ts +42 -0
  276. package/src/telemetry/{LoggerTelemetryAdapter.ts → TelemetryLoggerSink.ts} +21 -14
  277. package/src/telemetry/TelemetryService.test.ts +7 -7
  278. package/src/telemetry/TelemetryService.ts +2 -4
  279. package/src/tools/definitions.test.ts +76 -0
  280. package/src/tools/definitions.ts +41 -2
  281. package/src/tools/executors/apply-patch.ts +1 -1
  282. package/src/tools/executors/editor.ts +1 -1
  283. package/src/tools/executors/file-read.ts +1 -1
  284. package/src/tools/executors/search.ts +1 -1
  285. package/src/tools/executors/web-fetch.ts +1 -1
  286. package/src/tools/index.ts +6 -1
  287. package/src/tools/model-tool-routing.ts +2 -0
  288. package/src/tools/presets.test.ts +8 -0
  289. package/src/tools/presets.ts +40 -2
  290. package/src/tools/schemas.ts +19 -0
  291. package/src/tools/types.ts +31 -2
  292. package/src/types/config.ts +61 -7
  293. package/src/types/events.ts +1 -1
  294. package/src/types/index.ts +0 -1
  295. package/src/types/provider-settings.ts +1 -1
  296. package/src/types/storage.ts +2 -5
  297. package/src/types.ts +32 -44
  298. package/dist/agents/agent-config-loader.d.ts.map +0 -1
  299. package/dist/agents/agent-config-parser.d.ts.map +0 -1
  300. package/dist/agents/hooks-config-loader.d.ts.map +0 -1
  301. package/dist/agents/index.d.ts.map +0 -1
  302. package/dist/agents/plugin-config-loader.d.ts.map +0 -1
  303. package/dist/agents/plugin-loader.d.ts.map +0 -1
  304. package/dist/agents/plugin-sandbox-bootstrap.js +0 -446
  305. package/dist/agents/plugin-sandbox.d.ts.map +0 -1
  306. package/dist/agents/unified-config-file-watcher.d.ts.map +0 -1
  307. package/dist/agents/user-instruction-config-loader.d.ts.map +0 -1
  308. package/dist/mcp/config-loader.d.ts.map +0 -1
  309. package/dist/mcp/index.d.ts +0 -5
  310. package/dist/mcp/index.d.ts.map +0 -1
  311. package/dist/mcp/manager.d.ts.map +0 -1
  312. package/dist/mcp/types.d.ts.map +0 -1
  313. package/dist/runtime/commands.d.ts.map +0 -1
  314. package/dist/runtime/sandbox/subprocess-sandbox.d.ts.map +0 -1
  315. package/dist/runtime/skills.d.ts +0 -14
  316. package/dist/runtime/skills.d.ts.map +0 -1
  317. package/dist/runtime/workflows.d.ts +0 -14
  318. package/dist/runtime/workflows.d.ts.map +0 -1
  319. package/dist/session/unified-session-persistence-service.d.ts.map +0 -1
  320. package/dist/telemetry/LoggerTelemetryAdapter.d.ts.map +0 -1
  321. package/dist/types/workspace.d.ts +0 -8
  322. package/dist/types/workspace.d.ts.map +0 -1
  323. package/src/agents/plugin-loader.ts +0 -175
  324. package/src/runtime/skills.ts +0 -44
  325. package/src/runtime/workflows.test.ts +0 -119
  326. package/src/runtime/workflows.ts +0 -45
  327. package/src/session/unified-session-persistence-service.test.ts +0 -85
  328. package/src/telemetry/LoggerTelemetryAdapter.test.ts +0 -42
  329. package/src/types/workspace.ts +0 -7
  330. /package/dist/{agents → extensions/config}/agent-config-loader.d.ts +0 -0
  331. /package/dist/{agents → extensions/config}/unified-config-file-watcher.d.ts +0 -0
  332. /package/dist/{agents → extensions/config}/user-instruction-config-loader.d.ts +0 -0
  333. /package/dist/{mcp → extensions/mcp}/config-loader.d.ts +0 -0
  334. /package/dist/runtime/{sandbox/subprocess-sandbox.d.ts → subprocess-sandbox.d.ts} +0 -0
  335. /package/src/{agents → extensions/config}/agent-config-loader.ts +0 -0
  336. /package/src/{agents → extensions/config}/hooks-config-loader.test.ts +0 -0
  337. /package/src/{agents → extensions/config}/unified-config-file-watcher.test.ts +0 -0
  338. /package/src/{mcp → extensions/mcp}/config-loader.test.ts +0 -0
  339. /package/src/{mcp → extensions/mcp}/config-loader.ts +0 -0
@@ -24,17 +24,17 @@ describe("plugin-config-loader", () => {
24
24
  try {
25
25
  const nested = join(root, "nested");
26
26
  await mkdir(nested, { recursive: true });
27
- await writeFile(join(root, "a.mjs"), "export default {}", "utf8");
27
+ await writeFile(join(root, "a.js"), "export default {}", "utf8");
28
28
  await writeFile(join(nested, "b.ts"), "export default {}", "utf8");
29
29
  await writeFile(
30
- join(root, ".a.mjs.cline-plugin.mjs"),
30
+ join(root, ".a.js.cline-plugin.js"),
31
31
  "export default {}",
32
32
  "utf8",
33
33
  );
34
34
  await writeFile(join(root, "ignore.txt"), "noop", "utf8");
35
35
 
36
36
  const discovered = discoverPluginModulePaths(root);
37
- expect(discovered).toEqual([join(root, "a.mjs"), join(nested, "b.ts")]);
37
+ expect(discovered).toEqual([join(root, "a.js"), join(nested, "b.ts")]);
38
38
  } finally {
39
39
  await rm(root, { recursive: true, force: true });
40
40
  }
@@ -47,13 +47,13 @@ describe("plugin-config-loader", () => {
47
47
  setHomeDir(root);
48
48
  const pluginsDir = join(root, "plugins");
49
49
  await mkdir(pluginsDir, { recursive: true });
50
- const filePath = join(root, "direct.mjs");
51
- const dirPluginPath = join(pluginsDir, "dir-plugin.mjs");
50
+ const filePath = join(root, "direct.js");
51
+ const dirPluginPath = join(pluginsDir, "dir-plugin.js");
52
52
  await writeFile(filePath, "export default {}", "utf8");
53
53
  await writeFile(dirPluginPath, "export default {}", "utf8");
54
54
 
55
55
  const resolved = resolveAgentPluginPaths({
56
- pluginPaths: ["./direct.mjs", "./plugins"],
56
+ pluginPaths: ["./direct.js", "./plugins"],
57
57
  workspacePath: join(root, "workspace"),
58
58
  cwd: root,
59
59
  });
@@ -71,14 +71,19 @@ describe("plugin-config-loader", () => {
71
71
  const srcDir = join(pluginDir, "src");
72
72
  await mkdir(srcDir, { recursive: true });
73
73
  const declaredEntry = join(srcDir, "index.ts");
74
- const ignoredEntry = join(pluginDir, "ignored.mjs");
74
+ const ignoredEntry = join(pluginDir, "ignored.js");
75
75
  await writeFile(
76
76
  join(pluginDir, "package.json"),
77
77
  JSON.stringify({
78
78
  name: "plugin-package",
79
79
  private: true,
80
80
  cline: {
81
- plugins: ["./src/index.ts"],
81
+ plugins: [
82
+ {
83
+ paths: ["./src/index.ts"],
84
+ capabilities: ["tools"],
85
+ },
86
+ ],
82
87
  },
83
88
  }),
84
89
  "utf8",
@@ -109,15 +114,15 @@ describe("plugin-config-loader", () => {
109
114
  try {
110
115
  process.env.HOME = home;
111
116
  setHomeDir(home);
112
- const workspacePlugins = join(workspace, ".clinerules", "plugins");
117
+ const workspacePlugins = join(workspace, ".cline", "plugins");
113
118
  const userPlugins = join(home, ".cline", "plugins");
114
- const documentsPlugins = join(home, "Documents", "Plugins");
119
+ const documentsPlugins = join(home, "Documents", "Cline", "Plugins");
115
120
  await mkdir(workspacePlugins, { recursive: true });
116
121
  await mkdir(userPlugins, { recursive: true });
117
122
  await mkdir(documentsPlugins, { recursive: true });
118
- const workspacePlugin = join(workspacePlugins, "workspace.mjs");
119
- const userPlugin = join(userPlugins, "user.mjs");
120
- const documentsPlugin = join(documentsPlugins, "documents.mjs");
123
+ const workspacePlugin = join(workspacePlugins, "workspace.js");
124
+ const userPlugin = join(userPlugins, "user.js");
125
+ const documentsPlugin = join(documentsPlugins, "documents.js");
121
126
  await writeFile(workspacePlugin, "export default {}", "utf8");
122
127
  await writeFile(userPlugin, "export default {}", "utf8");
123
128
  await writeFile(documentsPlugin, "export default {}", "utf8");
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from "node:fs";
2
- import type { AgentConfig } from "@clinebot/agents";
2
+ import type { AgentConfig } from "@clinebot/shared";
3
3
  import {
4
4
  discoverPluginModulePaths as discoverPluginModulePathsFromShared,
5
5
  resolveConfiguredPluginModulePaths,
@@ -117,10 +117,36 @@ describe("plugin-loader", () => {
117
117
  await writeFile(
118
118
  join(copyDir, "portable-subagents.ts"),
119
119
  [
120
+ "import { safeJsonStringify } from '@clinebot/shared';",
120
121
  "import { resolveClineDataDir } from '@clinebot/shared/storage';",
121
122
  "import YAML from 'yaml';",
122
123
  "export default {",
123
- " name: typeof resolveClineDataDir === 'function' ? YAML.stringify({ ok: true }) : 'invalid',",
124
+ " name: typeof safeJsonStringify === 'function' ? YAML.stringify({ ok: !!resolveClineDataDir() }) : 'invalid',",
125
+ " manifest: { capabilities: ['tools'] },",
126
+ "};",
127
+ ].join("\n"),
128
+ "utf8",
129
+ );
130
+
131
+ const packagedCopyDir = join(copyDir, "packaged-plugin");
132
+ await mkdir(packagedCopyDir, { recursive: true });
133
+ await writeFile(
134
+ join(packagedCopyDir, "package.json"),
135
+ JSON.stringify({
136
+ name: "packaged-plugin",
137
+ type: "module",
138
+ cline: {
139
+ plugins: ["index.ts"],
140
+ },
141
+ }),
142
+ "utf8",
143
+ );
144
+ await writeFile(
145
+ join(packagedCopyDir, "index.ts"),
146
+ [
147
+ "import YAML from 'yaml';",
148
+ "export default {",
149
+ " name: YAML.stringify({ ok: true }),",
124
150
  " manifest: { capabilities: ['tools'] },",
125
151
  "};",
126
152
  ].join("\n"),
@@ -193,11 +219,22 @@ describe("plugin-loader", () => {
193
219
  expect(plugin.name).toBe("plugin-installed-sdk");
194
220
  });
195
221
 
196
- it("requires copied plugins to provide their own non-SDK dependencies", async () => {
197
- await expect(
198
- loadAgentPluginFromPath(join(copyDir, "portable-subagents.ts"), {
222
+ it("allows standalone file plugins to use host runtime dependencies", async () => {
223
+ const plugin = await loadAgentPluginFromPath(
224
+ join(copyDir, "portable-subagents.ts"),
225
+ {
199
226
  cwd: copyDir,
200
227
  useCache: true,
228
+ },
229
+ );
230
+ expect(plugin.name).toMatch(/ok: true/i);
231
+ });
232
+
233
+ it("requires package-based plugins to provide their own non-SDK dependencies", async () => {
234
+ await expect(
235
+ loadAgentPluginFromPath(join(copyDir, "packaged-plugin", "index.ts"), {
236
+ cwd: join(copyDir, "packaged-plugin"),
237
+ useCache: true,
201
238
  }),
202
239
  ).rejects.toThrow(/Cannot find (package|module) 'yaml'/i);
203
240
  });
@@ -0,0 +1,106 @@
1
+ import { resolve } from "node:path";
2
+ import type { AgentConfig } from "@clinebot/shared";
3
+ import { importPluginModule } from "./plugin-module-import";
4
+
5
+ type AgentPlugin = NonNullable<AgentConfig["extensions"]>[number];
6
+ type PluginLike = {
7
+ name: string;
8
+ manifest: {
9
+ capabilities: string[];
10
+ hookStages?: string[];
11
+ };
12
+ };
13
+
14
+ export interface LoadAgentPluginFromPathOptions {
15
+ exportName?: string;
16
+ cwd?: string;
17
+ useCache?: boolean;
18
+ }
19
+
20
+ function isObject(value: unknown): value is Record<string, unknown> {
21
+ return typeof value === "object" && value !== null;
22
+ }
23
+
24
+ function hasValidStringArray(value: unknown): value is string[] {
25
+ return (
26
+ Array.isArray(value) && value.every((entry) => typeof entry === "string")
27
+ );
28
+ }
29
+
30
+ function validatePluginManifest(
31
+ plugin: PluginLike,
32
+ absolutePath: string,
33
+ ): void {
34
+ if (!isObject(plugin.manifest)) {
35
+ throw new Error(
36
+ `Invalid plugin module at ${absolutePath}: missing required "manifest"`,
37
+ );
38
+ }
39
+ if (!hasValidStringArray(plugin.manifest.capabilities)) {
40
+ throw new Error(
41
+ `Invalid plugin module at ${absolutePath}: manifest.capabilities must be a string array`,
42
+ );
43
+ }
44
+ if (plugin.manifest.capabilities.length === 0) {
45
+ throw new Error(
46
+ `Invalid plugin module at ${absolutePath}: manifest.capabilities cannot be empty`,
47
+ );
48
+ }
49
+ if (
50
+ Object.hasOwn(plugin.manifest, "hookStages") &&
51
+ !hasValidStringArray(plugin.manifest.hookStages)
52
+ ) {
53
+ throw new Error(
54
+ `Invalid plugin module at ${absolutePath}: manifest.hookStages must be a string array when provided`,
55
+ );
56
+ }
57
+ }
58
+
59
+ function validatePluginExport(
60
+ plugin: unknown,
61
+ absolutePath: string,
62
+ ): asserts plugin is PluginLike {
63
+ if (!isObject(plugin)) {
64
+ throw new Error(
65
+ `Invalid plugin module at ${absolutePath}: expected object export`,
66
+ );
67
+ }
68
+ if (typeof plugin.name !== "string" || plugin.name.length === 0) {
69
+ throw new Error(
70
+ `Invalid plugin module at ${absolutePath}: expected non-empty "name"`,
71
+ );
72
+ }
73
+ if (!Object.hasOwn(plugin, "manifest")) {
74
+ throw new Error(
75
+ `Invalid plugin module at ${absolutePath}: missing required "manifest"`,
76
+ );
77
+ }
78
+ validatePluginManifest(plugin as PluginLike, absolutePath);
79
+ }
80
+
81
+ export async function loadAgentPluginFromPath(
82
+ pluginPath: string,
83
+ options: LoadAgentPluginFromPathOptions = {},
84
+ ): Promise<AgentPlugin> {
85
+ const absolutePath = resolve(options.cwd ?? process.cwd(), pluginPath);
86
+ const moduleExports = await importPluginModule(absolutePath, {
87
+ useCache: options.useCache,
88
+ });
89
+ const exportName = options.exportName ?? "plugin";
90
+ const plugin = (moduleExports.default ??
91
+ moduleExports[exportName]) as unknown;
92
+
93
+ validatePluginExport(plugin, absolutePath);
94
+ return plugin as AgentPlugin;
95
+ }
96
+
97
+ export async function loadAgentPluginsFromPaths(
98
+ pluginPaths: string[],
99
+ options: LoadAgentPluginFromPathOptions = {},
100
+ ): Promise<AgentPlugin[]> {
101
+ const loaded: AgentPlugin[] = [];
102
+ for (const pluginPath of pluginPaths) {
103
+ loaded.push(await loadAgentPluginFromPath(pluginPath, options));
104
+ }
105
+ return loaded;
106
+ }
@@ -0,0 +1,278 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { builtinModules, createRequire } from "node:module";
3
+ import { dirname, extname, isAbsolute, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { PLUGIN_FILE_EXTENSIONS } from "@clinebot/shared";
6
+ import createJiti from "jiti";
7
+
8
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
9
+ const HOST_REQUIRE = createRequire(import.meta.url);
10
+ // `plugin-module-import.ts` lives at `packages/core/src/extensions/plugin`, so
11
+ // walking up five levels lands at the repo root.
12
+ const WORKSPACE_ROOT = resolve(MODULE_DIR, "..", "..", "..", "..", "..");
13
+ const WORKSPACE_ALIASES = collectWorkspaceAliases(WORKSPACE_ROOT);
14
+ const BUILTIN_MODULES = new Set(
15
+ builtinModules.flatMap((id) => [id, id.replace(/^node:/, "")]),
16
+ );
17
+ const SUPPORTED_PLUGIN_EXTENSIONS = new Set(PLUGIN_FILE_EXTENSIONS);
18
+
19
+ export interface ImportPluginModuleOptions {
20
+ useCache?: boolean;
21
+ }
22
+
23
+ function collectWorkspaceAliases(root: string): Record<string, string> {
24
+ const aliases: Record<string, string> = {};
25
+ const candidates: Record<string, string> = {
26
+ "@clinebot/agents": resolve(root, "packages/agents/src/index.ts"),
27
+ "@clinebot/core": resolve(root, "packages/core/src/index.ts"),
28
+ "@clinebot/llms": resolve(root, "packages/llms/src/index.ts"),
29
+ "@clinebot/rpc": resolve(root, "packages/rpc/src/index.ts"),
30
+ "@clinebot/scheduler": resolve(root, "packages/scheduler/src/index.ts"),
31
+ "@clinebot/shared": resolve(root, "packages/shared/src/index.ts"),
32
+ "@clinebot/shared/storage": resolve(
33
+ root,
34
+ "packages/shared/src/storage/index.ts",
35
+ ),
36
+ "@clinebot/shared/db": resolve(root, "packages/shared/src/db/index.ts"),
37
+ };
38
+ for (const [key, value] of Object.entries(candidates)) {
39
+ if (existsSync(value)) {
40
+ aliases[key] = value;
41
+ }
42
+ }
43
+ return aliases;
44
+ }
45
+
46
+ function isBareSpecifier(specifier: string): boolean {
47
+ return !(
48
+ specifier.startsWith(".") ||
49
+ specifier.startsWith("/") ||
50
+ specifier.startsWith("file:") ||
51
+ specifier.startsWith("data:") ||
52
+ specifier.startsWith("http:") ||
53
+ specifier.startsWith("https:")
54
+ );
55
+ }
56
+
57
+ function getPackageName(specifier: string): string {
58
+ if (specifier.startsWith("@")) {
59
+ const [scope, name] = specifier.split("/", 3);
60
+ return name ? `${scope}/${name}` : specifier;
61
+ }
62
+ return specifier.split("/", 1)[0] ?? specifier;
63
+ }
64
+
65
+ function hasInstalledDependency(
66
+ pluginFilePath: string,
67
+ specifier: string,
68
+ ): boolean {
69
+ const packageName = getPackageName(specifier);
70
+ let current = dirname(pluginFilePath);
71
+ while (true) {
72
+ const packageDir = resolve(current, "node_modules", packageName);
73
+ if (
74
+ existsSync(packageDir) ||
75
+ existsSync(resolve(packageDir, "package.json"))
76
+ ) {
77
+ return true;
78
+ }
79
+ const parent = resolve(current, "..");
80
+ if (parent === current) {
81
+ return false;
82
+ }
83
+ current = parent;
84
+ }
85
+ }
86
+
87
+ function resolvesFromHostRuntime(specifier: string): boolean {
88
+ try {
89
+ HOST_REQUIRE.resolve(specifier);
90
+ return true;
91
+ } catch {
92
+ return false;
93
+ }
94
+ }
95
+
96
+ function resolveFromHostRuntime(specifier: string): string | null {
97
+ try {
98
+ return HOST_REQUIRE.resolve(specifier);
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
103
+
104
+ function isPackageBasedPlugin(pluginFilePath: string): boolean {
105
+ // Walk up from the plugin file looking for a package.json with a `cline`
106
+ // manifest. Stop at the first package.json we encounter — if it doesn't
107
+ // declare `cline` we've left the plugin boundary (e.g. hit the workspace
108
+ // root). Also cap the traversal so we never wander far from the plugin
109
+ // search root (.cline/plugins).
110
+ const MAX_DEPTH = 4;
111
+ let current = dirname(pluginFilePath);
112
+ for (let depth = 0; depth < MAX_DEPTH; depth++) {
113
+ const packageJsonPath = resolve(current, "package.json");
114
+ if (existsSync(packageJsonPath)) {
115
+ try {
116
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
117
+ return pkg != null && typeof pkg === "object" && "cline" in pkg;
118
+ } catch {
119
+ return false;
120
+ }
121
+ }
122
+ const parent = resolve(current, "..");
123
+ if (parent === current) {
124
+ return false;
125
+ }
126
+ current = parent;
127
+ }
128
+ return false;
129
+ }
130
+
131
+ function resolveRelativeImportPath(
132
+ fromPath: string,
133
+ specifier: string,
134
+ ): string | null {
135
+ const resolvedBase = specifier.startsWith("file:")
136
+ ? fileURLToPath(specifier)
137
+ : isAbsolute(specifier)
138
+ ? specifier
139
+ : resolve(dirname(fromPath), specifier);
140
+ if (
141
+ existsSync(resolvedBase) &&
142
+ SUPPORTED_PLUGIN_EXTENSIONS.has(extname(resolvedBase))
143
+ ) {
144
+ return resolvedBase;
145
+ }
146
+ for (const extension of SUPPORTED_PLUGIN_EXTENSIONS) {
147
+ const withExtension = `${resolvedBase}${extension}`;
148
+ if (existsSync(withExtension)) {
149
+ return withExtension;
150
+ }
151
+ }
152
+ for (const extension of SUPPORTED_PLUGIN_EXTENSIONS) {
153
+ const indexPath = resolve(resolvedBase, `index${extension}`);
154
+ if (existsSync(indexPath)) {
155
+ return indexPath;
156
+ }
157
+ }
158
+ return null;
159
+ }
160
+
161
+ function collectStaticModuleSpecifiers(source: string): string[] {
162
+ const specifiers = new Set<string>();
163
+ const patterns = [
164
+ /\bimport\s+(?:type\s+)?[^"'`]*?\bfrom\s*["'`]([^"'`]+)["'`]/g,
165
+ /\bexport\s+[^"'`]*?\bfrom\s*["'`]([^"'`]+)["'`]/g,
166
+ /\bimport\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,
167
+ /\brequire\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,
168
+ ];
169
+ for (const pattern of patterns) {
170
+ for (const match of source.matchAll(pattern)) {
171
+ const specifier = match[1];
172
+ if (specifier) {
173
+ specifiers.add(specifier);
174
+ }
175
+ }
176
+ }
177
+ return [...specifiers];
178
+ }
179
+
180
+ function assertPluginDependenciesInstalled(
181
+ pluginPath: string,
182
+ preferHostRuntimeDependencies: boolean,
183
+ seen = new Set<string>(),
184
+ ): void {
185
+ if (seen.has(pluginPath) || !existsSync(pluginPath)) {
186
+ return;
187
+ }
188
+ seen.add(pluginPath);
189
+
190
+ if (!SUPPORTED_PLUGIN_EXTENSIONS.has(extname(pluginPath))) {
191
+ return;
192
+ }
193
+
194
+ const source = readFileSync(pluginPath, "utf8");
195
+ for (const specifier of collectStaticModuleSpecifiers(source)) {
196
+ if (specifier.startsWith("node:") || BUILTIN_MODULES.has(specifier)) {
197
+ continue;
198
+ }
199
+ if (isBareSpecifier(specifier)) {
200
+ if (
201
+ Object.hasOwn(WORKSPACE_ALIASES, specifier) ||
202
+ Object.hasOwn(WORKSPACE_ALIASES, getPackageName(specifier)) ||
203
+ hasInstalledDependency(pluginPath, specifier) ||
204
+ (preferHostRuntimeDependencies && resolvesFromHostRuntime(specifier))
205
+ ) {
206
+ continue;
207
+ }
208
+ throw new Error(`Cannot find module '${getPackageName(specifier)}'`);
209
+ }
210
+ const resolvedPath = resolveRelativeImportPath(pluginPath, specifier);
211
+ if (resolvedPath) {
212
+ assertPluginDependenciesInstalled(
213
+ resolvedPath,
214
+ preferHostRuntimeDependencies,
215
+ seen,
216
+ );
217
+ }
218
+ }
219
+ }
220
+
221
+ function collectPluginImportAliases(
222
+ pluginPath: string,
223
+ preferHostRuntimeDependencies: boolean,
224
+ ): Record<string, string> {
225
+ const pluginRequire = createRequire(pluginPath);
226
+ const aliases: Record<string, string> = {};
227
+ for (const [specifier, sourcePath] of Object.entries(WORKSPACE_ALIASES)) {
228
+ try {
229
+ pluginRequire.resolve(specifier);
230
+ continue;
231
+ } catch {
232
+ // Use the workspace source only when the plugin package does not provide
233
+ // its own installed SDK dependency.
234
+ }
235
+ aliases[specifier] = sourcePath;
236
+ }
237
+ if (preferHostRuntimeDependencies) {
238
+ const source = readFileSync(pluginPath, "utf8");
239
+ for (const specifier of collectStaticModuleSpecifiers(source)) {
240
+ if (
241
+ !isBareSpecifier(specifier) ||
242
+ specifier.startsWith("node:") ||
243
+ BUILTIN_MODULES.has(specifier) ||
244
+ Object.hasOwn(aliases, specifier) ||
245
+ hasInstalledDependency(pluginPath, specifier)
246
+ ) {
247
+ continue;
248
+ }
249
+ const resolved = resolveFromHostRuntime(specifier);
250
+ if (resolved) {
251
+ aliases[specifier] = resolved;
252
+ }
253
+ }
254
+ }
255
+ return aliases;
256
+ }
257
+
258
+ export async function importPluginModule(
259
+ pluginPath: string,
260
+ options: ImportPluginModuleOptions = {},
261
+ ): Promise<Record<string, unknown>> {
262
+ const preferHostRuntimeDependencies = !isPackageBasedPlugin(pluginPath);
263
+ assertPluginDependenciesInstalled(pluginPath, preferHostRuntimeDependencies);
264
+ const aliases = collectPluginImportAliases(
265
+ pluginPath,
266
+ preferHostRuntimeDependencies,
267
+ );
268
+ const jiti = createJiti(pluginPath, {
269
+ alias: aliases,
270
+ cache: options.useCache,
271
+ requireCache: options.useCache,
272
+ esmResolve: true,
273
+ interopDefault: false,
274
+ nativeModules: [...BUILTIN_MODULES],
275
+ transformModules: Object.keys(aliases),
276
+ });
277
+ return (await jiti.import(pluginPath, {})) as Record<string, unknown>;
278
+ }