@clinebot/core 0.0.18 → 0.0.21

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 (356) hide show
  1. package/dist/account/cline-account-service.d.ts +3 -2
  2. package/dist/account/cline-account-service.d.ts.map +1 -0
  3. package/dist/account/index.d.ts +1 -0
  4. package/dist/account/index.d.ts.map +1 -0
  5. package/dist/account/rpc.d.ts +1 -0
  6. package/dist/account/rpc.d.ts.map +1 -0
  7. package/dist/account/types.d.ts +1 -0
  8. package/dist/account/types.d.ts.map +1 -0
  9. package/dist/agents/agent-config-loader.d.ts +1 -0
  10. package/dist/agents/agent-config-loader.d.ts.map +1 -0
  11. package/dist/agents/agent-config-parser.d.ts +1 -0
  12. package/dist/agents/agent-config-parser.d.ts.map +1 -0
  13. package/dist/agents/hooks-config-loader.d.ts +1 -0
  14. package/dist/agents/hooks-config-loader.d.ts.map +1 -0
  15. package/dist/agents/index.d.ts +1 -0
  16. package/dist/agents/index.d.ts.map +1 -0
  17. package/dist/agents/plugin-config-loader.d.ts +1 -0
  18. package/dist/agents/plugin-config-loader.d.ts.map +1 -0
  19. package/dist/agents/plugin-loader.d.ts +1 -0
  20. package/dist/agents/plugin-loader.d.ts.map +1 -0
  21. package/dist/agents/plugin-sandbox.d.ts +1 -0
  22. package/dist/agents/plugin-sandbox.d.ts.map +1 -0
  23. package/dist/agents/unified-config-file-watcher.d.ts +1 -0
  24. package/dist/agents/unified-config-file-watcher.d.ts.map +1 -0
  25. package/dist/agents/user-instruction-config-loader.d.ts +1 -0
  26. package/dist/agents/user-instruction-config-loader.d.ts.map +1 -0
  27. package/dist/auth/client.d.ts +1 -0
  28. package/dist/auth/client.d.ts.map +1 -0
  29. package/dist/auth/cline.d.ts +1 -0
  30. package/dist/auth/cline.d.ts.map +1 -0
  31. package/dist/auth/codex.d.ts +1 -0
  32. package/dist/auth/codex.d.ts.map +1 -0
  33. package/dist/auth/oca.d.ts +1 -0
  34. package/dist/auth/oca.d.ts.map +1 -0
  35. package/dist/auth/server.d.ts +1 -0
  36. package/dist/auth/server.d.ts.map +1 -0
  37. package/dist/auth/types.d.ts +1 -0
  38. package/dist/auth/types.d.ts.map +1 -0
  39. package/dist/auth/utils.d.ts +1 -0
  40. package/dist/auth/utils.d.ts.map +1 -0
  41. package/dist/chat/chat-schema.d.ts +13 -12
  42. package/dist/chat/chat-schema.d.ts.map +1 -0
  43. package/dist/index.d.ts +3 -1
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.node.d.ts +2 -0
  46. package/dist/index.node.d.ts.map +1 -0
  47. package/dist/index.node.js +303 -302
  48. package/dist/input/file-indexer.d.ts +1 -0
  49. package/dist/input/file-indexer.d.ts.map +1 -0
  50. package/dist/input/index.d.ts +1 -0
  51. package/dist/input/index.d.ts.map +1 -0
  52. package/dist/input/mention-enricher.d.ts +1 -0
  53. package/dist/input/mention-enricher.d.ts.map +1 -0
  54. package/dist/mcp/config-loader.d.ts +1 -0
  55. package/dist/mcp/config-loader.d.ts.map +1 -0
  56. package/dist/mcp/index.d.ts +1 -0
  57. package/dist/mcp/index.d.ts.map +1 -0
  58. package/dist/mcp/manager.d.ts +1 -0
  59. package/dist/mcp/manager.d.ts.map +1 -0
  60. package/dist/mcp/types.d.ts +1 -0
  61. package/dist/mcp/types.d.ts.map +1 -0
  62. package/dist/providers/local-provider-registry.d.ts +36 -0
  63. package/dist/providers/local-provider-registry.d.ts.map +1 -0
  64. package/dist/providers/local-provider-service.d.ts +2 -1
  65. package/dist/providers/local-provider-service.d.ts.map +1 -0
  66. package/dist/runtime/commands.d.ts +1 -0
  67. package/dist/runtime/commands.d.ts.map +1 -0
  68. package/dist/runtime/hook-file-hooks.d.ts +1 -0
  69. package/dist/runtime/hook-file-hooks.d.ts.map +1 -0
  70. package/dist/runtime/rules.d.ts +1 -0
  71. package/dist/runtime/rules.d.ts.map +1 -0
  72. package/dist/runtime/runtime-builder.d.ts +1 -0
  73. package/dist/runtime/runtime-builder.d.ts.map +1 -0
  74. package/dist/runtime/sandbox/subprocess-sandbox.d.ts +1 -0
  75. package/dist/runtime/sandbox/subprocess-sandbox.d.ts.map +1 -0
  76. package/dist/runtime/session-runtime.d.ts +2 -0
  77. package/dist/runtime/session-runtime.d.ts.map +1 -0
  78. package/dist/runtime/skills.d.ts +1 -0
  79. package/dist/runtime/skills.d.ts.map +1 -0
  80. package/dist/runtime/tool-approval.d.ts +1 -0
  81. package/dist/runtime/tool-approval.d.ts.map +1 -0
  82. package/dist/runtime/workflows.d.ts +1 -0
  83. package/dist/runtime/workflows.d.ts.map +1 -0
  84. package/dist/session/default-session-manager.d.ts +4 -0
  85. package/dist/session/default-session-manager.d.ts.map +1 -0
  86. package/dist/session/file-session-service.d.ts +1 -0
  87. package/dist/session/file-session-service.d.ts.map +1 -0
  88. package/dist/session/rpc-session-service.d.ts +1 -0
  89. package/dist/session/rpc-session-service.d.ts.map +1 -0
  90. package/dist/session/rpc-spawn-lease.d.ts +1 -0
  91. package/dist/session/rpc-spawn-lease.d.ts.map +1 -0
  92. package/dist/session/runtime-oauth-token-manager.d.ts +1 -0
  93. package/dist/session/runtime-oauth-token-manager.d.ts.map +1 -0
  94. package/dist/session/session-agent-events.d.ts +20 -1
  95. package/dist/session/session-agent-events.d.ts.map +1 -0
  96. package/dist/session/session-artifacts.d.ts +1 -0
  97. package/dist/session/session-artifacts.d.ts.map +1 -0
  98. package/dist/session/session-config-builder.d.ts +1 -0
  99. package/dist/session/session-config-builder.d.ts.map +1 -0
  100. package/dist/session/session-graph.d.ts +1 -0
  101. package/dist/session/session-graph.d.ts.map +1 -0
  102. package/dist/session/session-host.d.ts +1 -0
  103. package/dist/session/session-host.d.ts.map +1 -0
  104. package/dist/session/session-manager.d.ts +1 -0
  105. package/dist/session/session-manager.d.ts.map +1 -0
  106. package/dist/session/session-manifest.d.ts +2 -1
  107. package/dist/session/session-manifest.d.ts.map +1 -0
  108. package/dist/session/session-service.d.ts +1 -0
  109. package/dist/session/session-service.d.ts.map +1 -0
  110. package/dist/session/session-team-coordination.d.ts +1 -0
  111. package/dist/session/session-team-coordination.d.ts.map +1 -0
  112. package/dist/session/session-telemetry.d.ts +3 -1
  113. package/dist/session/session-telemetry.d.ts.map +1 -0
  114. package/dist/session/sqlite-rpc-session-backend.d.ts +1 -0
  115. package/dist/session/sqlite-rpc-session-backend.d.ts.map +1 -0
  116. package/dist/session/unified-session-persistence-service.d.ts +1 -0
  117. package/dist/session/unified-session-persistence-service.d.ts.map +1 -0
  118. package/dist/session/utils/helpers.d.ts +1 -0
  119. package/dist/session/utils/helpers.d.ts.map +1 -0
  120. package/dist/session/utils/types.d.ts +1 -0
  121. package/dist/session/utils/types.d.ts.map +1 -0
  122. package/dist/session/utils/usage.d.ts +1 -0
  123. package/dist/session/utils/usage.d.ts.map +1 -0
  124. package/dist/session/workspace-manager.d.ts +1 -0
  125. package/dist/session/workspace-manager.d.ts.map +1 -0
  126. package/dist/session/workspace-manifest.d.ts +1 -0
  127. package/dist/session/workspace-manifest.d.ts.map +1 -0
  128. package/dist/storage/file-team-store.d.ts +1 -0
  129. package/dist/storage/file-team-store.d.ts.map +1 -0
  130. package/dist/storage/provider-settings-legacy-migration.d.ts +1 -0
  131. package/dist/storage/provider-settings-legacy-migration.d.ts.map +1 -0
  132. package/dist/storage/provider-settings-manager.d.ts +1 -0
  133. package/dist/storage/provider-settings-manager.d.ts.map +1 -0
  134. package/dist/storage/sqlite-session-store.d.ts +1 -0
  135. package/dist/storage/sqlite-session-store.d.ts.map +1 -0
  136. package/dist/storage/sqlite-team-store.d.ts +1 -0
  137. package/dist/storage/sqlite-team-store.d.ts.map +1 -0
  138. package/dist/storage/team-store.d.ts +1 -0
  139. package/dist/storage/team-store.d.ts.map +1 -0
  140. package/dist/team/index.d.ts +1 -0
  141. package/dist/team/index.d.ts.map +1 -0
  142. package/dist/team/projections.d.ts +1 -0
  143. package/dist/team/projections.d.ts.map +1 -0
  144. package/dist/telemetry/ITelemetryAdapter.d.ts +1 -0
  145. package/dist/telemetry/ITelemetryAdapter.d.ts.map +1 -0
  146. package/dist/telemetry/LoggerTelemetryAdapter.d.ts +1 -0
  147. package/dist/telemetry/LoggerTelemetryAdapter.d.ts.map +1 -0
  148. package/dist/telemetry/OpenTelemetryAdapter.d.ts +1 -0
  149. package/dist/telemetry/OpenTelemetryAdapter.d.ts.map +1 -0
  150. package/dist/telemetry/OpenTelemetryProvider.d.ts +1 -0
  151. package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -0
  152. package/dist/telemetry/TelemetryService.d.ts +1 -0
  153. package/dist/telemetry/TelemetryService.d.ts.map +1 -0
  154. package/dist/telemetry/core-events.d.ts +55 -22
  155. package/dist/telemetry/core-events.d.ts.map +1 -0
  156. package/dist/telemetry/opentelemetry.d.ts +1 -0
  157. package/dist/telemetry/opentelemetry.d.ts.map +1 -0
  158. package/dist/tools/constants.d.ts +1 -0
  159. package/dist/tools/constants.d.ts.map +1 -0
  160. package/dist/tools/definitions.d.ts +8 -1
  161. package/dist/tools/definitions.d.ts.map +1 -0
  162. package/dist/tools/executors/apply-patch-parser.d.ts +1 -0
  163. package/dist/tools/executors/apply-patch-parser.d.ts.map +1 -0
  164. package/dist/tools/executors/apply-patch.d.ts +1 -0
  165. package/dist/tools/executors/apply-patch.d.ts.map +1 -0
  166. package/dist/tools/executors/bash.d.ts +2 -1
  167. package/dist/tools/executors/bash.d.ts.map +1 -0
  168. package/dist/tools/executors/editor.d.ts +1 -0
  169. package/dist/tools/executors/editor.d.ts.map +1 -0
  170. package/dist/tools/executors/file-read.d.ts +1 -0
  171. package/dist/tools/executors/file-read.d.ts.map +1 -0
  172. package/dist/tools/executors/index.d.ts +14 -7
  173. package/dist/tools/executors/index.d.ts.map +1 -0
  174. package/dist/tools/executors/search.d.ts +1 -0
  175. package/dist/tools/executors/search.d.ts.map +1 -0
  176. package/dist/tools/executors/web-fetch.d.ts +1 -0
  177. package/dist/tools/executors/web-fetch.d.ts.map +1 -0
  178. package/dist/tools/helpers.d.ts +15 -0
  179. package/dist/tools/helpers.d.ts.map +1 -0
  180. package/dist/tools/index.d.ts +2 -1
  181. package/dist/tools/index.d.ts.map +1 -0
  182. package/dist/tools/model-tool-routing.d.ts +1 -0
  183. package/dist/tools/model-tool-routing.d.ts.map +1 -0
  184. package/dist/tools/presets.d.ts +1 -0
  185. package/dist/tools/presets.d.ts.map +1 -0
  186. package/dist/tools/schemas.d.ts +41 -0
  187. package/dist/tools/schemas.d.ts.map +1 -0
  188. package/dist/tools/types.d.ts +3 -2
  189. package/dist/tools/types.d.ts.map +1 -0
  190. package/dist/types/common.d.ts +1 -0
  191. package/dist/types/common.d.ts.map +1 -0
  192. package/dist/types/config.d.ts +1 -0
  193. package/dist/types/config.d.ts.map +1 -0
  194. package/dist/types/events.d.ts +1 -0
  195. package/dist/types/events.d.ts.map +1 -0
  196. package/dist/types/provider-settings.d.ts +1 -0
  197. package/dist/types/provider-settings.d.ts.map +1 -0
  198. package/dist/types/sessions.d.ts +1 -0
  199. package/dist/types/sessions.d.ts.map +1 -0
  200. package/dist/types/storage.d.ts +1 -0
  201. package/dist/types/storage.d.ts.map +1 -0
  202. package/dist/types/workspace.d.ts +1 -0
  203. package/dist/types/workspace.d.ts.map +1 -0
  204. package/dist/types.d.ts +1 -0
  205. package/dist/types.d.ts.map +1 -0
  206. package/package.json +8 -6
  207. package/src/account/cline-account-service.test.ts +0 -101
  208. package/src/account/cline-account-service.ts +0 -287
  209. package/src/account/index.ts +0 -22
  210. package/src/account/rpc.test.ts +0 -62
  211. package/src/account/rpc.ts +0 -172
  212. package/src/account/types.ts +0 -98
  213. package/src/agents/agent-config-loader.test.ts +0 -236
  214. package/src/agents/agent-config-loader.ts +0 -108
  215. package/src/agents/agent-config-parser.ts +0 -198
  216. package/src/agents/hooks-config-loader.test.ts +0 -20
  217. package/src/agents/hooks-config-loader.ts +0 -118
  218. package/src/agents/index.ts +0 -85
  219. package/src/agents/plugin-config-loader.test.ts +0 -140
  220. package/src/agents/plugin-config-loader.ts +0 -97
  221. package/src/agents/plugin-loader.test.ts +0 -228
  222. package/src/agents/plugin-loader.ts +0 -172
  223. package/src/agents/plugin-sandbox-bootstrap.ts +0 -445
  224. package/src/agents/plugin-sandbox.test.ts +0 -317
  225. package/src/agents/plugin-sandbox.ts +0 -341
  226. package/src/agents/unified-config-file-watcher.test.ts +0 -196
  227. package/src/agents/unified-config-file-watcher.ts +0 -483
  228. package/src/agents/user-instruction-config-loader.test.ts +0 -158
  229. package/src/agents/user-instruction-config-loader.ts +0 -438
  230. package/src/auth/client.test.ts +0 -40
  231. package/src/auth/client.ts +0 -25
  232. package/src/auth/cline.test.ts +0 -130
  233. package/src/auth/cline.ts +0 -420
  234. package/src/auth/codex.test.ts +0 -170
  235. package/src/auth/codex.ts +0 -491
  236. package/src/auth/oca.test.ts +0 -215
  237. package/src/auth/oca.ts +0 -573
  238. package/src/auth/server.ts +0 -216
  239. package/src/auth/types.ts +0 -81
  240. package/src/auth/utils.test.ts +0 -128
  241. package/src/auth/utils.ts +0 -247
  242. package/src/chat/chat-schema.ts +0 -82
  243. package/src/index.node.ts +0 -285
  244. package/src/index.ts +0 -211
  245. package/src/input/file-indexer.d.ts +0 -11
  246. package/src/input/file-indexer.test.ts +0 -127
  247. package/src/input/file-indexer.ts +0 -327
  248. package/src/input/index.ts +0 -7
  249. package/src/input/mention-enricher.test.ts +0 -85
  250. package/src/input/mention-enricher.ts +0 -122
  251. package/src/mcp/config-loader.test.ts +0 -238
  252. package/src/mcp/config-loader.ts +0 -219
  253. package/src/mcp/index.ts +0 -26
  254. package/src/mcp/manager.test.ts +0 -106
  255. package/src/mcp/manager.ts +0 -262
  256. package/src/mcp/types.ts +0 -88
  257. package/src/providers/local-provider-service.ts +0 -608
  258. package/src/runtime/commands.test.ts +0 -98
  259. package/src/runtime/commands.ts +0 -83
  260. package/src/runtime/hook-file-hooks.test.ts +0 -237
  261. package/src/runtime/hook-file-hooks.ts +0 -859
  262. package/src/runtime/index.ts +0 -37
  263. package/src/runtime/rules.ts +0 -34
  264. package/src/runtime/runtime-builder.team-persistence.test.ts +0 -202
  265. package/src/runtime/runtime-builder.test.ts +0 -371
  266. package/src/runtime/runtime-builder.ts +0 -589
  267. package/src/runtime/runtime-parity.test.ts +0 -143
  268. package/src/runtime/sandbox/subprocess-sandbox.ts +0 -231
  269. package/src/runtime/session-runtime.ts +0 -46
  270. package/src/runtime/skills.ts +0 -44
  271. package/src/runtime/tool-approval.ts +0 -104
  272. package/src/runtime/workflows.test.ts +0 -119
  273. package/src/runtime/workflows.ts +0 -45
  274. package/src/session/default-session-manager.e2e.test.ts +0 -384
  275. package/src/session/default-session-manager.test.ts +0 -1741
  276. package/src/session/default-session-manager.ts +0 -1233
  277. package/src/session/file-session-service.ts +0 -280
  278. package/src/session/index.ts +0 -42
  279. package/src/session/rpc-session-service.ts +0 -107
  280. package/src/session/rpc-spawn-lease.test.ts +0 -49
  281. package/src/session/rpc-spawn-lease.ts +0 -122
  282. package/src/session/runtime-oauth-token-manager.test.ts +0 -137
  283. package/src/session/runtime-oauth-token-manager.ts +0 -272
  284. package/src/session/session-agent-events.ts +0 -159
  285. package/src/session/session-artifacts.ts +0 -106
  286. package/src/session/session-config-builder.ts +0 -113
  287. package/src/session/session-graph.ts +0 -92
  288. package/src/session/session-host.test.ts +0 -29
  289. package/src/session/session-host.ts +0 -242
  290. package/src/session/session-manager.ts +0 -69
  291. package/src/session/session-manifest.ts +0 -29
  292. package/src/session/session-service.team-persistence.test.ts +0 -48
  293. package/src/session/session-service.ts +0 -673
  294. package/src/session/session-team-coordination.ts +0 -229
  295. package/src/session/session-telemetry.ts +0 -95
  296. package/src/session/sqlite-rpc-session-backend.ts +0 -303
  297. package/src/session/unified-session-persistence-service.test.ts +0 -85
  298. package/src/session/unified-session-persistence-service.ts +0 -996
  299. package/src/session/utils/helpers.ts +0 -139
  300. package/src/session/utils/types.ts +0 -57
  301. package/src/session/utils/usage.ts +0 -32
  302. package/src/session/workspace-manager.ts +0 -98
  303. package/src/session/workspace-manifest.ts +0 -100
  304. package/src/storage/artifact-store.ts +0 -1
  305. package/src/storage/file-team-store.ts +0 -257
  306. package/src/storage/index.ts +0 -11
  307. package/src/storage/provider-settings-legacy-migration.test.ts +0 -307
  308. package/src/storage/provider-settings-legacy-migration.ts +0 -689
  309. package/src/storage/provider-settings-manager.test.ts +0 -145
  310. package/src/storage/provider-settings-manager.ts +0 -150
  311. package/src/storage/session-store.ts +0 -1
  312. package/src/storage/sqlite-session-store.ts +0 -275
  313. package/src/storage/sqlite-team-store.ts +0 -454
  314. package/src/storage/team-store.ts +0 -40
  315. package/src/team/index.ts +0 -4
  316. package/src/team/projections.ts +0 -285
  317. package/src/telemetry/ITelemetryAdapter.ts +0 -94
  318. package/src/telemetry/LoggerTelemetryAdapter.test.ts +0 -42
  319. package/src/telemetry/LoggerTelemetryAdapter.ts +0 -114
  320. package/src/telemetry/OpenTelemetryAdapter.test.ts +0 -157
  321. package/src/telemetry/OpenTelemetryAdapter.ts +0 -348
  322. package/src/telemetry/OpenTelemetryProvider.test.ts +0 -113
  323. package/src/telemetry/OpenTelemetryProvider.ts +0 -322
  324. package/src/telemetry/TelemetryService.test.ts +0 -134
  325. package/src/telemetry/TelemetryService.ts +0 -141
  326. package/src/telemetry/core-events.ts +0 -344
  327. package/src/telemetry/opentelemetry.ts +0 -20
  328. package/src/tools/constants.ts +0 -35
  329. package/src/tools/definitions.test.ts +0 -658
  330. package/src/tools/definitions.ts +0 -726
  331. package/src/tools/executors/apply-patch-parser.ts +0 -520
  332. package/src/tools/executors/apply-patch.ts +0 -359
  333. package/src/tools/executors/bash.ts +0 -205
  334. package/src/tools/executors/editor.test.ts +0 -35
  335. package/src/tools/executors/editor.ts +0 -219
  336. package/src/tools/executors/file-read.test.ts +0 -49
  337. package/src/tools/executors/file-read.ts +0 -110
  338. package/src/tools/executors/index.ts +0 -75
  339. package/src/tools/executors/search.ts +0 -278
  340. package/src/tools/executors/web-fetch.ts +0 -259
  341. package/src/tools/index.ts +0 -168
  342. package/src/tools/model-tool-routing.test.ts +0 -86
  343. package/src/tools/model-tool-routing.ts +0 -132
  344. package/src/tools/presets.test.ts +0 -62
  345. package/src/tools/presets.ts +0 -168
  346. package/src/tools/schemas.ts +0 -284
  347. package/src/tools/types.ts +0 -328
  348. package/src/types/common.ts +0 -14
  349. package/src/types/config.ts +0 -84
  350. package/src/types/events.ts +0 -74
  351. package/src/types/index.ts +0 -24
  352. package/src/types/provider-settings.ts +0 -43
  353. package/src/types/sessions.ts +0 -16
  354. package/src/types/storage.ts +0 -64
  355. package/src/types/workspace.ts +0 -7
  356. package/src/types.ts +0 -128
@@ -1,1233 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { readFile, stat } from "node:fs/promises";
3
- import { homedir } from "node:os";
4
- import { isAbsolute, join, resolve } from "node:path";
5
- import {
6
- Agent,
7
- type AgentConfig,
8
- type AgentEvent,
9
- type AgentResult,
10
- createSpawnAgentTool,
11
- type TeamEvent,
12
- type Tool,
13
- type ToolApprovalRequest,
14
- type ToolApprovalResult,
15
- } from "@clinebot/agents";
16
- import type { LlmsProviders } from "@clinebot/llms";
17
- import {
18
- type ITelemetryService,
19
- isLikelyAuthError,
20
- normalizeUserInput,
21
- } from "@clinebot/shared";
22
- import { setHomeDirIfUnset } from "@clinebot/shared/storage";
23
- import { nanoid } from "nanoid";
24
- import { enrichPromptWithMentions } from "../input";
25
- import { DefaultRuntimeBuilder } from "../runtime/runtime-builder";
26
- import type { RuntimeBuilder } from "../runtime/session-runtime";
27
- import { ProviderSettingsManager } from "../storage/provider-settings-manager";
28
- import {
29
- captureConversationTurnEvent,
30
- captureModeSwitch,
31
- captureSubagentExecution,
32
- captureTaskCompleted,
33
- } from "../telemetry/core-events";
34
- import { createBuiltinTools, type ToolExecutors, ToolPresets } from "../tools";
35
- import { SessionSource, type SessionStatus } from "../types/common";
36
- import type { CoreSessionConfig } from "../types/config";
37
- import type { CoreSessionEvent } from "../types/events";
38
- import type { SessionRecord } from "../types/sessions";
39
- import type { FileSessionService } from "./file-session-service";
40
- import type { RpcCoreSessionService } from "./rpc-session-service";
41
- import {
42
- OAuthReauthRequiredError,
43
- type RuntimeOAuthResolution,
44
- RuntimeOAuthTokenManager,
45
- } from "./runtime-oauth-token-manager";
46
- import {
47
- type AgentEventContext,
48
- handleAgentEvent,
49
- } from "./session-agent-events";
50
- import { nowIso } from "./session-artifacts";
51
- import {
52
- buildEffectiveConfig,
53
- buildResolvedProviderConfig,
54
- resolveReasoningSettings,
55
- resolveWorkspacePath,
56
- } from "./session-config-builder";
57
- import type {
58
- SendSessionInput,
59
- SessionAccumulatedUsage,
60
- SessionManager,
61
- StartSessionInput,
62
- StartSessionResult,
63
- } from "./session-manager";
64
- import { SessionManifestSchema } from "./session-manifest";
65
- import type {
66
- CoreSessionService,
67
- RootSessionArtifacts,
68
- SessionRow,
69
- } from "./session-service";
70
- import {
71
- buildTeamRunContinuationPrompt,
72
- dispatchTeamEventToBackend,
73
- emitTeamProgress,
74
- formatModePrompt,
75
- hasPendingTeamRunWork,
76
- notifyTeamRunWaiters,
77
- shouldAutoContinueTeamRuns,
78
- trackTeamRunState,
79
- waitForTeamRunUpdates,
80
- } from "./session-team-coordination";
81
- import {
82
- emitMentionTelemetry,
83
- emitSessionCreationTelemetry,
84
- } from "./session-telemetry";
85
- import {
86
- extractWorkspaceMetadataFromSystemPrompt,
87
- toSessionRecord,
88
- withLatestAssistantTurnMetadata,
89
- } from "./utils/helpers";
90
- import type { ActiveSession, PreparedTurnInput } from "./utils/types";
91
- import {
92
- accumulateUsageTotals,
93
- createInitialAccumulatedUsage,
94
- } from "./utils/usage";
95
-
96
- type SessionBackend =
97
- | CoreSessionService
98
- | RpcCoreSessionService
99
- | FileSessionService;
100
-
101
- const MAX_SCAN_LIMIT = 5000;
102
- const MAX_USER_FILE_BYTES = 20 * 1_000 * 1_024;
103
-
104
- async function loadUserFileContent(path: string): Promise<string> {
105
- const fileStat = await stat(path);
106
- if (!fileStat.isFile()) {
107
- throw new Error("Path is not a file");
108
- }
109
- if (fileStat.size > MAX_USER_FILE_BYTES) {
110
- throw new Error("File is too large to read into context.");
111
- }
112
- const content = await readFile(path, "utf8");
113
- if (content.includes("\u0000")) {
114
- throw new Error("Cannot read binary file into context.");
115
- }
116
- return content;
117
- }
118
-
119
- export interface DefaultSessionManagerOptions {
120
- distinctId: string;
121
- sessionService: SessionBackend;
122
- runtimeBuilder?: RuntimeBuilder;
123
- createAgent?: (config: AgentConfig) => Agent;
124
- defaultToolExecutors?: Partial<ToolExecutors>;
125
- toolPolicies?: AgentConfig["toolPolicies"];
126
- providerSettingsManager?: ProviderSettingsManager;
127
- oauthTokenManager?: RuntimeOAuthTokenManager;
128
- telemetry?: ITelemetryService;
129
- requestToolApproval?: (
130
- request: ToolApprovalRequest,
131
- ) => Promise<ToolApprovalResult>;
132
- }
133
-
134
- export class DefaultSessionManager implements SessionManager {
135
- private readonly sessionService: SessionBackend;
136
- private readonly runtimeBuilder: RuntimeBuilder;
137
- private readonly createAgentInstance: (config: AgentConfig) => Agent;
138
- private readonly defaultToolExecutors?: Partial<ToolExecutors>;
139
- private readonly defaultToolPolicies?: AgentConfig["toolPolicies"];
140
- private readonly providerSettingsManager: ProviderSettingsManager;
141
- private readonly oauthTokenManager: RuntimeOAuthTokenManager;
142
- private readonly defaultTelemetry?: ITelemetryService;
143
- private readonly defaultRequestToolApproval?: (
144
- request: ToolApprovalRequest,
145
- ) => Promise<ToolApprovalResult>;
146
- private readonly listeners = new Set<(event: CoreSessionEvent) => void>();
147
- private readonly sessions = new Map<string, ActiveSession>();
148
- private readonly usageBySession = new Map<string, SessionAccumulatedUsage>();
149
- private readonly subAgentStarts = new Map<
150
- string,
151
- { startedAt: number; rootSessionId: string }
152
- >();
153
-
154
- constructor(options: DefaultSessionManagerOptions) {
155
- const homeDir = homedir();
156
- if (homeDir) setHomeDirIfUnset(homeDir);
157
- this.sessionService = options.sessionService;
158
- this.runtimeBuilder = options.runtimeBuilder ?? new DefaultRuntimeBuilder();
159
- this.createAgentInstance =
160
- options.createAgent ?? ((config) => new Agent(config));
161
- this.defaultToolExecutors = options.defaultToolExecutors;
162
- this.defaultToolPolicies = options.toolPolicies;
163
- this.providerSettingsManager =
164
- options.providerSettingsManager ?? new ProviderSettingsManager();
165
- this.oauthTokenManager =
166
- options.oauthTokenManager ??
167
- new RuntimeOAuthTokenManager({
168
- providerSettingsManager: this.providerSettingsManager,
169
- telemetry: options.telemetry,
170
- });
171
- this.defaultTelemetry = options.telemetry;
172
- this.defaultRequestToolApproval = options.requestToolApproval;
173
- }
174
-
175
- // ── Public API ──────────────────────────────────────────────────────
176
-
177
- async start(input: StartSessionInput): Promise<StartSessionResult> {
178
- const source = input.source ?? SessionSource.CLI;
179
- const startedAt = nowIso();
180
- const requestedSessionId = input.config.sessionId?.trim() ?? "";
181
- const sessionId =
182
- requestedSessionId.length > 0
183
- ? requestedSessionId
184
- : `${Date.now()}_${nanoid(5)}`;
185
- this.usageBySession.set(sessionId, createInitialAccumulatedUsage());
186
-
187
- const sessionsDir =
188
- ((await this.invokeOptionalValue("ensureSessionsDir")) as
189
- | string
190
- | undefined) ?? "";
191
- if (!sessionsDir) {
192
- throw new Error(
193
- "session service method not available: ensureSessionsDir",
194
- );
195
- }
196
-
197
- const sessionDir = join(sessionsDir, sessionId);
198
- const transcriptPath = join(sessionDir, `${sessionId}.log`);
199
- const hookPath = join(sessionDir, `${sessionId}.hooks.jsonl`);
200
- const messagesPath = join(sessionDir, `${sessionId}.messages.json`);
201
- const manifestPath = join(sessionDir, `${sessionId}.json`);
202
- const workspacePath = resolveWorkspacePath(input.config);
203
-
204
- const manifest = SessionManifestSchema.parse({
205
- version: 1,
206
- session_id: sessionId,
207
- source,
208
- pid: process.pid,
209
- started_at: startedAt,
210
- status: "running",
211
- interactive: input.interactive === true,
212
- provider: input.config.providerId,
213
- model: input.config.modelId,
214
- cwd: input.config.cwd,
215
- workspace_root: workspacePath,
216
- team_name: input.config.teamName,
217
- enable_tools: input.config.enableTools,
218
- enable_spawn: input.config.enableSpawnAgent,
219
- enable_teams: input.config.enableAgentTeams,
220
- prompt: input.prompt?.trim() || undefined,
221
- messages_path: messagesPath,
222
- });
223
-
224
- const { config: effectiveConfig, pluginSandboxShutdown } =
225
- await buildEffectiveConfig(
226
- input,
227
- hookPath,
228
- sessionId,
229
- this.defaultTelemetry,
230
- (e) => void this.handlePluginEvent(sessionId, e),
231
- );
232
- const providerConfig = buildResolvedProviderConfig(
233
- effectiveConfig,
234
- this.providerSettingsManager,
235
- resolveReasoningSettings,
236
- );
237
- const configWithProvider: CoreSessionConfig = {
238
- ...effectiveConfig,
239
- providerConfig,
240
- };
241
-
242
- const runtime = this.runtimeBuilder.build({
243
- config: configWithProvider,
244
- hooks: effectiveConfig.hooks,
245
- extensions: effectiveConfig.extensions,
246
- logger: configWithProvider.logger,
247
- telemetry: configWithProvider.telemetry,
248
- onTeamEvent: (event: TeamEvent) => {
249
- void this.handleTeamEvent(sessionId, event);
250
- configWithProvider.onTeamEvent?.(event);
251
- },
252
- createSpawnTool: () =>
253
- this.createSpawnTool(configWithProvider, sessionId),
254
- onTeamRestored: input.onTeamRestored,
255
- userInstructionWatcher: input.userInstructionWatcher,
256
- defaultToolExecutors:
257
- input.defaultToolExecutors ?? this.defaultToolExecutors,
258
- });
259
-
260
- const tools = [...runtime.tools, ...(configWithProvider.extraTools ?? [])];
261
- emitSessionCreationTelemetry(
262
- configWithProvider,
263
- sessionId,
264
- source,
265
- requestedSessionId.length > 0,
266
- workspacePath,
267
- );
268
-
269
- const agent = this.createAgentInstance({
270
- providerId: providerConfig.providerId,
271
- modelId: providerConfig.modelId,
272
- apiKey: providerConfig.apiKey,
273
- baseUrl: providerConfig.baseUrl,
274
- headers: providerConfig.headers,
275
- knownModels: providerConfig.knownModels,
276
- providerConfig,
277
- thinking: configWithProvider.thinking,
278
- reasoningEffort:
279
- configWithProvider.reasoningEffort ?? providerConfig.reasoningEffort,
280
- systemPrompt: configWithProvider.systemPrompt,
281
- maxIterations: configWithProvider.maxIterations,
282
- maxConsecutiveMistakes: configWithProvider.maxConsecutiveMistakes,
283
- tools,
284
- hooks: effectiveConfig.hooks,
285
- extensions: effectiveConfig.extensions,
286
- hookErrorMode: configWithProvider.hookErrorMode,
287
- initialMessages: input.initialMessages,
288
- userFileContentLoader: loadUserFileContent,
289
- toolPolicies: input.toolPolicies ?? this.defaultToolPolicies,
290
- requestToolApproval:
291
- input.requestToolApproval ?? this.defaultRequestToolApproval,
292
- onConsecutiveMistakeLimitReached:
293
- configWithProvider.onConsecutiveMistakeLimitReached,
294
- completionGuard: runtime.completionGuard,
295
- logger: runtime.logger ?? configWithProvider.logger,
296
- onEvent: (event: AgentEvent) =>
297
- this.onAgentEvent(sessionId, configWithProvider, event),
298
- });
299
-
300
- const active: ActiveSession = {
301
- sessionId,
302
- config: configWithProvider,
303
- source,
304
- startedAt,
305
- pendingPrompt: manifest.prompt,
306
- runtime,
307
- agent,
308
- started: false,
309
- aborting: false,
310
- interactive: input.interactive === true,
311
- persistedMessages: input.initialMessages,
312
- activeTeamRunIds: new Set<string>(),
313
- pendingTeamRunUpdates: [],
314
- teamRunWaiters: [],
315
- pendingPrompts: [],
316
- drainingPendingPrompts: false,
317
- pluginSandboxShutdown,
318
- };
319
- this.sessions.set(sessionId, active);
320
- this.emitStatus(sessionId, "running");
321
-
322
- let result: AgentResult | undefined;
323
- try {
324
- if (input.prompt?.trim()) {
325
- result = await this.runTurn(active, {
326
- prompt: input.prompt,
327
- userImages: input.userImages,
328
- userFiles: input.userFiles,
329
- });
330
- if (!active.interactive) {
331
- await this.finalizeSingleRun(active, result.finishReason);
332
- }
333
- }
334
- } catch (error) {
335
- await this.failSession(active);
336
- throw error;
337
- }
338
-
339
- return {
340
- sessionId,
341
- manifest,
342
- manifestPath,
343
- transcriptPath,
344
- hookPath,
345
- messagesPath,
346
- result,
347
- };
348
- }
349
-
350
- async send(input: SendSessionInput): Promise<AgentResult | undefined> {
351
- const session = this.getSessionOrThrow(input.sessionId);
352
- session.config.telemetry?.capture({
353
- event: "session.input_sent",
354
- properties: {
355
- sessionId: input.sessionId,
356
- promptLength: input.prompt.length,
357
- userImageCount: input.userImages?.length ?? 0,
358
- userFileCount: input.userFiles?.length ?? 0,
359
- delivery: input.delivery ?? "immediate",
360
- },
361
- });
362
- if (input.delivery === "queue" || input.delivery === "steer") {
363
- this.enqueuePendingPrompt(input.sessionId, {
364
- prompt: input.prompt,
365
- delivery: input.delivery,
366
- userImages: input.userImages,
367
- userFiles: input.userFiles,
368
- });
369
- return undefined;
370
- }
371
- try {
372
- const result = await this.runTurn(session, {
373
- prompt: input.prompt,
374
- userImages: input.userImages,
375
- userFiles: input.userFiles,
376
- });
377
- if (!session.interactive) {
378
- await this.finalizeSingleRun(session, result.finishReason);
379
- }
380
- queueMicrotask(() => {
381
- void this.drainPendingPrompts(input.sessionId);
382
- });
383
- return result;
384
- } catch (error) {
385
- await this.failSession(session);
386
- throw error;
387
- }
388
- }
389
-
390
- async getAccumulatedUsage(
391
- sessionId: string,
392
- ): Promise<SessionAccumulatedUsage | undefined> {
393
- const usage = this.usageBySession.get(sessionId);
394
- return usage ? { ...usage } : undefined;
395
- }
396
-
397
- async abort(sessionId: string, reason?: unknown): Promise<void> {
398
- const session = this.sessions.get(sessionId);
399
- if (!session) return;
400
- session.config.telemetry?.capture({
401
- event: "session.aborted",
402
- properties: { sessionId },
403
- });
404
- session.aborting = true;
405
- (
406
- session.agent as Agent & {
407
- abort: (abortReason?: unknown) => void;
408
- }
409
- ).abort(reason);
410
- }
411
-
412
- async stop(sessionId: string): Promise<void> {
413
- const session = this.sessions.get(sessionId);
414
- if (!session) return;
415
- session.config.telemetry?.capture({
416
- event: "session.stopped",
417
- properties: { sessionId },
418
- });
419
- await this.shutdownSession(session, {
420
- status: "cancelled",
421
- exitCode: 0,
422
- shutdownReason: "session_stop",
423
- endReason: "stopped",
424
- });
425
- }
426
-
427
- async dispose(reason = "session_manager_dispose"): Promise<void> {
428
- const sessions = [...this.sessions.values()];
429
- if (sessions.length === 0) return;
430
- await Promise.allSettled(
431
- sessions.map((session) =>
432
- this.shutdownSession(session, {
433
- status: "cancelled",
434
- exitCode: 0,
435
- shutdownReason: reason,
436
- endReason: "disposed",
437
- }),
438
- ),
439
- );
440
- this.usageBySession.clear();
441
- }
442
-
443
- async get(sessionId: string): Promise<SessionRecord | undefined> {
444
- const row = await this.getRow(sessionId);
445
- return row ? toSessionRecord(row) : undefined;
446
- }
447
-
448
- async list(limit = 200): Promise<SessionRecord[]> {
449
- const rows = await this.listRows(limit);
450
- return rows.map(toSessionRecord);
451
- }
452
-
453
- async delete(sessionId: string): Promise<boolean> {
454
- if (this.sessions.has(sessionId)) {
455
- await this.stop(sessionId);
456
- }
457
- const result = await this.invoke<{ deleted: boolean }>(
458
- "deleteSession",
459
- sessionId,
460
- );
461
- if (result.deleted) {
462
- this.usageBySession.delete(sessionId);
463
- }
464
- return result.deleted;
465
- }
466
-
467
- async readTranscript(sessionId: string, maxChars?: number): Promise<string> {
468
- const row = await this.getRow(sessionId);
469
- if (!row?.transcriptPath || !existsSync(row.transcriptPath)) return "";
470
- const raw = readFileSync(row.transcriptPath, "utf8");
471
- if (typeof maxChars === "number" && Number.isFinite(maxChars)) {
472
- return raw.slice(-Math.max(0, Math.floor(maxChars)));
473
- }
474
- return raw;
475
- }
476
-
477
- async readMessages(sessionId: string): Promise<LlmsProviders.Message[]> {
478
- const row = await this.getRow(sessionId);
479
- const messagesPath = row?.messagesPath?.trim();
480
- if (!messagesPath || !existsSync(messagesPath)) return [];
481
- try {
482
- const raw = readFileSync(messagesPath, "utf8").trim();
483
- if (!raw) return [];
484
- const parsed = JSON.parse(raw) as unknown;
485
- if (Array.isArray(parsed)) return parsed as LlmsProviders.Message[];
486
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
487
- const messages = (parsed as { messages?: unknown }).messages;
488
- if (Array.isArray(messages)) return messages as LlmsProviders.Message[];
489
- }
490
- return [];
491
- } catch {
492
- return [];
493
- }
494
- }
495
-
496
- async readHooks(sessionId: string, limit = 200): Promise<unknown[]> {
497
- const row = await this.getRow(sessionId);
498
- if (!row?.hookPath || !existsSync(row.hookPath)) return [];
499
- const lines = readFileSync(row.hookPath, "utf8")
500
- .split("\n")
501
- .filter((line) => line.trim().length > 0);
502
- return lines.slice(-Math.max(1, Math.floor(limit))).map((line) => {
503
- try {
504
- return JSON.parse(line) as unknown;
505
- } catch {
506
- return { raw: line };
507
- }
508
- });
509
- }
510
-
511
- subscribe(listener: (event: CoreSessionEvent) => void): () => void {
512
- this.listeners.add(listener);
513
- return () => {
514
- this.listeners.delete(listener);
515
- };
516
- }
517
-
518
- async updateSessionModel(sessionId: string, modelId: string): Promise<void> {
519
- const session = this.getSessionOrThrow(sessionId);
520
- session.config.modelId = modelId;
521
- this.updateAgentConnection(session, { modelId });
522
- }
523
-
524
- // ── Turn execution ──────────────────────────────────────────────────
525
-
526
- private async runTurn(
527
- session: ActiveSession,
528
- input: {
529
- prompt: string;
530
- userImages?: string[];
531
- userFiles?: string[];
532
- },
533
- ): Promise<AgentResult> {
534
- const preparedInput = await this.prepareTurnInput(session, input);
535
- const prompt = preparedInput.prompt.trim();
536
- if (!prompt) throw new Error("prompt cannot be empty");
537
-
538
- if (!session.artifacts && !session.pendingPrompt) {
539
- session.pendingPrompt = prompt;
540
- }
541
- await this.ensureSessionPersisted(session);
542
- await this.syncOAuthCredentials(session);
543
-
544
- let result = await this.executeAgentTurn(
545
- session,
546
- prompt,
547
- preparedInput.userImages,
548
- preparedInput.userFiles,
549
- );
550
-
551
- while (shouldAutoContinueTeamRuns(session, result.finishReason)) {
552
- const updates = await waitForTeamRunUpdates(session);
553
- if (updates.length === 0) break;
554
- const continuationPrompt = buildTeamRunContinuationPrompt(
555
- session,
556
- updates,
557
- );
558
- result = await this.executeAgentTurn(session, continuationPrompt);
559
- }
560
-
561
- return result;
562
- }
563
-
564
- private async executeAgentTurn(
565
- session: ActiveSession,
566
- prompt: string,
567
- userImages?: string[],
568
- userFiles?: string[],
569
- ): Promise<AgentResult> {
570
- const shouldContinue =
571
- session.started || session.agent.getMessages().length > 0;
572
- const baselineMessages =
573
- session.persistedMessages ?? session.agent.getMessages();
574
- const usageBaseline =
575
- this.usageBySession.get(session.sessionId) ??
576
- createInitialAccumulatedUsage();
577
- session.turnUsageBaseline = usageBaseline;
578
-
579
- captureModeSwitch(
580
- session.config.telemetry,
581
- session.sessionId,
582
- session.config.mode,
583
- );
584
- captureConversationTurnEvent(session.config.telemetry, {
585
- ulid: session.sessionId,
586
- provider: session.config.providerId,
587
- model: session.config.modelId,
588
- source: "user",
589
- mode: session.config.mode,
590
- isNativeToolCall: false,
591
- });
592
-
593
- try {
594
- const runFn = shouldContinue
595
- ? () => session.agent.continue(prompt, userImages, userFiles)
596
- : () => session.agent.run(prompt, userImages, userFiles);
597
- const result = await this.runWithAuthRetry(
598
- session,
599
- runFn,
600
- baselineMessages,
601
- );
602
-
603
- session.started = true;
604
- const persistedMessages = withLatestAssistantTurnMetadata(
605
- result.messages,
606
- result,
607
- baselineMessages,
608
- );
609
- session.persistedMessages = persistedMessages;
610
- this.usageBySession.set(
611
- session.sessionId,
612
- accumulateUsageTotals(usageBaseline, result.usage),
613
- );
614
- await this.invoke<void>(
615
- "persistSessionMessages",
616
- session.sessionId,
617
- persistedMessages,
618
- session.config.systemPrompt,
619
- );
620
- return result;
621
- } catch (error) {
622
- await this.invoke<void>(
623
- "persistSessionMessages",
624
- session.sessionId,
625
- session.agent.getMessages(),
626
- session.config.systemPrompt,
627
- );
628
- throw error;
629
- } finally {
630
- session.turnUsageBaseline = undefined;
631
- }
632
- }
633
-
634
- private async prepareTurnInput(
635
- session: ActiveSession,
636
- input: {
637
- prompt: string;
638
- userImages?: string[];
639
- userFiles?: string[];
640
- },
641
- ): Promise<PreparedTurnInput> {
642
- const mentionBaseDir = resolveWorkspacePath(session.config);
643
- const normalizedPrompt = normalizeUserInput(input.prompt).trim();
644
- if (!normalizedPrompt) {
645
- return {
646
- prompt: "",
647
- userImages: input.userImages,
648
- userFiles: this.resolveAbsoluteFilePaths(
649
- session.config.cwd,
650
- input.userFiles,
651
- ),
652
- };
653
- }
654
-
655
- const enriched = await enrichPromptWithMentions(
656
- normalizedPrompt,
657
- mentionBaseDir,
658
- );
659
- emitMentionTelemetry(session.config.telemetry, enriched);
660
-
661
- const prompt = formatModePrompt(enriched.prompt, session.config.mode);
662
- const explicitUserFiles = this.resolveAbsoluteFilePaths(
663
- session.config.cwd,
664
- input.userFiles,
665
- );
666
- const mentionedFiles = this.resolveAbsoluteFilePaths(
667
- mentionBaseDir,
668
- enriched.matchedFiles,
669
- );
670
- const mergedUserFiles = Array.from(
671
- new Set([...explicitUserFiles, ...mentionedFiles]),
672
- );
673
-
674
- return {
675
- prompt,
676
- userImages: input.userImages,
677
- userFiles: mergedUserFiles.length > 0 ? mergedUserFiles : undefined,
678
- };
679
- }
680
-
681
- // ── Session lifecycle ───────────────────────────────────────────────
682
-
683
- private async ensureSessionPersisted(session: ActiveSession): Promise<void> {
684
- if (session.artifacts) return;
685
- const workspacePath = resolveWorkspacePath(session.config);
686
- session.artifacts = (await this.invoke("createRootSessionWithArtifacts", {
687
- sessionId: session.sessionId,
688
- source: session.source,
689
- pid: process.pid,
690
- interactive: session.interactive,
691
- provider: session.config.providerId,
692
- model: session.config.modelId,
693
- cwd: session.config.cwd,
694
- workspaceRoot: workspacePath,
695
- teamName: session.config.teamName,
696
- enableTools: session.config.enableTools,
697
- enableSpawn: session.config.enableSpawnAgent,
698
- enableTeams: session.config.enableAgentTeams,
699
- prompt: session.pendingPrompt,
700
- startedAt: session.startedAt,
701
- })) as RootSessionArtifacts;
702
- }
703
-
704
- private async finalizeSingleRun(
705
- session: ActiveSession,
706
- finishReason: AgentResult["finishReason"],
707
- ): Promise<void> {
708
- if (hasPendingTeamRunWork(session)) return;
709
- const isAborted = finishReason === "aborted" || session.aborting;
710
- await this.shutdownSession(session, {
711
- status: isAborted ? "cancelled" : "completed",
712
- exitCode: 0,
713
- shutdownReason: "session_complete",
714
- endReason: finishReason,
715
- });
716
- }
717
-
718
- private async failSession(session: ActiveSession): Promise<void> {
719
- await this.shutdownSession(session, {
720
- status: "failed",
721
- exitCode: 1,
722
- shutdownReason: "session_error",
723
- endReason: "error",
724
- });
725
- }
726
-
727
- private async shutdownSession(
728
- session: ActiveSession,
729
- input: {
730
- status: SessionStatus;
731
- exitCode: number | null;
732
- shutdownReason: string;
733
- endReason: string;
734
- },
735
- ): Promise<void> {
736
- if (input.status === "completed") {
737
- captureTaskCompleted(session.config.telemetry, {
738
- ulid: session.sessionId,
739
- provider: session.config.providerId,
740
- modelId: session.config.modelId,
741
- mode: session.config.mode,
742
- durationMs: Date.now() - Date.parse(session.startedAt),
743
- });
744
- }
745
- notifyTeamRunWaiters(session);
746
-
747
- if (session.artifacts) {
748
- await this.updateStatus(session, input.status, input.exitCode);
749
- await session.agent.shutdown(input.shutdownReason);
750
- }
751
- await Promise.resolve(session.runtime.shutdown(input.shutdownReason));
752
- await session.pluginSandboxShutdown?.();
753
- this.sessions.delete(session.sessionId);
754
- this.emit({
755
- type: "ended",
756
- payload: {
757
- sessionId: session.sessionId,
758
- reason: input.endReason,
759
- ts: Date.now(),
760
- },
761
- });
762
- }
763
-
764
- private async updateStatus(
765
- session: ActiveSession,
766
- status: SessionStatus,
767
- exitCode?: number | null,
768
- ): Promise<void> {
769
- if (!session.artifacts) return;
770
- const result = await this.invoke<{ updated: boolean; endedAt?: string }>(
771
- "updateSessionStatus",
772
- session.sessionId,
773
- status,
774
- exitCode,
775
- );
776
- if (!result.updated) return;
777
- session.artifacts.manifest.status = status;
778
- session.artifacts.manifest.ended_at = result.endedAt ?? nowIso();
779
- session.artifacts.manifest.exit_code =
780
- typeof exitCode === "number" ? exitCode : null;
781
- await this.invoke<void>(
782
- "writeSessionManifest",
783
- session.artifacts.manifestPath,
784
- session.artifacts.manifest,
785
- );
786
- this.emitStatus(session.sessionId, status);
787
- }
788
-
789
- private async handlePluginEvent(
790
- rootSessionId: string,
791
- event: { name: string; payload?: unknown },
792
- ): Promise<void> {
793
- if (
794
- event.name !== "steer_message" &&
795
- event.name !== "queue_message" &&
796
- event.name !== "pending_prompt"
797
- ) {
798
- return;
799
- }
800
- const payload =
801
- event.payload && typeof event.payload === "object"
802
- ? (event.payload as Record<string, unknown>)
803
- : undefined;
804
- const targetSessionId =
805
- typeof payload?.sessionId === "string" &&
806
- payload.sessionId.trim().length > 0
807
- ? payload.sessionId.trim()
808
- : rootSessionId;
809
- const prompt =
810
- typeof payload?.prompt === "string" ? payload.prompt.trim() : "";
811
- if (!prompt) {
812
- return;
813
- }
814
- const delivery =
815
- event.name === "steer_message"
816
- ? "steer"
817
- : event.name === "queue_message"
818
- ? "queue"
819
- : payload?.delivery === "steer"
820
- ? "steer"
821
- : "queue";
822
- this.enqueuePendingPrompt(targetSessionId, {
823
- prompt,
824
- delivery,
825
- });
826
- }
827
-
828
- private enqueuePendingPrompt(
829
- sessionId: string,
830
- entry: {
831
- prompt: string;
832
- delivery: "queue" | "steer";
833
- userImages?: string[];
834
- userFiles?: string[];
835
- },
836
- ): void {
837
- const session = this.sessions.get(sessionId);
838
- if (!session) {
839
- return;
840
- }
841
- const { prompt, delivery, userImages, userFiles } = entry;
842
- const existingIndex = session.pendingPrompts.findIndex(
843
- (queued) => queued.prompt === prompt,
844
- );
845
- if (existingIndex >= 0) {
846
- const [existing] = session.pendingPrompts.splice(existingIndex, 1);
847
- if (delivery === "steer" || existing.delivery === "steer") {
848
- session.pendingPrompts.unshift({
849
- id: existing.id,
850
- prompt,
851
- delivery: "steer",
852
- userImages: userImages ?? existing.userImages,
853
- userFiles: userFiles ?? existing.userFiles,
854
- });
855
- } else {
856
- session.pendingPrompts.push({
857
- ...existing,
858
- userImages: userImages ?? existing.userImages,
859
- userFiles: userFiles ?? existing.userFiles,
860
- });
861
- }
862
- } else if (delivery === "steer") {
863
- session.pendingPrompts.unshift({
864
- id: `pending_${Date.now()}_${nanoid(5)}`,
865
- prompt,
866
- delivery,
867
- userImages,
868
- userFiles,
869
- });
870
- } else {
871
- session.pendingPrompts.push({
872
- id: `pending_${Date.now()}_${nanoid(5)}`,
873
- prompt,
874
- delivery,
875
- userImages,
876
- userFiles,
877
- });
878
- }
879
- this.emitPendingPrompts(session);
880
- queueMicrotask(() => {
881
- void this.drainPendingPrompts(sessionId);
882
- });
883
- }
884
-
885
- private async drainPendingPrompts(sessionId: string): Promise<void> {
886
- const session = this.sessions.get(sessionId);
887
- if (!session || session.drainingPendingPrompts) {
888
- return;
889
- }
890
- const canStartRun =
891
- typeof (session.agent as Agent & { canStartRun?: () => boolean })
892
- .canStartRun === "function"
893
- ? (
894
- session.agent as Agent & {
895
- canStartRun: () => boolean;
896
- }
897
- ).canStartRun()
898
- : true;
899
- if (!canStartRun) {
900
- return;
901
- }
902
- const next = session.pendingPrompts.shift();
903
- if (!next) {
904
- return;
905
- }
906
- this.emitPendingPrompts(session);
907
- this.emitPendingPromptSubmitted(session, next);
908
- session.drainingPendingPrompts = true;
909
- try {
910
- await this.send({
911
- sessionId,
912
- prompt: next.prompt,
913
- userImages: next.userImages,
914
- userFiles: next.userFiles,
915
- });
916
- } catch (error) {
917
- const message = error instanceof Error ? error.message : String(error);
918
- if (message.includes("already in progress")) {
919
- session.pendingPrompts.unshift(next);
920
- this.emitPendingPrompts(session);
921
- } else {
922
- throw error;
923
- }
924
- } finally {
925
- session.drainingPendingPrompts = false;
926
- if (session.pendingPrompts.length > 0) {
927
- queueMicrotask(() => {
928
- void this.drainPendingPrompts(sessionId);
929
- });
930
- }
931
- }
932
- }
933
-
934
- // ── Agent event handling ────────────────────────────────────────────
935
-
936
- private onAgentEvent(
937
- sessionId: string,
938
- config: CoreSessionConfig,
939
- event: AgentEvent,
940
- ): void {
941
- const ctx: AgentEventContext = {
942
- sessionId,
943
- config,
944
- liveSession: this.sessions.get(sessionId),
945
- usageBySession: this.usageBySession,
946
- persistMessages: (sid, messages, systemPrompt) => {
947
- void this.invoke<void>(
948
- "persistSessionMessages",
949
- sid,
950
- messages,
951
- systemPrompt,
952
- );
953
- },
954
- emit: (e) => this.emit(e),
955
- };
956
- handleAgentEvent(ctx, event);
957
- }
958
-
959
- private emitPendingPrompts(session: ActiveSession): void {
960
- this.emit({
961
- type: "pending_prompts",
962
- payload: {
963
- sessionId: session.sessionId,
964
- prompts: session.pendingPrompts.map((entry) => ({
965
- id: entry.id,
966
- prompt: entry.prompt,
967
- delivery: entry.delivery,
968
- attachmentCount:
969
- (entry.userImages?.length ?? 0) + (entry.userFiles?.length ?? 0),
970
- })),
971
- },
972
- });
973
- }
974
-
975
- private emitPendingPromptSubmitted(
976
- session: ActiveSession,
977
- entry: {
978
- id: string;
979
- prompt: string;
980
- delivery: "queue" | "steer";
981
- userImages?: string[];
982
- userFiles?: string[];
983
- },
984
- ): void {
985
- this.emit({
986
- type: "pending_prompt_submitted",
987
- payload: {
988
- sessionId: session.sessionId,
989
- id: entry.id,
990
- prompt: entry.prompt,
991
- delivery: entry.delivery,
992
- attachmentCount:
993
- (entry.userImages?.length ?? 0) + (entry.userFiles?.length ?? 0),
994
- },
995
- });
996
- }
997
-
998
- // ── Spawn / sub-agents ──────────────────────────────────────────────
999
-
1000
- private createSpawnTool(
1001
- config: CoreSessionConfig,
1002
- rootSessionId: string,
1003
- ): Tool {
1004
- const createSubAgentTools = () => {
1005
- const tools: Tool[] = config.enableTools
1006
- ? createBuiltinTools({
1007
- cwd: config.cwd,
1008
- ...(config.mode === "plan"
1009
- ? ToolPresets.readonly
1010
- : ToolPresets.development),
1011
- executors: this.defaultToolExecutors,
1012
- })
1013
- : [];
1014
- if (config.enableSpawnAgent) {
1015
- tools.push(this.createSpawnTool(config, rootSessionId));
1016
- }
1017
- return tools;
1018
- };
1019
-
1020
- return createSpawnAgentTool({
1021
- providerId: config.providerId,
1022
- modelId: config.modelId,
1023
- cwd: config.cwd,
1024
- apiKey: config.apiKey,
1025
- baseUrl: config.baseUrl,
1026
- providerConfig: config.providerConfig,
1027
- knownModels: config.knownModels,
1028
- clineWorkspaceMetadata:
1029
- config.providerId === "cline"
1030
- ? extractWorkspaceMetadataFromSystemPrompt(config.systemPrompt)
1031
- : undefined,
1032
- createSubAgentTools,
1033
- hooks: config.hooks,
1034
- extensions: config.extensions,
1035
- toolPolicies: this.defaultToolPolicies,
1036
- requestToolApproval: this.defaultRequestToolApproval,
1037
- logger: config.logger,
1038
- onSubAgentStart: (context) => {
1039
- this.subAgentStarts.set(context.subAgentId, {
1040
- startedAt: Date.now(),
1041
- rootSessionId,
1042
- });
1043
- void this.invokeOptional("handleSubAgentStart", rootSessionId, context);
1044
- },
1045
- onSubAgentEnd: (context) => {
1046
- const started = this.subAgentStarts.get(context.subAgentId);
1047
- const durationMs = started ? Date.now() - started.startedAt : 0;
1048
- const outputLines = context.result?.text
1049
- ? context.result.text.split("\n").length
1050
- : 0;
1051
- captureSubagentExecution(config.telemetry, {
1052
- ulid: rootSessionId,
1053
- durationMs,
1054
- outputLines,
1055
- success: !context.error,
1056
- });
1057
- this.subAgentStarts.delete(context.subAgentId);
1058
- void this.invokeOptional("handleSubAgentEnd", rootSessionId, context);
1059
- },
1060
- }) as Tool;
1061
- }
1062
-
1063
- // ── Team run coordination ───────────────────────────────────────────
1064
-
1065
- private async handleTeamEvent(
1066
- rootSessionId: string,
1067
- event: TeamEvent,
1068
- ): Promise<void> {
1069
- const session = this.sessions.get(rootSessionId);
1070
- if (session) {
1071
- trackTeamRunState(session, event);
1072
- }
1073
-
1074
- await dispatchTeamEventToBackend(
1075
- rootSessionId,
1076
- event,
1077
- this.invokeOptional.bind(this),
1078
- );
1079
-
1080
- if (session) {
1081
- emitTeamProgress(session, rootSessionId, event, (e) => this.emit(e));
1082
- }
1083
- }
1084
-
1085
- // ── OAuth & auth ────────────────────────────────────────────────────
1086
-
1087
- private async runWithAuthRetry(
1088
- session: ActiveSession,
1089
- run: () => Promise<AgentResult>,
1090
- baselineMessages: LlmsProviders.Message[],
1091
- ): Promise<AgentResult> {
1092
- try {
1093
- return await run();
1094
- } catch (error) {
1095
- if (!isLikelyAuthError(error, session.config.providerId)) {
1096
- throw error;
1097
- }
1098
- await this.syncOAuthCredentials(session, { forceRefresh: true });
1099
- session.agent.restore(baselineMessages);
1100
- return run();
1101
- }
1102
- }
1103
-
1104
- private async syncOAuthCredentials(
1105
- session: ActiveSession,
1106
- options?: { forceRefresh?: boolean },
1107
- ): Promise<void> {
1108
- let resolved: RuntimeOAuthResolution | null = null;
1109
- try {
1110
- resolved = await this.oauthTokenManager.resolveProviderApiKey({
1111
- providerId: session.config.providerId,
1112
- forceRefresh: options?.forceRefresh,
1113
- });
1114
- } catch (error) {
1115
- if (error instanceof OAuthReauthRequiredError) {
1116
- throw new Error(
1117
- `OAuth session for "${error.providerId}" requires re-authentication. Run "clite auth ${error.providerId}" and retry.`,
1118
- );
1119
- }
1120
- throw error;
1121
- }
1122
- if (!resolved?.apiKey || session.config.apiKey === resolved.apiKey) return;
1123
- session.config.apiKey = resolved.apiKey;
1124
- this.updateAgentConnection(session, { apiKey: resolved.apiKey });
1125
- session.runtime.teamRuntime?.updateTeammateConnections({
1126
- apiKey: resolved.apiKey,
1127
- });
1128
- }
1129
-
1130
- // ── Utility methods ─────────────────────────────────────────────────
1131
-
1132
- private getSessionOrThrow(sessionId: string): ActiveSession {
1133
- const session = this.sessions.get(sessionId);
1134
- if (!session) throw new Error(`session not found: ${sessionId}`);
1135
- return session;
1136
- }
1137
-
1138
- private resolveAbsoluteFilePaths(cwd: string, paths?: string[]): string[] {
1139
- if (!paths || paths.length === 0) return [];
1140
- const resolved = paths
1141
- .map((p) => p.trim())
1142
- .filter((p) => p.length > 0)
1143
- .map((p) => (isAbsolute(p) ? p : resolve(cwd, p)));
1144
- return Array.from(new Set(resolved));
1145
- }
1146
-
1147
- private updateAgentConnection(
1148
- session: ActiveSession,
1149
- overrides: { apiKey?: string; modelId?: string },
1150
- ): void {
1151
- const agentWithConnection = session.agent as Agent & {
1152
- updateConnection?: (overrides: {
1153
- apiKey?: string;
1154
- modelId?: string;
1155
- }) => void;
1156
- };
1157
- agentWithConnection.updateConnection?.(overrides);
1158
- }
1159
-
1160
- private emitStatus(sessionId: string, status: string): void {
1161
- this.emit({
1162
- type: "status",
1163
- payload: { sessionId, status },
1164
- });
1165
- }
1166
-
1167
- private emit(event: CoreSessionEvent): void {
1168
- for (const listener of this.listeners) listener(event);
1169
- }
1170
-
1171
- private async listRows(limit: number): Promise<SessionRow[]> {
1172
- return this.invoke<SessionRow[]>(
1173
- "listSessions",
1174
- Math.min(Math.max(1, Math.floor(limit)), MAX_SCAN_LIMIT),
1175
- );
1176
- }
1177
-
1178
- private async getRow(sessionId: string): Promise<SessionRow | undefined> {
1179
- const target = sessionId.trim();
1180
- if (!target) return undefined;
1181
- const rows = await this.listRows(MAX_SCAN_LIMIT);
1182
- return rows.find((row) => row.sessionId === target);
1183
- }
1184
-
1185
- // ── Session service invocation ──────────────────────────────────────
1186
-
1187
- private async invoke<T>(method: string, ...args: unknown[]): Promise<T> {
1188
- const callable = (
1189
- this.sessionService as unknown as Record<string, unknown>
1190
- )[method];
1191
- if (typeof callable !== "function") {
1192
- throw new Error(`session service method not available: ${method}`);
1193
- }
1194
- return Promise.resolve(
1195
- (callable as (...params: unknown[]) => T | Promise<T>).apply(
1196
- this.sessionService,
1197
- args,
1198
- ),
1199
- );
1200
- }
1201
-
1202
- private async invokeOptional(
1203
- method: string,
1204
- ...args: unknown[]
1205
- ): Promise<void> {
1206
- const callable = (
1207
- this.sessionService as unknown as Record<string, unknown>
1208
- )[method];
1209
- if (typeof callable !== "function") return;
1210
- await Promise.resolve(
1211
- (callable as (...params: unknown[]) => unknown).apply(
1212
- this.sessionService,
1213
- args,
1214
- ),
1215
- );
1216
- }
1217
-
1218
- private async invokeOptionalValue<T = unknown>(
1219
- method: string,
1220
- ...args: unknown[]
1221
- ): Promise<T | undefined> {
1222
- const callable = (
1223
- this.sessionService as unknown as Record<string, unknown>
1224
- )[method];
1225
- if (typeof callable !== "function") return undefined;
1226
- return await Promise.resolve(
1227
- (callable as (...params: unknown[]) => T | Promise<T>).apply(
1228
- this.sessionService,
1229
- args,
1230
- ),
1231
- );
1232
- }
1233
- }