@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.
- package/README.md +73 -5
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +346 -27
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/render/capabilities.d.ts +9 -0
- package/dist/cli/render/capabilities.d.ts.map +1 -0
- package/dist/cli/render/capabilities.js +24 -0
- package/dist/cli/render/capabilities.js.map +1 -0
- package/dist/cli/render/format.d.ts +20 -0
- package/dist/cli/render/format.d.ts.map +1 -0
- package/dist/cli/render/format.js +58 -0
- package/dist/cli/render/format.js.map +1 -0
- package/dist/cli/render/index.d.ts +5 -0
- package/dist/cli/render/index.d.ts.map +1 -0
- package/dist/cli/render/index.js +5 -0
- package/dist/cli/render/index.js.map +1 -0
- package/dist/cli/render/symbols.d.ts +11 -0
- package/dist/cli/render/symbols.d.ts.map +1 -0
- package/dist/cli/render/symbols.js +21 -0
- package/dist/cli/render/symbols.js.map +1 -0
- package/dist/cli/render/theme.d.ts +15 -0
- package/dist/cli/render/theme.d.ts.map +1 -0
- package/dist/cli/render/theme.js +17 -0
- package/dist/cli/render/theme.js.map +1 -0
- package/dist/connectors/registry.d.ts +1 -0
- package/dist/connectors/registry.d.ts.map +1 -1
- package/dist/connectors/registry.js +34 -2
- package/dist/connectors/registry.js.map +1 -1
- package/dist/core/cli-types.d.ts +13 -0
- package/dist/core/cli-types.d.ts.map +1 -1
- package/dist/core/cli-types.js +3 -0
- package/dist/core/cli-types.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/paths.d.ts +0 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +0 -3
- package/dist/core/paths.js.map +1 -1
- package/dist/core/state-store.d.ts +1 -0
- package/dist/core/state-store.d.ts.map +1 -1
- package/dist/core/state-store.js.map +1 -1
- package/dist/runtime/core/contracts.d.ts +69 -0
- package/dist/runtime/core/contracts.d.ts.map +1 -0
- package/dist/runtime/core/contracts.js +2 -0
- package/dist/runtime/core/contracts.js.map +1 -0
- package/dist/runtime/core/index.d.ts +2 -0
- package/dist/runtime/core/index.d.ts.map +1 -0
- package/dist/runtime/core/index.js +2 -0
- package/dist/runtime/core/index.js.map +1 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/managed-playwright.d.ts +2 -2
- package/dist/runtime/managed-playwright.d.ts.map +1 -1
- package/dist/runtime/managed-playwright.js +59 -209
- package/dist/runtime/managed-playwright.js.map +1 -1
- package/dist/runtime/playwright/browser.d.ts +11 -0
- package/dist/runtime/playwright/browser.d.ts.map +1 -0
- package/dist/runtime/playwright/browser.js +208 -0
- package/dist/runtime/playwright/browser.js.map +1 -0
- package/dist/runtime/playwright/in-process-run.d.ts +6 -0
- package/dist/runtime/playwright/in-process-run.d.ts.map +1 -0
- package/dist/runtime/playwright/in-process-run.js +534 -0
- package/dist/runtime/playwright/in-process-run.js.map +1 -0
- package/dist/runtime/playwright/index.d.ts +3 -0
- package/dist/runtime/playwright/index.d.ts.map +1 -0
- package/dist/runtime/playwright/index.js +3 -0
- package/dist/runtime/playwright/index.js.map +1 -0
- package/dist/runtime/repo-paths.d.ts.map +1 -1
- package/dist/runtime/repo-paths.js +24 -7
- package/dist/runtime/repo-paths.js.map +1 -1
- package/package.json +21 -9
- 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
|
-
|
|
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
|
-
|
|
86
|
+
brew tap vana-com/vana
|
|
87
|
+
brew install vana
|
|
85
88
|
```
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
macOS and Linux:
|
|
88
91
|
|
|
89
92
|
```bash
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
package/dist/cli/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
211
|
-
emit.info(`Next:
|
|
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
|
|
331
|
-
|
|
332
|
-
|
|
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.
|
|
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.
|
|
357
|
-
emit.
|
|
358
|
-
emit.
|
|
359
|
-
emit.
|
|
360
|
-
emit.
|
|
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.
|
|
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)}:
|
|
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
|
|
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
|