@opendatalabs/connect 0.11.6 → 0.12.0-canary.7843ac9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
package/dist/cli/index.js CHANGED
@@ -35,6 +35,7 @@ import { listAvailableSkills, installSkill, readInstalledSkills, } from "../skil
35
35
  import { queryStatus, querySources, queryDataList, queryDataShow, queryDoctor, } from "./queries.js";
36
36
  import { checkForUpdate, readUpdateCheck, isNewerVersion, } from "./update-check.js";
37
37
  import { loadCredentials, saveCredentials, clearCredentials, isExpired, formatAddress, formatExpiresIn, getAuthTarget, resolvePersonalServerUrl, runDeviceCodeFlow, runSelfHostedLoginFlow, } from "./auth.js";
38
+ import { createCliTelemetrySession, flushTelemetryOutbox, getActiveTelemetrySession, getTelemetryStatus, setActiveTelemetrySession, setTelemetryEnabled, trackActiveTelemetryEvent, } from "./telemetry.js";
38
39
  function cleanDescription(desc) {
39
40
  return desc
40
41
  .replace(/ using Playwright browser automation\.?/i, ".")
@@ -53,6 +54,12 @@ export async function runCli(argv = process.argv) {
53
54
  const parsedOptions = extractGlobalOptions(normalizedArgv);
54
55
  const cliVersion = getCliVersion();
55
56
  const installMethod = getCliInstallMethod();
57
+ const telemetryBaseContext = {
58
+ cliVersion,
59
+ channel: getCliChannel(cliVersion),
60
+ installMethod,
61
+ options: parsedOptions,
62
+ };
56
63
  // Non-blocking update check — compute suppression flags early
57
64
  const shouldNotify = !parsedOptions.json &&
58
65
  process.stdout.isTTY &&
@@ -108,17 +115,18 @@ More:
108
115
  .description("Print CLI version")
109
116
  .option("--json", "Output machine-readable JSON")
110
117
  .action(async () => {
111
- if (parsedOptions.json) {
112
- process.stdout.write(`${JSON.stringify({
113
- cliVersion,
114
- channel: getCliChannel(cliVersion),
115
- installMethod: getCliInstallMethod(),
116
- })}\n`);
117
- process.exitCode = 0;
118
- return;
119
- }
120
- process.stdout.write(`${cliVersion} (${getCliChannel(cliVersion)}, ${formatInstallMethodLabel(getCliInstallMethod()).toLowerCase()})\n`);
121
- process.exitCode = 0;
118
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "version" }, async () => {
119
+ if (parsedOptions.json) {
120
+ process.stdout.write(`${JSON.stringify({
121
+ cliVersion,
122
+ channel: getCliChannel(cliVersion),
123
+ installMethod: getCliInstallMethod(),
124
+ })}\n`);
125
+ return 0;
126
+ }
127
+ process.stdout.write(`${cliVersion} (${getCliChannel(cliVersion)}, ${formatInstallMethodLabel(getCliInstallMethod()).toLowerCase()})\n`);
128
+ return 0;
129
+ });
122
130
  });
123
131
  const connectCommand = program
124
132
  .command("connect [source]")
@@ -130,13 +138,14 @@ More:
130
138
  .option("--quiet", "Reduce non-essential output")
131
139
  .option("--detach", "Run in the background")
132
140
  .action(async (source) => {
133
- if (parsedOptions.detach && source) {
134
- process.exitCode = await runDetached("connect", source, parsedOptions);
135
- return;
136
- }
137
- process.exitCode = source
138
- ? await runConnect(source, parsedOptions)
139
- : await runConnectEntry(parsedOptions);
141
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "connect", source }, async () => {
142
+ if (parsedOptions.detach && source) {
143
+ return runDetached("connect", source, parsedOptions);
144
+ }
145
+ return source
146
+ ? runConnect(source, parsedOptions)
147
+ : runConnectEntry(parsedOptions);
148
+ });
140
149
  });
141
150
  connectCommand.addHelpText("after", `
142
151
  Examples:
@@ -150,9 +159,9 @@ Examples:
150
159
  .description("List supported sources, or show detail for one source")
151
160
  .option("--json", "Output machine-readable JSON")
152
161
  .action(async (source) => {
153
- process.exitCode = source
154
- ? await runSourceDetail(source, parsedOptions)
155
- : await runList(parsedOptions);
162
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "sources", source }, async () => source
163
+ ? runSourceDetail(source, parsedOptions)
164
+ : runList(parsedOptions));
156
165
  });
157
166
  sourcesCommand.addHelpText("after", `
158
167
  Examples:
@@ -171,13 +180,14 @@ Examples:
171
180
  .option("--detach", "Run in the background")
172
181
  .option("--all", "Collect from all connected sources")
173
182
  .action(async (source) => {
174
- if (parsedOptions.detach && source) {
175
- process.exitCode = await runDetached("collect", source, parsedOptions);
176
- return;
177
- }
178
- process.exitCode = source
179
- ? await runCollect(source, parsedOptions)
180
- : await runCollectAll(parsedOptions);
183
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "collect", source }, async () => {
184
+ if (parsedOptions.detach && source) {
185
+ return runDetached("collect", source, parsedOptions);
186
+ }
187
+ return source
188
+ ? runCollect(source, parsedOptions)
189
+ : runCollectAll(parsedOptions);
190
+ });
181
191
  });
182
192
  collectCommand.addHelpText("after", `
183
193
  Examples:
@@ -190,7 +200,7 @@ Examples:
190
200
  .description("Show runtime and Personal Server status")
191
201
  .option("--json", "Output machine-readable JSON")
192
202
  .action(async () => {
193
- process.exitCode = await runStatus(parsedOptions);
203
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "status" }, async () => runStatus(parsedOptions));
194
204
  });
195
205
  statusCommand.addHelpText("after", `
196
206
  Examples:
@@ -202,7 +212,7 @@ Examples:
202
212
  .description("Inspect local CLI, runtime, and install health")
203
213
  .option("--json", "Output machine-readable JSON")
204
214
  .action(async () => {
205
- process.exitCode = await runDoctor(parsedOptions);
215
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "doctor" }, async () => runDoctor(parsedOptions));
206
216
  });
207
217
  doctorCommand.addHelpText("after", `
208
218
  Examples:
@@ -215,7 +225,7 @@ Examples:
215
225
  .option("--json", "Output machine-readable JSON")
216
226
  .option("--yes", "Approve safe setup prompts automatically")
217
227
  .action(async () => {
218
- process.exitCode = await runSetup(parsedOptions);
228
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "setup" }, async () => runSetup(parsedOptions));
219
229
  });
220
230
  setupCommand.addHelpText("after", `
221
231
  Examples:
@@ -240,7 +250,7 @@ Examples:
240
250
  .description("List locally available collected datasets")
241
251
  .option("--json", "Output machine-readable JSON")
242
252
  .action(async () => {
243
- process.exitCode = await runDataList(parsedOptions);
253
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "data", subcommand: "list" }, async () => runDataList(parsedOptions));
244
254
  });
245
255
  dataListCommand.addHelpText("after", `
246
256
  Examples:
@@ -252,7 +262,12 @@ Examples:
252
262
  .description("Show a collected dataset")
253
263
  .option("--json", "Output machine-readable JSON")
254
264
  .action(async (source) => {
255
- process.exitCode = await runDataShow(source, parsedOptions);
265
+ process.exitCode = await runCommandWithTelemetry({
266
+ ...telemetryBaseContext,
267
+ command: "data",
268
+ subcommand: "show",
269
+ source,
270
+ }, async () => runDataShow(source, parsedOptions));
256
271
  });
257
272
  dataShowCommand.addHelpText("after", `
258
273
  Examples:
@@ -264,7 +279,12 @@ Examples:
264
279
  .description("Print the local path for a collected dataset")
265
280
  .option("--json", "Output machine-readable JSON")
266
281
  .action(async (source) => {
267
- process.exitCode = await runDataPath(source, parsedOptions);
282
+ process.exitCode = await runCommandWithTelemetry({
283
+ ...telemetryBaseContext,
284
+ command: "data",
285
+ subcommand: "path",
286
+ source,
287
+ }, async () => runDataPath(source, parsedOptions));
268
288
  });
269
289
  dataPathCommand.addHelpText("after", `
270
290
  Examples:
@@ -276,7 +296,7 @@ Examples:
276
296
  .description("Inspect stored connector run logs")
277
297
  .option("--json", "Output machine-readable JSON")
278
298
  .action(async (source) => {
279
- process.exitCode = await runLogs(source, parsedOptions);
299
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "logs", source }, async () => runLogs(source, parsedOptions));
280
300
  });
281
301
  logsCommand.addHelpText("after", `
282
302
  Examples:
@@ -296,62 +316,89 @@ Examples:
296
316
  vana server clear-url
297
317
  `);
298
318
  server.action(async () => {
299
- process.exitCode = await runServerStatus(parsedOptions);
319
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "server", subcommand: "status" }, async () => runServerStatus(parsedOptions));
300
320
  });
301
321
  server
302
322
  .command("status")
303
323
  .description("Show Personal Server status")
304
324
  .option("--json", "Output machine-readable JSON")
305
325
  .action(async () => {
306
- process.exitCode = await runServerStatus(parsedOptions);
326
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "server", subcommand: "status" }, async () => runServerStatus(parsedOptions));
307
327
  });
308
328
  server
309
329
  .command("set-url <url>")
310
330
  .description("Save a Personal Server URL")
311
331
  .option("--json", "Output machine-readable JSON")
312
332
  .action(async (url) => {
313
- process.exitCode = await runServerSetUrl(url, parsedOptions);
333
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "server", subcommand: "set-url" }, async () => runServerSetUrl(url, parsedOptions));
314
334
  });
315
335
  server
316
336
  .command("clear-url")
317
337
  .description("Remove the saved Personal Server URL")
318
338
  .option("--json", "Output machine-readable JSON")
319
339
  .action(async () => {
320
- process.exitCode = await runServerClearUrl(parsedOptions);
340
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "server", subcommand: "clear-url" }, async () => runServerClearUrl(parsedOptions));
321
341
  });
322
342
  server
323
343
  .command("sync")
324
344
  .description("Sync all local-only datasets to your Personal Server")
325
345
  .option("--json", "Output machine-readable JSON")
326
346
  .action(async () => {
327
- process.exitCode = await runServerSync(parsedOptions);
347
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "server", subcommand: "sync" }, async () => runServerSync(parsedOptions));
328
348
  });
329
349
  server
330
350
  .command("data [scope]")
331
351
  .description("List scopes stored in your Personal Server")
332
352
  .option("--json", "Output machine-readable JSON")
333
353
  .action(async (scope) => {
334
- process.exitCode = await runServerData(scope, parsedOptions);
354
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "server", subcommand: "data" }, async () => runServerData(scope, parsedOptions));
335
355
  });
336
356
  program
337
357
  .command("login")
338
358
  .description("Log in to your Vana account or a self-hosted Personal Server")
339
359
  .option("-s, --server <url>", "Self-hosted Personal Server URL")
340
360
  .action(async (loginOptions) => {
341
- process.exitCode = await runLogin(parsedOptions, loginOptions.server);
361
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "login" }, async () => runLogin(parsedOptions, loginOptions.server));
342
362
  });
343
363
  program
344
364
  .command("logout")
345
365
  .description("Log out and remove saved credentials")
346
366
  .action(async () => {
347
- process.exitCode = await runLogout(parsedOptions);
367
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "logout" }, async () => runLogout(parsedOptions));
368
+ });
369
+ const telemetry = program
370
+ .command("telemetry")
371
+ .description("Inspect and manage CLI telemetry");
372
+ telemetry.action(async () => {
373
+ process.exitCode = await runTelemetryStatus(parsedOptions);
374
+ });
375
+ telemetry
376
+ .command("status")
377
+ .description("Show telemetry state")
378
+ .option("--json", "Output machine-readable JSON")
379
+ .action(async () => {
380
+ process.exitCode = await runTelemetryStatus(parsedOptions);
381
+ });
382
+ telemetry
383
+ .command("enable")
384
+ .description("Enable telemetry")
385
+ .action(async () => {
386
+ process.exitCode = await runTelemetryEnable(parsedOptions);
387
+ });
388
+ telemetry
389
+ .command("disable")
390
+ .description("Disable telemetry")
391
+ .action(async () => {
392
+ process.exitCode = await runTelemetryDisable(parsedOptions);
348
393
  });
349
394
  program
350
395
  .command("mcp")
351
396
  .description("Start MCP server for agent integration")
352
397
  .action(async () => {
353
- const { startMcpServer } = await import("./mcp-server.js");
354
- await startMcpServer();
398
+ process.exitCode = await runLongRunningCommandWithTelemetry({ ...telemetryBaseContext, command: "mcp" }, async () => {
399
+ const { startMcpServer } = await import("./mcp-server.js");
400
+ await startMcpServer();
401
+ });
355
402
  });
356
403
  const skill = program
357
404
  .command("skills")
@@ -364,26 +411,26 @@ Examples:
364
411
  vana skills show connect-data
365
412
  `);
366
413
  skill.action(async () => {
367
- process.exitCode = await runSkillsGuidedPicker(parsedOptions);
414
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "skills" }, async () => runSkillsGuidedPicker(parsedOptions));
368
415
  });
369
416
  skill
370
417
  .command("list")
371
418
  .description("List available agent skills")
372
419
  .option("--json", "Output as JSON")
373
420
  .action(async () => {
374
- process.exitCode = await runSkillList(parsedOptions);
421
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "skills", subcommand: "list" }, async () => runSkillList(parsedOptions));
375
422
  });
376
423
  skill
377
424
  .command("install <name>")
378
425
  .description("Install a skill for your agent")
379
426
  .action(async (name) => {
380
- process.exitCode = await runSkillInstall(name, parsedOptions);
427
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "skills", subcommand: "install" }, async () => runSkillInstall(name, parsedOptions));
381
428
  });
382
429
  skill
383
430
  .command("show <name>")
384
431
  .description("Show skill details")
385
432
  .action(async (name) => {
386
- process.exitCode = await runSkillShow(name, parsedOptions);
433
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "skills", subcommand: "show" }, async () => runSkillShow(name, parsedOptions));
387
434
  });
388
435
  // --- Schedule commands ---
389
436
  const schedule = program
@@ -405,20 +452,20 @@ Examples:
405
452
  .description("Add a scheduled collection")
406
453
  .option("--every <interval>", "Collection interval (e.g. 24h, 12h, 1h)", "24h")
407
454
  .action(async (opts) => {
408
- process.exitCode = await runScheduleAdd(opts.every, parsedOptions);
455
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "schedule", subcommand: "add" }, async () => runScheduleAdd(opts.every, parsedOptions));
409
456
  });
410
457
  schedule
411
458
  .command("list")
412
459
  .description("Show scheduled tasks")
413
460
  .option("--json", "Output machine-readable JSON")
414
461
  .action(async () => {
415
- process.exitCode = await runScheduleList(parsedOptions);
462
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "schedule", subcommand: "list" }, async () => runScheduleList(parsedOptions));
416
463
  });
417
464
  schedule
418
465
  .command("remove")
419
466
  .description("Remove the scheduled collection")
420
467
  .action(async () => {
421
- process.exitCode = await runScheduleRemove(parsedOptions);
468
+ process.exitCode = await runCommandWithTelemetry({ ...telemetryBaseContext, command: "schedule", subcommand: "remove" }, async () => runScheduleRemove(parsedOptions));
422
469
  });
423
470
  try {
424
471
  await program.parseAsync(normalizedArgv);
@@ -457,6 +504,155 @@ Examples:
457
504
  }
458
505
  return Number(process.exitCode ?? 0);
459
506
  }
507
+ function classifyCommandFailure(error) {
508
+ if (error instanceof Error) {
509
+ const value = error.message.toLowerCase();
510
+ if (value.includes("needs_input") ||
511
+ value.includes("needs input") ||
512
+ value.includes("input required") ||
513
+ value.includes("manual step"))
514
+ return "needs_input";
515
+ if (value.includes("prompt_cancelled") || value.includes("cancelled"))
516
+ return "prompt_cancelled";
517
+ if (value.includes("personal_server_unavailable") ||
518
+ value.includes("personal server unavailable"))
519
+ return "personal_server_unavailable";
520
+ if (value.includes("auth expired"))
521
+ return "auth_expired";
522
+ if (value.includes("auth"))
523
+ return "auth_failed";
524
+ if (value.includes("setup"))
525
+ return "setup_required";
526
+ if (value.includes("timeout") || value.includes("timed out"))
527
+ return "timeout";
528
+ if (value.includes("network"))
529
+ return "network_error";
530
+ if (value.includes("runtime"))
531
+ return "runtime_error";
532
+ if (value.includes("connector"))
533
+ return "connector_unavailable";
534
+ if (value.includes("ingest"))
535
+ return "ingest_failed";
536
+ }
537
+ return "unknown";
538
+ }
539
+ async function runCommandWithTelemetry(context, action) {
540
+ const session = await createCliTelemetrySession({
541
+ ...context,
542
+ options: {
543
+ json: Boolean(context.options.json),
544
+ noInput: Boolean(context.options.noInput),
545
+ quiet: Boolean(context.options.quiet),
546
+ detach: Boolean(context.options.detach),
547
+ ipc: Boolean(context.options.ipc),
548
+ },
549
+ localOnly: context.localOnly,
550
+ });
551
+ setActiveTelemetrySession(session);
552
+ await flushTelemetryOutbox();
553
+ try {
554
+ const exitCode = await action();
555
+ session.markCommandResult({ exitCode });
556
+ return exitCode;
557
+ }
558
+ catch (error) {
559
+ session.markCommandResult({
560
+ exitCode: 1,
561
+ errorClass: classifyCommandFailure(error),
562
+ });
563
+ throw error;
564
+ }
565
+ finally {
566
+ await session.persist();
567
+ await session.flush();
568
+ setActiveTelemetrySession(null);
569
+ }
570
+ }
571
+ async function runLongRunningCommandWithTelemetry(context, action) {
572
+ const session = await createCliTelemetrySession({
573
+ ...context,
574
+ options: {
575
+ json: Boolean(context.options.json),
576
+ noInput: Boolean(context.options.noInput),
577
+ quiet: Boolean(context.options.quiet),
578
+ detach: Boolean(context.options.detach),
579
+ ipc: Boolean(context.options.ipc),
580
+ },
581
+ });
582
+ setActiveTelemetrySession(session);
583
+ await flushTelemetryOutbox();
584
+ session.trackCustomEvent("mcp_started");
585
+ session.markCommandResult({ exitCode: 0, outcome: "started" });
586
+ await session.persist();
587
+ await session.flush();
588
+ try {
589
+ await action();
590
+ return 0;
591
+ }
592
+ finally {
593
+ setActiveTelemetrySession(null);
594
+ }
595
+ }
596
+ async function runTelemetryStatus(options) {
597
+ const status = await getTelemetryStatus();
598
+ const endpointHost = (() => {
599
+ try {
600
+ return new URL(status.endpoint).host;
601
+ }
602
+ catch {
603
+ return status.endpoint;
604
+ }
605
+ })();
606
+ if (options.json) {
607
+ process.stdout.write(`${JSON.stringify(status)}\n`);
608
+ return 0;
609
+ }
610
+ const emit = createEmitter(options);
611
+ emit.title("Telemetry");
612
+ emit.blank();
613
+ emit.keyValue("Enabled", status.enabled ? "yes" : "no");
614
+ emit.keyValue("Mode", status.mode);
615
+ emit.keyValue("Reason", status.reason.replaceAll("_", " "));
616
+ emit.keyValue("Endpoint", endpointHost);
617
+ emit.keyValue("Queued", String(status.queuedBatches));
618
+ emit.detail("Collected data stays local. Remote telemetry only includes small operational events.");
619
+ if (status.enabled) {
620
+ emit.detail(`Disable with: ${emit.code("vana telemetry disable")}`);
621
+ }
622
+ else {
623
+ emit.detail(`Enable with: ${emit.code("vana telemetry enable")}`);
624
+ }
625
+ if (process.env.VANA_TELEMETRY_DEBUG === "1") {
626
+ emit.detail(`Debug mode is active via ${emit.code("VANA_TELEMETRY_DEBUG=1")}. Events print to stderr and are not uploaded.`);
627
+ }
628
+ if (process.env.VANA_TELEMETRY_DISABLED === "1") {
629
+ emit.detail(`Telemetry is currently overridden by ${emit.code("VANA_TELEMETRY_DISABLED=1")}.`);
630
+ }
631
+ return 0;
632
+ }
633
+ async function runTelemetryEnable(options) {
634
+ await setTelemetryEnabled(true);
635
+ if (options.json) {
636
+ process.stdout.write(`${JSON.stringify({ enabled: true })}\n`);
637
+ return 0;
638
+ }
639
+ const emit = createEmitter(options);
640
+ emit.success("Telemetry enabled.");
641
+ if (process.env.VANA_TELEMETRY_DISABLED === "1") {
642
+ emit.detail(`The current shell still disables uploads via ${emit.code("VANA_TELEMETRY_DISABLED=1")}.`);
643
+ }
644
+ return 0;
645
+ }
646
+ async function runTelemetryDisable(options) {
647
+ await setTelemetryEnabled(false);
648
+ if (options.json) {
649
+ process.stdout.write(`${JSON.stringify({ enabled: false })}\n`);
650
+ return 0;
651
+ }
652
+ const emit = createEmitter(options);
653
+ emit.success("Telemetry disabled.");
654
+ return 0;
655
+ }
460
656
  async function runConnect(rawSource, options) {
461
657
  const source = rawSource.toLowerCase();
462
658
  const runtime = new ManagedPlaywrightRuntime();
@@ -510,7 +706,18 @@ async function runConnect(rawSource, options) {
510
706
  }
511
707
  process.stderr.write("\n");
512
708
  }
513
- const installResult = await runtime.ensureInstalled(Boolean(options.yes));
709
+ trackActiveTelemetryEvent("runtime_install_started", { source });
710
+ let installResult;
711
+ try {
712
+ installResult = await runtime.ensureInstalled(Boolean(options.yes));
713
+ }
714
+ catch (error) {
715
+ trackActiveTelemetryEvent("runtime_install_failed", {
716
+ source,
717
+ errorClass: classifyCommandFailure(error),
718
+ });
719
+ throw error;
720
+ }
514
721
  setupLogPath = installResult.logPath;
515
722
  emit.event({
516
723
  type: "setup-complete",
@@ -599,6 +806,13 @@ async function runConnect(rawSource, options) {
599
806
  }
600
807
  }
601
808
  if (fetched.updated && fetched.previousVersion) {
809
+ trackActiveTelemetryEvent("connector_update_applied", {
810
+ source,
811
+ metadata: {
812
+ previousVersion: fetched.previousVersion,
813
+ connectorVersion: fetched.version,
814
+ },
815
+ });
602
816
  renderer?.detail(`Updated connector (${fetched.previousVersion} → ${fetched.version}).`);
603
817
  }
604
818
  fetchLogPath = fetched.logPath;
@@ -613,6 +827,10 @@ async function runConnect(rawSource, options) {
613
827
  connectorPath: resolution.connectorPath,
614
828
  logPath: fetched.logPath,
615
829
  });
830
+ trackActiveTelemetryEvent("connector_version_detected", {
831
+ source: resolution.source,
832
+ connectorVersion: fetched.version,
833
+ });
616
834
  // --- Phase 3: Pre-connection validation (silent) ---
617
835
  const profilePath = path.join(getBrowserProfilesDir(), `${path.basename(resolution.connectorPath, path.extname(resolution.connectorPath))}`);
618
836
  if (sourceDetails?.authMode === "legacy" &&
@@ -2196,7 +2414,11 @@ async function runCollectAll(options) {
2196
2414
  async function runServerSync(options) {
2197
2415
  const emit = createEmitter(options);
2198
2416
  const target = await detectPersonalServerTarget();
2417
+ trackActiveTelemetryEvent("server_sync_started");
2199
2418
  if (target.state !== "available") {
2419
+ trackActiveTelemetryEvent("server_sync_failed", {
2420
+ errorClass: "personal_server_unavailable",
2421
+ });
2200
2422
  if (options.json) {
2201
2423
  process.stdout.write(`${JSON.stringify({
2202
2424
  error: "personal_server_unavailable",
@@ -2209,7 +2431,16 @@ async function runServerSync(options) {
2209
2431
  return 1;
2210
2432
  }
2211
2433
  const syncResult = await syncPendingSources(target, "manual");
2434
+ const storedScopeCount = syncResult.sourceResults.reduce((total, entry) => total +
2435
+ (entry.scopeResults?.filter((scopeResult) => scopeResult.status === "stored").length ?? 0), 0);
2436
+ const failedScopeCount = syncResult.sourceResults.reduce((total, entry) => total +
2437
+ (entry.scopeResults?.filter((scopeResult) => scopeResult.status === "failed").length ?? 0), 0);
2212
2438
  if (syncResult.sourceResults.length === 0) {
2439
+ trackActiveTelemetryEvent("server_sync_completed", {
2440
+ storedScopeCount: 0,
2441
+ failedScopeCount: 0,
2442
+ metadata: { syncedSources: 0 },
2443
+ });
2213
2444
  if (options.json) {
2214
2445
  process.stdout.write(`${JSON.stringify({ message: "No pending datasets to sync.", syncedCount: 0 })}\n`);
2215
2446
  }
@@ -2250,6 +2481,11 @@ async function runServerSync(options) {
2250
2481
  emit.next("vana server sync");
2251
2482
  }
2252
2483
  }
2484
+ trackActiveTelemetryEvent("server_sync_completed", {
2485
+ storedScopeCount,
2486
+ failedScopeCount,
2487
+ metadata: { syncedSources: syncResult.syncedCount },
2488
+ });
2253
2489
  return 0;
2254
2490
  }
2255
2491
  async function runServerData(scope, options) {
@@ -2414,6 +2650,7 @@ function createEmitter(options) {
2414
2650
  const renderer = createHumanRenderer();
2415
2651
  return {
2416
2652
  event(event) {
2653
+ getActiveTelemetrySession()?.trackCliEvent(event);
2417
2654
  if (options.json) {
2418
2655
  process.stdout.write(`${JSON.stringify(event)}\n`);
2419
2656
  }
@@ -3560,6 +3797,7 @@ async function runDetached(command, source, options) {
3560
3797
  stdio: ["ignore", logFd, logFd],
3561
3798
  env: { ...process.env, VANA_DETACHED: "1" },
3562
3799
  });
3800
+ trackActiveTelemetryEvent("detached_run_spawned", { source });
3563
3801
  child.unref();
3564
3802
  fs.closeSync(logFd);
3565
3803
  // Write session file
@@ -3764,6 +4002,9 @@ async function runScheduleAdd(interval, options) {
3764
4002
  emit.detail(`launchctl load "${LAUNCHD_PLIST_PATH}"`);
3765
4003
  return 1;
3766
4004
  }
4005
+ trackActiveTelemetryEvent("schedule_added", {
4006
+ metadata: { interval: intervalLabel, mechanism: "launchd" },
4007
+ });
3767
4008
  if (options.json) {
3768
4009
  process.stdout.write(`${JSON.stringify({ ok: true, interval: intervalLabel, mechanism: "launchd", plistPath: LAUNCHD_PLIST_PATH })}\n`);
3769
4010
  return 0;
@@ -3804,6 +4045,9 @@ async function runScheduleAdd(interval, options) {
3804
4045
  emit.detail(entry);
3805
4046
  return 1;
3806
4047
  }
4048
+ trackActiveTelemetryEvent("schedule_added", {
4049
+ metadata: { interval: intervalLabel, mechanism: "cron" },
4050
+ });
3807
4051
  if (options.json) {
3808
4052
  process.stdout.write(`${JSON.stringify({ ok: true, interval: intervalLabel, mechanism: "cron" })}\n`);
3809
4053
  return 0;
@@ -3845,6 +4089,9 @@ async function runScheduleAdd(interval, options) {
3845
4089
  emit.detail(`schtasks /Create /TN "${WINDOWS_TASK_NAME}" /TR "${trCmd}" /SC DAILY /ST 09:00 /F`);
3846
4090
  return 1;
3847
4091
  }
4092
+ trackActiveTelemetryEvent("schedule_added", {
4093
+ metadata: { interval: intervalLabel, mechanism: "schtasks" },
4094
+ });
3848
4095
  if (options.json) {
3849
4096
  process.stdout.write(`${JSON.stringify({ ok: true, interval: intervalLabel, mechanism: "schtasks" })}\n`);
3850
4097
  return 0;
@@ -3962,6 +4209,9 @@ async function runScheduleRemove(options) {
3962
4209
  // Already unloaded
3963
4210
  }
3964
4211
  await fsp.unlink(LAUNCHD_PLIST_PATH);
4212
+ trackActiveTelemetryEvent("schedule_removed", {
4213
+ metadata: { mechanism: "launchd" },
4214
+ });
3965
4215
  if (options.json) {
3966
4216
  process.stdout.write(`${JSON.stringify({ ok: true, removed: true })}\n`);
3967
4217
  return 0;
@@ -3987,6 +4237,9 @@ async function runScheduleRemove(options) {
3987
4237
  input: `${filtered.trimEnd()}\n`,
3988
4238
  encoding: "utf8",
3989
4239
  });
4240
+ trackActiveTelemetryEvent("schedule_removed", {
4241
+ metadata: { mechanism: "cron" },
4242
+ });
3990
4243
  if (options.json) {
3991
4244
  process.stdout.write(`${JSON.stringify({ ok: true, removed: true })}\n`);
3992
4245
  return 0;
@@ -4004,6 +4257,9 @@ async function runScheduleRemove(options) {
4004
4257
  execSync(`schtasks /Delete /TN "${WINDOWS_TASK_NAME}" /F`, {
4005
4258
  stdio: "ignore",
4006
4259
  });
4260
+ trackActiveTelemetryEvent("schedule_removed", {
4261
+ metadata: { mechanism: "schtasks" },
4262
+ });
4007
4263
  if (options.json) {
4008
4264
  process.stdout.write(`${JSON.stringify({ ok: true, removed: true })}\n`);
4009
4265
  return 0;
@@ -4158,6 +4414,9 @@ async function runSkillInstall(name, options) {
4158
4414
  const emit = createEmitter(options);
4159
4415
  try {
4160
4416
  const { installedPath } = await installSkill(name);
4417
+ trackActiveTelemetryEvent("skill_installed", {
4418
+ metadata: { skillName: name },
4419
+ });
4161
4420
  if (options.json) {
4162
4421
  process.stdout.write(`${JSON.stringify({ ok: true, id: name, installedPath })}\n`);
4163
4422
  return 0;