flaio-cli 1.0.12 → 1.0.13

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 (35) hide show
  1. package/dist/agents/agent-session.d.ts +2 -0
  2. package/dist/agents/agent-session.d.ts.map +1 -1
  3. package/dist/agents/agent-session.js +39 -1
  4. package/dist/agents/agent-session.js.map +1 -1
  5. package/dist/agents/drivers/base-driver.d.ts.map +1 -1
  6. package/dist/agents/drivers/base-driver.js +2 -2
  7. package/dist/agents/drivers/base-driver.js.map +1 -1
  8. package/dist/analytics/index.d.ts +1 -1
  9. package/dist/analytics/index.d.ts.map +1 -1
  10. package/dist/analytics/index.js +1 -1
  11. package/dist/analytics/index.js.map +1 -1
  12. package/dist/analytics/posthog.d.ts.map +1 -1
  13. package/dist/analytics/posthog.js +18 -0
  14. package/dist/analytics/posthog.js.map +1 -1
  15. package/dist/analytics/resource-monitor.d.ts.map +1 -1
  16. package/dist/analytics/resource-monitor.js +15 -0
  17. package/dist/analytics/resource-monitor.js.map +1 -1
  18. package/dist/analytics/sentry.d.ts +5 -0
  19. package/dist/analytics/sentry.d.ts.map +1 -1
  20. package/dist/analytics/sentry.js +27 -1
  21. package/dist/analytics/sentry.js.map +1 -1
  22. package/dist/cli.js +8 -0
  23. package/dist/cli.js.map +1 -1
  24. package/dist/config/config.d.ts +40 -40
  25. package/dist/relay/relay-client.d.ts +2 -0
  26. package/dist/relay/relay-client.d.ts.map +1 -1
  27. package/dist/relay/relay-client.js +48 -1
  28. package/dist/relay/relay-client.js.map +1 -1
  29. package/dist/store/connector-store.js +19 -2
  30. package/dist/store/connector-store.js.map +1 -1
  31. package/dist/strip-ansi.d.ts +2 -0
  32. package/dist/strip-ansi.d.ts.map +1 -0
  33. package/dist/strip-ansi.js +9 -0
  34. package/dist/strip-ansi.js.map +1 -0
  35. package/package.json +2 -1
@@ -7,19 +7,19 @@ declare const SlackConfigSchema: z.ZodObject<{
7
7
  pollInterval: z.ZodDefault<z.ZodNumber>;
8
8
  timeout: z.ZodDefault<z.ZodNumber>;
9
9
  }, "strip", z.ZodTypeAny, {
10
- timeout: number;
11
10
  enabled: boolean;
12
11
  pollInterval: number;
12
+ timeout: number;
13
13
  botToken?: string | undefined;
14
14
  appToken?: string | undefined;
15
15
  channelId?: string | undefined;
16
16
  }, {
17
- timeout?: number | undefined;
18
17
  enabled?: boolean | undefined;
19
18
  botToken?: string | undefined;
20
19
  appToken?: string | undefined;
21
20
  channelId?: string | undefined;
22
21
  pollInterval?: number | undefined;
22
+ timeout?: number | undefined;
23
23
  }>;
24
24
  declare const DiscordConfigSchema: z.ZodObject<{
25
25
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -27,15 +27,15 @@ declare const DiscordConfigSchema: z.ZodObject<{
27
27
  channelId: z.ZodOptional<z.ZodString>;
28
28
  timeout: z.ZodDefault<z.ZodNumber>;
29
29
  }, "strip", z.ZodTypeAny, {
30
- timeout: number;
31
30
  enabled: boolean;
31
+ timeout: number;
32
32
  botToken?: string | undefined;
33
33
  channelId?: string | undefined;
34
34
  }, {
35
- timeout?: number | undefined;
36
35
  enabled?: boolean | undefined;
37
36
  botToken?: string | undefined;
38
37
  channelId?: string | undefined;
38
+ timeout?: number | undefined;
39
39
  }>;
40
40
  declare const TelegramConfigSchema: z.ZodObject<{
41
41
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -43,14 +43,14 @@ declare const TelegramConfigSchema: z.ZodObject<{
43
43
  chatId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
44
44
  timeout: z.ZodDefault<z.ZodNumber>;
45
45
  }, "strip", z.ZodTypeAny, {
46
- timeout: number;
47
46
  enabled: boolean;
47
+ timeout: number;
48
48
  botToken?: string | undefined;
49
49
  chatId?: string | number | undefined;
50
50
  }, {
51
- timeout?: number | undefined;
52
51
  enabled?: boolean | undefined;
53
52
  botToken?: string | undefined;
53
+ timeout?: number | undefined;
54
54
  chatId?: string | number | undefined;
55
55
  }>;
56
56
  declare const RelayConfigSchema: z.ZodObject<{
@@ -66,7 +66,7 @@ declare const RelayConfigSchema: z.ZodObject<{
66
66
  }, "strip", z.ZodTypeAny, {
67
67
  enabled: boolean;
68
68
  autoConnect: boolean;
69
- defaultShareMode: "read-only" | "read-write";
69
+ defaultShareMode: "read-write" | "read-only";
70
70
  maxReplayBufferKB: number;
71
71
  e2eEncryption: boolean;
72
72
  relayUrl: string;
@@ -78,7 +78,7 @@ declare const RelayConfigSchema: z.ZodObject<{
78
78
  authToken?: string | undefined;
79
79
  refreshToken?: string | undefined;
80
80
  autoConnect?: boolean | undefined;
81
- defaultShareMode?: "read-only" | "read-write" | undefined;
81
+ defaultShareMode?: "read-write" | "read-only" | undefined;
82
82
  maxReplayBufferKB?: number | undefined;
83
83
  e2eEncryption?: boolean | undefined;
84
84
  relayUrl?: string | undefined;
@@ -123,19 +123,19 @@ declare const AppConfigSchema: z.ZodObject<{
123
123
  pollInterval: z.ZodDefault<z.ZodNumber>;
124
124
  timeout: z.ZodDefault<z.ZodNumber>;
125
125
  }, "strip", z.ZodTypeAny, {
126
- timeout: number;
127
126
  enabled: boolean;
128
127
  pollInterval: number;
128
+ timeout: number;
129
129
  botToken?: string | undefined;
130
130
  appToken?: string | undefined;
131
131
  channelId?: string | undefined;
132
132
  }, {
133
- timeout?: number | undefined;
134
133
  enabled?: boolean | undefined;
135
134
  botToken?: string | undefined;
136
135
  appToken?: string | undefined;
137
136
  channelId?: string | undefined;
138
137
  pollInterval?: number | undefined;
138
+ timeout?: number | undefined;
139
139
  }>>;
140
140
  discord: z.ZodDefault<z.ZodObject<{
141
141
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -143,15 +143,15 @@ declare const AppConfigSchema: z.ZodObject<{
143
143
  channelId: z.ZodOptional<z.ZodString>;
144
144
  timeout: z.ZodDefault<z.ZodNumber>;
145
145
  }, "strip", z.ZodTypeAny, {
146
- timeout: number;
147
146
  enabled: boolean;
147
+ timeout: number;
148
148
  botToken?: string | undefined;
149
149
  channelId?: string | undefined;
150
150
  }, {
151
- timeout?: number | undefined;
152
151
  enabled?: boolean | undefined;
153
152
  botToken?: string | undefined;
154
153
  channelId?: string | undefined;
154
+ timeout?: number | undefined;
155
155
  }>>;
156
156
  telegram: z.ZodDefault<z.ZodObject<{
157
157
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -159,56 +159,56 @@ declare const AppConfigSchema: z.ZodObject<{
159
159
  chatId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
160
160
  timeout: z.ZodDefault<z.ZodNumber>;
161
161
  }, "strip", z.ZodTypeAny, {
162
- timeout: number;
163
162
  enabled: boolean;
163
+ timeout: number;
164
164
  botToken?: string | undefined;
165
165
  chatId?: string | number | undefined;
166
166
  }, {
167
- timeout?: number | undefined;
168
167
  enabled?: boolean | undefined;
169
168
  botToken?: string | undefined;
169
+ timeout?: number | undefined;
170
170
  chatId?: string | number | undefined;
171
171
  }>>;
172
172
  }, "strip", z.ZodTypeAny, {
173
173
  slack: {
174
- timeout: number;
175
174
  enabled: boolean;
176
175
  pollInterval: number;
176
+ timeout: number;
177
177
  botToken?: string | undefined;
178
178
  appToken?: string | undefined;
179
179
  channelId?: string | undefined;
180
180
  };
181
181
  discord: {
182
- timeout: number;
183
182
  enabled: boolean;
183
+ timeout: number;
184
184
  botToken?: string | undefined;
185
185
  channelId?: string | undefined;
186
186
  };
187
187
  telegram: {
188
- timeout: number;
189
188
  enabled: boolean;
189
+ timeout: number;
190
190
  botToken?: string | undefined;
191
191
  chatId?: string | number | undefined;
192
192
  };
193
193
  }, {
194
194
  slack?: {
195
- timeout?: number | undefined;
196
195
  enabled?: boolean | undefined;
197
196
  botToken?: string | undefined;
198
197
  appToken?: string | undefined;
199
198
  channelId?: string | undefined;
200
199
  pollInterval?: number | undefined;
200
+ timeout?: number | undefined;
201
201
  } | undefined;
202
202
  discord?: {
203
- timeout?: number | undefined;
204
203
  enabled?: boolean | undefined;
205
204
  botToken?: string | undefined;
206
205
  channelId?: string | undefined;
206
+ timeout?: number | undefined;
207
207
  } | undefined;
208
208
  telegram?: {
209
- timeout?: number | undefined;
210
209
  enabled?: boolean | undefined;
211
210
  botToken?: string | undefined;
211
+ timeout?: number | undefined;
212
212
  chatId?: string | number | undefined;
213
213
  } | undefined;
214
214
  }>>;
@@ -235,7 +235,7 @@ declare const AppConfigSchema: z.ZodObject<{
235
235
  }, "strip", z.ZodTypeAny, {
236
236
  enabled: boolean;
237
237
  autoConnect: boolean;
238
- defaultShareMode: "read-only" | "read-write";
238
+ defaultShareMode: "read-write" | "read-only";
239
239
  maxReplayBufferKB: number;
240
240
  e2eEncryption: boolean;
241
241
  relayUrl: string;
@@ -247,7 +247,7 @@ declare const AppConfigSchema: z.ZodObject<{
247
247
  authToken?: string | undefined;
248
248
  refreshToken?: string | undefined;
249
249
  autoConnect?: boolean | undefined;
250
- defaultShareMode?: "read-only" | "read-write" | undefined;
250
+ defaultShareMode?: "read-write" | "read-only" | undefined;
251
251
  maxReplayBufferKB?: number | undefined;
252
252
  e2eEncryption?: boolean | undefined;
253
253
  relayUrl?: string | undefined;
@@ -281,11 +281,6 @@ declare const AppConfigSchema: z.ZodObject<{
281
281
  statusCheckInterval: number;
282
282
  detectorInterval: number;
283
283
  };
284
- worktree: {
285
- planning: boolean;
286
- interactivePlanning: boolean;
287
- implementation: boolean;
288
- };
289
284
  ui: {
290
285
  sidebarWidth: number;
291
286
  narrowBreakpoint: number;
@@ -294,22 +289,22 @@ declare const AppConfigSchema: z.ZodObject<{
294
289
  };
295
290
  connectors: {
296
291
  slack: {
297
- timeout: number;
298
292
  enabled: boolean;
299
293
  pollInterval: number;
294
+ timeout: number;
300
295
  botToken?: string | undefined;
301
296
  appToken?: string | undefined;
302
297
  channelId?: string | undefined;
303
298
  };
304
299
  discord: {
305
- timeout: number;
306
300
  enabled: boolean;
301
+ timeout: number;
307
302
  botToken?: string | undefined;
308
303
  channelId?: string | undefined;
309
304
  };
310
305
  telegram: {
311
- timeout: number;
312
306
  enabled: boolean;
307
+ timeout: number;
313
308
  botToken?: string | undefined;
314
309
  chatId?: string | number | undefined;
315
310
  };
@@ -317,7 +312,7 @@ declare const AppConfigSchema: z.ZodObject<{
317
312
  relay: {
318
313
  enabled: boolean;
319
314
  autoConnect: boolean;
320
- defaultShareMode: "read-only" | "read-write";
315
+ defaultShareMode: "read-write" | "read-only";
321
316
  maxReplayBufferKB: number;
322
317
  e2eEncryption: boolean;
323
318
  relayUrl: string;
@@ -325,6 +320,11 @@ declare const AppConfigSchema: z.ZodObject<{
325
320
  authToken?: string | undefined;
326
321
  refreshToken?: string | undefined;
327
322
  };
323
+ worktree: {
324
+ planning: boolean;
325
+ interactivePlanning: boolean;
326
+ implementation: boolean;
327
+ };
328
328
  telemetry: {
329
329
  enabled: boolean;
330
330
  crashReports: boolean;
@@ -334,11 +334,6 @@ declare const AppConfigSchema: z.ZodObject<{
334
334
  statusCheckInterval?: number | undefined;
335
335
  detectorInterval?: number | undefined;
336
336
  } | undefined;
337
- worktree?: {
338
- planning?: boolean | undefined;
339
- interactivePlanning?: boolean | undefined;
340
- implementation?: boolean | undefined;
341
- } | undefined;
342
337
  ui?: {
343
338
  sidebarWidth?: number | undefined;
344
339
  narrowBreakpoint?: number | undefined;
@@ -347,23 +342,23 @@ declare const AppConfigSchema: z.ZodObject<{
347
342
  } | undefined;
348
343
  connectors?: {
349
344
  slack?: {
350
- timeout?: number | undefined;
351
345
  enabled?: boolean | undefined;
352
346
  botToken?: string | undefined;
353
347
  appToken?: string | undefined;
354
348
  channelId?: string | undefined;
355
349
  pollInterval?: number | undefined;
350
+ timeout?: number | undefined;
356
351
  } | undefined;
357
352
  discord?: {
358
- timeout?: number | undefined;
359
353
  enabled?: boolean | undefined;
360
354
  botToken?: string | undefined;
361
355
  channelId?: string | undefined;
356
+ timeout?: number | undefined;
362
357
  } | undefined;
363
358
  telegram?: {
364
- timeout?: number | undefined;
365
359
  enabled?: boolean | undefined;
366
360
  botToken?: string | undefined;
361
+ timeout?: number | undefined;
367
362
  chatId?: string | number | undefined;
368
363
  } | undefined;
369
364
  } | undefined;
@@ -372,12 +367,17 @@ declare const AppConfigSchema: z.ZodObject<{
372
367
  authToken?: string | undefined;
373
368
  refreshToken?: string | undefined;
374
369
  autoConnect?: boolean | undefined;
375
- defaultShareMode?: "read-only" | "read-write" | undefined;
370
+ defaultShareMode?: "read-write" | "read-only" | undefined;
376
371
  maxReplayBufferKB?: number | undefined;
377
372
  e2eEncryption?: boolean | undefined;
378
373
  relayUrl?: string | undefined;
379
374
  authUrl?: string | undefined;
380
375
  } | undefined;
376
+ worktree?: {
377
+ planning?: boolean | undefined;
378
+ interactivePlanning?: boolean | undefined;
379
+ implementation?: boolean | undefined;
380
+ } | undefined;
381
381
  telemetry?: {
382
382
  enabled?: boolean | undefined;
383
383
  crashReports?: boolean | undefined;
@@ -10,6 +10,8 @@ export declare class RelayClient extends EventEmitter {
10
10
  private pingTimer;
11
11
  private pongTimer;
12
12
  private started;
13
+ private lastPingTime;
14
+ private connectSpan;
13
15
  private inputLimiter;
14
16
  private browseLimiter;
15
17
  private createSessionLimiter;
@@ -1 +1 @@
1
- {"version":3,"file":"relay-client.d.ts","sourceRoot":"","sources":["../../src/relay/relay-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgI3C,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,EAAE,CAAuC;IACjD,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,UAAU,CAA6B;IAG/C,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,eAAe,CAAS;IAGhC,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,SAAS,CAA8C;IAE/D,OAAO,CAAC,OAAO,CAAS;IAGxB,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,oBAAoB,CAA2B;;IAQvD,OAAO,KAAK,UAAU,GAErB;IAMK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YA4Cb,OAAO;IAmFrB,OAAO,CAAC,aAAa;YAsGP,iBAAiB;IAa/B,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,kBAAkB;YAUZ,iBAAiB;YAajB,eAAe;YA6Cf,iBAAiB;YAoDjB,oBAAoB;YA6EpB,mBAAmB;YAwJnB,8BAA8B;YA4E9B,yBAAyB;IA6HvC,OAAO,CAAC,oBAAoB;YAsBd,qBAAqB;YA+CrB,oBAAoB;IAoClC,OAAO,CAAC,mBAAmB;YAWb,WAAW;YAiCX,mBAAmB;YAyBnB,aAAa;YA+Cb,YAAY;IA2G1B,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,eAAe;IA4CvB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,mBAAmB;IAWpB,gBAAgB,CAAC,gBAAgB,EAAE,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,mBAAmB,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI;IAOtI,OAAO,CAAC,IAAI;CAiBb"}
1
+ {"version":3,"file":"relay-client.d.ts","sourceRoot":"","sources":["../../src/relay/relay-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAmI3C,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,EAAE,CAAuC;IACjD,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,UAAU,CAA6B;IAG/C,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,eAAe,CAAS;IAGhC,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,SAAS,CAA8C;IAE/D,OAAO,CAAC,OAAO,CAAS;IAGxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAqB;IAGxC,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,oBAAoB,CAA2B;;IAQvD,OAAO,KAAK,UAAU,GAErB;IAMK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAUtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YA4Cb,OAAO;IA8FrB,OAAO,CAAC,aAAa;YA4GP,iBAAiB;IAa/B,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,wBAAwB;IAsBhC,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,kBAAkB;YAUZ,iBAAiB;YAajB,eAAe;YA6Cf,iBAAiB;YAoDjB,oBAAoB;YA6EpB,mBAAmB;YAwJnB,8BAA8B;YA4E9B,yBAAyB;IA6HvC,OAAO,CAAC,oBAAoB;YAsBd,qBAAqB;YA+CrB,oBAAoB;IAoClC,OAAO,CAAC,mBAAmB;YAWb,WAAW;YAwDX,mBAAmB;YAyBnB,aAAa;YA+Cb,YAAY;IA2G1B,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,eAAe;IA4CvB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,mBAAmB;IAWpB,gBAAgB,CAAC,gBAAgB,EAAE,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,mBAAmB,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI;IAOtI,OAAO,CAAC,IAAI;CAiBb"}
@@ -1,3 +1,4 @@
1
+ import { stripAnsi } from "../strip-ansi.js";
1
2
  import { EventEmitter } from "node:events";
2
3
  import fs from "node:fs/promises";
3
4
  import os from "node:os";
@@ -15,6 +16,8 @@ import { makeDebugLog } from "../connectors/debug.js";
15
16
  import { RelayToCliMsgSchema } from "./relay-message-schemas.js";
16
17
  import { RateLimiter } from "./rate-limiter.js";
17
18
  import { sessionMetadataStore } from "../agents/session-metadata.js";
19
+ import { trackCliEvent, startTransaction } from "../analytics/index.js";
20
+ import * as Sentry from "@sentry/node";
18
21
  const debugLog = makeDebugLog("relay");
19
22
  // ---------------------------------------------------------------------------
20
23
  // Replay buffer — ring buffer of recent PTY output per session
@@ -70,6 +73,9 @@ export class RelayClient extends EventEmitter {
70
73
  pingTimer = null;
71
74
  pongTimer = null;
72
75
  started = false;
76
+ // Analytics
77
+ lastPingTime = 0;
78
+ connectSpan = null;
73
79
  // Rate limiters
74
80
  inputLimiter = new RateLimiter(30, 30); // 30 inputs/sec per key
75
81
  browseLimiter = new RateLimiter(10, 10); // 10 browse requests/sec
@@ -137,6 +143,7 @@ export class RelayClient extends EventEmitter {
137
143
  return;
138
144
  }
139
145
  setRelayConnectionStatus("connecting");
146
+ this.connectSpan = startTransaction("relay.connect", "websocket.connect");
140
147
  try {
141
148
  // Clean up previous WebSocket if it exists (e.g. on reconnect)
142
149
  if (this.ws) {
@@ -152,9 +159,14 @@ export class RelayClient extends EventEmitter {
152
159
  this.ws = new WebSocket(relayUrl);
153
160
  this.ws.on("open", () => {
154
161
  debugLog("relay: connected to relay server");
162
+ this.connectSpan?.end();
163
+ this.connectSpan = null;
155
164
  setRelayConnectionStatus("authenticating");
156
165
  this.send({ type: "cli_auth", token: token });
157
166
  this.startHeartbeat();
167
+ trackCliEvent("cli_relay_connected", {
168
+ attempt: this.reconnectAttempt,
169
+ });
158
170
  });
159
171
  this.ws.on("message", (raw) => {
160
172
  try {
@@ -186,6 +198,11 @@ export class RelayClient extends EventEmitter {
186
198
  });
187
199
  this.ws.on("error", (err) => {
188
200
  debugLog(`relay: WebSocket error: ${err.message}`);
201
+ if (this.connectSpan) {
202
+ this.connectSpan.setStatus({ code: 2, message: err.message });
203
+ this.connectSpan.end();
204
+ this.connectSpan = null;
205
+ }
189
206
  setRelayConnectionStatus("error", err.message);
190
207
  });
191
208
  }
@@ -243,6 +260,12 @@ export class RelayClient extends EventEmitter {
243
260
  this.handleBrowseFiles(msg.requestId, msg.viewerId, msg.path);
244
261
  break;
245
262
  case "relay_ping":
263
+ if (this.lastPingTime > 0) {
264
+ const latencyMs = Date.now() - this.lastPingTime;
265
+ trackCliEvent("cli_relay_latency", { latencyMs });
266
+ Sentry.setMeasurement("relay.ping_latency", latencyMs, "millisecond");
267
+ }
268
+ this.lastPingTime = Date.now();
246
269
  this.send({ type: "cli_pong" });
247
270
  this.resetPongTimer();
248
271
  break;
@@ -636,7 +659,7 @@ export class RelayClient extends EventEmitter {
636
659
  const onExit = () => {
637
660
  rawUnsub();
638
661
  // Strip ANSI escape sequences from raw PTY output
639
- const plainText = rawOutput.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").trim();
662
+ const plainText = stripAnsi(rawOutput).trim();
640
663
  ticketTracker.updateStatus(msg.ticketId, "plan_ready");
641
664
  this.send({
642
665
  type: "cli_plan_ready",
@@ -918,6 +941,7 @@ export class RelayClient extends EventEmitter {
918
941
  // Encrypted PTY data sending
919
942
  // -------------------------------------------------------------------------
920
943
  async sendPtyData(tracked, rawData) {
944
+ const encryptStart = performance.now();
921
945
  if (tracked.sck) {
922
946
  // E2E enabled — encrypt with SCK
923
947
  try {
@@ -930,6 +954,16 @@ export class RelayClient extends EventEmitter {
930
954
  data: encrypted,
931
955
  seq,
932
956
  });
957
+ // Sample 1 in 100 to avoid event flood
958
+ if (Math.random() < 0.01) {
959
+ const encryptMs = performance.now() - encryptStart;
960
+ trackCliEvent("cli_pty_data_sent", {
961
+ sessionId: tracked.sessionId,
962
+ dataLenBytes: rawData.length,
963
+ encrypted: true,
964
+ encryptMs: Math.round(encryptMs * 100) / 100,
965
+ });
966
+ }
933
967
  }
934
968
  catch (err) {
935
969
  const message = err instanceof Error ? err.message : String(err);
@@ -950,6 +984,15 @@ export class RelayClient extends EventEmitter {
950
984
  sessionId: tracked.sessionId,
951
985
  data: base64,
952
986
  });
987
+ // Sample 1 in 100 to avoid event flood
988
+ if (Math.random() < 0.01) {
989
+ trackCliEvent("cli_pty_data_sent", {
990
+ sessionId: tracked.sessionId,
991
+ dataLenBytes: rawData.length,
992
+ encrypted: false,
993
+ encryptMs: 0,
994
+ });
995
+ }
953
996
  }
954
997
  }
955
998
  async sendEncryptedReplay(tracked) {
@@ -1222,6 +1265,10 @@ export class RelayClient extends EventEmitter {
1222
1265
  this.reconnectAttempt++;
1223
1266
  debugLog(`relay: reconnecting in ${delay}ms (attempt ${this.reconnectAttempt})`);
1224
1267
  setRelayConnectionStatus("connecting", undefined, this.reconnectAttempt);
1268
+ trackCliEvent("cli_relay_reconnect", {
1269
+ attempt: this.reconnectAttempt,
1270
+ delayMs: delay,
1271
+ });
1225
1272
  this.reconnectTimer = setTimeout(() => {
1226
1273
  this.reconnectTimer = null;
1227
1274
  if (this.shouldReconnect) {