@opendatalabs/connect 0.8.1-canary.ac15bfe → 0.8.1-canary.d23fbf5

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 (75) hide show
  1. package/README.md +73 -5
  2. package/dist/cli/index.d.ts.map +1 -1
  3. package/dist/cli/index.js +346 -27
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/cli/render/capabilities.d.ts +9 -0
  6. package/dist/cli/render/capabilities.d.ts.map +1 -0
  7. package/dist/cli/render/capabilities.js +24 -0
  8. package/dist/cli/render/capabilities.js.map +1 -0
  9. package/dist/cli/render/format.d.ts +20 -0
  10. package/dist/cli/render/format.d.ts.map +1 -0
  11. package/dist/cli/render/format.js +58 -0
  12. package/dist/cli/render/format.js.map +1 -0
  13. package/dist/cli/render/index.d.ts +5 -0
  14. package/dist/cli/render/index.d.ts.map +1 -0
  15. package/dist/cli/render/index.js +5 -0
  16. package/dist/cli/render/index.js.map +1 -0
  17. package/dist/cli/render/symbols.d.ts +11 -0
  18. package/dist/cli/render/symbols.d.ts.map +1 -0
  19. package/dist/cli/render/symbols.js +21 -0
  20. package/dist/cli/render/symbols.js.map +1 -0
  21. package/dist/cli/render/theme.d.ts +15 -0
  22. package/dist/cli/render/theme.d.ts.map +1 -0
  23. package/dist/cli/render/theme.js +17 -0
  24. package/dist/cli/render/theme.js.map +1 -0
  25. package/dist/connectors/registry.d.ts +1 -0
  26. package/dist/connectors/registry.d.ts.map +1 -1
  27. package/dist/connectors/registry.js +34 -2
  28. package/dist/connectors/registry.js.map +1 -1
  29. package/dist/core/cli-types.d.ts +13 -0
  30. package/dist/core/cli-types.d.ts.map +1 -1
  31. package/dist/core/cli-types.js +3 -0
  32. package/dist/core/cli-types.js.map +1 -1
  33. package/dist/core/index.d.ts +1 -1
  34. package/dist/core/index.d.ts.map +1 -1
  35. package/dist/core/index.js +1 -1
  36. package/dist/core/index.js.map +1 -1
  37. package/dist/core/paths.d.ts +0 -1
  38. package/dist/core/paths.d.ts.map +1 -1
  39. package/dist/core/paths.js +0 -3
  40. package/dist/core/paths.js.map +1 -1
  41. package/dist/core/state-store.d.ts +1 -0
  42. package/dist/core/state-store.d.ts.map +1 -1
  43. package/dist/core/state-store.js.map +1 -1
  44. package/dist/runtime/core/contracts.d.ts +69 -0
  45. package/dist/runtime/core/contracts.d.ts.map +1 -0
  46. package/dist/runtime/core/contracts.js +2 -0
  47. package/dist/runtime/core/contracts.js.map +1 -0
  48. package/dist/runtime/core/index.d.ts +2 -0
  49. package/dist/runtime/core/index.d.ts.map +1 -0
  50. package/dist/runtime/core/index.js +2 -0
  51. package/dist/runtime/core/index.js.map +1 -0
  52. package/dist/runtime/index.d.ts +1 -0
  53. package/dist/runtime/index.d.ts.map +1 -1
  54. package/dist/runtime/index.js.map +1 -1
  55. package/dist/runtime/managed-playwright.d.ts +2 -2
  56. package/dist/runtime/managed-playwright.d.ts.map +1 -1
  57. package/dist/runtime/managed-playwright.js +59 -209
  58. package/dist/runtime/managed-playwright.js.map +1 -1
  59. package/dist/runtime/playwright/browser.d.ts +11 -0
  60. package/dist/runtime/playwright/browser.d.ts.map +1 -0
  61. package/dist/runtime/playwright/browser.js +208 -0
  62. package/dist/runtime/playwright/browser.js.map +1 -0
  63. package/dist/runtime/playwright/in-process-run.d.ts +6 -0
  64. package/dist/runtime/playwright/in-process-run.d.ts.map +1 -0
  65. package/dist/runtime/playwright/in-process-run.js +534 -0
  66. package/dist/runtime/playwright/in-process-run.js.map +1 -0
  67. package/dist/runtime/playwright/index.d.ts +3 -0
  68. package/dist/runtime/playwright/index.d.ts.map +1 -0
  69. package/dist/runtime/playwright/index.js +3 -0
  70. package/dist/runtime/playwright/index.js.map +1 -0
  71. package/dist/runtime/repo-paths.d.ts.map +1 -1
  72. package/dist/runtime/repo-paths.js +24 -7
  73. package/dist/runtime/repo-paths.js.map +1 -1
  74. package/package.json +21 -9
  75. package/runtime-assets/run-connector.cjs +0 -275
package/README.md CHANGED
@@ -78,28 +78,84 @@ If you prefer to integrate the SDK into an existing project, follow the steps be
78
78
 
79
79
  ### Install
80
80
 
81
- Use the published package directly:
81
+ If you are evaluating this branch before it lands on `main`, use the prerelease path in the next section. The stable install commands below are the intended post-merge install path.
82
+
83
+ macOS with Homebrew:
82
84
 
83
85
  ```bash
84
- pnpm dlx @opendatalabs/connect status
86
+ brew tap vana-com/vana
87
+ brew install vana
85
88
  ```
86
89
 
87
- Or install it globally:
90
+ macOS and Linux:
88
91
 
89
92
  ```bash
90
- pnpm add -g @opendatalabs/connect
91
- vana status
93
+ curl -fsSL https://raw.githubusercontent.com/vana-com/vana-connect/main/install/install.sh | sh
94
+ ```
95
+
96
+ Windows PowerShell:
97
+
98
+ ```powershell
99
+ iwr https://raw.githubusercontent.com/vana-com/vana-connect/main/install/install.ps1 -useb | iex
100
+ ```
101
+
102
+ Both installers fetch the latest GitHub release asset for your platform, verify its checksum, and install `vana` without requiring Node or npm.
103
+
104
+ ### Canary / prerelease testing
105
+
106
+ If you are testing an unreleased branch build, install from the branch installer and pass the prerelease tag explicitly.
107
+
108
+ macOS with Homebrew:
109
+
110
+ ```bash
111
+ brew tap vana-com/vana
112
+ brew install vana
113
+ ```
114
+
115
+ The current Homebrew tap is following the latest `vana-connect` canary while this CLI is still rolling out.
116
+
117
+ macOS and Linux:
118
+
119
+ ```bash
120
+ curl -fsSL https://raw.githubusercontent.com/vana-com/vana-connect/feat/connect-cli-v1/install/install.sh | sh -s -- --version canary-feat-connect-cli-v1
121
+ ```
122
+
123
+ Windows PowerShell:
124
+
125
+ ```powershell
126
+ & ([scriptblock]::Create((iwr https://raw.githubusercontent.com/vana-com/vana-connect/feat/connect-cli-v1/install/install.ps1 -useb).Content)) --version canary-feat-connect-cli-v1
127
+ ```
128
+
129
+ The current hosted prerelease is:
130
+
131
+ `canary-feat-connect-cli-v1`
132
+
133
+ Release page:
134
+
135
+ `https://github.com/vana-com/vana-connect/releases/tag/canary-feat-connect-cli-v1`
136
+
137
+ If you want the npm package path as a fallback:
138
+
139
+ ```bash
140
+ npx -y @opendatalabs/connect status
92
141
  ```
93
142
 
94
143
  ### Commands
95
144
 
96
145
  ```bash
146
+ vana connect
97
147
  vana sources
98
148
  vana connect github
99
149
  vana status
100
150
  vana setup
151
+ vana data list
152
+ vana data show github --json | jq
101
153
  ```
102
154
 
155
+ - `vana connect` opens a guided source picker in human mode.
156
+ - `vana connect <source>` runs the end-to-end collection flow.
157
+ - `vana data ...` lets you inspect collected local datasets without opening the raw JSON file yourself.
158
+
103
159
  ### Local development
104
160
 
105
161
  From this repo:
@@ -111,6 +167,18 @@ node dist/cli/bin.js status
111
167
  ```
112
168
 
113
169
  The CLI installs its local browser runtime under `~/.dataconnect/`.
170
+ That runtime is bundled from `vana-connect` itself, so `vana setup` does not require a separate `data-connect` checkout.
171
+
172
+ To build a standalone launcher plus app payload locally:
173
+
174
+ ```bash
175
+ pnpm build
176
+ pnpm build:sea
177
+ ./artifacts/sea/vana-linux-x64/vana status --json
178
+ ```
179
+
180
+ `pnpm build:sea` uses Node 25's `--build-sea` flow to create a small `vana` launcher and packages the real app payload next to it under `app/`.
181
+ It produces a platform-specific release directory plus a release archive and matching checksum file under `artifacts/sea/`.
114
182
 
115
183
  ### Programmatic runtime access
116
184
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAkDA,wBAAsB,MAAM,CAAC,IAAI,WAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA2CjE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAuEA,wBAAsB,MAAM,CAAC,IAAI,WAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAsEjE"}
package/dist/cli/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import fs from "node:fs";
2
2
  import fsp from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { confirm, input, password } from "@inquirer/prompts";
4
+ import { confirm, input, password, select } from "@inquirer/prompts";
5
5
  import { Command } from "commander";
6
+ import { createHumanRenderer } from "./render/index.js";
6
7
  import { CliOutcomeStatus, getBrowserProfilesDir, getConnectorCacheDir, getLastResultPath, readCliState, updateSourceState, } from "../core/index.js";
7
8
  import { listAvailableSources } from "../connectors/registry.js";
8
9
  import { detectPersonalServerTarget, ingestResult, } from "../personal-server/index.js";
@@ -13,13 +14,15 @@ export async function runCli(argv = process.argv) {
13
14
  const program = new Command();
14
15
  program.name("vana").description("Vana Connect CLI");
15
16
  program
16
- .command("connect <source>")
17
+ .command("connect [source]")
17
18
  .option("--json", "Output machine-readable JSON")
18
19
  .option("--no-input", "Fail instead of prompting for input")
19
20
  .option("--yes", "Approve safe setup prompts automatically")
20
21
  .option("--quiet", "Reduce non-essential output")
21
22
  .action(async (source) => {
22
- process.exitCode = await runConnect(source, parsedOptions);
23
+ process.exitCode = source
24
+ ? await runConnect(source, parsedOptions)
25
+ : await runConnectEntry(parsedOptions);
23
26
  });
24
27
  program
25
28
  .command("sources")
@@ -43,6 +46,27 @@ export async function runCli(argv = process.argv) {
43
46
  .action(async () => {
44
47
  process.exitCode = await runSetup(parsedOptions);
45
48
  });
49
+ const data = program.command("data").description("Inspect collected data");
50
+ data
51
+ .command("list")
52
+ .description("List locally available collected datasets")
53
+ .option("--json", "Output machine-readable JSON")
54
+ .action(async () => {
55
+ process.exitCode = await runDataList(parsedOptions);
56
+ });
57
+ data
58
+ .command("show <source>")
59
+ .description("Show a collected dataset")
60
+ .option("--json", "Output machine-readable JSON")
61
+ .action(async (source) => {
62
+ process.exitCode = await runDataShow(source, parsedOptions);
63
+ });
64
+ data
65
+ .command("path <source>")
66
+ .description("Print the local path for a collected dataset")
67
+ .action(async (source) => {
68
+ process.exitCode = await runDataPath(source, parsedOptions);
69
+ });
46
70
  await program.parseAsync(normalizedArgv);
47
71
  return Number(process.exitCode ?? 0);
48
72
  }
@@ -61,7 +85,7 @@ async function runConnect(source, options) {
61
85
  emit.info(`Vana Connect needs a local browser runtime before it can connect ${displaySource(source, sourceLabels)}.`);
62
86
  emit.info("");
63
87
  emit.info("This will install:");
64
- emit.info("- the connector runner");
88
+ emit.info("- the local browser runtime");
65
89
  emit.info("- a Chromium browser engine");
66
90
  emit.info("- local runtime files under ~/.dataconnect/");
67
91
  emit.info("");
@@ -199,16 +223,26 @@ async function runConnect(source, options) {
199
223
  }
200
224
  return 1;
201
225
  }
226
+ if (event.type === "headed-required") {
227
+ if (event.message) {
228
+ emit.info(event.message);
229
+ }
230
+ if (event.url) {
231
+ emit.info(`Opening ${displaySource(source, sourceLabels)} in a local browser session...`);
232
+ }
233
+ continue;
234
+ }
202
235
  if (event.type === "legacy-auth") {
203
236
  await updateSourceState(resolution.source, {
204
237
  lastRunAt: new Date().toISOString(),
205
238
  lastRunOutcome: CliOutcomeStatus.LEGACY_AUTH,
206
239
  lastError: event.message ?? "Legacy authentication is required.",
207
240
  dataState: "none",
241
+ lastResultPath: null,
208
242
  });
209
243
  emit.info(event.message ??
210
- "This connector requires legacy headed authentication that is not available in batch mode.");
211
- emit.info(`Next: establish a reusable ${displaySource(source, sourceLabels)} session manually, or migrate this connector to requestInput.`);
244
+ "This connector needs a manual browser step that is not available in non-interactive mode.");
245
+ emit.info(`Next: run \`vana connect ${source}\` without \`--no-input\`.`);
212
246
  if (event.logPath) {
213
247
  emit.info(`Run log: ${event.logPath}`);
214
248
  }
@@ -240,6 +274,7 @@ async function runConnect(source, options) {
240
274
  lastRunOutcome: CliOutcomeStatus.UNEXPECTED_INTERNAL_ERROR,
241
275
  dataState: "none",
242
276
  lastError: "Connector run ended without a result.",
277
+ lastResultPath: null,
243
278
  });
244
279
  emit.event({
245
280
  type: "outcome",
@@ -262,7 +297,9 @@ async function runConnect(source, options) {
262
297
  lastRunOutcome: finalStatus,
263
298
  dataState,
264
299
  lastError: null,
300
+ lastResultPath: resultPath,
265
301
  });
302
+ const resultSummary = await readResultSummary(resultPath);
266
303
  if (finalStatus === CliOutcomeStatus.CONNECTED_AND_INGESTED) {
267
304
  emit.info(`Connected ${displaySource(source, sourceLabels)}.`);
268
305
  emit.info(`Collected your ${displaySource(source, sourceLabels)} data and synced it to your Personal Server.`);
@@ -275,6 +312,13 @@ async function runConnect(source, options) {
275
312
  emit.info(`Collected your ${displaySource(source, sourceLabels)} data and saved it locally.`);
276
313
  emit.info(`Local result: ${resultPath}`);
277
314
  }
315
+ if (resultSummary) {
316
+ emit.info("");
317
+ emit.info("Collected:");
318
+ for (const line of resultSummary.lines) {
319
+ emit.info(`- ${line}`);
320
+ }
321
+ }
278
322
  if (runLogPath) {
279
323
  emit.info(`Run log: ${runLogPath}`);
280
324
  }
@@ -314,6 +358,41 @@ async function runConnect(source, options) {
314
358
  return 1;
315
359
  }
316
360
  }
361
+ async function runConnectEntry(options) {
362
+ const emit = createEmitter(options);
363
+ const sources = await loadRegistrySources();
364
+ if (options.json || options.noInput) {
365
+ emit.info("Specify a source. Run `vana sources` to see available options.");
366
+ return 1;
367
+ }
368
+ if (sources.length === 0) {
369
+ emit.info("No sources are available right now.");
370
+ emit.info("Run `vana sources` to verify the local connector registry.");
371
+ return 1;
372
+ }
373
+ emit.title("Connect data");
374
+ emit.blank();
375
+ emit.info("Choose a source to connect:");
376
+ let source;
377
+ try {
378
+ source = await select({
379
+ message: "Source",
380
+ choices: sources.map((item) => ({
381
+ name: `${item.name}${formatAuthModeBadge(item.authMode, emit)}${item.description ? ` - ${item.description}` : ""}`,
382
+ value: item.id,
383
+ })),
384
+ });
385
+ }
386
+ catch (error) {
387
+ if (isPromptCancelled(error)) {
388
+ emit.info("Cancelled.");
389
+ return 1;
390
+ }
391
+ throw error;
392
+ }
393
+ emit.blank();
394
+ return runConnect(source, options);
395
+ }
317
396
  async function runList(options) {
318
397
  const sources = await loadRegistrySources();
319
398
  const installedSourceIds = new Set((await listInstalledConnectorFiles()).map((source) => source.source));
@@ -326,10 +405,23 @@ async function runList(options) {
326
405
  return 0;
327
406
  }
328
407
  const emit = createEmitter(options);
408
+ emit.title("Available sources");
409
+ emit.blank();
329
410
  for (const source of enrichedSources) {
330
- const description = source.description ? ` - ${source.description}` : "";
331
- const installed = source.installed ? " [installed]" : "";
332
- emit.info(`${source.name}${installed}${description}`);
411
+ const badges = [];
412
+ if (source.installed) {
413
+ badges.push({ text: "installed", tone: "success" });
414
+ }
415
+ if (source.authMode === "interactive") {
416
+ badges.push({ text: "interactive", tone: "info" });
417
+ }
418
+ else if (source.authMode === "legacy") {
419
+ badges.push({ text: "legacy", tone: "warning" });
420
+ }
421
+ emit.sourceTitle(source.name, badges);
422
+ if (source.description) {
423
+ emit.detail(source.description);
424
+ }
333
425
  }
334
426
  return 0;
335
427
  }
@@ -344,7 +436,7 @@ async function runStatus(options) {
344
436
  const sources = await gatherSourceStatuses(state.sources, sourceMetadata);
345
437
  const status = {
346
438
  runtime: runtime.state,
347
- runtimePath: runtime.state === "installed" ? runtime.runnerDir : null,
439
+ runtimePath: runtime.runtimePath,
348
440
  personalServer: personalServer.state,
349
441
  personalServerUrl: personalServer.url,
350
442
  sources,
@@ -353,16 +445,20 @@ async function runStatus(options) {
353
445
  process.stdout.write(`${JSON.stringify(status)}\n`);
354
446
  return 0;
355
447
  }
356
- emit.info("Vana Connect status");
357
- emit.info("");
358
- emit.info(`Runtime: ${status.runtime}`);
359
- emit.info(`Personal Server: ${status.personalServer}`);
360
- emit.info("");
448
+ emit.title("Vana Connect status");
449
+ emit.blank();
450
+ emit.section("Environment");
451
+ emit.keyValue("Runtime", status.runtime, toneForRuntime(status.runtime));
452
+ emit.keyValue("Personal Server", status.personalServer, status.personalServer === "available" ? "success" : "muted");
453
+ if (status.sources.length > 0) {
454
+ emit.blank();
455
+ emit.section("Sources");
456
+ }
361
457
  for (const source of status.sources) {
362
- emit.info(formatSourceStatus(source, sourceLabels));
458
+ emit.info(formatSourceStatus(source, sourceLabels, emit));
363
459
  const details = formatSourceStatusDetail(source);
364
460
  if (details) {
365
- emit.info(` ${details}`);
461
+ emit.detail(details);
366
462
  }
367
463
  }
368
464
  return 0;
@@ -401,7 +497,101 @@ async function runSetup(options) {
401
497
  return 1;
402
498
  }
403
499
  }
500
+ async function runDataList(options) {
501
+ const state = await readCliState();
502
+ const sources = await gatherSourceStatuses(state.sources, createSourceMetadataMap(await loadRegistrySources()));
503
+ const datasets = sources
504
+ .filter((source) => Boolean(source.lastResultPath))
505
+ .map((source) => ({
506
+ source: source.source,
507
+ name: source.name,
508
+ dataState: source.dataState,
509
+ lastRunAt: source.lastRunAt ?? null,
510
+ path: source.lastResultPath ?? null,
511
+ }));
512
+ if (options.json) {
513
+ process.stdout.write(`${JSON.stringify({ datasets })}\n`);
514
+ return 0;
515
+ }
516
+ const emit = createEmitter(options);
517
+ if (datasets.length === 0) {
518
+ emit.info("No local datasets collected yet.");
519
+ emit.info("Run `vana connect <source>` to collect data.");
520
+ return 0;
521
+ }
522
+ emit.title("Collected data");
523
+ emit.blank();
524
+ for (const dataset of datasets) {
525
+ const badges = dataset.dataState === "ingested_personal_server"
526
+ ? [{ text: "synced", tone: "success" }]
527
+ : [{ text: "local", tone: "muted" }];
528
+ emit.sourceTitle(dataset.name ?? displaySource(dataset.source), badges);
529
+ emit.detail(dataset.path ?? "");
530
+ }
531
+ return 0;
532
+ }
533
+ async function runDataShow(source, options) {
534
+ const sourceLabels = createSourceLabelMap(await loadRegistrySources());
535
+ const state = await readCliState();
536
+ const record = state.sources[source];
537
+ const resultPath = record?.lastResultPath;
538
+ const emit = createEmitter(options);
539
+ if (!resultPath) {
540
+ if (options.json) {
541
+ process.stdout.write(`${JSON.stringify({
542
+ error: "dataset_not_found",
543
+ source,
544
+ message: `No collected dataset found for ${displaySource(source, sourceLabels)}. Run \`vana connect ${source}\` first.`,
545
+ })}\n`);
546
+ }
547
+ else {
548
+ emit.info(`No collected dataset found for ${displaySource(source, sourceLabels)}. Run \`vana connect ${source}\` first.`);
549
+ }
550
+ return 1;
551
+ }
552
+ try {
553
+ const raw = await fsp.readFile(resultPath, "utf8");
554
+ const data = JSON.parse(raw);
555
+ if (options.json) {
556
+ process.stdout.write(`${JSON.stringify({ source, path: resultPath, data })}\n`);
557
+ return 0;
558
+ }
559
+ const summary = summarizeResultData(data);
560
+ emit.title(`${displaySource(source, sourceLabels)} data`);
561
+ emit.blank();
562
+ if (summary) {
563
+ for (const line of summary.lines) {
564
+ emit.bullet(line);
565
+ }
566
+ emit.blank();
567
+ }
568
+ emit.keyValue("Path", resultPath, "muted");
569
+ return 0;
570
+ }
571
+ catch (error) {
572
+ const message = error instanceof Error ? error.message : `Could not read ${resultPath}.`;
573
+ if (options.json) {
574
+ process.stdout.write(`${JSON.stringify({ error: "dataset_read_failed", source, path: resultPath, message })}\n`);
575
+ }
576
+ else {
577
+ emit.info(message);
578
+ }
579
+ return 1;
580
+ }
581
+ }
582
+ async function runDataPath(source, options) {
583
+ const sourceLabels = createSourceLabelMap(await loadRegistrySources());
584
+ const state = await readCliState();
585
+ const resultPath = state.sources[source]?.lastResultPath;
586
+ if (!resultPath) {
587
+ createEmitter(options).info(`No collected dataset found for ${displaySource(source, sourceLabels)}.`);
588
+ return 1;
589
+ }
590
+ process.stdout.write(`${resultPath}\n`);
591
+ return 0;
592
+ }
404
593
  function createEmitter(options) {
594
+ const renderer = createHumanRenderer();
405
595
  return {
406
596
  event(event) {
407
597
  if (options.json) {
@@ -414,6 +604,54 @@ function createEmitter(options) {
414
604
  }
415
605
  process.stdout.write(`${message}\n`);
416
606
  },
607
+ blank() {
608
+ if (options.json || options.quiet) {
609
+ return;
610
+ }
611
+ process.stdout.write("\n");
612
+ },
613
+ title(message) {
614
+ if (options.json || options.quiet) {
615
+ return;
616
+ }
617
+ process.stdout.write(`${renderer.title(message)}\n`);
618
+ },
619
+ section(message) {
620
+ if (options.json || options.quiet) {
621
+ return;
622
+ }
623
+ process.stdout.write(`${renderer.section(message)}\n`);
624
+ },
625
+ keyValue(label, value, tone = "muted") {
626
+ if (options.json || options.quiet) {
627
+ return;
628
+ }
629
+ process.stdout.write(`${renderer.keyValue(label, value, tone)}\n`);
630
+ },
631
+ detail(message) {
632
+ if (options.json || options.quiet) {
633
+ return;
634
+ }
635
+ process.stdout.write(`${renderer.detail(message)}\n`);
636
+ },
637
+ bullet(message) {
638
+ if (options.json || options.quiet) {
639
+ return;
640
+ }
641
+ process.stdout.write(`${renderer.bullet(message)}\n`);
642
+ },
643
+ sourceTitle(name, badges = []) {
644
+ if (options.json || options.quiet) {
645
+ return;
646
+ }
647
+ process.stdout.write(`${renderer.sourceTitle(name, badges.map((badge) => renderer.badge(badge.text, badge.tone)))}\n`);
648
+ },
649
+ badge(text, tone = "muted") {
650
+ return renderer.badge(text, tone);
651
+ },
652
+ code(text) {
653
+ return renderer.theme.code(text);
654
+ },
417
655
  };
418
656
  }
419
657
  function displaySource(source, labels = {}) {
@@ -442,6 +680,7 @@ async function gatherSourceStatuses(storedSources, metadata = {}) {
442
680
  name: details?.name,
443
681
  company: details?.company,
444
682
  description: details?.description,
683
+ authMode: details?.authMode ?? inferInstalledAuthMode(installedFiles, source),
445
684
  installed,
446
685
  sessionPresent: stored.sessionPresent ?? false,
447
686
  lastRunAt: stored.lastRunAt ?? null,
@@ -452,6 +691,7 @@ async function gatherSourceStatuses(storedSources, metadata = {}) {
452
691
  ? "collected_local"
453
692
  : "none",
454
693
  lastError: stored.lastError ?? null,
694
+ lastResultPath: stored.lastResultPath ?? null,
455
695
  };
456
696
  });
457
697
  }
@@ -482,29 +722,30 @@ async function listInstalledConnectorFiles() {
482
722
  return [];
483
723
  }
484
724
  }
485
- function formatSourceStatus(source, labels = {}) {
725
+ function formatSourceStatus(source, labels = {}, emit) {
726
+ const authModeSuffix = formatAuthModeBadge(source.authMode, emit);
486
727
  if (!source.installed) {
487
- return `${displaySource(source.source, labels)}: not connected`;
728
+ return `${displaySource(source.source, labels)}${authModeSuffix}: not connected`;
488
729
  }
489
730
  if (!source.lastRunOutcome) {
490
- return `${displaySource(source.source, labels)}: installed`;
731
+ return `${displaySource(source.source, labels)}${authModeSuffix}: installed`;
491
732
  }
492
733
  if (source.lastRunOutcome === CliOutcomeStatus.NEEDS_INPUT) {
493
- return `${displaySource(source.source, labels)}: needs input`;
734
+ return `${displaySource(source.source, labels)}${authModeSuffix}: needs input`;
494
735
  }
495
736
  if (source.lastRunOutcome === CliOutcomeStatus.RUNTIME_ERROR) {
496
- return `${displaySource(source.source, labels)}: error`;
737
+ return `${displaySource(source.source, labels)}${authModeSuffix}: error`;
497
738
  }
498
739
  if (source.lastRunOutcome === CliOutcomeStatus.LEGACY_AUTH) {
499
- return `${displaySource(source.source, labels)}: legacy auth required`;
740
+ return `${displaySource(source.source, labels)}${authModeSuffix}: manual browser step required`;
500
741
  }
501
742
  if (source.dataState === "ingested_personal_server") {
502
- return `${displaySource(source.source, labels)}: connected, synced`;
743
+ return `${displaySource(source.source, labels)}${authModeSuffix}: connected, synced`;
503
744
  }
504
745
  if (source.dataState === "collected_local") {
505
- return `${displaySource(source.source, labels)}: connected, local only`;
746
+ return `${displaySource(source.source, labels)}${authModeSuffix}: connected, local only`;
506
747
  }
507
- return `${displaySource(source.source, labels)}: connected`;
748
+ return `${displaySource(source.source, labels)}${authModeSuffix}: connected`;
508
749
  }
509
750
  function formatSourceStatusDetail(source) {
510
751
  if (source.lastRunOutcome === CliOutcomeStatus.NEEDS_INPUT) {
@@ -513,7 +754,7 @@ function formatSourceStatusDetail(source) {
513
754
  : `Run \`vana connect ${source.source}\` interactively.`;
514
755
  }
515
756
  if (source.lastRunOutcome === CliOutcomeStatus.LEGACY_AUTH) {
516
- return "This source still uses legacy headed auth and cannot complete in batch mode.";
757
+ return `Run \`vana connect ${source.source}\` without \`--no-input\` to complete the manual browser step.`;
517
758
  }
518
759
  if (source.lastRunOutcome === CliOutcomeStatus.RUNTIME_ERROR) {
519
760
  return source.lastError ?? "The last connector run failed.";
@@ -553,9 +794,47 @@ function createSourceMetadataMap(sources) {
553
794
  name: source.name,
554
795
  company: source.company,
555
796
  description: source.description,
797
+ authMode: source.authMode,
556
798
  },
557
799
  ]));
558
800
  }
801
+ function formatAuthModeBadge(authMode, emit) {
802
+ if (authMode === "legacy") {
803
+ return ` ${emit ? emit.badge("legacy", "warning") : "[legacy]"}`;
804
+ }
805
+ if (authMode === "interactive") {
806
+ return ` ${emit ? emit.badge("interactive", "info") : "[interactive]"}`;
807
+ }
808
+ return "";
809
+ }
810
+ function toneForRuntime(runtime) {
811
+ if (runtime === "installed") {
812
+ return "success";
813
+ }
814
+ if (runtime === "missing") {
815
+ return "warning";
816
+ }
817
+ return "muted";
818
+ }
819
+ function inferInstalledAuthMode(installedFiles, source) {
820
+ const match = installedFiles.find((file) => file.source === source);
821
+ if (!match) {
822
+ return undefined;
823
+ }
824
+ try {
825
+ const script = fs.readFileSync(match.path, "utf8");
826
+ if (/page\.requestInput\(/.test(script)) {
827
+ return "interactive";
828
+ }
829
+ if (/page\.(showBrowser|promptUser)\(/.test(script)) {
830
+ return "legacy";
831
+ }
832
+ return "automated";
833
+ }
834
+ catch {
835
+ return undefined;
836
+ }
837
+ }
559
838
  async function loadRegistrySources() {
560
839
  try {
561
840
  return ((await listAvailableSources(findDataConnectorsDir() ?? undefined)) ?? []);
@@ -564,4 +843,44 @@ async function loadRegistrySources() {
564
843
  return [];
565
844
  }
566
845
  }
846
+ async function readResultSummary(resultPath) {
847
+ try {
848
+ const raw = await fsp.readFile(resultPath, "utf8");
849
+ return summarizeResultData(JSON.parse(raw));
850
+ }
851
+ catch {
852
+ return null;
853
+ }
854
+ }
855
+ function summarizeResultData(data) {
856
+ const lines = [];
857
+ const exportSummary = typeof data.exportSummary === "object" && data.exportSummary
858
+ ? data.exportSummary
859
+ : null;
860
+ const profile = typeof data.profile === "object" && data.profile
861
+ ? data.profile
862
+ : null;
863
+ if (profile?.username && typeof profile.username === "string") {
864
+ lines.push(`Profile: ${profile.username}`);
865
+ }
866
+ if (Array.isArray(data.repositories)) {
867
+ lines.push(`Repositories: ${data.repositories.length}`);
868
+ }
869
+ if (Array.isArray(data.starred)) {
870
+ lines.push(`Starred: ${data.starred.length}`);
871
+ }
872
+ if (Array.isArray(data.orders)) {
873
+ lines.push(`Orders: ${data.orders.length}`);
874
+ }
875
+ if (exportSummary?.details &&
876
+ typeof exportSummary.details === "string" &&
877
+ !lines.includes(exportSummary.details)) {
878
+ lines.push(exportSummary.details);
879
+ }
880
+ return lines.length > 0 ? { lines } : null;
881
+ }
882
+ function isPromptCancelled(error) {
883
+ return (error instanceof Error &&
884
+ (error.name === "ExitPromptError" || error.message.includes("SIGINT")));
885
+ }
567
886
  //# sourceMappingURL=index.js.map