@clinebot/core 0.0.22 → 0.0.23

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 (260) hide show
  1. package/dist/ClineCore.d.ts +110 -0
  2. package/dist/ClineCore.d.ts.map +1 -0
  3. package/dist/account/cline-account-service.d.ts +2 -1
  4. package/dist/account/cline-account-service.d.ts.map +1 -1
  5. package/dist/account/index.d.ts +1 -1
  6. package/dist/account/index.d.ts.map +1 -1
  7. package/dist/account/rpc.d.ts +3 -1
  8. package/dist/account/rpc.d.ts.map +1 -1
  9. package/dist/account/types.d.ts +3 -0
  10. package/dist/account/types.d.ts.map +1 -1
  11. package/dist/agents/plugin-loader.d.ts.map +1 -1
  12. package/dist/agents/plugin-sandbox-bootstrap.js +17 -17
  13. package/dist/auth/client.d.ts +1 -1
  14. package/dist/auth/client.d.ts.map +1 -1
  15. package/dist/auth/cline.d.ts +1 -1
  16. package/dist/auth/cline.d.ts.map +1 -1
  17. package/dist/auth/codex.d.ts +1 -1
  18. package/dist/auth/codex.d.ts.map +1 -1
  19. package/dist/auth/oca.d.ts +1 -1
  20. package/dist/auth/oca.d.ts.map +1 -1
  21. package/dist/auth/utils.d.ts +2 -2
  22. package/dist/auth/utils.d.ts.map +1 -1
  23. package/dist/index.d.ts +50 -5
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +949 -0
  26. package/dist/providers/local-provider-service.d.ts +4 -4
  27. package/dist/providers/local-provider-service.d.ts.map +1 -1
  28. package/dist/runtime/runtime-builder.d.ts +1 -0
  29. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  30. package/dist/runtime/session-runtime.d.ts +2 -1
  31. package/dist/runtime/session-runtime.d.ts.map +1 -1
  32. package/dist/runtime/team-runtime-registry.d.ts +13 -0
  33. package/dist/runtime/team-runtime-registry.d.ts.map +1 -0
  34. package/dist/session/default-session-manager.d.ts +2 -2
  35. package/dist/session/default-session-manager.d.ts.map +1 -1
  36. package/dist/session/rpc-runtime-ensure.d.ts +53 -0
  37. package/dist/session/rpc-runtime-ensure.d.ts.map +1 -0
  38. package/dist/session/session-config-builder.d.ts +2 -3
  39. package/dist/session/session-config-builder.d.ts.map +1 -1
  40. package/dist/session/session-host.d.ts +8 -18
  41. package/dist/session/session-host.d.ts.map +1 -1
  42. package/dist/session/session-manager.d.ts +1 -1
  43. package/dist/session/session-manager.d.ts.map +1 -1
  44. package/dist/session/session-manifest.d.ts +1 -2
  45. package/dist/session/session-manifest.d.ts.map +1 -1
  46. package/dist/session/unified-session-persistence-service.d.ts +2 -2
  47. package/dist/session/unified-session-persistence-service.d.ts.map +1 -1
  48. package/dist/session/utils/helpers.d.ts +1 -1
  49. package/dist/session/utils/helpers.d.ts.map +1 -1
  50. package/dist/session/utils/types.d.ts +1 -1
  51. package/dist/session/utils/types.d.ts.map +1 -1
  52. package/dist/storage/provider-settings-legacy-migration.d.ts.map +1 -1
  53. package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
  54. package/dist/telemetry/distinct-id.d.ts +2 -0
  55. package/dist/telemetry/distinct-id.d.ts.map +1 -0
  56. package/dist/telemetry/{opentelemetry.d.ts → index.d.ts} +1 -1
  57. package/dist/telemetry/index.d.ts.map +1 -0
  58. package/dist/telemetry/index.js +28 -0
  59. package/dist/tools/constants.d.ts +1 -1
  60. package/dist/tools/constants.d.ts.map +1 -1
  61. package/dist/tools/definitions.d.ts +3 -3
  62. package/dist/tools/definitions.d.ts.map +1 -1
  63. package/dist/tools/executors/apply-patch.d.ts +1 -1
  64. package/dist/tools/executors/apply-patch.d.ts.map +1 -1
  65. package/dist/tools/executors/bash.d.ts +1 -1
  66. package/dist/tools/executors/bash.d.ts.map +1 -1
  67. package/dist/tools/executors/editor.d.ts +1 -1
  68. package/dist/tools/executors/editor.d.ts.map +1 -1
  69. package/dist/tools/executors/file-read.d.ts +1 -1
  70. package/dist/tools/executors/file-read.d.ts.map +1 -1
  71. package/dist/tools/executors/index.d.ts +14 -14
  72. package/dist/tools/executors/index.d.ts.map +1 -1
  73. package/dist/tools/executors/search.d.ts +1 -1
  74. package/dist/tools/executors/search.d.ts.map +1 -1
  75. package/dist/tools/executors/web-fetch.d.ts +1 -1
  76. package/dist/tools/executors/web-fetch.d.ts.map +1 -1
  77. package/dist/tools/helpers.d.ts +1 -1
  78. package/dist/tools/helpers.d.ts.map +1 -1
  79. package/dist/tools/index.d.ts +10 -10
  80. package/dist/tools/index.d.ts.map +1 -1
  81. package/dist/tools/model-tool-routing.d.ts +1 -1
  82. package/dist/tools/model-tool-routing.d.ts.map +1 -1
  83. package/dist/tools/presets.d.ts +1 -1
  84. package/dist/tools/presets.d.ts.map +1 -1
  85. package/dist/types/common.d.ts +17 -8
  86. package/dist/types/common.d.ts.map +1 -1
  87. package/dist/types/config.d.ts +4 -3
  88. package/dist/types/config.d.ts.map +1 -1
  89. package/dist/types/provider-settings.d.ts +1 -1
  90. package/dist/types/provider-settings.d.ts.map +1 -1
  91. package/dist/types.d.ts +5 -2
  92. package/dist/types.d.ts.map +1 -1
  93. package/dist/version.d.ts +2 -0
  94. package/dist/version.d.ts.map +1 -0
  95. package/package.json +44 -38
  96. package/src/ClineCore.ts +137 -0
  97. package/src/account/cline-account-service.test.ts +101 -0
  98. package/src/account/cline-account-service.ts +300 -0
  99. package/src/account/featurebase-token.test.ts +175 -0
  100. package/src/account/index.ts +23 -0
  101. package/src/account/rpc.test.ts +63 -0
  102. package/src/account/rpc.ts +185 -0
  103. package/src/account/types.ts +102 -0
  104. package/src/agents/agent-config-loader.test.ts +236 -0
  105. package/src/agents/agent-config-loader.ts +108 -0
  106. package/src/agents/agent-config-parser.ts +198 -0
  107. package/src/agents/hooks-config-loader.test.ts +20 -0
  108. package/src/agents/hooks-config-loader.ts +118 -0
  109. package/src/agents/index.ts +85 -0
  110. package/src/agents/plugin-config-loader.test.ts +140 -0
  111. package/src/agents/plugin-config-loader.ts +97 -0
  112. package/src/agents/plugin-loader.test.ts +210 -0
  113. package/src/agents/plugin-loader.ts +175 -0
  114. package/src/agents/plugin-sandbox-bootstrap.ts +448 -0
  115. package/src/agents/plugin-sandbox.test.ts +296 -0
  116. package/src/agents/plugin-sandbox.ts +341 -0
  117. package/src/agents/unified-config-file-watcher.test.ts +196 -0
  118. package/src/agents/unified-config-file-watcher.ts +483 -0
  119. package/src/agents/user-instruction-config-loader.test.ts +158 -0
  120. package/src/agents/user-instruction-config-loader.ts +438 -0
  121. package/src/auth/client.test.ts +40 -0
  122. package/src/auth/client.ts +25 -0
  123. package/src/auth/cline.test.ts +130 -0
  124. package/src/auth/cline.ts +420 -0
  125. package/src/auth/codex.test.ts +170 -0
  126. package/src/auth/codex.ts +491 -0
  127. package/src/auth/oca.test.ts +215 -0
  128. package/src/auth/oca.ts +573 -0
  129. package/src/auth/server.ts +216 -0
  130. package/src/auth/types.ts +81 -0
  131. package/src/auth/utils.test.ts +128 -0
  132. package/src/auth/utils.ts +247 -0
  133. package/src/chat/chat-schema.ts +82 -0
  134. package/src/index.ts +479 -0
  135. package/src/input/file-indexer.d.ts +11 -0
  136. package/src/input/file-indexer.test.ts +127 -0
  137. package/src/input/file-indexer.ts +327 -0
  138. package/src/input/index.ts +7 -0
  139. package/src/input/mention-enricher.test.ts +85 -0
  140. package/src/input/mention-enricher.ts +122 -0
  141. package/src/mcp/config-loader.test.ts +238 -0
  142. package/src/mcp/config-loader.ts +219 -0
  143. package/src/mcp/index.ts +26 -0
  144. package/src/mcp/manager.test.ts +106 -0
  145. package/src/mcp/manager.ts +262 -0
  146. package/src/mcp/types.ts +88 -0
  147. package/src/providers/local-provider-registry.ts +232 -0
  148. package/src/providers/local-provider-service.test.ts +783 -0
  149. package/src/providers/local-provider-service.ts +471 -0
  150. package/src/runtime/commands.test.ts +98 -0
  151. package/src/runtime/commands.ts +83 -0
  152. package/src/runtime/hook-file-hooks.test.ts +237 -0
  153. package/src/runtime/hook-file-hooks.ts +859 -0
  154. package/src/runtime/index.ts +37 -0
  155. package/src/runtime/rules.ts +34 -0
  156. package/src/runtime/runtime-builder.team-persistence.test.ts +245 -0
  157. package/src/runtime/runtime-builder.test.ts +371 -0
  158. package/src/runtime/runtime-builder.ts +631 -0
  159. package/src/runtime/runtime-parity.test.ts +143 -0
  160. package/src/runtime/sandbox/subprocess-sandbox.ts +231 -0
  161. package/src/runtime/session-runtime.ts +49 -0
  162. package/src/runtime/skills.ts +44 -0
  163. package/src/runtime/team-runtime-registry.ts +46 -0
  164. package/src/runtime/tool-approval.ts +104 -0
  165. package/src/runtime/workflows.test.ts +119 -0
  166. package/src/runtime/workflows.ts +45 -0
  167. package/src/session/default-session-manager.e2e.test.ts +384 -0
  168. package/src/session/default-session-manager.test.ts +1931 -0
  169. package/src/session/default-session-manager.ts +1422 -0
  170. package/src/session/file-session-service.ts +280 -0
  171. package/src/session/index.ts +45 -0
  172. package/src/session/rpc-runtime-ensure.ts +521 -0
  173. package/src/session/rpc-session-service.ts +107 -0
  174. package/src/session/rpc-spawn-lease.test.ts +49 -0
  175. package/src/session/rpc-spawn-lease.ts +122 -0
  176. package/src/session/runtime-oauth-token-manager.test.ts +137 -0
  177. package/src/session/runtime-oauth-token-manager.ts +272 -0
  178. package/src/session/session-agent-events.ts +248 -0
  179. package/src/session/session-artifacts.ts +106 -0
  180. package/src/session/session-config-builder.ts +113 -0
  181. package/src/session/session-graph.ts +92 -0
  182. package/src/session/session-host.test.ts +89 -0
  183. package/src/session/session-host.ts +205 -0
  184. package/src/session/session-manager.ts +69 -0
  185. package/src/session/session-manifest.ts +29 -0
  186. package/src/session/session-service.team-persistence.test.ts +48 -0
  187. package/src/session/session-service.ts +673 -0
  188. package/src/session/session-team-coordination.ts +229 -0
  189. package/src/session/session-telemetry.ts +100 -0
  190. package/src/session/sqlite-rpc-session-backend.ts +303 -0
  191. package/src/session/unified-session-persistence-service.test.ts +85 -0
  192. package/src/session/unified-session-persistence-service.ts +994 -0
  193. package/src/session/utils/helpers.ts +139 -0
  194. package/src/session/utils/types.ts +57 -0
  195. package/src/session/utils/usage.ts +32 -0
  196. package/src/session/workspace-manager.ts +98 -0
  197. package/src/session/workspace-manifest.ts +100 -0
  198. package/src/storage/artifact-store.ts +1 -0
  199. package/src/storage/file-team-store.ts +257 -0
  200. package/src/storage/index.ts +11 -0
  201. package/src/storage/provider-settings-legacy-migration.test.ts +424 -0
  202. package/src/storage/provider-settings-legacy-migration.ts +826 -0
  203. package/src/storage/provider-settings-manager.test.ts +191 -0
  204. package/src/storage/provider-settings-manager.ts +152 -0
  205. package/src/storage/session-store.ts +1 -0
  206. package/src/storage/sqlite-session-store.ts +275 -0
  207. package/src/storage/sqlite-team-store.ts +454 -0
  208. package/src/storage/team-store.ts +40 -0
  209. package/src/team/index.ts +4 -0
  210. package/src/team/projections.ts +285 -0
  211. package/src/telemetry/ITelemetryAdapter.ts +94 -0
  212. package/src/telemetry/LoggerTelemetryAdapter.test.ts +42 -0
  213. package/src/telemetry/LoggerTelemetryAdapter.ts +114 -0
  214. package/src/telemetry/OpenTelemetryAdapter.test.ts +157 -0
  215. package/src/telemetry/OpenTelemetryAdapter.ts +348 -0
  216. package/src/telemetry/OpenTelemetryProvider.test.ts +113 -0
  217. package/src/telemetry/OpenTelemetryProvider.ts +325 -0
  218. package/src/telemetry/TelemetryService.test.ts +134 -0
  219. package/src/telemetry/TelemetryService.ts +141 -0
  220. package/src/telemetry/core-events.ts +400 -0
  221. package/src/telemetry/distinct-id.test.ts +57 -0
  222. package/src/telemetry/distinct-id.ts +58 -0
  223. package/src/telemetry/index.ts +20 -0
  224. package/src/tools/constants.ts +35 -0
  225. package/src/tools/definitions.test.ts +704 -0
  226. package/src/tools/definitions.ts +709 -0
  227. package/src/tools/executors/apply-patch-parser.ts +520 -0
  228. package/src/tools/executors/apply-patch.ts +359 -0
  229. package/src/tools/executors/bash.test.ts +87 -0
  230. package/src/tools/executors/bash.ts +207 -0
  231. package/src/tools/executors/editor.test.ts +35 -0
  232. package/src/tools/executors/editor.ts +219 -0
  233. package/src/tools/executors/file-read.test.ts +49 -0
  234. package/src/tools/executors/file-read.ts +110 -0
  235. package/src/tools/executors/index.ts +87 -0
  236. package/src/tools/executors/search.ts +278 -0
  237. package/src/tools/executors/web-fetch.ts +259 -0
  238. package/src/tools/helpers.ts +130 -0
  239. package/src/tools/index.ts +169 -0
  240. package/src/tools/model-tool-routing.test.ts +86 -0
  241. package/src/tools/model-tool-routing.ts +132 -0
  242. package/src/tools/presets.test.ts +62 -0
  243. package/src/tools/presets.ts +168 -0
  244. package/src/tools/schemas.ts +327 -0
  245. package/src/tools/types.ts +329 -0
  246. package/src/types/common.ts +26 -0
  247. package/src/types/config.ts +86 -0
  248. package/src/types/events.ts +74 -0
  249. package/src/types/index.ts +24 -0
  250. package/src/types/provider-settings.ts +43 -0
  251. package/src/types/sessions.ts +16 -0
  252. package/src/types/storage.ts +64 -0
  253. package/src/types/workspace.ts +7 -0
  254. package/src/types.ts +132 -0
  255. package/src/version.ts +3 -0
  256. package/dist/index.node.d.ts +0 -47
  257. package/dist/index.node.d.ts.map +0 -1
  258. package/dist/index.node.js +0 -948
  259. package/dist/telemetry/opentelemetry.d.ts.map +0 -1
  260. package/dist/telemetry/opentelemetry.js +0 -27
@@ -0,0 +1,348 @@
1
+ import type { Meter } from "@opentelemetry/api";
2
+ import type { Logger as OpenTelemetryLogger } from "@opentelemetry/api-logs";
3
+ import type { LoggerProvider } from "@opentelemetry/sdk-logs";
4
+ import type { MeterProvider } from "@opentelemetry/sdk-metrics";
5
+ import type {
6
+ ITelemetryAdapter,
7
+ TelemetryMetadata,
8
+ TelemetryPrimitive,
9
+ TelemetryProperties,
10
+ } from "./ITelemetryAdapter";
11
+
12
+ type FlatTelemetryAttributes = Record<string, string | number | boolean>;
13
+
14
+ export interface OpenTelemetryAdapterOptions {
15
+ readonly metadata: TelemetryMetadata;
16
+ readonly meterProvider?: MeterProvider | null;
17
+ readonly loggerProvider?: LoggerProvider | null;
18
+ readonly name?: string;
19
+ readonly enabled?: boolean | (() => boolean);
20
+ readonly distinctId?: string;
21
+ readonly commonProperties?: TelemetryProperties;
22
+ }
23
+
24
+ export class OpenTelemetryAdapter implements ITelemetryAdapter {
25
+ readonly name: string;
26
+
27
+ private readonly metadata: TelemetryMetadata;
28
+ private readonly meter: Meter | null;
29
+ private readonly logger: OpenTelemetryLogger | null;
30
+ private readonly enabled: boolean | (() => boolean);
31
+ private distinctId?: string;
32
+ private commonProperties: TelemetryProperties;
33
+ private counters = new Map<string, ReturnType<Meter["createCounter"]>>();
34
+ private histograms = new Map<string, ReturnType<Meter["createHistogram"]>>();
35
+ private gauges = new Map<
36
+ string,
37
+ ReturnType<Meter["createObservableGauge"]>
38
+ >();
39
+ private gaugeValues = new Map<
40
+ string,
41
+ Map<string, { value: number; attributes?: TelemetryProperties }>
42
+ >();
43
+ private readonly meterProvider?: MeterProvider | null;
44
+ private readonly loggerProvider?: LoggerProvider | null;
45
+
46
+ constructor(options: OpenTelemetryAdapterOptions) {
47
+ this.name = options.name ?? "OpenTelemetryAdapter";
48
+ this.metadata = { ...options.metadata };
49
+ this.meterProvider = options.meterProvider;
50
+ this.loggerProvider = options.loggerProvider;
51
+ this.meter = options.meterProvider?.getMeter("cline") ?? null;
52
+ this.logger = options.loggerProvider?.getLogger("cline") ?? null;
53
+ this.enabled = options.enabled ?? true;
54
+ this.distinctId = options.distinctId;
55
+ this.commonProperties = options.commonProperties
56
+ ? { ...options.commonProperties }
57
+ : {};
58
+ }
59
+
60
+ emit(event: string, properties?: TelemetryProperties): void {
61
+ if (!this.isEnabled()) {
62
+ return;
63
+ }
64
+ this.emitLog(event, properties, false);
65
+ }
66
+
67
+ emitRequired(event: string, properties?: TelemetryProperties): void {
68
+ this.emitLog(event, properties, true);
69
+ }
70
+
71
+ recordCounter(
72
+ name: string,
73
+ value: number,
74
+ attributes?: TelemetryProperties,
75
+ description?: string,
76
+ required = false,
77
+ ): void {
78
+ if (!this.meter || (!required && !this.isEnabled())) {
79
+ return;
80
+ }
81
+
82
+ let counter = this.counters.get(name);
83
+ if (!counter) {
84
+ counter = this.meter.createCounter(
85
+ name,
86
+ description ? { description } : undefined,
87
+ );
88
+ this.counters.set(name, counter);
89
+ }
90
+
91
+ counter.add(
92
+ value,
93
+ this.flattenProperties(this.buildAttributes(attributes)),
94
+ );
95
+ }
96
+
97
+ recordHistogram(
98
+ name: string,
99
+ value: number,
100
+ attributes?: TelemetryProperties,
101
+ description?: string,
102
+ required = false,
103
+ ): void {
104
+ if (!this.meter || (!required && !this.isEnabled())) {
105
+ return;
106
+ }
107
+
108
+ let histogram = this.histograms.get(name);
109
+ if (!histogram) {
110
+ histogram = this.meter.createHistogram(
111
+ name,
112
+ description ? { description } : undefined,
113
+ );
114
+ this.histograms.set(name, histogram);
115
+ }
116
+
117
+ histogram.record(
118
+ value,
119
+ this.flattenProperties(this.buildAttributes(attributes)),
120
+ );
121
+ }
122
+
123
+ recordGauge(
124
+ name: string,
125
+ value: number | null,
126
+ attributes?: TelemetryProperties,
127
+ description?: string,
128
+ required = false,
129
+ ): void {
130
+ if (!this.meter || (!required && !this.isEnabled())) {
131
+ return;
132
+ }
133
+
134
+ const mergedAttributes = this.buildAttributes(attributes);
135
+ const attrKey = JSON.stringify(mergedAttributes);
136
+ const existingSeries = this.gaugeValues.get(name);
137
+
138
+ if (value === null) {
139
+ if (existingSeries) {
140
+ existingSeries.delete(attrKey);
141
+ if (existingSeries.size === 0) {
142
+ this.gaugeValues.delete(name);
143
+ this.gauges.delete(name);
144
+ }
145
+ }
146
+ return;
147
+ }
148
+
149
+ let series = existingSeries;
150
+ if (!series) {
151
+ series = new Map();
152
+ this.gaugeValues.set(name, series);
153
+ }
154
+
155
+ if (!this.gauges.has(name)) {
156
+ const gauge = this.meter.createObservableGauge(
157
+ name,
158
+ description ? { description } : undefined,
159
+ );
160
+ gauge.addCallback((observableResult) => {
161
+ for (const data of this.snapshotGaugeSeries(name)) {
162
+ observableResult.observe(
163
+ data.value,
164
+ this.flattenProperties(data.attributes),
165
+ );
166
+ }
167
+ });
168
+ this.gauges.set(name, gauge);
169
+ }
170
+
171
+ series.set(attrKey, { value, attributes: mergedAttributes });
172
+ }
173
+
174
+ isEnabled(): boolean {
175
+ return typeof this.enabled === "function" ? this.enabled() : this.enabled;
176
+ }
177
+
178
+ setDistinctId(distinctId?: string): void {
179
+ this.distinctId = distinctId;
180
+ }
181
+
182
+ setCommonProperties(properties: TelemetryProperties): void {
183
+ this.commonProperties = { ...properties };
184
+ }
185
+
186
+ updateCommonProperties(properties: TelemetryProperties): void {
187
+ this.commonProperties = {
188
+ ...this.commonProperties,
189
+ ...properties,
190
+ };
191
+ }
192
+
193
+ async flush(): Promise<void> {
194
+ await Promise.all([
195
+ this.meterProvider?.forceFlush?.(),
196
+ this.loggerProvider?.forceFlush?.(),
197
+ ]);
198
+ }
199
+
200
+ async dispose(): Promise<void> {
201
+ await Promise.all([
202
+ this.meterProvider?.shutdown?.(),
203
+ this.loggerProvider?.shutdown?.(),
204
+ ]);
205
+ }
206
+
207
+ private emitLog(
208
+ event: string,
209
+ properties: TelemetryProperties | undefined,
210
+ required: boolean,
211
+ ): void {
212
+ if (!this.logger) {
213
+ return;
214
+ }
215
+
216
+ const attributes = this.flattenProperties(
217
+ this.buildAttributes(properties, required),
218
+ );
219
+ this.logger.emit({
220
+ severityText: "INFO",
221
+ body: event,
222
+ attributes,
223
+ });
224
+ }
225
+
226
+ private buildAttributes(
227
+ properties?: TelemetryProperties,
228
+ required = false,
229
+ ): TelemetryProperties {
230
+ return {
231
+ ...this.commonProperties,
232
+ ...properties,
233
+ ...this.metadata,
234
+ ...(this.distinctId ? { distinct_id: this.distinctId } : {}),
235
+ ...(required ? { _required: true } : {}),
236
+ };
237
+ }
238
+
239
+ private snapshotGaugeSeries(
240
+ name: string,
241
+ ): Array<{ value: number; attributes?: TelemetryProperties }> {
242
+ const series = this.gaugeValues.get(name);
243
+ if (!series) {
244
+ return [];
245
+ }
246
+ return Array.from(series.values(), (entry) => ({
247
+ value: entry.value,
248
+ attributes: entry.attributes ? { ...entry.attributes } : undefined,
249
+ }));
250
+ }
251
+
252
+ private flattenProperties(
253
+ properties?: TelemetryProperties,
254
+ prefix = "",
255
+ seen: WeakSet<object> = new WeakSet(),
256
+ depth = 0,
257
+ ): FlatTelemetryAttributes {
258
+ if (!properties) {
259
+ return {};
260
+ }
261
+
262
+ const flattened: FlatTelemetryAttributes = {};
263
+ const maxArraySize = 100;
264
+ const maxDepth = 10;
265
+
266
+ for (const [key, value] of Object.entries(properties)) {
267
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
268
+ continue;
269
+ }
270
+
271
+ const fullKey = prefix ? `${prefix}.${key}` : key;
272
+
273
+ if (value === null || value === undefined) {
274
+ flattened[fullKey] = String(value);
275
+ continue;
276
+ }
277
+
278
+ if (Array.isArray(value)) {
279
+ const limited =
280
+ value.length > maxArraySize ? value.slice(0, maxArraySize) : value;
281
+ try {
282
+ flattened[fullKey] = JSON.stringify(limited);
283
+ } catch {
284
+ flattened[fullKey] = "[UnserializableArray]";
285
+ }
286
+ if (value.length > maxArraySize) {
287
+ flattened[`${fullKey}_truncated`] = true;
288
+ flattened[`${fullKey}_original_length`] = value.length;
289
+ }
290
+ continue;
291
+ }
292
+
293
+ if (typeof value === "object") {
294
+ if (value instanceof Date) {
295
+ flattened[fullKey] = value.toISOString();
296
+ continue;
297
+ }
298
+ if (value instanceof Error) {
299
+ flattened[fullKey] = value.message;
300
+ continue;
301
+ }
302
+ if (seen.has(value)) {
303
+ flattened[fullKey] = "[Circular]";
304
+ continue;
305
+ }
306
+ if (depth >= maxDepth) {
307
+ flattened[fullKey] = "[MaxDepthExceeded]";
308
+ continue;
309
+ }
310
+
311
+ seen.add(value);
312
+ Object.assign(
313
+ flattened,
314
+ this.flattenProperties(
315
+ value as TelemetryProperties,
316
+ fullKey,
317
+ seen,
318
+ depth + 1,
319
+ ),
320
+ );
321
+ continue;
322
+ }
323
+
324
+ if (isTelemetryPrimitive(value)) {
325
+ flattened[fullKey] = value;
326
+ continue;
327
+ }
328
+
329
+ try {
330
+ flattened[fullKey] = JSON.stringify(value);
331
+ } catch {
332
+ flattened[fullKey] = String(value);
333
+ }
334
+ }
335
+
336
+ return flattened;
337
+ }
338
+ }
339
+
340
+ function isTelemetryPrimitive(
341
+ value: unknown,
342
+ ): value is Exclude<TelemetryPrimitive, null | undefined> {
343
+ return (
344
+ typeof value === "string" ||
345
+ typeof value === "number" ||
346
+ typeof value === "boolean"
347
+ );
348
+ }
@@ -0,0 +1,113 @@
1
+ import type { BasicLogger } from "@clinebot/shared";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import {
4
+ createConfiguredTelemetryService,
5
+ createOpenTelemetryTelemetryService,
6
+ OpenTelemetryProvider,
7
+ } from "./OpenTelemetryProvider";
8
+ import { TelemetryService } from "./TelemetryService";
9
+
10
+ describe("createOpenTelemetryTelemetryService", () => {
11
+ afterEach(() => {
12
+ vi.restoreAllMocks();
13
+ });
14
+
15
+ it("logs a provider creation event during bootstrap", async () => {
16
+ const captureRequired = vi
17
+ .spyOn(TelemetryService.prototype, "captureRequired")
18
+ .mockImplementation(() => {});
19
+
20
+ const { provider } = createOpenTelemetryTelemetryService({
21
+ metadata: {
22
+ extension_version: "1.2.3",
23
+ cline_type: "cli",
24
+ platform: "terminal",
25
+ platform_version: process.version,
26
+ os_type: process.platform,
27
+ os_version: "unknown",
28
+ },
29
+ enabled: true,
30
+ logsExporter: "console",
31
+ metricsExporter: "otlp",
32
+ otlpProtocol: "http/json",
33
+ otlpEndpoint: "http://localhost:4318",
34
+ serviceName: "cline-cli",
35
+ serviceVersion: "1.2.3",
36
+ });
37
+
38
+ expect(captureRequired).toHaveBeenCalledWith(
39
+ "telemetry.provider_created",
40
+ expect.objectContaining({
41
+ provider: "opentelemetry",
42
+ enabled: true,
43
+ logsExporter: "console",
44
+ metricsExporter: "otlp",
45
+ otlpProtocol: "http/json",
46
+ hasOtlpEndpoint: true,
47
+ serviceName: "cline-cli",
48
+ serviceVersion: "1.2.3",
49
+ }),
50
+ );
51
+
52
+ await provider.dispose();
53
+ });
54
+
55
+ it("does not create an OTEL provider when disabled", () => {
56
+ const providerSpy = vi.spyOn(
57
+ OpenTelemetryProvider.prototype,
58
+ "createTelemetryService",
59
+ );
60
+
61
+ const { telemetry, provider } = createConfiguredTelemetryService({
62
+ metadata: {
63
+ extension_version: "1.2.3",
64
+ cline_type: "cli",
65
+ platform: "terminal",
66
+ platform_version: process.version,
67
+ os_type: process.platform,
68
+ os_version: "unknown",
69
+ },
70
+ enabled: false,
71
+ });
72
+
73
+ expect(provider).toBeUndefined();
74
+ expect(providerSpy).not.toHaveBeenCalled();
75
+ expect(telemetry).toBeInstanceOf(TelemetryService);
76
+ });
77
+
78
+ it("attaches the logger adapter when creating configured telemetry", () => {
79
+ const logger: BasicLogger = {
80
+ debug: vi.fn(),
81
+ info: vi.fn(),
82
+ warn: vi.fn(),
83
+ error: vi.fn(),
84
+ };
85
+ const { telemetry, provider } = createConfiguredTelemetryService({
86
+ metadata: {
87
+ extension_version: "1.2.3",
88
+ cline_type: "cli",
89
+ platform: "terminal",
90
+ platform_version: process.version,
91
+ os_type: process.platform,
92
+ os_version: "unknown",
93
+ },
94
+ enabled: true,
95
+ logsExporter: "console",
96
+ logger,
97
+ });
98
+
99
+ telemetry.capture({
100
+ event: "session.started",
101
+ properties: { sessionId: "session-1" },
102
+ });
103
+
104
+ expect(logger.info).toHaveBeenCalledWith(
105
+ "telemetry.event",
106
+ expect.objectContaining({
107
+ event: "session.started",
108
+ }),
109
+ );
110
+
111
+ return provider?.dispose();
112
+ });
113
+ });