@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
@@ -0,0 +1,150 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import type {
3
+ StartSessionInput,
4
+ StartSessionResult,
5
+ } from "./session/session-manager";
6
+
7
+ const { createSessionHostMock } = vi.hoisted(() => ({
8
+ createSessionHostMock: vi.fn(),
9
+ }));
10
+
11
+ vi.mock("./session/session-host", () => ({
12
+ createSessionHost: createSessionHostMock,
13
+ }));
14
+
15
+ import { ClineCore } from "./ClineCore";
16
+
17
+ function createStartInput(): StartSessionInput {
18
+ return {
19
+ config: {
20
+ providerId: "anthropic",
21
+ modelId: "claude-sonnet-4-6",
22
+ apiKey: "test",
23
+ cwd: "/tmp/workspace",
24
+ workspaceRoot: "/tmp/workspace",
25
+ systemPrompt: "You are concise.",
26
+ enableTools: true,
27
+ enableSpawnAgent: false,
28
+ enableAgentTeams: false,
29
+ },
30
+ prompt: "hello",
31
+ interactive: false,
32
+ };
33
+ }
34
+
35
+ function createStartResult(sessionId: string): StartSessionResult {
36
+ return {
37
+ sessionId,
38
+ manifest: {} as StartSessionResult["manifest"],
39
+ manifestPath: `/tmp/${sessionId}.json`,
40
+ transcriptPath: `/tmp/${sessionId}.log`,
41
+ hookPath: `/tmp/${sessionId}.hooks.jsonl`,
42
+ messagesPath: `/tmp/${sessionId}.messages.json`,
43
+ };
44
+ }
45
+
46
+ describe("ClineCore", () => {
47
+ beforeEach(() => {
48
+ createSessionHostMock.mockReset();
49
+ });
50
+
51
+ it("applies start-session bootstraps before delegating to the host", async () => {
52
+ const listeners: Array<
53
+ (event: { type: string; payload: { sessionId: string } }) => void
54
+ > = [];
55
+ const host = {
56
+ start: vi.fn(async (input: StartSessionInput) => {
57
+ expect(input.config.systemPrompt).toBe("Bootstrapped prompt");
58
+ expect(input.config.extensions).toEqual([{ name: "enterprise" }]);
59
+ return createStartResult("session-1");
60
+ }),
61
+ send: vi.fn(),
62
+ getAccumulatedUsage: vi.fn(),
63
+ abort: vi.fn(),
64
+ stop: vi.fn(),
65
+ dispose: vi.fn(),
66
+ get: vi.fn(async () => undefined),
67
+ list: vi.fn(),
68
+ delete: vi.fn(),
69
+ readMessages: vi.fn(),
70
+ readTranscript: vi.fn(),
71
+ readHooks: vi.fn(),
72
+ subscribe: vi.fn((listener) => {
73
+ listeners.push(listener);
74
+ return () => {};
75
+ }),
76
+ updateSessionModel: vi.fn(),
77
+ };
78
+ createSessionHostMock.mockResolvedValue(host);
79
+
80
+ const dispose = vi.fn(async () => {});
81
+ const applyToStartSessionInput = vi.fn(
82
+ async (input: StartSessionInput) => ({
83
+ ...input,
84
+ config: {
85
+ ...input.config,
86
+ systemPrompt: "Bootstrapped prompt",
87
+ extensions: [
88
+ { name: "enterprise" },
89
+ ] as StartSessionInput["config"]["extensions"],
90
+ },
91
+ }),
92
+ );
93
+
94
+ const core = await ClineCore.create({
95
+ prepare: async () => ({
96
+ applyToStartSessionInput,
97
+ dispose,
98
+ }),
99
+ });
100
+
101
+ await core.start(createStartInput());
102
+
103
+ expect(applyToStartSessionInput).toHaveBeenCalledTimes(1);
104
+ expect(host.start).toHaveBeenCalledTimes(1);
105
+ expect(dispose).toHaveBeenCalledTimes(1);
106
+ expect(listeners).toHaveLength(1);
107
+ });
108
+
109
+ it("disposes active session bootstraps when the session ends", async () => {
110
+ let listener:
111
+ | ((event: { type: string; payload: { sessionId: string } }) => void)
112
+ | undefined;
113
+ const host = {
114
+ start: vi.fn(async () => createStartResult("session-2")),
115
+ send: vi.fn(),
116
+ getAccumulatedUsage: vi.fn(),
117
+ abort: vi.fn(),
118
+ stop: vi.fn(),
119
+ dispose: vi.fn(),
120
+ get: vi.fn(async () => ({ sessionId: "session-2" })),
121
+ list: vi.fn(),
122
+ delete: vi.fn(),
123
+ readMessages: vi.fn(),
124
+ readTranscript: vi.fn(),
125
+ readHooks: vi.fn(),
126
+ subscribe: vi.fn((nextListener) => {
127
+ listener = nextListener;
128
+ return () => {};
129
+ }),
130
+ updateSessionModel: vi.fn(),
131
+ };
132
+ createSessionHostMock.mockResolvedValue(host);
133
+
134
+ const dispose = vi.fn(async () => {});
135
+ const core = await ClineCore.create({
136
+ prepare: async () => ({
137
+ applyToStartSessionInput: (input) => input,
138
+ dispose,
139
+ }),
140
+ });
141
+
142
+ await core.start(createStartInput());
143
+ expect(dispose).not.toHaveBeenCalled();
144
+
145
+ listener?.({ type: "ended", payload: { sessionId: "session-2" } });
146
+ await Promise.resolve();
147
+
148
+ expect(dispose).toHaveBeenCalledTimes(1);
149
+ });
150
+ });
package/src/ClineCore.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  import type {
2
2
  AgentConfig,
3
+ ITelemetryService,
3
4
  ToolApprovalRequest,
4
5
  ToolApprovalResult,
5
- } from "@clinebot/agents";
6
- import type { ITelemetryService } from "@clinebot/shared";
6
+ } from "@clinebot/shared";
7
+ import type { TeamToolsFactory } from "./runtime/session-runtime";
7
8
  import {
8
9
  createSessionHost,
9
10
  type SessionBackend,
10
11
  type SessionHost,
11
12
  } from "./session/session-host";
13
+ import type { StartSessionInput } from "./session/session-manager";
12
14
  import type { ToolExecutors } from "./tools";
13
15
 
14
16
  /** Advanced options for connecting to or spawning the Cline RPC server. */
@@ -87,6 +89,34 @@ export interface ClineCoreOptions {
87
89
  * @internal
88
90
  */
89
91
  sessionService?: SessionBackend;
92
+ /**
93
+ * Factory that creates team management tools for the multi-agent team system.
94
+ * When provided, team tools are registered whenever `enableAgentTeams` is `true`
95
+ * on a session config.
96
+ *
97
+ * Consumers that depend on `@clinebot/enterprise` can pass
98
+ * `bootstrapAgentTeams` here directly.
99
+ */
100
+ teamToolsFactory?: TeamToolsFactory;
101
+ /**
102
+ * Optional hook invoked before each session starts.
103
+ * Use this to prepare workspace-scoped runtime state and then return an
104
+ * adapter that mutates the `StartSessionInput` generically before core
105
+ * builds the runtime.
106
+ */
107
+ prepare?: (
108
+ input: StartSessionInput,
109
+ ) =>
110
+ | Promise<StartSessionBootstrap | undefined>
111
+ | StartSessionBootstrap
112
+ | undefined;
113
+ }
114
+
115
+ export interface StartSessionBootstrap {
116
+ applyToStartSessionInput(
117
+ input: StartSessionInput,
118
+ ): Promise<StartSessionInput> | StartSessionInput;
119
+ dispose?(): Promise<void> | void;
90
120
  }
91
121
 
92
122
  /**
@@ -103,27 +133,103 @@ export interface ClineCoreOptions {
103
133
  export class ClineCore implements SessionHost {
104
134
  readonly clientName: string | undefined;
105
135
  private readonly host: SessionHost;
136
+ private readonly prepare: ClineCoreOptions["prepare"] | undefined;
137
+ private readonly teamToolsFactory: TeamToolsFactory | undefined;
138
+ private readonly activeSessionBootstraps = new Map<
139
+ string,
140
+ StartSessionBootstrap
141
+ >();
142
+ private readonly unsubscribeBootstrapCleanup: () => void;
106
143
 
107
- private constructor(host: SessionHost, clientName: string | undefined) {
144
+ private constructor(
145
+ host: SessionHost,
146
+ clientName: string | undefined,
147
+ prepare: ClineCoreOptions["prepare"],
148
+ teamToolsFactory: TeamToolsFactory | undefined,
149
+ ) {
108
150
  this.clientName = clientName;
109
151
  this.host = host;
152
+ this.prepare = prepare;
153
+ this.teamToolsFactory = teamToolsFactory;
154
+ this.unsubscribeBootstrapCleanup = this.host.subscribe((event) => {
155
+ if (event.type !== "ended") {
156
+ return;
157
+ }
158
+ void this.disposeSessionBootstrap(event.payload.sessionId);
159
+ });
110
160
  }
111
161
 
112
162
  static async create(options: ClineCoreOptions = {}): Promise<ClineCore> {
113
163
  const host = await createSessionHost(options);
114
- return new ClineCore(host, options.clientName);
164
+ return new ClineCore(
165
+ host,
166
+ options.clientName,
167
+ options.prepare,
168
+ options.teamToolsFactory,
169
+ );
170
+ }
171
+
172
+ private async disposeSessionBootstrap(sessionId: string): Promise<void> {
173
+ const bootstrap = this.activeSessionBootstraps.get(sessionId);
174
+ if (!bootstrap) {
175
+ return;
176
+ }
177
+ this.activeSessionBootstraps.delete(sessionId);
178
+ await Promise.resolve(bootstrap.dispose?.());
115
179
  }
116
180
 
117
- start: SessionHost["start"] = (...args) => this.host.start(...args);
181
+ start: SessionHost["start"] = async (input) => {
182
+ const inputWithFactory: StartSessionInput = this.teamToolsFactory
183
+ ? { teamToolsFactory: this.teamToolsFactory, ...input }
184
+ : input;
185
+ const bootstrap = await this.prepare?.(inputWithFactory);
186
+ try {
187
+ const effectiveInput = bootstrap
188
+ ? await bootstrap.applyToStartSessionInput(inputWithFactory)
189
+ : inputWithFactory;
190
+ const result = await this.host.start(effectiveInput);
191
+ if (bootstrap) {
192
+ const activeSession = await this.host.get(result.sessionId);
193
+ if (activeSession) {
194
+ this.activeSessionBootstraps.set(result.sessionId, bootstrap);
195
+ } else {
196
+ await Promise.resolve(bootstrap.dispose?.());
197
+ }
198
+ }
199
+ return result;
200
+ } catch (error) {
201
+ await Promise.resolve(bootstrap?.dispose?.());
202
+ throw error;
203
+ }
204
+ };
118
205
  send: SessionHost["send"] = (...args) => this.host.send(...args);
119
206
  getAccumulatedUsage: SessionHost["getAccumulatedUsage"] = (...args) =>
120
207
  this.host.getAccumulatedUsage(...args);
121
208
  abort: SessionHost["abort"] = (...args) => this.host.abort(...args);
122
- stop: SessionHost["stop"] = (...args) => this.host.stop(...args);
123
- dispose: SessionHost["dispose"] = (...args) => this.host.dispose(...args);
209
+ stop: SessionHost["stop"] = async (sessionId) => {
210
+ await this.host.stop(sessionId);
211
+ await this.disposeSessionBootstrap(sessionId);
212
+ };
213
+ dispose: SessionHost["dispose"] = async (...args) => {
214
+ try {
215
+ await this.host.dispose(...args);
216
+ } finally {
217
+ this.unsubscribeBootstrapCleanup();
218
+ const sessionIds = [...this.activeSessionBootstraps.keys()];
219
+ await Promise.allSettled(
220
+ sessionIds.map((sessionId) => this.disposeSessionBootstrap(sessionId)),
221
+ );
222
+ }
223
+ };
124
224
  get: SessionHost["get"] = (...args) => this.host.get(...args);
125
225
  list: SessionHost["list"] = (...args) => this.host.list(...args);
126
- delete: SessionHost["delete"] = (...args) => this.host.delete(...args);
226
+ delete: SessionHost["delete"] = async (sessionId) => {
227
+ const deleted = await this.host.delete(sessionId);
228
+ if (deleted) {
229
+ await this.disposeSessionBootstrap(sessionId);
230
+ }
231
+ return deleted;
232
+ };
127
233
  readMessages: SessionHost["readMessages"] = (...args) =>
128
234
  this.host.readMessages(...args);
129
235
  readTranscript: SessionHost["readTranscript"] = (...args) =>
@@ -82,6 +82,90 @@ describe("ClineAccountService", () => {
82
82
  expect(transactions).toEqual([{ id: "tx-1" }]);
83
83
  });
84
84
 
85
+ it("fetches remote config with organizations list", async () => {
86
+ const remoteConfigPayload = {
87
+ organizationId: "org-1",
88
+ value: '{"model":"claude-4"}',
89
+ enabled: true,
90
+ organizations: [
91
+ { organizationId: "org-1", name: "Acme Corp" },
92
+ { organizationId: "org-2", name: "Beta Inc" },
93
+ ],
94
+ };
95
+
96
+ const fetchImpl = vi.fn(async (input: unknown) => {
97
+ expect(String(input)).toBe(
98
+ "https://api.cline.bot/api/v1/users/me/remote-config",
99
+ );
100
+ return new Response(
101
+ JSON.stringify({ success: true, data: remoteConfigPayload }),
102
+ { status: 200, headers: { "Content-Type": "application/json" } },
103
+ );
104
+ });
105
+
106
+ const service = new ClineAccountService({
107
+ apiBaseUrl: "https://api.cline.bot",
108
+ getAuthToken: async () => "workos:token-123",
109
+ fetchImpl: fetchImpl as unknown as typeof fetch,
110
+ });
111
+
112
+ const config = await service.fetchRemoteConfig();
113
+ expect(config).toEqual(remoteConfigPayload);
114
+ expect(config?.organizations).toHaveLength(2);
115
+ expect(config?.organizations?.[0]).toEqual({
116
+ organizationId: "org-1",
117
+ name: "Acme Corp",
118
+ });
119
+ });
120
+
121
+ it("fetches remote config with fallback org selected", async () => {
122
+ const remoteConfigPayload = {
123
+ organizationId: "org-fallback",
124
+ value: '{"model":"claude-4"}',
125
+ enabled: true,
126
+ organizations: [{ organizationId: "org-fallback", name: "Fallback Org" }],
127
+ };
128
+
129
+ const fetchImpl = vi.fn(async () => {
130
+ return new Response(
131
+ JSON.stringify({ success: true, data: remoteConfigPayload }),
132
+ { status: 200, headers: { "Content-Type": "application/json" } },
133
+ );
134
+ });
135
+
136
+ const service = new ClineAccountService({
137
+ apiBaseUrl: "https://api.cline.bot",
138
+ getAuthToken: async () => "workos:token-123",
139
+ fetchImpl: fetchImpl as unknown as typeof fetch,
140
+ });
141
+
142
+ const config = await service.fetchRemoteConfig();
143
+ expect(config?.organizationId).toBe("org-fallback");
144
+ expect(config?.organizations).toHaveLength(1);
145
+ expect(config?.organizations?.[0]).toEqual({
146
+ organizationId: "org-fallback",
147
+ name: "Fallback Org",
148
+ });
149
+ });
150
+
151
+ it("returns null when no org has remote config (data: null)", async () => {
152
+ const fetchImpl = vi.fn(async () => {
153
+ return new Response(JSON.stringify({ success: true, data: null }), {
154
+ status: 200,
155
+ headers: { "Content-Type": "application/json" },
156
+ });
157
+ });
158
+
159
+ const service = new ClineAccountService({
160
+ apiBaseUrl: "https://api.cline.bot",
161
+ getAuthToken: async () => "workos:token-123",
162
+ fetchImpl: fetchImpl as unknown as typeof fetch,
163
+ });
164
+
165
+ const config = await service.fetchRemoteConfig();
166
+ expect(config).toBeNull();
167
+ });
168
+
85
169
  it("switchAccount sends null org id for personal account", async () => {
86
170
  const fetchImpl = vi.fn(async (_input: unknown, init?: RequestInit) => {
87
171
  expect(init?.method).toBe("PUT");
@@ -66,8 +66,8 @@ export class ClineAccountService {
66
66
  return this.request<ClineAccountUser>("/api/v1/users/me");
67
67
  }
68
68
 
69
- public async fetchRemoteConfig(): Promise<UserRemoteConfigResponse> {
70
- return this.request<UserRemoteConfigResponse>(
69
+ public async fetchRemoteConfig(): Promise<UserRemoteConfigResponse | null> {
70
+ return this.request<UserRemoteConfigResponse | null>(
71
71
  "/api/v1/users/me/remote-config",
72
72
  );
73
73
  }
@@ -19,5 +19,6 @@ export type {
19
19
  ClineAccountUser,
20
20
  ClineOrganization,
21
21
  FeaturebaseTokenResponse,
22
+ UserRemoteConfigOrganization,
22
23
  UserRemoteConfigResponse,
23
24
  } from "./types";
@@ -16,10 +16,16 @@ export interface ClineAccountUser {
16
16
  organizations: ClineAccountOrganization[];
17
17
  }
18
18
 
19
+ export interface UserRemoteConfigOrganization {
20
+ organizationId: string;
21
+ name: string;
22
+ }
23
+
19
24
  export interface UserRemoteConfigResponse {
20
25
  organizationId: string;
21
26
  value: string;
22
27
  enabled: boolean;
28
+ organizations?: UserRemoteConfigOrganization[];
23
29
  }
24
30
 
25
31
  export interface ClineAccountBalance {
@@ -0,0 +1,38 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { BoundedTtlCache } from "./bounded-ttl-cache";
3
+
4
+ describe("BoundedTtlCache", () => {
5
+ it("returns undefined after TTL", () => {
6
+ const cache = new BoundedTtlCache(1_000, 10);
7
+ cache.set("a", "one", 0);
8
+ expect(cache.get("a", 500)).toBe("one");
9
+ expect(cache.get("a", 1_500)).toBeUndefined();
10
+ });
11
+
12
+ it("evicts oldest entries when over max size", () => {
13
+ const cache = new BoundedTtlCache(60_000, 2);
14
+ cache.set("a", "1", 0);
15
+ cache.set("b", "2", 0);
16
+ cache.set("c", "3", 0);
17
+ expect(cache.get("a", 0)).toBeUndefined();
18
+ expect(cache.get("b", 0)).toBe("2");
19
+ expect(cache.get("c", 0)).toBe("3");
20
+ });
21
+
22
+ it("refreshes recency on get so hot keys survive eviction", () => {
23
+ const cache = new BoundedTtlCache(60_000, 2);
24
+ cache.set("a", "1", 0);
25
+ cache.set("b", "2", 0);
26
+ expect(cache.get("a", 0)).toBe("1");
27
+ cache.set("c", "3", 0);
28
+ expect(cache.get("a", 0)).toBe("1");
29
+ expect(cache.get("b", 0)).toBeUndefined();
30
+ });
31
+
32
+ it("supports per-entry TTL override", () => {
33
+ const cache = new BoundedTtlCache(60_000, 2);
34
+ cache.set("short", "v", 0, 1_000);
35
+ expect(cache.get("short", 500)).toBe("v");
36
+ expect(cache.get("short", 1_500)).toBeUndefined();
37
+ });
38
+ });
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Small process-local string cache with TTL expiry and a hard entry cap.
3
+ * Used where unbounded Maps would grow without bound in long-running processes.
4
+ */
5
+ export class BoundedTtlCache {
6
+ private readonly entries = new Map<
7
+ string,
8
+ { value: string; expiresAt: number }
9
+ >();
10
+
11
+ constructor(
12
+ private readonly ttlMs: number,
13
+ private readonly maxEntries: number,
14
+ ) {}
15
+
16
+ get(key: string, now = Date.now()): string | undefined {
17
+ this.pruneExpired(now);
18
+ const hit = this.entries.get(key);
19
+ if (!hit) {
20
+ return undefined;
21
+ }
22
+ // Bump recency for FIFO eviction under cap.
23
+ this.entries.delete(key);
24
+ this.entries.set(key, hit);
25
+ return hit.value;
26
+ }
27
+
28
+ set(
29
+ key: string,
30
+ value: string,
31
+ now = Date.now(),
32
+ ttlMsOverride = this.ttlMs,
33
+ ): void {
34
+ this.pruneExpired(now);
35
+ this.entries.delete(key);
36
+ while (this.entries.size >= this.maxEntries) {
37
+ const first = this.entries.keys().next().value as string | undefined;
38
+ if (first === undefined) {
39
+ break;
40
+ }
41
+ this.entries.delete(first);
42
+ }
43
+ this.entries.set(key, { value, expiresAt: now + ttlMsOverride });
44
+ }
45
+
46
+ private pruneExpired(now: number): void {
47
+ for (const [k, v] of this.entries) {
48
+ if (v.expiresAt <= now) {
49
+ this.entries.delete(k);
50
+ }
51
+ }
52
+ }
53
+ }