@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
@@ -229,8 +229,8 @@ export class OpenTelemetryAdapter implements ITelemetryAdapter {
229
229
  ): TelemetryProperties {
230
230
  return {
231
231
  ...this.commonProperties,
232
- ...properties,
233
232
  ...this.metadata,
233
+ ...properties,
234
234
  ...(this.distinctId ? { distinct_id: this.distinctId } : {}),
235
235
  ...(required ? { _required: true } : {}),
236
236
  };
@@ -52,6 +52,29 @@ describe("createOpenTelemetryTelemetryService", () => {
52
52
  await provider.dispose();
53
53
  });
54
54
 
55
+ it("registers a tracer provider when tracesExporter is set", async () => {
56
+ const { provider } = createOpenTelemetryTelemetryService({
57
+ metadata: {
58
+ extension_version: "1.2.3",
59
+ cline_type: "cli",
60
+ platform: "terminal",
61
+ platform_version: process.version,
62
+ os_type: process.platform,
63
+ os_version: "unknown",
64
+ },
65
+ enabled: true,
66
+ tracesExporter: "console",
67
+ logsExporter: "console",
68
+ metricsExporter: "console",
69
+ serviceName: "cline-test",
70
+ });
71
+
72
+ expect(provider.tracerProvider).not.toBeNull();
73
+ const span = provider.getTracer("test").startSpan("verify.tracing");
74
+ span.end();
75
+ await provider.dispose();
76
+ });
77
+
55
78
  it("does not create an OTEL provider when disabled", () => {
56
79
  const providerSpy = vi.spyOn(
57
80
  OpenTelemetryProvider.prototype,
@@ -75,11 +98,201 @@ describe("createOpenTelemetryTelemetryService", () => {
75
98
  expect(telemetry).toBeInstanceOf(TelemetryService);
76
99
  });
77
100
 
101
+ it("preserves metadata when disabled", () => {
102
+ const metadata = {
103
+ extension_version: "1.0.0",
104
+ cline_type: "kanban",
105
+ platform: "kanban",
106
+ platform_version: "v22.0.0",
107
+ os_type: "darwin",
108
+ os_version: "15.0",
109
+ };
110
+ const { telemetry } = createConfiguredTelemetryService({
111
+ metadata,
112
+ enabled: false,
113
+ });
114
+ const spy = vi.fn();
115
+ (telemetry as any).adapters.push({
116
+ name: "test",
117
+ emit: spy,
118
+ emitRequired: spy,
119
+ isEnabled: () => true,
120
+ recordCounter: vi.fn(),
121
+ recordHistogram: vi.fn(),
122
+ recordGauge: vi.fn(),
123
+ flush: async () => {},
124
+ dispose: async () => {},
125
+ });
126
+ telemetry.captureRequired("test.event", {});
127
+ expect(spy).toHaveBeenCalledWith(
128
+ "test.event",
129
+ expect.objectContaining({
130
+ cline_type: "kanban",
131
+ platform: "kanban",
132
+ }),
133
+ );
134
+ });
135
+
136
+ it("preserves metadata in the enabled (OTEL) path", async () => {
137
+ const metadata = {
138
+ extension_version: "1.0.0",
139
+ cline_type: "kanban",
140
+ platform: "kanban",
141
+ platform_version: "v22.0.0",
142
+ os_type: "darwin",
143
+ os_version: "15.0",
144
+ };
145
+ const { telemetry, provider } = createOpenTelemetryTelemetryService({
146
+ metadata,
147
+ enabled: true,
148
+ logsExporter: "console",
149
+ });
150
+ const spy = vi.fn();
151
+ (telemetry as any).adapters.push({
152
+ name: "test",
153
+ emit: spy,
154
+ emitRequired: spy,
155
+ isEnabled: () => true,
156
+ recordCounter: vi.fn(),
157
+ recordHistogram: vi.fn(),
158
+ recordGauge: vi.fn(),
159
+ flush: async () => {},
160
+ dispose: async () => {},
161
+ });
162
+ telemetry.captureRequired("test.event", {});
163
+ expect(spy).toHaveBeenCalledWith(
164
+ "test.event",
165
+ expect.objectContaining({
166
+ cline_type: "kanban",
167
+ platform: "kanban",
168
+ }),
169
+ );
170
+ await provider.dispose();
171
+ });
172
+
173
+ it("delivers metadata to the OTEL logger without duplication", async () => {
174
+ const otelEmit = vi.fn();
175
+ const provider = new OpenTelemetryProvider({
176
+ enabled: true,
177
+ });
178
+ // Replace the loggerProvider with a mock so we can inspect emit calls
179
+ (provider as any).loggerProvider = {
180
+ getLogger: () => ({ emit: otelEmit }),
181
+ forceFlush: async () => {},
182
+ shutdown: async () => {},
183
+ };
184
+
185
+ const metadata = {
186
+ extension_version: "1.0.0",
187
+ cline_type: "kanban",
188
+ platform: "kanban",
189
+ platform_version: "v22.0.0",
190
+ os_type: "darwin",
191
+ os_version: "15.0",
192
+ };
193
+
194
+ const telemetry = provider.createTelemetryService({ metadata });
195
+
196
+ telemetry.captureRequired("test.otel_event", { custom_prop: "value" });
197
+
198
+ expect(otelEmit).toHaveBeenCalledTimes(1);
199
+ const emittedAttributes = otelEmit.mock.calls[0][0].attributes;
200
+
201
+ // Metadata fields must be present
202
+ expect(emittedAttributes).toMatchObject({
203
+ cline_type: "kanban",
204
+ platform: "kanban",
205
+ extension_version: "1.0.0",
206
+ custom_prop: "value",
207
+ });
208
+
209
+ // Verify no key appears more than once (flattened object can't have
210
+ // duplicate keys, but this guards against nested duplication patterns
211
+ // like metadata appearing under a sub-prefix)
212
+ const keys = Object.keys(emittedAttributes);
213
+ const metadataKeys = Object.keys(metadata);
214
+ for (const mk of metadataKeys) {
215
+ const occurrences = keys.filter((k) => k === mk || k.endsWith(`.${mk}`));
216
+ expect(
217
+ occurrences,
218
+ `metadata key "${mk}" should appear exactly once, found: ${occurrences.join(", ")}`,
219
+ ).toHaveLength(1);
220
+ }
221
+
222
+ await provider.dispose();
223
+ });
224
+
225
+ it("propagates updateMetadata to OTEL logger output", async () => {
226
+ const otelEmit = vi.fn();
227
+ const provider = new OpenTelemetryProvider({
228
+ enabled: true,
229
+ });
230
+ (provider as any).loggerProvider = {
231
+ getLogger: () => ({ emit: otelEmit }),
232
+ forceFlush: async () => {},
233
+ shutdown: async () => {},
234
+ };
235
+
236
+ const metadata = {
237
+ extension_version: "1.0.0",
238
+ cline_type: "kanban",
239
+ platform: "kanban",
240
+ platform_version: "v22.0.0",
241
+ os_type: "darwin",
242
+ os_version: "15.0",
243
+ };
244
+
245
+ const telemetry = provider.createTelemetryService({ metadata });
246
+
247
+ // Update metadata after construction
248
+ telemetry.updateMetadata({ cline_type: "kanban-updated" });
249
+
250
+ telemetry.captureRequired("test.updated_event", {});
251
+
252
+ // The OTEL logger should see the updated value
253
+ const emittedAttributes =
254
+ otelEmit.mock.calls[otelEmit.mock.calls.length - 1][0].attributes;
255
+ expect(emittedAttributes.cline_type).toBe("kanban-updated");
256
+
257
+ await provider.dispose();
258
+ });
259
+
260
+ it("preserves logger when disabled", () => {
261
+ const logger: BasicLogger = {
262
+ debug: vi.fn(),
263
+ log: vi.fn(),
264
+ error: vi.fn(),
265
+ };
266
+ const { telemetry } = createConfiguredTelemetryService({
267
+ metadata: {
268
+ extension_version: "1.0.0",
269
+ cline_type: "kanban",
270
+ platform: "kanban",
271
+ platform_version: "v22.0.0",
272
+ os_type: "darwin",
273
+ os_version: "15.0",
274
+ },
275
+ enabled: false,
276
+ logger,
277
+ });
278
+
279
+ telemetry.capture({
280
+ event: "session.started",
281
+ properties: { sessionId: "session-1" },
282
+ });
283
+
284
+ expect(logger.log).toHaveBeenCalledWith(
285
+ "telemetry.event",
286
+ expect.objectContaining({
287
+ event: "session.started",
288
+ }),
289
+ );
290
+ });
291
+
78
292
  it("attaches the logger adapter when creating configured telemetry", () => {
79
293
  const logger: BasicLogger = {
80
294
  debug: vi.fn(),
81
- info: vi.fn(),
82
- warn: vi.fn(),
295
+ log: vi.fn(),
83
296
  error: vi.fn(),
84
297
  };
85
298
  const { telemetry, provider } = createConfiguredTelemetryService({
@@ -101,7 +314,7 @@ describe("createOpenTelemetryTelemetryService", () => {
101
314
  properties: { sessionId: "session-1" },
102
315
  });
103
316
 
104
- expect(logger.info).toHaveBeenCalledWith(
317
+ expect(logger.log).toHaveBeenCalledWith(
105
318
  "telemetry.event",
106
319
  expect.objectContaining({
107
320
  event: "session.started",
@@ -4,11 +4,12 @@ import type {
4
4
  OpenTelemetryClientConfig,
5
5
  TelemetryMetadata,
6
6
  } from "@clinebot/shared";
7
- import { metrics } from "@opentelemetry/api";
7
+ import { metrics, type Tracer, trace } from "@opentelemetry/api";
8
8
  import { logs } from "@opentelemetry/api-logs";
9
9
  import { OTLPLogExporter as OTLPLogExporterHttp } from "@opentelemetry/exporter-logs-otlp-http";
10
10
  import { OTLPMetricExporter as OTLPMetricExporterHttp } from "@opentelemetry/exporter-metrics-otlp-http";
11
- import { Resource } from "@opentelemetry/resources";
11
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
12
+ import { resourceFromAttributes } from "@opentelemetry/resources";
12
13
  import {
13
14
  BatchLogRecordProcessor,
14
15
  ConsoleLogRecordExporter,
@@ -21,6 +22,13 @@ import {
21
22
  type MetricReader,
22
23
  PeriodicExportingMetricReader,
23
24
  } from "@opentelemetry/sdk-metrics";
25
+ import {
26
+ BatchSpanProcessor,
27
+ ConsoleSpanExporter,
28
+ SimpleSpanProcessor,
29
+ type SpanProcessor,
30
+ } from "@opentelemetry/sdk-trace-base";
31
+ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
24
32
  import {
25
33
  ATTR_SERVICE_NAME,
26
34
  ATTR_SERVICE_VERSION,
@@ -38,13 +46,14 @@ type OpenTelemetryProtocol = "http/json";
38
46
  export interface OpenTelemetryProviderOptions
39
47
  extends Omit<
40
48
  OpenTelemetryClientConfig,
41
- "enabled" | "logsExporter" | "metricsExporter"
49
+ "enabled" | "logsExporter" | "metricsExporter" | "tracesExporter"
42
50
  > {
43
51
  serviceName?: string;
44
52
  serviceVersion?: string;
45
53
  enabled?: boolean;
46
54
  logsExporter?: string | OpenTelemetryExporterKind[];
47
55
  metricsExporter?: string | OpenTelemetryExporterKind[];
56
+ tracesExporter?: string | OpenTelemetryExporterKind[];
48
57
  metricExportIntervalMs?: number;
49
58
  logMaxQueueSize?: number;
50
59
  logBatchSize?: number;
@@ -64,11 +73,12 @@ export interface CreateOpenTelemetryTelemetryServiceOptions
64
73
  export class OpenTelemetryProvider {
65
74
  readonly meterProvider: MeterProvider | null;
66
75
  readonly loggerProvider: LoggerProvider | null;
76
+ readonly tracerProvider: NodeTracerProvider | null;
67
77
  private readonly options: OpenTelemetryProviderOptions;
68
78
 
69
79
  constructor(options: OpenTelemetryProviderOptions = {}) {
70
80
  this.options = options;
71
- const resource = new Resource({
81
+ const resource = resourceFromAttributes({
72
82
  [ATTR_SERVICE_NAME]: options.serviceName ?? "cline",
73
83
  ...(options.serviceVersion
74
84
  ? { [ATTR_SERVICE_VERSION]: options.serviceVersion }
@@ -77,6 +87,7 @@ export class OpenTelemetryProvider {
77
87
 
78
88
  this.meterProvider = this.createMeterProvider(resource);
79
89
  this.loggerProvider = this.createLoggerProvider(resource);
90
+ this.tracerProvider = this.createTracerProvider(resource);
80
91
 
81
92
  if (this.meterProvider) {
82
93
  metrics.setGlobalMeterProvider(this.meterProvider);
@@ -84,6 +95,17 @@ export class OpenTelemetryProvider {
84
95
  if (this.loggerProvider) {
85
96
  logs.setGlobalLoggerProvider(this.loggerProvider);
86
97
  }
98
+ if (this.tracerProvider) {
99
+ this.tracerProvider.register();
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Returns a tracer for manual spans. Requires {@link OpenTelemetryProviderOptions.tracesExporter}
105
+ * so that a {@link NodeTracerProvider} is registered.
106
+ */
107
+ getTracer(name = "cline", version?: string): Tracer {
108
+ return trace.getTracer(name, version ?? this.options.serviceVersion);
87
109
  }
88
110
 
89
111
  createAdapter(
@@ -111,10 +133,9 @@ export class OpenTelemetryProvider {
111
133
  metadata: options.metadata,
112
134
  });
113
135
  return new TelemetryService({
136
+ ...options,
114
137
  adapters: [adapter],
115
138
  distinctId: resolveCoreDistinctId(options.distinctId),
116
- commonProperties: options.commonProperties,
117
- logger: options.logger,
118
139
  });
119
140
  }
120
141
 
@@ -122,6 +143,7 @@ export class OpenTelemetryProvider {
122
143
  await Promise.all([
123
144
  this.meterProvider?.forceFlush?.(),
124
145
  this.loggerProvider?.forceFlush?.(),
146
+ this.tracerProvider?.forceFlush?.(),
125
147
  ]);
126
148
  }
127
149
 
@@ -129,10 +151,13 @@ export class OpenTelemetryProvider {
129
151
  await Promise.all([
130
152
  this.meterProvider?.shutdown?.(),
131
153
  this.loggerProvider?.shutdown?.(),
154
+ this.tracerProvider?.shutdown?.(),
132
155
  ]);
133
156
  }
134
157
 
135
- private createMeterProvider(resource: Resource): MeterProvider | null {
158
+ private createMeterProvider(
159
+ resource: ReturnType<typeof resourceFromAttributes>,
160
+ ): MeterProvider | null {
136
161
  const exporters = normalizeExporters(this.options.metricsExporter);
137
162
  if (exporters.length === 0) {
138
163
  return null;
@@ -168,35 +193,71 @@ export class OpenTelemetryProvider {
168
193
  });
169
194
  }
170
195
 
171
- private createLoggerProvider(resource: Resource): LoggerProvider | null {
172
- const exporters = normalizeExporters(this.options.logsExporter);
196
+ private createTracerProvider(
197
+ resource: ReturnType<typeof resourceFromAttributes>,
198
+ ): NodeTracerProvider | null {
199
+ const exporters = normalizeExporters(this.options.tracesExporter);
173
200
  if (exporters.length === 0) {
174
201
  return null;
175
202
  }
176
203
 
177
- const provider = new LoggerProvider({ resource });
204
+ const traceEndpoint =
205
+ this.options.otlpTracesEndpoint ?? this.options.otlpEndpoint;
206
+ const traceHeaders =
207
+ this.options.otlpTracesHeaders ?? this.options.otlpHeaders;
208
+
209
+ const processors: SpanProcessor[] = [];
178
210
  for (const exporter of exporters) {
179
- const logExporter = createLogExporter(exporter, {
180
- endpoint: this.options.otlpEndpoint,
181
- headers: this.options.otlpHeaders,
211
+ const processor = createSpanProcessor(exporter, {
212
+ endpoint: traceEndpoint,
213
+ headers: traceHeaders,
182
214
  insecure: this.options.otlpInsecure ?? false,
183
215
  protocol: "http/json",
184
216
  });
185
- if (!logExporter) {
186
- continue;
217
+ if (processor) {
218
+ processors.push(processor);
187
219
  }
188
- provider.addLogRecordProcessor(
189
- new BatchLogRecordProcessor(logExporter, {
220
+ }
221
+ if (processors.length === 0) {
222
+ return null;
223
+ }
224
+
225
+ return new NodeTracerProvider({ resource, spanProcessors: processors });
226
+ }
227
+
228
+ private createLoggerProvider(
229
+ resource: ReturnType<typeof resourceFromAttributes>,
230
+ ): LoggerProvider | null {
231
+ const exporters = normalizeExporters(this.options.logsExporter);
232
+ if (exporters.length === 0) {
233
+ return null;
234
+ }
235
+
236
+ const processors = exporters
237
+ .map((exporter) => {
238
+ const logExporter = createLogExporter(exporter, {
239
+ endpoint: this.options.otlpEndpoint,
240
+ headers: this.options.otlpHeaders,
241
+ insecure: this.options.otlpInsecure ?? false,
242
+ protocol: "http/json",
243
+ });
244
+ if (!logExporter) {
245
+ return null;
246
+ }
247
+ return new BatchLogRecordProcessor(logExporter, {
190
248
  maxQueueSize: this.options.logMaxQueueSize ?? 2048,
191
249
  maxExportBatchSize: this.options.logBatchSize ?? 512,
192
250
  scheduledDelayMillis:
193
251
  this.options.logBatchTimeoutMs ??
194
252
  this.options.logBatchTimeout ??
195
253
  5000,
196
- }),
197
- );
254
+ });
255
+ })
256
+ .filter((p): p is BatchLogRecordProcessor => p !== null);
257
+ if (processors.length === 0) {
258
+ return null;
198
259
  }
199
- return provider;
260
+ return new LoggerProvider({ resource, processors });
200
261
  }
201
262
  }
202
263
 
@@ -214,6 +275,9 @@ export function createOpenTelemetryTelemetryService(
214
275
  metricsExporter: Array.isArray(options.metricsExporter)
215
276
  ? options.metricsExporter.join(",")
216
277
  : options.metricsExporter,
278
+ tracesExporter: Array.isArray(options.tracesExporter)
279
+ ? options.tracesExporter.join(",")
280
+ : options.tracesExporter,
217
281
  otlpProtocol: options.otlpProtocol,
218
282
  hasOtlpEndpoint: Boolean(options.otlpEndpoint),
219
283
  serviceName: options.serviceName,
@@ -234,6 +298,7 @@ export function createConfiguredTelemetryService(
234
298
  if (options.enabled !== true) {
235
299
  return {
236
300
  telemetry: new TelemetryService({
301
+ ...options,
237
302
  distinctId: resolveCoreDistinctId(options.distinctId),
238
303
  }),
239
304
  };
@@ -280,6 +345,31 @@ function createLogExporter(
280
345
  });
281
346
  }
282
347
 
348
+ function createSpanProcessor(
349
+ exporter: OpenTelemetryExporterKind,
350
+ options: {
351
+ endpoint?: string;
352
+ headers?: Record<string, string>;
353
+ insecure: boolean;
354
+ protocol: OpenTelemetryProtocol;
355
+ },
356
+ ): SpanProcessor | null {
357
+ if (exporter === "console") {
358
+ return new SimpleSpanProcessor(new ConsoleSpanExporter());
359
+ }
360
+ if (!options.endpoint) {
361
+ return null;
362
+ }
363
+
364
+ const endpoint = ensurePathSuffix(options.endpoint, "/v1/traces");
365
+ return new BatchSpanProcessor(
366
+ new OTLPTraceExporter({
367
+ url: endpoint,
368
+ headers: options.headers,
369
+ }),
370
+ );
371
+ }
372
+
283
373
  function createMetricReader(
284
374
  exporter: OpenTelemetryExporterKind,
285
375
  options: {
@@ -0,0 +1,42 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { TelemetryLoggerSink } from "./TelemetryLoggerSink";
3
+
4
+ describe("TelemetryLoggerSink", () => {
5
+ it("logs events and metrics through the provided logger", async () => {
6
+ const logger = {
7
+ debug: vi.fn(),
8
+ log: vi.fn(),
9
+ };
10
+ const sink = new TelemetryLoggerSink({ logger });
11
+
12
+ sink.emit("session.started", { sessionId: "s1" });
13
+ sink.emitRequired("user.opt_out", { reason: "manual" });
14
+ sink.recordCounter("cline.session.starts.total", 1, {
15
+ sessionId: "s1",
16
+ });
17
+
18
+ expect(logger.log).toHaveBeenCalledWith("telemetry.event", {
19
+ telemetrySink: "TelemetryLoggerSink",
20
+ event: "session.started",
21
+ properties: { sessionId: "s1" },
22
+ });
23
+ expect(logger.log).toHaveBeenCalledWith("telemetry.required_event", {
24
+ telemetrySink: "TelemetryLoggerSink",
25
+ severity: "warn",
26
+ event: "user.opt_out",
27
+ properties: { reason: "manual" },
28
+ });
29
+ expect(logger.debug).toHaveBeenCalledWith("telemetry.metric", {
30
+ telemetrySink: "TelemetryLoggerSink",
31
+ instrument: "counter",
32
+ name: "cline.session.starts.total",
33
+ value: 1,
34
+ attributes: { sessionId: "s1" },
35
+ description: undefined,
36
+ required: false,
37
+ });
38
+
39
+ await sink.flush();
40
+ await sink.dispose();
41
+ });
42
+ });
@@ -4,20 +4,26 @@ import type {
4
4
  TelemetryProperties,
5
5
  } from "./ITelemetryAdapter";
6
6
 
7
- export interface LoggerTelemetryAdapterOptions {
7
+ /**
8
+ * {@link ITelemetryAdapter} implementation that forwards telemetry to a {@link BasicLogger}.
9
+ *
10
+ * This is intentionally named *Sink* (not "adapter") to distinguish it from host logging bridges
11
+ * such as the CLI Pino bundle: it consumes telemetry events and writes them to the injected logger.
12
+ */
13
+ export interface TelemetryLoggerSinkOptions {
8
14
  logger?: BasicLogger;
9
15
  name?: string;
10
16
  enabled?: boolean | (() => boolean);
11
17
  }
12
18
 
13
- export class LoggerTelemetryAdapter implements ITelemetryAdapter {
19
+ export class TelemetryLoggerSink implements ITelemetryAdapter {
14
20
  readonly name: string;
15
21
 
16
22
  private readonly logger?: BasicLogger;
17
23
  private readonly enabled: boolean | (() => boolean);
18
24
 
19
- constructor(options: LoggerTelemetryAdapterOptions = {}) {
20
- this.name = options.name ?? "LoggerTelemetryAdapter";
25
+ constructor(options: TelemetryLoggerSinkOptions = {}) {
26
+ this.name = options.name ?? "TelemetryLoggerSink";
21
27
  this.logger = options.logger;
22
28
  this.enabled = options.enabled ?? true;
23
29
  }
@@ -26,16 +32,17 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
26
32
  if (!this.isEnabled()) {
27
33
  return;
28
34
  }
29
- this.logger?.info?.("telemetry.event", {
30
- adapter: this.name,
35
+ this.logger?.log("telemetry.event", {
36
+ telemetrySink: this.name,
31
37
  event,
32
38
  properties,
33
39
  });
34
40
  }
35
41
 
36
42
  emitRequired(event: string, properties?: TelemetryProperties): void {
37
- this.logger?.warn?.("telemetry.required_event", {
38
- adapter: this.name,
43
+ this.logger?.log("telemetry.required_event", {
44
+ telemetrySink: this.name,
45
+ severity: "warn",
39
46
  event,
40
47
  properties,
41
48
  });
@@ -51,8 +58,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
51
58
  if (!required && !this.isEnabled()) {
52
59
  return;
53
60
  }
54
- this.logger?.debug?.("telemetry.metric", {
55
- adapter: this.name,
61
+ this.logger?.debug("telemetry.metric", {
62
+ telemetrySink: this.name,
56
63
  instrument: "counter",
57
64
  name,
58
65
  value,
@@ -72,8 +79,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
72
79
  if (!required && !this.isEnabled()) {
73
80
  return;
74
81
  }
75
- this.logger?.debug?.("telemetry.metric", {
76
- adapter: this.name,
82
+ this.logger?.debug("telemetry.metric", {
83
+ telemetrySink: this.name,
77
84
  instrument: "histogram",
78
85
  name,
79
86
  value,
@@ -93,8 +100,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
93
100
  if (!required && !this.isEnabled()) {
94
101
  return;
95
102
  }
96
- this.logger?.debug?.("telemetry.metric", {
97
- adapter: this.name,
103
+ this.logger?.debug("telemetry.metric", {
104
+ telemetrySink: this.name,
98
105
  instrument: "gauge",
99
106
  name,
100
107
  value,
@@ -53,8 +53,7 @@ describe("TelemetryService", () => {
53
53
  it("mirrors telemetry events into the logger when provided", () => {
54
54
  const logger: BasicLogger = {
55
55
  debug: vi.fn(),
56
- info: vi.fn(),
57
- warn: vi.fn(),
56
+ log: vi.fn(),
58
57
  error: vi.fn(),
59
58
  };
60
59
  const service = new TelemetryService({
@@ -75,10 +74,10 @@ describe("TelemetryService", () => {
75
74
  sessionId: "session-1",
76
75
  });
77
76
 
78
- expect(logger.info).toHaveBeenCalledWith(
77
+ expect(logger.log).toHaveBeenCalledWith(
79
78
  "telemetry.event",
80
79
  expect.objectContaining({
81
- adapter: "LoggerTelemetryAdapter",
80
+ telemetrySink: "TelemetryLoggerSink",
82
81
  event: "session.started",
83
82
  properties: expect.objectContaining({
84
83
  sessionId: "session-1",
@@ -87,10 +86,11 @@ describe("TelemetryService", () => {
87
86
  }),
88
87
  }),
89
88
  );
90
- expect(logger.warn).toHaveBeenCalledWith(
89
+ expect(logger.log).toHaveBeenCalledWith(
91
90
  "telemetry.required_event",
92
91
  expect.objectContaining({
93
- adapter: "LoggerTelemetryAdapter",
92
+ telemetrySink: "TelemetryLoggerSink",
93
+ severity: "warn",
94
94
  event: "user.opt_out",
95
95
  properties: expect.objectContaining({
96
96
  reason: "manual",
@@ -101,7 +101,7 @@ describe("TelemetryService", () => {
101
101
  expect(logger.debug).toHaveBeenCalledWith(
102
102
  "telemetry.metric",
103
103
  expect.objectContaining({
104
- adapter: "LoggerTelemetryAdapter",
104
+ telemetrySink: "TelemetryLoggerSink",
105
105
  instrument: "counter",
106
106
  name: "cline.session.starts.total",
107
107
  }),
@@ -5,7 +5,7 @@ import type {
5
5
  TelemetryProperties,
6
6
  } from "@clinebot/shared";
7
7
  import type { ITelemetryAdapter } from "./ITelemetryAdapter";
8
- import { LoggerTelemetryAdapter } from "./LoggerTelemetryAdapter";
8
+ import { TelemetryLoggerSink } from "./TelemetryLoggerSink";
9
9
 
10
10
  export interface TelemetryServiceOptions {
11
11
  adapters?: ITelemetryAdapter[];
@@ -24,9 +24,7 @@ export class TelemetryService implements ITelemetryService {
24
24
  constructor(options: TelemetryServiceOptions = {}) {
25
25
  this.adapters = [...(options.adapters ?? [])];
26
26
  if (options.logger) {
27
- this.adapters.push(
28
- new LoggerTelemetryAdapter({ logger: options.logger }),
29
- );
27
+ this.adapters.push(new TelemetryLoggerSink({ logger: options.logger }));
30
28
  }
31
29
  this.metadata = { ...(options.metadata ?? {}) };
32
30
  this.distinctId = options.distinctId;