@opendatalabs/connect 0.9.2 → 0.9.4-canary.888d13a
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/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +132 -58
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/update-check.d.ts +3 -3
- package/dist/cli/update-check.d.ts.map +1 -1
- package/dist/cli/update-check.js +43 -11
- package/dist/cli/update-check.js.map +1 -1
- package/dist/core/cli-types.d.ts +27 -0
- package/dist/core/cli-types.d.ts.map +1 -1
- package/dist/core/cli-types.js +6 -0
- package/dist/core/cli-types.js.map +1 -1
- package/dist/core/state-store.d.ts +3 -0
- package/dist/core/state-store.d.ts.map +1 -1
- package/dist/core/state-store.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/update-check-worker.d.ts +0 -2
- package/dist/cli/update-check-worker.d.ts.map +0 -1
- package/dist/cli/update-check-worker.js +0 -55
- package/dist/cli/update-check-worker.js.map +0 -1
package/dist/cli/index.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export declare function buildDataListNextSteps(datasetRecords: Array<{
|
|
|
40
40
|
authMode?: "automated" | "interactive" | "legacy";
|
|
41
41
|
}>): string[];
|
|
42
42
|
export declare function buildDataShowNextSteps(source: string, datasetCount: number, sourceLabels?: SourceLabelMap): string[];
|
|
43
|
+
/** Derive a human-readable message from a stored `connectionHealthReason`. */
|
|
44
|
+
export declare function formatHealthMessage(reason: string | undefined): string | null;
|
|
43
45
|
export declare function getCliVersion(): string;
|
|
44
46
|
export declare function getCliChannel(version?: string): "stable" | "canary";
|
|
45
47
|
export declare function getCliInstallMethod(execPath?: string): CliInstallMethod;
|
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":"AAuCA,OAAO,EAQL,YAAY,EAIb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACV,UAAU,EAEV,gBAAgB,EAEhB,SAAS,EACT,YAAY,EACb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAyCjE,UAAU,cAAc;IACtB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED,UAAU,iBAAiB;IACzB,CAAC,MAAM,EAAE,MAAM,GAAG;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,QAAQ,CAAC;KACnD,CAAC;CACH;AA2BD,KAAK,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAehF,wBAAsB,MAAM,CAAC,IAAI,WAAe,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
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
|
@@ -33,7 +33,7 @@ import { detectPersonalServerTarget, ingestResult, } from "../personal-server/in
|
|
|
33
33
|
import { findDataConnectorsDir, ManagedPlaywrightRuntime, } from "../runtime/index.js";
|
|
34
34
|
import { listAvailableSkills, installSkill, readInstalledSkills, } from "../skills/index.js";
|
|
35
35
|
import { queryStatus, querySources, queryDataList, queryDataShow, queryDoctor, } from "./queries.js";
|
|
36
|
-
import { readUpdateCheck, isNewerVersion,
|
|
36
|
+
import { checkForUpdate, readUpdateCheck, isNewerVersion, } from "./update-check.js";
|
|
37
37
|
function cleanDescription(desc) {
|
|
38
38
|
return desc
|
|
39
39
|
.replace(/ using Playwright browser automation\.?/i, ".")
|
|
@@ -51,6 +51,7 @@ export async function runCli(argv = process.argv) {
|
|
|
51
51
|
}
|
|
52
52
|
const parsedOptions = extractGlobalOptions(normalizedArgv);
|
|
53
53
|
const cliVersion = getCliVersion();
|
|
54
|
+
const installMethod = getCliInstallMethod();
|
|
54
55
|
// Non-blocking update check — compute suppression flags early
|
|
55
56
|
const shouldNotify = !parsedOptions.json &&
|
|
56
57
|
process.stdout.isTTY &&
|
|
@@ -58,23 +59,12 @@ export async function runCli(argv = process.argv) {
|
|
|
58
59
|
!process.env.CI &&
|
|
59
60
|
!process.env.AGENT &&
|
|
60
61
|
!process.env.VANA_DETACHED;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
updateNotice = `\nUpdate available: ${cliVersion} → ${cached.latestVersion}\nRun: ${lifecycle.upgrade}\n`;
|
|
68
|
-
}
|
|
69
|
-
else if (!cached) {
|
|
70
|
-
// Cache missing or expired — spawn background check
|
|
71
|
-
spawnUpdateCheck(cliVersion, getCliInstallMethod());
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
// Suppress all errors — update check is purely informational
|
|
76
|
-
}
|
|
77
|
-
}
|
|
62
|
+
// Fire update check concurrently — no await, runs in the background.
|
|
63
|
+
// If it finishes before the command completes, the cache is written and
|
|
64
|
+
// the SAME run can read it for the notification below.
|
|
65
|
+
const updateCheckPromise = shouldNotify
|
|
66
|
+
? checkForUpdate(cliVersion, installMethod).catch(() => { })
|
|
67
|
+
: undefined;
|
|
78
68
|
const program = new Command();
|
|
79
69
|
program
|
|
80
70
|
.name("vana")
|
|
@@ -415,29 +405,41 @@ Examples:
|
|
|
415
405
|
process.exitCode = await runScheduleRemove(parsedOptions);
|
|
416
406
|
});
|
|
417
407
|
try {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (error
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
error.code === "commander.version") {
|
|
426
|
-
process.exitCode = error.exitCode;
|
|
427
|
-
return Number(process.exitCode ?? 0);
|
|
428
|
-
}
|
|
429
|
-
// Commander already printed to stderr; just set exit code.
|
|
408
|
+
await program.parseAsync(normalizedArgv);
|
|
409
|
+
}
|
|
410
|
+
catch (error) {
|
|
411
|
+
if (error instanceof CommanderError) {
|
|
412
|
+
if (error.code === "commander.help" ||
|
|
413
|
+
error.code === "commander.helpDisplayed" ||
|
|
414
|
+
error.code === "commander.version") {
|
|
430
415
|
process.exitCode = error.exitCode;
|
|
431
|
-
return Number(process.exitCode ??
|
|
416
|
+
return Number(process.exitCode ?? 0);
|
|
432
417
|
}
|
|
433
|
-
|
|
418
|
+
// Commander already printed to stderr; just set exit code.
|
|
419
|
+
process.exitCode = error.exitCode;
|
|
420
|
+
return Number(process.exitCode ?? 1);
|
|
434
421
|
}
|
|
435
|
-
|
|
422
|
+
throw error;
|
|
436
423
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
424
|
+
// Show update notification if a newer version is available.
|
|
425
|
+
// The concurrent check may have populated the cache during this run.
|
|
426
|
+
if (shouldNotify) {
|
|
427
|
+
try {
|
|
428
|
+
await Promise.race([
|
|
429
|
+
updateCheckPromise,
|
|
430
|
+
new Promise((resolve) => setTimeout(resolve, 2000)),
|
|
431
|
+
]);
|
|
432
|
+
const cache = await readUpdateCheck();
|
|
433
|
+
if (cache && isNewerVersion(cliVersion, cache.latestVersion)) {
|
|
434
|
+
const { upgrade } = getLifecycleCommands(installMethod, getCliChannel(cliVersion));
|
|
435
|
+
process.stderr.write(`\nUpdate available: ${cliVersion} → ${cache.latestVersion}\nRun: ${upgrade}\n`);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
// Never block exit for update notification failures
|
|
440
|
+
}
|
|
440
441
|
}
|
|
442
|
+
return Number(process.exitCode ?? 0);
|
|
441
443
|
}
|
|
442
444
|
async function runConnect(rawSource, options) {
|
|
443
445
|
const source = rawSource.toLowerCase();
|
|
@@ -450,7 +452,7 @@ async function runConnect(rawSource, options) {
|
|
|
450
452
|
let setupLogPath;
|
|
451
453
|
let fetchLogPath;
|
|
452
454
|
let runLogPath;
|
|
453
|
-
let
|
|
455
|
+
let pendingExitCode = null;
|
|
454
456
|
try {
|
|
455
457
|
// Title
|
|
456
458
|
renderer?.title(displayName);
|
|
@@ -688,7 +690,7 @@ async function runConnect(rawSource, options) {
|
|
|
688
690
|
if (event.logPath) {
|
|
689
691
|
runLogPath = event.logPath;
|
|
690
692
|
}
|
|
691
|
-
if (
|
|
693
|
+
if (pendingExitCode !== null && event.type !== "collection-complete") {
|
|
692
694
|
continue;
|
|
693
695
|
}
|
|
694
696
|
if (event.type === "needs-input") {
|
|
@@ -698,6 +700,9 @@ async function runConnect(rawSource, options) {
|
|
|
698
700
|
lastError: event.message ?? "Input required.",
|
|
699
701
|
lastLogPath: event.logPath,
|
|
700
702
|
connectionHealth: "needs_reauth",
|
|
703
|
+
connectionHealthChangedAt: new Date().toISOString(),
|
|
704
|
+
connectionHealthReason: `needs-input: ${event.message ?? "Input required."}`,
|
|
705
|
+
connectionHealthRetryable: false,
|
|
701
706
|
});
|
|
702
707
|
emit.event({
|
|
703
708
|
type: "outcome",
|
|
@@ -705,8 +710,7 @@ async function runConnect(rawSource, options) {
|
|
|
705
710
|
source: resolution.source,
|
|
706
711
|
});
|
|
707
712
|
renderer?.fail(`${displayName} needs credentials. Run without --no-input to authenticate.`);
|
|
708
|
-
|
|
709
|
-
continue;
|
|
713
|
+
pendingExitCode = 1;
|
|
710
714
|
}
|
|
711
715
|
if (event.type === "progress-update") {
|
|
712
716
|
// Drive the renderer with scope information from the event
|
|
@@ -735,6 +739,9 @@ async function runConnect(rawSource, options) {
|
|
|
735
739
|
lastError: event.message ?? "Connector run failed.",
|
|
736
740
|
lastLogPath: event.logPath,
|
|
737
741
|
connectionHealth: "error",
|
|
742
|
+
connectionHealthChangedAt: new Date().toISOString(),
|
|
743
|
+
connectionHealthReason: `runtime-error: ${event.message ?? "Connector run failed."}`,
|
|
744
|
+
connectionHealthRetryable: /timeout|ECONNREFUSED|ENOTFOUND|rate.?limit|50[234]|socket hang up/i.test(event.message ?? ""),
|
|
738
745
|
});
|
|
739
746
|
renderer?.fail(`Problem connecting ${displayName}.`);
|
|
740
747
|
renderer?.detail(event.message ?? "Connector run failed.");
|
|
@@ -744,7 +751,7 @@ async function runConnect(rawSource, options) {
|
|
|
744
751
|
status: CliOutcomeStatus.RUNTIME_ERROR,
|
|
745
752
|
source: resolution.source,
|
|
746
753
|
});
|
|
747
|
-
|
|
754
|
+
pendingExitCode = 1;
|
|
748
755
|
continue;
|
|
749
756
|
}
|
|
750
757
|
if (event.type === "headed-required") {
|
|
@@ -760,6 +767,9 @@ async function runConnect(rawSource, options) {
|
|
|
760
767
|
lastResultPath: null,
|
|
761
768
|
lastLogPath: event.logPath,
|
|
762
769
|
connectionHealth: "needs_reauth",
|
|
770
|
+
connectionHealthChangedAt: new Date().toISOString(),
|
|
771
|
+
connectionHealthReason: `legacy-auth: ${event.message ?? "Legacy authentication is required."}`,
|
|
772
|
+
connectionHealthRetryable: false,
|
|
763
773
|
});
|
|
764
774
|
renderer?.fail(`Manual step required for ${displayName}.`);
|
|
765
775
|
renderer?.detail(`Complete the browser step locally, then rerun vana connect ${source}.`);
|
|
@@ -768,8 +778,7 @@ async function runConnect(rawSource, options) {
|
|
|
768
778
|
status: CliOutcomeStatus.LEGACY_AUTH,
|
|
769
779
|
source: resolution.source,
|
|
770
780
|
});
|
|
771
|
-
|
|
772
|
-
continue;
|
|
781
|
+
pendingExitCode = 1;
|
|
773
782
|
}
|
|
774
783
|
if (event.type === "collection-complete" && event.resultPath) {
|
|
775
784
|
// Check if the result is actually an error object
|
|
@@ -781,13 +790,17 @@ async function runConnect(rawSource, options) {
|
|
|
781
790
|
"error" in parsed &&
|
|
782
791
|
Object.keys(parsed).length <= 2) {
|
|
783
792
|
// Connector returned an error, not real data
|
|
793
|
+
const errorMsg = typeof parsed.error === "string"
|
|
794
|
+
? parsed.error
|
|
795
|
+
: "Collection returned an error";
|
|
784
796
|
await updateSourceState(source, {
|
|
785
797
|
lastRunAt: new Date().toISOString(),
|
|
786
798
|
lastRunOutcome: CliOutcomeStatus.RUNTIME_ERROR,
|
|
787
799
|
connectionHealth: "error",
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
800
|
+
connectionHealthChangedAt: new Date().toISOString(),
|
|
801
|
+
connectionHealthReason: `error-result: ${errorMsg}`,
|
|
802
|
+
connectionHealthRetryable: false,
|
|
803
|
+
lastError: errorMsg,
|
|
791
804
|
lastLogPath: runLogPath ?? fetchLogPath,
|
|
792
805
|
});
|
|
793
806
|
renderer?.fail(`Problem connecting ${displayName}.`);
|
|
@@ -799,12 +812,15 @@ async function runConnect(rawSource, options) {
|
|
|
799
812
|
status: CliOutcomeStatus.RUNTIME_ERROR,
|
|
800
813
|
source,
|
|
801
814
|
});
|
|
802
|
-
|
|
815
|
+
pendingExitCode = 1;
|
|
803
816
|
continue;
|
|
804
817
|
}
|
|
805
818
|
}
|
|
806
|
-
catch {
|
|
807
|
-
|
|
819
|
+
catch (parseError) {
|
|
820
|
+
const msg = parseError instanceof Error ? parseError.message : "Unknown error";
|
|
821
|
+
await updateSourceState(source, {
|
|
822
|
+
lastError: `Failed to parse result file (${event.resultPath}): ${msg}`,
|
|
823
|
+
});
|
|
808
824
|
}
|
|
809
825
|
collectedResult = true;
|
|
810
826
|
resultPath = event.resultPath;
|
|
@@ -845,8 +861,8 @@ async function runConnect(rawSource, options) {
|
|
|
845
861
|
}));
|
|
846
862
|
}
|
|
847
863
|
}
|
|
848
|
-
if (
|
|
849
|
-
return
|
|
864
|
+
if (pendingExitCode !== null && !collectedResult) {
|
|
865
|
+
return pendingExitCode;
|
|
850
866
|
}
|
|
851
867
|
if (!collectedResult) {
|
|
852
868
|
await updateSourceState(resolution.source, {
|
|
@@ -881,7 +897,10 @@ async function runConnect(rawSource, options) {
|
|
|
881
897
|
lastError: ingestFailureMessage,
|
|
882
898
|
lastResultPath: resultPath,
|
|
883
899
|
lastLogPath: runLogPath ?? fetchLogPath ?? setupLogPath ?? null,
|
|
884
|
-
connectionHealth: "healthy",
|
|
900
|
+
connectionHealth: pendingExitCode !== null ? undefined : "healthy",
|
|
901
|
+
connectionHealthChangedAt: pendingExitCode !== null ? undefined : new Date().toISOString(),
|
|
902
|
+
connectionHealthReason: pendingExitCode !== null ? undefined : "collection-complete",
|
|
903
|
+
connectionHealthRetryable: undefined,
|
|
885
904
|
ingestScopes: ingestScopeResults,
|
|
886
905
|
});
|
|
887
906
|
// Build scope-aware success summary
|
|
@@ -904,6 +923,8 @@ async function runConnect(rawSource, options) {
|
|
|
904
923
|
else {
|
|
905
924
|
successSummary = `Collected your ${displayName} data and saved it locally.`;
|
|
906
925
|
}
|
|
926
|
+
// Auto-schedule collection if no schedule exists (non-blocking)
|
|
927
|
+
await maybeAutoSchedule(emit, options).catch(() => { });
|
|
907
928
|
// --- Phase 7: Success summary ---
|
|
908
929
|
renderer?.success(`Connected ${displayName}.`);
|
|
909
930
|
renderer?.detail(successSummary);
|
|
@@ -941,9 +962,9 @@ async function runConnect(rawSource, options) {
|
|
|
941
962
|
source: resolution.source,
|
|
942
963
|
resultPath,
|
|
943
964
|
});
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
965
|
+
if (pendingExitCode !== null) {
|
|
966
|
+
return pendingExitCode;
|
|
967
|
+
}
|
|
947
968
|
return 0;
|
|
948
969
|
}
|
|
949
970
|
catch (error) {
|
|
@@ -1120,7 +1141,12 @@ async function runStatus(options) {
|
|
|
1120
1141
|
if (stored) {
|
|
1121
1142
|
sourceHealthMap[sourceId] = {
|
|
1122
1143
|
connectionHealth: stored.connectionHealth,
|
|
1144
|
+
connectionHealthChangedAt: stored.connectionHealthChangedAt,
|
|
1145
|
+
connectionHealthReason: stored.connectionHealthReason,
|
|
1146
|
+
connectionHealthRetryable: stored.connectionHealthRetryable,
|
|
1123
1147
|
lastCollectedAt: stored.lastCollectedAt,
|
|
1148
|
+
lastLogPath: stored.lastLogPath,
|
|
1149
|
+
lastError: stored.lastError,
|
|
1124
1150
|
};
|
|
1125
1151
|
}
|
|
1126
1152
|
}
|
|
@@ -1187,6 +1213,16 @@ async function runStatus(options) {
|
|
|
1187
1213
|
? `collected ${formatRelativeTime(stored.lastCollectedAt)}`
|
|
1188
1214
|
: "";
|
|
1189
1215
|
emit.keyValue(` ${displayName}`, `${healthLabel}${staleTag} ${collectedAgo}`, healthTone);
|
|
1216
|
+
if ((health === "needs_reauth" || health === "error") &&
|
|
1217
|
+
stored?.connectionHealthReason) {
|
|
1218
|
+
const msg = formatHealthMessage(stored.connectionHealthReason);
|
|
1219
|
+
const ago = stored.connectionHealthChangedAt
|
|
1220
|
+
? ` (${formatRelativeTime(stored.connectionHealthChangedAt)})`
|
|
1221
|
+
: "";
|
|
1222
|
+
if (msg) {
|
|
1223
|
+
emit.detail(` \u21b3 ${msg}${ago} Run \`vana connect ${sourceId}\``);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1190
1226
|
if (health === "needs_reauth" && !needsReauthSource) {
|
|
1191
1227
|
needsReauthSource = sourceId;
|
|
1192
1228
|
}
|
|
@@ -2038,14 +2074,16 @@ async function runServerData(scope, options) {
|
|
|
2038
2074
|
}
|
|
2039
2075
|
// If PS is available, try to list remote scopes via client
|
|
2040
2076
|
let remoteScopes = [];
|
|
2077
|
+
let remoteScopeFallbackReason;
|
|
2041
2078
|
if (target.state === "available" && target.url) {
|
|
2042
2079
|
try {
|
|
2043
2080
|
const { createPersonalServerClient: createClient } = await import("../personal-server/client.js");
|
|
2044
2081
|
const client = createClient({ url: target.url });
|
|
2045
2082
|
remoteScopes = await client.listScopes(scope);
|
|
2046
2083
|
}
|
|
2047
|
-
catch {
|
|
2048
|
-
|
|
2084
|
+
catch (err) {
|
|
2085
|
+
remoteScopeFallbackReason =
|
|
2086
|
+
err instanceof Error ? err.message : "unknown error";
|
|
2049
2087
|
}
|
|
2050
2088
|
}
|
|
2051
2089
|
// Use remote scopes if available, otherwise fall back to local
|
|
@@ -2063,6 +2101,7 @@ async function runServerData(scope, options) {
|
|
|
2063
2101
|
count: scopeList.length,
|
|
2064
2102
|
scopes: scopeList,
|
|
2065
2103
|
source: remoteScopes.length > 0 ? "remote" : "local",
|
|
2104
|
+
...(remoteScopeFallbackReason ? { remoteScopeFallbackReason } : {}),
|
|
2066
2105
|
})}\n`);
|
|
2067
2106
|
return 0;
|
|
2068
2107
|
}
|
|
@@ -2321,6 +2360,10 @@ export async function gatherSourceStatuses(storedSources, metadata = {}) {
|
|
|
2321
2360
|
connectorVersion: stored.connectorVersion,
|
|
2322
2361
|
exportFrequency: stored.exportFrequency,
|
|
2323
2362
|
lastCollectedAt: stored.lastCollectedAt,
|
|
2363
|
+
connectionHealth: stored.connectionHealth,
|
|
2364
|
+
connectionHealthChangedAt: stored.connectionHealthChangedAt,
|
|
2365
|
+
connectionHealthReason: stored.connectionHealthReason,
|
|
2366
|
+
connectionHealthRetryable: stored.connectionHealthRetryable,
|
|
2324
2367
|
installed,
|
|
2325
2368
|
sessionPresent: stored.sessionPresent ?? false,
|
|
2326
2369
|
lastRunAt: stored.lastRunAt ?? null,
|
|
@@ -2472,6 +2515,14 @@ function formatSourceStatusDetails(source) {
|
|
|
2472
2515
|
tone: "muted",
|
|
2473
2516
|
});
|
|
2474
2517
|
}
|
|
2518
|
+
if (source.connectionHealthReason && source.connectionHealth !== "healthy") {
|
|
2519
|
+
details.push({
|
|
2520
|
+
kind: "row",
|
|
2521
|
+
label: "Cause",
|
|
2522
|
+
value: source.connectionHealthReason,
|
|
2523
|
+
tone: "muted",
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2475
2526
|
if (source.lastRunAt) {
|
|
2476
2527
|
details.push({
|
|
2477
2528
|
kind: "row",
|
|
@@ -2632,6 +2683,28 @@ function buildLogsNextSteps(records) {
|
|
|
2632
2683
|
"Check overall status with `vana status`.",
|
|
2633
2684
|
];
|
|
2634
2685
|
}
|
|
2686
|
+
/** Derive a human-readable message from a stored `connectionHealthReason`. */
|
|
2687
|
+
export function formatHealthMessage(reason) {
|
|
2688
|
+
if (!reason)
|
|
2689
|
+
return null;
|
|
2690
|
+
const colonIndex = reason.indexOf(": ");
|
|
2691
|
+
const prefix = colonIndex > 0 ? reason.slice(0, colonIndex) : reason;
|
|
2692
|
+
const detail = colonIndex > 0 ? reason.slice(colonIndex + 2).replace(/\.$/, "") : "";
|
|
2693
|
+
switch (prefix) {
|
|
2694
|
+
case "needs-input":
|
|
2695
|
+
return `Requires interactive login${detail ? `: ${detail}` : ""}.`;
|
|
2696
|
+
case "legacy-auth":
|
|
2697
|
+
return `Needed a browser window${detail ? `: ${detail}` : ""}. Reconnect interactively.`;
|
|
2698
|
+
case "runtime-error":
|
|
2699
|
+
return `Collection failed${detail ? ` — ${detail}` : ""}.`;
|
|
2700
|
+
case "error-result":
|
|
2701
|
+
return `Connector returned an error${detail ? `: ${detail}` : ""}.`;
|
|
2702
|
+
case "collection-complete":
|
|
2703
|
+
return null; // No message needed for healthy state
|
|
2704
|
+
default:
|
|
2705
|
+
return reason; // Graceful fallback for unknown prefixes
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2635
2708
|
/** Extract a `vana ...` command from a next-step sentence wrapped in backticks. */
|
|
2636
2709
|
function extractCommand(sentence) {
|
|
2637
2710
|
const match = sentence.match(/`(vana\s[^`]+)`/);
|
|
@@ -3280,7 +3353,7 @@ async function getExistingScheduleInterval() {
|
|
|
3280
3353
|
}
|
|
3281
3354
|
return null;
|
|
3282
3355
|
}
|
|
3283
|
-
async function maybeAutoSchedule(options) {
|
|
3356
|
+
async function maybeAutoSchedule(emit, options) {
|
|
3284
3357
|
// Skip if --no-input (detached/agent context shouldn't create schedules)
|
|
3285
3358
|
if (options.noInput)
|
|
3286
3359
|
return;
|
|
@@ -3291,6 +3364,7 @@ async function maybeAutoSchedule(options) {
|
|
|
3291
3364
|
if (existing !== null)
|
|
3292
3365
|
return; // Schedule already exists
|
|
3293
3366
|
await runScheduleAdd("daily", { json: false, quiet: true });
|
|
3367
|
+
emit.detail("Auto-scheduled daily collection.");
|
|
3294
3368
|
}
|
|
3295
3369
|
function generateLaunchdPlist(vanaBinary, intervalSeconds) {
|
|
3296
3370
|
const logsPath = path.join(getLogsDir(), "schedule.log");
|