@buda-ai/connector 0.1.11 → 0.1.14
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.js +83 -38
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -517,7 +517,7 @@ import path2 from "path";
|
|
|
517
517
|
// package.json
|
|
518
518
|
var package_default = {
|
|
519
519
|
name: "@buda-ai/connector",
|
|
520
|
-
version: "0.1.
|
|
520
|
+
version: "0.1.14",
|
|
521
521
|
private: false,
|
|
522
522
|
type: "module",
|
|
523
523
|
publishConfig: {
|
|
@@ -2357,6 +2357,20 @@ async function registerConnector(config, launchConfig, bunnyDaemon, options) {
|
|
|
2357
2357
|
relayProtocol: result.relayProtocol
|
|
2358
2358
|
};
|
|
2359
2359
|
}
|
|
2360
|
+
async function registerConnectorForExplicitEnrollment(config, launchConfig, bunnyDaemon) {
|
|
2361
|
+
try {
|
|
2362
|
+
return await registerConnector(config, launchConfig, bunnyDaemon);
|
|
2363
|
+
} catch (error) {
|
|
2364
|
+
const hasSpaceToken = Boolean(config.token?.trim() || getConnectorToken(launchConfig));
|
|
2365
|
+
const hasOauthToken = Boolean(launchConfig?.oauthToken?.trim());
|
|
2366
|
+
if (!(error instanceof ConnectorDeletedError) || !hasSpaceToken || hasOauthToken) {
|
|
2367
|
+
throw error;
|
|
2368
|
+
}
|
|
2369
|
+
return registerConnector(config, launchConfig, bunnyDaemon, {
|
|
2370
|
+
recoverMissingProfile: true
|
|
2371
|
+
});
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2360
2374
|
async function heartbeatConnector(config, launchConfig, bunnyDaemon) {
|
|
2361
2375
|
const logs = takePendingLogs();
|
|
2362
2376
|
const result = await postJson(
|
|
@@ -2545,13 +2559,14 @@ var isProcessAlive2 = (pid) => {
|
|
|
2545
2559
|
return !(typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH");
|
|
2546
2560
|
}
|
|
2547
2561
|
};
|
|
2548
|
-
var getRuntimeCommandArgs = (runtime, mode) => [
|
|
2562
|
+
var getRuntimeCommandArgs = (runtime, mode, options = {}) => [
|
|
2549
2563
|
...runtime.nodeArgs ?? [],
|
|
2550
2564
|
runtime.entrypoint,
|
|
2551
2565
|
"daemon",
|
|
2552
2566
|
"--internal-daemon",
|
|
2553
2567
|
"--daemon-mode",
|
|
2554
2568
|
mode,
|
|
2569
|
+
...options.explicitEnrollment ? ["--explicit-enrollment"] : [],
|
|
2555
2570
|
"--plain"
|
|
2556
2571
|
];
|
|
2557
2572
|
var compareVersions = (left, right) => {
|
|
@@ -2578,9 +2593,9 @@ var waitForDaemon = async (launchConfig, deadline) => {
|
|
|
2578
2593
|
lastConfig ? "Connector daemon did not expose its control channel in time" : "Connector registration did not create a canonical local identity in time"
|
|
2579
2594
|
);
|
|
2580
2595
|
};
|
|
2581
|
-
var spawnInternalDaemon = async (launchConfig, mode, preparedRuntime) => {
|
|
2596
|
+
var spawnInternalDaemon = async (launchConfig, mode, preparedRuntime, options = {}) => {
|
|
2582
2597
|
const runtime = preparedRuntime ?? await ensureStableConnectorRuntime();
|
|
2583
|
-
const child = spawn(runtime.nodeExecutable, getRuntimeCommandArgs(runtime, mode), {
|
|
2598
|
+
const child = spawn(runtime.nodeExecutable, getRuntimeCommandArgs(runtime, mode, options), {
|
|
2584
2599
|
detached: true,
|
|
2585
2600
|
env: {
|
|
2586
2601
|
...process.env,
|
|
@@ -2603,7 +2618,7 @@ var stopOlderIdleDaemon = async (config, status) => {
|
|
|
2603
2618
|
}
|
|
2604
2619
|
throw new Error("Older Connector daemon did not stop cleanly; existing identity was preserved");
|
|
2605
2620
|
};
|
|
2606
|
-
async function ensureConnectorDaemon(launchConfig, mode) {
|
|
2621
|
+
async function ensureConnectorDaemon(launchConfig, mode, options = {}) {
|
|
2607
2622
|
const deviceId = await getOrCreateSystemDeviceId(getConfigRoot());
|
|
2608
2623
|
const scope = await resolveConnectorScope(deviceId, launchConfig);
|
|
2609
2624
|
launchConfig = { ...launchConfig, spaceId: scope.spaceId };
|
|
@@ -2623,7 +2638,7 @@ async function ensureConnectorDaemon(launchConfig, mode) {
|
|
|
2623
2638
|
const status = mode === "persistent" ? await requestDaemonControl(existingConfig, "persist", getConfigRoot()) : existingStatus;
|
|
2624
2639
|
return { config: existingConfig, status };
|
|
2625
2640
|
}
|
|
2626
|
-
await spawnInternalDaemon(launchConfig, mode, preparedRuntime);
|
|
2641
|
+
await spawnInternalDaemon(launchConfig, mode, preparedRuntime, options);
|
|
2627
2642
|
return await waitForDaemon(launchConfig, Date.now() + START_TIMEOUT_MS);
|
|
2628
2643
|
}
|
|
2629
2644
|
const persistedStatus = await readPersistedDaemonStatus(
|
|
@@ -2636,7 +2651,7 @@ async function ensureConnectorDaemon(launchConfig, mode) {
|
|
|
2636
2651
|
);
|
|
2637
2652
|
}
|
|
2638
2653
|
}
|
|
2639
|
-
await spawnInternalDaemon(launchConfig, mode);
|
|
2654
|
+
await spawnInternalDaemon(launchConfig, mode, void 0, options);
|
|
2640
2655
|
return await waitForDaemon(launchConfig, Date.now() + START_TIMEOUT_MS);
|
|
2641
2656
|
} finally {
|
|
2642
2657
|
await bootstrapLock.release();
|
|
@@ -2780,7 +2795,9 @@ async function runConnectorDashboard(launchConfig, options = {}) {
|
|
|
2780
2795
|
plain: options.plain
|
|
2781
2796
|
});
|
|
2782
2797
|
if (!dashboard) {
|
|
2783
|
-
const { config } = await ensureConnectorDaemon(launchConfig, "persistent"
|
|
2798
|
+
const { config } = await ensureConnectorDaemon(launchConfig, "persistent", {
|
|
2799
|
+
explicitEnrollment: true
|
|
2800
|
+
});
|
|
2784
2801
|
const stopLogs2 = streamDaemonLogs({
|
|
2785
2802
|
connectorId: config.connectorId,
|
|
2786
2803
|
dashboardActive: false,
|
|
@@ -2835,7 +2852,7 @@ async function runConnectorDashboard(launchConfig, options = {}) {
|
|
|
2835
2852
|
preferredConnectorId = config.connectorId;
|
|
2836
2853
|
}).catch(() => void 0).finally(() => refresh());
|
|
2837
2854
|
const timer = setInterval(() => void refresh(), 1e3);
|
|
2838
|
-
void ensureConnectorDaemon(launchConfig, "persistent").then(async ({ config }) => {
|
|
2855
|
+
void ensureConnectorDaemon(launchConfig, "persistent", { explicitEnrollment: true }).then(async ({ config }) => {
|
|
2839
2856
|
pendingConnector = void 0;
|
|
2840
2857
|
preferredConnectorId = config.connectorId;
|
|
2841
2858
|
await refresh();
|
|
@@ -3003,13 +3020,12 @@ var createTerminalSession = async (grant, nodePtyLoader) => {
|
|
|
3003
3020
|
try {
|
|
3004
3021
|
nodePty = await nodePtyLoader();
|
|
3005
3022
|
} catch (error) {
|
|
3023
|
+
const message = serializeErrorMessage(error);
|
|
3006
3024
|
void writeLog(
|
|
3007
3025
|
"error",
|
|
3008
3026
|
`local terminal could not load node-pty: ${serializeErrorMessage(error)}`
|
|
3009
3027
|
);
|
|
3010
|
-
throw new LocalTerminalUnavailableError(
|
|
3011
|
-
"Local terminal is unavailable because node-pty could not be loaded. The connector remains available for other capabilities."
|
|
3012
|
-
);
|
|
3028
|
+
throw new LocalTerminalUnavailableError(message);
|
|
3013
3029
|
}
|
|
3014
3030
|
const shell = process.platform === "win32" ? "powershell.exe" : process.env.SHELL || "/bin/bash";
|
|
3015
3031
|
const shellArgs = process.platform === "win32" ? [] : ["-l"];
|
|
@@ -3196,17 +3212,13 @@ var proxyConnectorTerminalTunnel = async (input) => {
|
|
|
3196
3212
|
headers: { "X-Buda-Local-Terminal-Token": input.localToken },
|
|
3197
3213
|
handshakeTimeout: TERMINAL_HANDSHAKE_TIMEOUT_MS
|
|
3198
3214
|
});
|
|
3199
|
-
try {
|
|
3200
|
-
await Promise.all([connectSocket(cloud), connectSocket(local)]);
|
|
3201
|
-
} catch (error) {
|
|
3202
|
-
cloud.terminate();
|
|
3203
|
-
local.terminate();
|
|
3204
|
-
throw error;
|
|
3205
|
-
}
|
|
3206
3215
|
let bridgeAccepted = false;
|
|
3216
|
+
let activityStarted = false;
|
|
3207
3217
|
let activityEnded = false;
|
|
3218
|
+
let localCloseAfterBridge = null;
|
|
3219
|
+
let localCloseAfterOpen = null;
|
|
3208
3220
|
const endActivity = () => {
|
|
3209
|
-
if (activityEnded) return;
|
|
3221
|
+
if (!activityStarted || activityEnded) return;
|
|
3210
3222
|
activityEnded = true;
|
|
3211
3223
|
input.onActivityEnd?.();
|
|
3212
3224
|
};
|
|
@@ -3228,7 +3240,9 @@ var proxyConnectorTerminalTunnel = async (input) => {
|
|
|
3228
3240
|
if (!bridgeAccepted) {
|
|
3229
3241
|
if (!isBinary && data.toString() === '{"type":"bridge-accepted"}') {
|
|
3230
3242
|
bridgeAccepted = true;
|
|
3231
|
-
local.
|
|
3243
|
+
if (local.readyState === WebSocket.OPEN) {
|
|
3244
|
+
local.send(JSON.stringify({ type: "bridge-start" }));
|
|
3245
|
+
}
|
|
3232
3246
|
for (const [frame, binary] of pendingCloudFrames) {
|
|
3233
3247
|
if (local.readyState === WebSocket.OPEN) local.send(frame, { binary });
|
|
3234
3248
|
}
|
|
@@ -3238,6 +3252,9 @@ var proxyConnectorTerminalTunnel = async (input) => {
|
|
|
3238
3252
|
pendingCloudFrames.length = 0;
|
|
3239
3253
|
pendingLocalFrames.length = 0;
|
|
3240
3254
|
pendingBytes = 0;
|
|
3255
|
+
if (localCloseAfterBridge && cloud.readyState === WebSocket.OPEN) {
|
|
3256
|
+
cloud.close(localCloseAfterBridge.code, localCloseAfterBridge.reason);
|
|
3257
|
+
}
|
|
3241
3258
|
return;
|
|
3242
3259
|
}
|
|
3243
3260
|
bufferFrame(pendingCloudFrames, data, isBinary);
|
|
@@ -3254,25 +3271,51 @@ var proxyConnectorTerminalTunnel = async (input) => {
|
|
|
3254
3271
|
});
|
|
3255
3272
|
cloud.once("close", (code, reason) => {
|
|
3256
3273
|
endActivity();
|
|
3274
|
+
const normalizedCode = normalizeTerminalCloseCode(code);
|
|
3275
|
+
const normalizedReason = truncateTerminalCloseReason(reason.toString());
|
|
3257
3276
|
if (!bridgeAccepted) {
|
|
3258
3277
|
void writeLog(
|
|
3259
3278
|
"warn",
|
|
3260
|
-
`terminal cloud tunnel closed before readiness session=${input.sessionId} code=${code} reason=${
|
|
3279
|
+
`terminal cloud tunnel closed before readiness session=${input.sessionId} code=${code} reason=${normalizedReason}`
|
|
3261
3280
|
);
|
|
3262
3281
|
}
|
|
3263
3282
|
if (local.readyState === WebSocket.OPEN) {
|
|
3264
|
-
local.close(
|
|
3283
|
+
local.close(normalizedCode, normalizedReason);
|
|
3284
|
+
} else if (local.readyState === WebSocket.CONNECTING) {
|
|
3285
|
+
localCloseAfterOpen = { code: normalizedCode, reason: normalizedReason };
|
|
3265
3286
|
}
|
|
3266
3287
|
});
|
|
3267
3288
|
local.once("close", (code, reason) => {
|
|
3268
3289
|
endActivity();
|
|
3269
|
-
|
|
3270
|
-
|
|
3290
|
+
const normalizedClose = {
|
|
3291
|
+
code: normalizeTerminalCloseCode(code),
|
|
3292
|
+
reason: truncateTerminalCloseReason(reason.toString())
|
|
3293
|
+
};
|
|
3294
|
+
if (!bridgeAccepted) {
|
|
3295
|
+
localCloseAfterBridge = normalizedClose;
|
|
3296
|
+
} else if (cloud.readyState === WebSocket.OPEN) {
|
|
3297
|
+
cloud.close(normalizedClose.code, normalizedClose.reason);
|
|
3298
|
+
}
|
|
3299
|
+
});
|
|
3300
|
+
local.once("open", () => {
|
|
3301
|
+
if (localCloseAfterOpen && local.readyState === WebSocket.OPEN) {
|
|
3302
|
+
local.close(localCloseAfterOpen.code, localCloseAfterOpen.reason);
|
|
3271
3303
|
}
|
|
3272
3304
|
});
|
|
3273
3305
|
cloud.once("error", () => local.terminate());
|
|
3274
3306
|
local.once("error", () => cloud.terminate());
|
|
3275
|
-
|
|
3307
|
+
try {
|
|
3308
|
+
await Promise.all([connectSocket(cloud), connectSocket(local)]);
|
|
3309
|
+
} catch (error) {
|
|
3310
|
+
cloud.terminate();
|
|
3311
|
+
local.terminate();
|
|
3312
|
+
throw error;
|
|
3313
|
+
}
|
|
3314
|
+
if (cloud.readyState !== WebSocket.OPEN) return;
|
|
3315
|
+
if (local.readyState === WebSocket.OPEN) {
|
|
3316
|
+
activityStarted = true;
|
|
3317
|
+
input.onActivityStart?.();
|
|
3318
|
+
}
|
|
3276
3319
|
cloud.send(JSON.stringify({ type: "bridge-ready" }));
|
|
3277
3320
|
await writeLog(
|
|
3278
3321
|
"info",
|
|
@@ -5396,9 +5439,7 @@ async function runOnboard(launchConfig, options = {}) {
|
|
|
5396
5439
|
await migrateLegacyWorkspaceRoot(config2.workdirRoot);
|
|
5397
5440
|
await provisionWorkdirLayout(config2.workdirRoot);
|
|
5398
5441
|
try {
|
|
5399
|
-
const registration = await
|
|
5400
|
-
recoverMissingProfile: false
|
|
5401
|
-
});
|
|
5442
|
+
const registration = await registerConnectorForExplicitEnrollment(config2, launchConfig);
|
|
5402
5443
|
config2.connectorId = registration.connectorId;
|
|
5403
5444
|
config2.spaceId = registration.spaceId ?? config2.spaceId;
|
|
5404
5445
|
relayProtocol = registration.relayProtocol;
|
|
@@ -5430,7 +5471,16 @@ async function runOnboard(launchConfig, options = {}) {
|
|
|
5430
5471
|
if (!existing) {
|
|
5431
5472
|
} else {
|
|
5432
5473
|
try {
|
|
5433
|
-
|
|
5474
|
+
const registration = await registerConnectorForExplicitEnrollment(
|
|
5475
|
+
config,
|
|
5476
|
+
launchConfig,
|
|
5477
|
+
bunnyDaemon
|
|
5478
|
+
);
|
|
5479
|
+
config.connectorId = registration.connectorId;
|
|
5480
|
+
config.spaceId = registration.spaceId ?? config.spaceId;
|
|
5481
|
+
if (!config.spaceId) throw new Error("Registration did not resolve a Space");
|
|
5482
|
+
relayProtocol = registration.relayProtocol;
|
|
5483
|
+
await writeDeviceConfig(config);
|
|
5434
5484
|
} catch (error) {
|
|
5435
5485
|
await stopEmbeddedBunnyDaemon(bunnyDaemon);
|
|
5436
5486
|
s.stop("Failed to register");
|
|
@@ -5518,15 +5568,12 @@ async function stopRecoveredIdleDaemon(config, configRoot) {
|
|
|
5518
5568
|
throw new Error(`Recovered Connector ${config.connectorId} did not stop cleanly.`);
|
|
5519
5569
|
}
|
|
5520
5570
|
async function runNewConnector(launchConfig) {
|
|
5521
|
-
const existing = await readDeviceConfig(launchConfig);
|
|
5522
5571
|
const config = await ensureDeviceConfig(launchConfig);
|
|
5523
5572
|
const paths = getConnectorPaths(config.serverUrl);
|
|
5524
5573
|
await migrateLegacyWorkspaceRoot(config.workdirRoot);
|
|
5525
5574
|
await provisionWorkdirLayout(config.workdirRoot);
|
|
5526
5575
|
await LocalWorkspaceRegistry.open(config.workdirRoot);
|
|
5527
|
-
const registration = await
|
|
5528
|
-
recoverMissingProfile: shouldRecoverMissingProfile(Boolean(existing), launchConfig)
|
|
5529
|
-
});
|
|
5576
|
+
const registration = await registerConnectorForExplicitEnrollment(config, launchConfig);
|
|
5530
5577
|
config.connectorId = registration.connectorId;
|
|
5531
5578
|
config.spaceId = registration.spaceId ?? config.spaceId;
|
|
5532
5579
|
await writeDeviceConfig(config);
|
|
@@ -5567,9 +5614,7 @@ async function runConnectorDaemon(launchConfig, options = {}) {
|
|
|
5567
5614
|
const workspaceRegistry = await LocalWorkspaceRegistry.open(config.workdirRoot);
|
|
5568
5615
|
bunnyDaemon = await startEmbeddedBunnyDaemon(config, launchConfig);
|
|
5569
5616
|
const activeBunnyDaemon = bunnyDaemon;
|
|
5570
|
-
const registration = await
|
|
5571
|
-
recoverMissingProfile: shouldRecoverMissingProfile(Boolean(existing), launchConfig)
|
|
5572
|
-
});
|
|
5617
|
+
const registration = options.explicitEnrollment ? await registerConnectorForExplicitEnrollment(config, launchConfig, activeBunnyDaemon) : await registerConnector(config, launchConfig, activeBunnyDaemon);
|
|
5573
5618
|
const connectorIdChanged = config.connectorId !== registration.connectorId;
|
|
5574
5619
|
if (connectorIdChanged) {
|
|
5575
5620
|
const registeredConfig = {
|
|
@@ -5678,7 +5723,6 @@ async function runConnectorDaemon(launchConfig, options = {}) {
|
|
|
5678
5723
|
throw error;
|
|
5679
5724
|
}
|
|
5680
5725
|
}
|
|
5681
|
-
var shouldRecoverMissingProfile = (hasExistingProfile, launchConfig) => !hasExistingProfile && Boolean(getConnectorToken(launchConfig)) && !launchConfig?.oauthToken?.trim();
|
|
5682
5726
|
|
|
5683
5727
|
// src/cli.ts
|
|
5684
5728
|
function printHelp() {
|
|
@@ -5770,6 +5814,7 @@ async function main() {
|
|
|
5770
5814
|
if (command === "daemon" && process.argv.includes("--internal-daemon")) {
|
|
5771
5815
|
await runConnectorDaemon(launchConfig, {
|
|
5772
5816
|
captureConsole: true,
|
|
5817
|
+
explicitEnrollment: process.argv.includes("--explicit-enrollment"),
|
|
5773
5818
|
mode: getDaemonModeFlag(),
|
|
5774
5819
|
version: CONNECTOR_RUNTIME_VERSION
|
|
5775
5820
|
});
|