@clinebot/core 0.0.28 → 0.0.30

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 (340) 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 +11 -11
  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 +9 -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 +15 -12
  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 +168 -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 +162 -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/OpenTelemetryAdapter.ts +1 -1
  274. package/src/telemetry/OpenTelemetryProvider.test.ts +216 -3
  275. package/src/telemetry/OpenTelemetryProvider.ts +110 -20
  276. package/src/telemetry/TelemetryLoggerSink.test.ts +42 -0
  277. package/src/telemetry/{LoggerTelemetryAdapter.ts → TelemetryLoggerSink.ts} +21 -14
  278. package/src/telemetry/TelemetryService.test.ts +7 -7
  279. package/src/telemetry/TelemetryService.ts +2 -4
  280. package/src/tools/definitions.test.ts +76 -0
  281. package/src/tools/definitions.ts +41 -2
  282. package/src/tools/executors/apply-patch.ts +1 -1
  283. package/src/tools/executors/editor.ts +1 -1
  284. package/src/tools/executors/file-read.ts +1 -1
  285. package/src/tools/executors/search.ts +1 -1
  286. package/src/tools/executors/web-fetch.ts +1 -1
  287. package/src/tools/index.ts +6 -1
  288. package/src/tools/model-tool-routing.ts +2 -0
  289. package/src/tools/presets.test.ts +8 -0
  290. package/src/tools/presets.ts +40 -2
  291. package/src/tools/schemas.ts +19 -0
  292. package/src/tools/types.ts +31 -2
  293. package/src/types/config.ts +61 -7
  294. package/src/types/events.ts +1 -1
  295. package/src/types/index.ts +0 -1
  296. package/src/types/provider-settings.ts +1 -1
  297. package/src/types/storage.ts +2 -5
  298. package/src/types.ts +32 -44
  299. package/dist/agents/agent-config-loader.d.ts.map +0 -1
  300. package/dist/agents/agent-config-parser.d.ts.map +0 -1
  301. package/dist/agents/hooks-config-loader.d.ts.map +0 -1
  302. package/dist/agents/index.d.ts.map +0 -1
  303. package/dist/agents/plugin-config-loader.d.ts.map +0 -1
  304. package/dist/agents/plugin-loader.d.ts.map +0 -1
  305. package/dist/agents/plugin-sandbox-bootstrap.js +0 -446
  306. package/dist/agents/plugin-sandbox.d.ts.map +0 -1
  307. package/dist/agents/unified-config-file-watcher.d.ts.map +0 -1
  308. package/dist/agents/user-instruction-config-loader.d.ts.map +0 -1
  309. package/dist/mcp/config-loader.d.ts.map +0 -1
  310. package/dist/mcp/index.d.ts +0 -5
  311. package/dist/mcp/index.d.ts.map +0 -1
  312. package/dist/mcp/manager.d.ts.map +0 -1
  313. package/dist/mcp/types.d.ts.map +0 -1
  314. package/dist/runtime/commands.d.ts.map +0 -1
  315. package/dist/runtime/sandbox/subprocess-sandbox.d.ts.map +0 -1
  316. package/dist/runtime/skills.d.ts +0 -14
  317. package/dist/runtime/skills.d.ts.map +0 -1
  318. package/dist/runtime/workflows.d.ts +0 -14
  319. package/dist/runtime/workflows.d.ts.map +0 -1
  320. package/dist/session/unified-session-persistence-service.d.ts.map +0 -1
  321. package/dist/telemetry/LoggerTelemetryAdapter.d.ts.map +0 -1
  322. package/dist/types/workspace.d.ts +0 -8
  323. package/dist/types/workspace.d.ts.map +0 -1
  324. package/src/agents/plugin-loader.ts +0 -175
  325. package/src/runtime/skills.ts +0 -44
  326. package/src/runtime/workflows.test.ts +0 -119
  327. package/src/runtime/workflows.ts +0 -45
  328. package/src/session/unified-session-persistence-service.test.ts +0 -85
  329. package/src/telemetry/LoggerTelemetryAdapter.test.ts +0 -42
  330. package/src/types/workspace.ts +0 -7
  331. /package/dist/{agents → extensions/config}/agent-config-loader.d.ts +0 -0
  332. /package/dist/{agents → extensions/config}/unified-config-file-watcher.d.ts +0 -0
  333. /package/dist/{agents → extensions/config}/user-instruction-config-loader.d.ts +0 -0
  334. /package/dist/{mcp → extensions/mcp}/config-loader.d.ts +0 -0
  335. /package/dist/runtime/{sandbox/subprocess-sandbox.d.ts → subprocess-sandbox.d.ts} +0 -0
  336. /package/src/{agents → extensions/config}/agent-config-loader.ts +0 -0
  337. /package/src/{agents → extensions/config}/hooks-config-loader.test.ts +0 -0
  338. /package/src/{agents → extensions/config}/unified-config-file-watcher.test.ts +0 -0
  339. /package/src/{mcp → extensions/mcp}/config-loader.test.ts +0 -0
  340. /package/src/{mcp → extensions/mcp}/config-loader.ts +0 -0
@@ -2,30 +2,30 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { readFile, stat } from "node:fs/promises";
3
3
  import { homedir } from "node:os";
4
4
  import { isAbsolute, join, resolve } from "node:path";
5
+ import { Agent } from "@clinebot/agents";
6
+ import type * as LlmsProviders from "@clinebot/llms";
5
7
  import {
6
- Agent,
7
8
  type AgentConfig,
8
9
  type AgentEvent,
9
10
  type AgentResult,
10
- createSpawnAgentTool,
11
- type TeamEvent,
12
- type Tool,
13
- type ToolApprovalRequest,
14
- type ToolApprovalResult,
15
- } from "@clinebot/agents";
16
- import type * as LlmsProviders from "@clinebot/llms/providers";
17
- import {
18
11
  createSessionId,
19
12
  type ITelemetryService,
20
13
  isLikelyAuthError,
21
14
  normalizeUserInput,
15
+ type Tool,
16
+ type ToolApprovalRequest,
17
+ type ToolApprovalResult,
22
18
  } from "@clinebot/shared";
23
19
  import { setHomeDirIfUnset } from "@clinebot/shared/storage";
24
20
  import { nanoid } from "nanoid";
21
+ import { createContextCompactionPrepareTurn } from "../extensions/context/compaction";
25
22
  import { enrichPromptWithMentions } from "../input";
23
+ import { createCheckpointHooks } from "../runtime/checkpoint-hooks";
24
+ import { mergeAgentHooks } from "../runtime/hook-file-hooks";
26
25
  import { DefaultRuntimeBuilder } from "../runtime/runtime-builder";
27
26
  import type { RuntimeBuilder } from "../runtime/session-runtime";
28
27
  import { ProviderSettingsManager } from "../storage/provider-settings-manager";
28
+ import { createSpawnAgentTool, type TeamEvent } from "../team";
29
29
  import {
30
30
  captureAgentCreated,
31
31
  captureAgentTeamCreated,
@@ -35,7 +35,12 @@ import {
35
35
  captureTaskCompleted,
36
36
  } from "../telemetry/core-events";
37
37
  import { resolveCoreDistinctId } from "../telemetry/distinct-id";
38
- import { createBuiltinTools, type ToolExecutors, ToolPresets } from "../tools";
38
+ import {
39
+ createBuiltinTools,
40
+ resolveToolPresetName,
41
+ type ToolExecutors,
42
+ ToolPresets,
43
+ } from "../tools";
39
44
  import { SessionSource, type SessionStatus } from "../types/common";
40
45
  import type { CoreSessionConfig } from "../types/config";
41
46
  import type { CoreSessionEvent } from "../types/events";
@@ -67,7 +72,10 @@ import type {
67
72
  StartSessionInput,
68
73
  StartSessionResult,
69
74
  } from "./session-manager";
70
- import { SessionManifestSchema } from "./session-manifest";
75
+ import {
76
+ type SessionManifest,
77
+ SessionManifestSchema,
78
+ } from "./session-manifest";
71
79
  import type {
72
80
  CoreSessionService,
73
81
  RootSessionArtifacts,
@@ -89,7 +97,6 @@ import {
89
97
  emitSessionCreationTelemetry,
90
98
  } from "./session-telemetry";
91
99
  import {
92
- extractWorkspaceMetadataFromSystemPrompt,
93
100
  toSessionRecord,
94
101
  withLatestAssistantTurnMetadata,
95
102
  } from "./utils/helpers";
@@ -98,6 +105,7 @@ import {
98
105
  accumulateUsageTotals,
99
106
  createInitialAccumulatedUsage,
100
107
  } from "./utils/usage";
108
+ import { buildWorkspaceMetadata } from "./workspace-manifest";
101
109
 
102
110
  type SessionBackend =
103
111
  | CoreSessionService
@@ -107,6 +115,11 @@ type SessionBackend =
107
115
  const MAX_SCAN_LIMIT = 5000;
108
116
  const MAX_USER_FILE_BYTES = 20 * 1_000 * 1_024;
109
117
 
118
+ // NOTE: Temporarily disabled until checkpoint is ready for production.
119
+ function isCheckpointFeatureEnabled(): boolean {
120
+ return process?.env?.CLINE_CHECKPOINT === "true";
121
+ }
122
+
110
123
  async function loadUserFileContent(path: string): Promise<string> {
111
124
  const fileStat = await stat(path);
112
125
  if (!fileStat.isFile()) {
@@ -187,6 +200,21 @@ export class DefaultSessionManager implements SessionManager {
187
200
  const startedAt = nowIso();
188
201
  const requestedSessionId = input.config.sessionId?.trim() ?? "";
189
202
  const sessionId = requestedSessionId || createSessionId();
203
+ const resumedRow = requestedSessionId
204
+ ? await this.getRow(sessionId)
205
+ : undefined;
206
+ const startInput: StartSessionInput =
207
+ resumedRow &&
208
+ !input.config.teamName?.trim() &&
209
+ resumedRow.teamName?.trim()
210
+ ? {
211
+ ...input,
212
+ config: {
213
+ ...input.config,
214
+ teamName: resumedRow.teamName,
215
+ },
216
+ }
217
+ : input;
190
218
  this.usageBySession.set(sessionId, createInitialAccumulatedUsage());
191
219
 
192
220
  const sessionsDir =
@@ -214,26 +242,29 @@ export class DefaultSessionManager implements SessionManager {
214
242
  started_at: startedAt,
215
243
  status: "running",
216
244
  interactive: input.interactive === true,
217
- provider: input.config.providerId,
218
- model: input.config.modelId,
219
- cwd: input.config.cwd,
245
+ provider: startInput.config.providerId,
246
+ model: startInput.config.modelId,
247
+ cwd: startInput.config.cwd,
220
248
  workspace_root: workspacePath,
221
- team_name: input.config.teamName,
222
- enable_tools: input.config.enableTools,
223
- enable_spawn: input.config.enableSpawnAgent,
224
- enable_teams: input.config.enableAgentTeams,
225
- prompt: input.prompt?.trim() || undefined,
249
+ team_name: startInput.config.teamName,
250
+ enable_tools: startInput.config.enableTools,
251
+ enable_spawn: startInput.config.enableSpawnAgent,
252
+ enable_teams: startInput.config.enableAgentTeams,
253
+ prompt: startInput.prompt?.trim() || undefined,
226
254
  messages_path: messagesPath,
227
255
  });
228
256
 
229
257
  const { config: effectiveConfig, pluginSandboxShutdown } =
230
258
  await buildEffectiveConfig(
231
- input,
259
+ startInput,
232
260
  hookPath,
233
261
  sessionId,
234
262
  this.defaultTelemetry,
235
263
  (e) => void this.handlePluginEvent(sessionId, e),
236
264
  );
265
+ const workspaceMetadata = await buildWorkspaceMetadata(
266
+ startInput.config.cwd,
267
+ );
237
268
  const providerConfig = buildResolvedProviderConfig(
238
269
  effectiveConfig,
239
270
  this.providerSettingsManager,
@@ -242,11 +273,29 @@ export class DefaultSessionManager implements SessionManager {
242
273
  const configWithProvider: CoreSessionConfig = {
243
274
  ...effectiveConfig,
244
275
  providerConfig,
276
+ workspaceMetadata,
245
277
  };
278
+ configWithProvider.hooks = mergeAgentHooks([
279
+ effectiveConfig.hooks,
280
+ isCheckpointFeatureEnabled()
281
+ ? createCheckpointHooks({
282
+ cwd: configWithProvider.cwd,
283
+ sessionId,
284
+ logger: configWithProvider.logger,
285
+ readSessionMetadata: async () =>
286
+ (await this.get(sessionId))?.metadata as
287
+ | Record<string, unknown>
288
+ | undefined,
289
+ writeSessionMetadata: async (metadata) => {
290
+ await this.persistSessionMetadata(sessionId, () => metadata);
291
+ },
292
+ })
293
+ : undefined,
294
+ ]);
246
295
 
247
- const runtime = this.runtimeBuilder.build({
296
+ const runtime = await this.runtimeBuilder.build({
248
297
  config: configWithProvider,
249
- hooks: effectiveConfig.hooks,
298
+ hooks: configWithProvider.hooks,
250
299
  extensions: effectiveConfig.extensions,
251
300
  logger: configWithProvider.logger,
252
301
  telemetry: configWithProvider.telemetry,
@@ -260,6 +309,7 @@ export class DefaultSessionManager implements SessionManager {
260
309
  userInstructionWatcher: input.userInstructionWatcher,
261
310
  defaultToolExecutors:
262
311
  input.defaultToolExecutors ?? this.defaultToolExecutors,
312
+ teamToolsFactory: input.teamToolsFactory,
263
313
  });
264
314
  if (runtime.teamRuntime && !configWithProvider.teamName?.trim()) {
265
315
  configWithProvider.teamName = runtime.teamRuntime.getTeamName();
@@ -267,7 +317,7 @@ export class DefaultSessionManager implements SessionManager {
267
317
 
268
318
  const tools = [...runtime.tools, ...(configWithProvider.extraTools ?? [])];
269
319
 
270
- const agent = this.createAgentInstance({
320
+ const agentConfig = {
271
321
  providerId: providerConfig.providerId,
272
322
  modelId: providerConfig.modelId,
273
323
  apiKey: providerConfig.apiKey,
@@ -281,8 +331,9 @@ export class DefaultSessionManager implements SessionManager {
281
331
  systemPrompt: configWithProvider.systemPrompt,
282
332
  maxIterations: configWithProvider.maxIterations,
283
333
  execution: configWithProvider.execution,
334
+ prepareTurn: createContextCompactionPrepareTurn(configWithProvider),
284
335
  tools,
285
- hooks: effectiveConfig.hooks,
336
+ hooks: configWithProvider.hooks,
286
337
  extensions: effectiveConfig.extensions,
287
338
  hookErrorMode: configWithProvider.hookErrorMode,
288
339
  initialMessages: input.initialMessages,
@@ -293,10 +344,14 @@ export class DefaultSessionManager implements SessionManager {
293
344
  onConsecutiveMistakeLimitReached:
294
345
  configWithProvider.onConsecutiveMistakeLimitReached,
295
346
  completionGuard: runtime.completionGuard,
347
+ consumePendingUserMessage: () => this.consumeSteerMessage(sessionId),
296
348
  logger: runtime.logger ?? configWithProvider.logger,
349
+ extensionContext: configWithProvider.extensionContext,
297
350
  onEvent: (event: AgentEvent) =>
298
351
  this.onAgentEvent(sessionId, configWithProvider, event),
299
- });
352
+ } as AgentConfig;
353
+ const agent = this.createAgentInstance(agentConfig);
354
+ runtime.registerLeadAgent?.(agent);
300
355
  const rootAgentIdentity = buildTelemetryAgentIdentity({
301
356
  agentId: this.readAgentId(agent),
302
357
  conversationId: this.readAgentConversationId(agent),
@@ -341,7 +396,7 @@ export class DefaultSessionManager implements SessionManager {
341
396
  started: false,
342
397
  aborting: false,
343
398
  interactive: input.interactive === true,
344
- persistedMessages: input.initialMessages,
399
+ persistedMessages: startInput.initialMessages,
345
400
  activeTeamRunIds: new Set<string>(),
346
401
  pendingTeamRunUpdates: [],
347
402
  teamRunWaiters: [],
@@ -354,11 +409,11 @@ export class DefaultSessionManager implements SessionManager {
354
409
 
355
410
  let result: AgentResult | undefined;
356
411
  try {
357
- if (input.prompt?.trim()) {
412
+ if (startInput.prompt?.trim()) {
358
413
  result = await this.runTurn(active, {
359
- prompt: input.prompt,
360
- userImages: input.userImages,
361
- userFiles: input.userFiles,
414
+ prompt: startInput.prompt,
415
+ userImages: startInput.userImages,
416
+ userFiles: startInput.userFiles,
362
417
  });
363
418
  if (!active.interactive) {
364
419
  await this.finalizeSingleRun(active, result.finishReason);
@@ -650,10 +705,15 @@ export class DefaultSessionManager implements SessionManager {
650
705
  baselineMessages,
651
706
  );
652
707
  session.persistedMessages = persistedMessages;
653
- this.usageBySession.set(
654
- session.sessionId,
655
- accumulateUsageTotals(usageBaseline, result.usage),
708
+ const accumulatedUsage = accumulateUsageTotals(
709
+ usageBaseline,
710
+ result.usage,
656
711
  );
712
+ this.usageBySession.set(session.sessionId, accumulatedUsage);
713
+ await this.persistSessionMetadata(session.sessionId, (current) => ({
714
+ ...(current ?? {}),
715
+ totalCost: accumulatedUsage.totalCost,
716
+ }));
657
717
  await this.invoke<void>(
658
718
  "persistSessionMessages",
659
719
  session.sessionId,
@@ -744,6 +804,37 @@ export class DefaultSessionManager implements SessionManager {
744
804
  })) as RootSessionArtifacts;
745
805
  }
746
806
 
807
+ private async persistSessionMetadata(
808
+ sessionId: string,
809
+ resolveMetadata: (
810
+ current: Record<string, unknown> | undefined,
811
+ ) => Record<string, unknown> | undefined,
812
+ ): Promise<void> {
813
+ const session = this.sessions.get(sessionId);
814
+ const currentManifest =
815
+ (await this.invokeOptionalValue<SessionManifest>(
816
+ "readSessionManifest",
817
+ sessionId,
818
+ )) ?? session?.artifacts?.manifest;
819
+ const metadata = resolveMetadata(
820
+ currentManifest?.metadata as Record<string, unknown> | undefined,
821
+ );
822
+ if (!session?.artifacts) {
823
+ return;
824
+ }
825
+ const result = await this.invokeOptionalValue<{ updated?: boolean }>(
826
+ "updateSession",
827
+ {
828
+ sessionId,
829
+ metadata,
830
+ },
831
+ );
832
+ if (result?.updated === false) {
833
+ return;
834
+ }
835
+ session.artifacts.manifest.metadata = metadata;
836
+ }
837
+
747
838
  private async finalizeSingleRun(
748
839
  session: ActiveSession,
749
840
  finishReason: AgentResult["finishReason"],
@@ -818,14 +909,19 @@ export class DefaultSessionManager implements SessionManager {
818
909
  exitCode,
819
910
  );
820
911
  if (!result.updated) return;
821
- session.artifacts.manifest.status = status;
822
- session.artifacts.manifest.ended_at = result.endedAt ?? nowIso();
823
- session.artifacts.manifest.exit_code =
824
- typeof exitCode === "number" ? exitCode : null;
912
+ const latestManifest =
913
+ (await this.invokeOptionalValue<SessionManifest>(
914
+ "readSessionManifest",
915
+ session.sessionId,
916
+ )) ?? session.artifacts.manifest;
917
+ latestManifest.status = status;
918
+ latestManifest.ended_at = result.endedAt ?? nowIso();
919
+ latestManifest.exit_code = typeof exitCode === "number" ? exitCode : null;
920
+ session.artifacts.manifest = latestManifest;
825
921
  await this.invoke<void>(
826
922
  "writeSessionManifest",
827
923
  session.artifacts.manifestPath,
828
- session.artifacts.manifest,
924
+ latestManifest,
829
925
  );
830
926
  this.emitStatus(session.sessionId, status);
831
927
  }
@@ -869,6 +965,27 @@ export class DefaultSessionManager implements SessionManager {
869
965
  });
870
966
  }
871
967
 
968
+ /**
969
+ * Consume the first steer-delivery pending prompt for injection into the
970
+ * running agent loop. Called synchronously by the agent between iterations.
971
+ */
972
+ private consumeSteerMessage(sessionId: string): string | undefined {
973
+ const session = this.sessions.get(sessionId);
974
+ if (!session) {
975
+ return undefined;
976
+ }
977
+ const steerIndex = session.pendingPrompts.findIndex(
978
+ (entry) => entry.delivery === "steer",
979
+ );
980
+ if (steerIndex < 0) {
981
+ return undefined;
982
+ }
983
+ const [steer] = session.pendingPrompts.splice(steerIndex, 1);
984
+ this.emitPendingPrompts(session);
985
+ this.emitPendingPromptSubmitted(session, steer);
986
+ return steer.prompt;
987
+ }
988
+
872
989
  private enqueuePendingPrompt(
873
990
  sessionId: string,
874
991
  entry: {
@@ -1065,9 +1182,12 @@ export class DefaultSessionManager implements SessionManager {
1065
1182
  const tools: Tool[] = config.enableTools
1066
1183
  ? createBuiltinTools({
1067
1184
  cwd: config.cwd,
1068
- ...(config.mode === "plan"
1069
- ? ToolPresets.readonly
1070
- : ToolPresets.development),
1185
+ ...ToolPresets[
1186
+ resolveToolPresetName({
1187
+ mode: config.mode,
1188
+ yolo: config.yolo,
1189
+ })
1190
+ ],
1071
1191
  executors: this.defaultToolExecutors,
1072
1192
  })
1073
1193
  : [];
@@ -1092,10 +1212,6 @@ export class DefaultSessionManager implements SessionManager {
1092
1212
  providerConfig: config.providerConfig,
1093
1213
  knownModels: config.knownModels,
1094
1214
  thinking: config.thinking,
1095
- clineWorkspaceMetadata:
1096
- config.providerId === "cline"
1097
- ? extractWorkspaceMetadataFromSystemPrompt(config.systemPrompt)
1098
- : undefined,
1099
1215
  maxIterations: config.maxIterations,
1100
1216
  hooks: config.hooks,
1101
1217
  extensions: config.extensions,
@@ -7,12 +7,12 @@ import {
7
7
  } from "node:fs";
8
8
  import { join } from "node:path";
9
9
  import { resolveSessionDataDir } from "@clinebot/shared/storage";
10
- import type { SessionRow } from "./session-service";
11
10
  import type {
12
11
  PersistedSessionUpdateInput,
13
12
  SessionPersistenceAdapter,
14
- } from "./unified-session-persistence-service";
15
- import { UnifiedSessionPersistenceService } from "./unified-session-persistence-service";
13
+ } from "./persistence-service";
14
+ import { UnifiedSessionPersistenceService } from "./persistence-service";
15
+ import type { SessionRow } from "./session-service";
16
16
 
17
17
  interface FileSessionIndex {
18
18
  version: 1;
@@ -1,3 +1,9 @@
1
+ export {
2
+ upsertWorkspaceInfo,
3
+ type WorkspaceInfo,
4
+ type WorkspaceManifest,
5
+ WorkspaceManifestSchema,
6
+ } from "@clinebot/shared";
1
7
  export type {
2
8
  ClineCore,
3
9
  ClineCoreOptions,
@@ -33,13 +39,7 @@ export type {
33
39
  WorkspaceManagerEvent,
34
40
  } from "./workspace-manager";
35
41
  export { InMemoryWorkspaceManager } from "./workspace-manager";
36
- export type { WorkspaceManifest } from "./workspace-manifest";
37
42
  export {
38
- buildWorkspaceMetadata,
39
- emptyWorkspaceManifest,
40
43
  generateWorkspaceInfo,
41
44
  normalizeWorkspacePath,
42
- upsertWorkspaceInfo,
43
- WorkspaceInfoSchema,
44
- WorkspaceManifestSchema,
45
45
  } from "./workspace-manifest";
@@ -0,0 +1,212 @@
1
+ import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+ import { SqliteSessionStore } from "../storage/sqlite-session-store";
6
+ import { SessionSource } from "../types/common";
7
+ import { CoreSessionService } from "./session-service";
8
+
9
+ describe("UnifiedSessionPersistenceService", () => {
10
+ const tempDirs: string[] = [];
11
+ const stores: Array<SqliteSessionStore> = [];
12
+
13
+ afterEach(() => {
14
+ for (const store of stores.splice(0)) {
15
+ store.close();
16
+ }
17
+ for (const dir of tempDirs.splice(0)) {
18
+ rmSync(dir, { recursive: true, force: true });
19
+ }
20
+ });
21
+
22
+ it("reconciles dead running sessions into failed manifests with terminal markers", async () => {
23
+ const sessionsDir = mkdtempSync(join(tmpdir(), "stale-session-reconcile-"));
24
+ tempDirs.push(sessionsDir);
25
+
26
+ const store = new SqliteSessionStore({ sessionsDir });
27
+ stores.push(store);
28
+ const service = new CoreSessionService(store);
29
+ const sessionId = "stale-root-session";
30
+ const artifacts = await service.createRootSessionWithArtifacts({
31
+ sessionId,
32
+ source: SessionSource.CLI,
33
+ pid: 999_999_999,
34
+ interactive: false,
35
+ provider: "mock-provider",
36
+ model: "mock-model",
37
+ cwd: "/tmp/project",
38
+ workspaceRoot: "/tmp/project",
39
+ enableTools: true,
40
+ enableSpawn: true,
41
+ enableTeams: false,
42
+ prompt: "hello",
43
+ startedAt: "2026-01-01T00:00:00.000Z",
44
+ });
45
+
46
+ const reconciled = await service.reconcileDeadSessions();
47
+ expect(reconciled).toBe(1);
48
+
49
+ const rows = await service.listSessions(10);
50
+ expect(rows).toHaveLength(1);
51
+ expect(rows[0]).toMatchObject({
52
+ sessionId,
53
+ status: "failed",
54
+ exitCode: 1,
55
+ });
56
+ expect(rows[0]?.endedAt).toBeTruthy();
57
+
58
+ const manifest = JSON.parse(
59
+ readFileSync(artifacts.manifestPath, "utf8"),
60
+ ) as Record<string, unknown>;
61
+ expect(manifest.status).toBe("failed");
62
+ expect(manifest.exit_code).toBe(1);
63
+ expect(manifest.ended_at).toBeTruthy();
64
+ expect(manifest.metadata).toMatchObject({
65
+ terminal_marker: "failed_external_process_exit",
66
+ terminal_marker_pid: 999_999_999,
67
+ terminal_marker_source: "stale_session_reconciler",
68
+ });
69
+ expect(
70
+ (manifest.metadata as Record<string, unknown>).terminal_marker_at,
71
+ ).toBeTruthy();
72
+
73
+ expect(existsSync(artifacts.hookPath)).toBe(true);
74
+ expect(existsSync(artifacts.transcriptPath)).toBe(true);
75
+ expect(readFileSync(artifacts.hookPath, "utf8")).toContain(
76
+ '"hookName":"session_shutdown"',
77
+ );
78
+ expect(readFileSync(artifacts.hookPath, "utf8")).toContain(
79
+ '"reason":"failed_external_process_exit"',
80
+ );
81
+ expect(readFileSync(artifacts.transcriptPath, "utf8")).toContain(
82
+ "[shutdown] failed_external_process_exit",
83
+ );
84
+ }, 15_000);
85
+
86
+ it("persists teammate task metadata in the file envelope and usage on messages", async () => {
87
+ const sessionsDir = mkdtempSync(join(tmpdir(), "team-task-messages-"));
88
+ tempDirs.push(sessionsDir);
89
+
90
+ const store = new SqliteSessionStore({ sessionsDir });
91
+ stores.push(store);
92
+ const service = new CoreSessionService(store);
93
+ const rootSessionId = "root-session";
94
+ await service.createRootSessionWithArtifacts({
95
+ sessionId: rootSessionId,
96
+ source: SessionSource.CLI,
97
+ pid: process.pid,
98
+ interactive: false,
99
+ provider: "anthropic",
100
+ model: "claude-sonnet-4-6",
101
+ cwd: "/tmp/project",
102
+ workspaceRoot: "/tmp/project",
103
+ enableTools: true,
104
+ enableSpawn: true,
105
+ enableTeams: true,
106
+ prompt: "lead task",
107
+ startedAt: "2026-04-10T19:00:00.000Z",
108
+ });
109
+
110
+ await service.onTeamTaskStart(
111
+ rootSessionId,
112
+ "java-haiku-agent",
113
+ "Write a haiku about Java",
114
+ );
115
+ await service.onTeamTaskEnd(
116
+ rootSessionId,
117
+ "java-haiku-agent",
118
+ "completed",
119
+ "[done] completed",
120
+ {
121
+ text: "Classes wrap the world\nWrite once, run on every machine —\nVerbose, yet it soars",
122
+ usage: {
123
+ inputTokens: 42,
124
+ outputTokens: 17,
125
+ cacheReadTokens: 9,
126
+ cacheWriteTokens: 0,
127
+ totalCost: 0.123,
128
+ },
129
+ messages: [
130
+ {
131
+ role: "user",
132
+ content: "Write a haiku about Java. Return only the haiku.",
133
+ },
134
+ {
135
+ role: "assistant",
136
+ content: [
137
+ {
138
+ type: "text",
139
+ text: "Classes wrap the world\nWrite once, run on every machine —\nVerbose, yet it soars",
140
+ },
141
+ ],
142
+ },
143
+ ],
144
+ toolCalls: [],
145
+ iterations: 1,
146
+ finishReason: "completed",
147
+ model: {
148
+ id: "claude-sonnet-4-6",
149
+ provider: "anthropic",
150
+ info: { id: "claude-sonnet-4-6" },
151
+ },
152
+ startedAt: new Date("2026-04-10T19:00:01.000Z"),
153
+ endedAt: new Date("2026-04-10T19:00:02.000Z"),
154
+ durationMs: 1000,
155
+ },
156
+ );
157
+
158
+ const childSessions = await service.listSessions(10);
159
+ const teammateSessionId = childSessions.find((row) =>
160
+ row.sessionId.includes("__teamtask__java-haiku-agent__"),
161
+ )?.sessionId;
162
+ expect(teammateSessionId).toBeTruthy();
163
+ const path = join(
164
+ sessionsDir,
165
+ rootSessionId,
166
+ "java-haiku-agent__" +
167
+ teammateSessionId?.slice(teammateSessionId?.lastIndexOf("__") + 2) +
168
+ ".messages.json",
169
+ );
170
+ const payload = JSON.parse(readFileSync(path, "utf8")) as {
171
+ agent?: string;
172
+ sessionId?: string;
173
+ taskType?: string;
174
+ messages: Array<Record<string, unknown>>;
175
+ };
176
+ const user = payload.messages[0] as Record<string, unknown>;
177
+ const assistant = payload.messages[1] as Record<string, unknown>;
178
+
179
+ expect(payload.agent).toBe("teammate");
180
+ expect(payload.sessionId).toBe(rootSessionId);
181
+ expect(payload.taskType).toBe("team");
182
+ expect(assistant.id).toEqual(expect.any(String));
183
+ expect(user.agent).toBeUndefined();
184
+ expect(user.sessionId).toBeUndefined();
185
+ expect(assistant.agent).toBeUndefined();
186
+ expect(assistant.sessionId).toBeUndefined();
187
+ expect(assistant.modelInfo).toMatchObject({
188
+ id: "claude-sonnet-4-6",
189
+ provider: "anthropic",
190
+ });
191
+ expect(assistant.metrics).toMatchObject({
192
+ inputTokens: 42,
193
+ outputTokens: 17,
194
+ cacheReadTokens: 9,
195
+ cacheWriteTokens: 0,
196
+ cost: 0.123,
197
+ });
198
+ const row = childSessions.find(
199
+ (item) => item.sessionId === teammateSessionId,
200
+ );
201
+ expect(row?.messagesPath).toBe(path);
202
+ expect(row?.transcriptPath).toBe(
203
+ join(
204
+ sessionsDir,
205
+ rootSessionId,
206
+ "java-haiku-agent__" +
207
+ teammateSessionId?.slice(teammateSessionId?.lastIndexOf("__") + 2) +
208
+ ".log",
209
+ ),
210
+ );
211
+ });
212
+ });