@buda-ai/connector 0.1.12 → 0.1.15

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 (2) hide show
  1. package/dist/cli.js +67 -40
  2. 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.12",
520
+ version: "0.1.15",
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(
@@ -2397,6 +2411,13 @@ import path6 from "path";
2397
2411
  import { promisify } from "util";
2398
2412
  var execFileAsync = promisify(execFile);
2399
2413
  var RUNTIME_INSTALL_TIMEOUT_MS = 5 * 6e4;
2414
+ var resolveBundledNodePlacement = (sourceRoot, sourceNode, pathApi = path6) => {
2415
+ const relativeNode = pathApi.relative(sourceRoot, sourceNode);
2416
+ return {
2417
+ copyNode: relativeNode.startsWith("..") || pathApi.isAbsolute(relativeNode),
2418
+ relativeNode
2419
+ };
2420
+ };
2400
2421
  var exists = async (filePath) => access(filePath).then(() => true).catch(() => false);
2401
2422
  var runtimeRoot = () => process.env.BUDA_CONNECTOR_RUNTIME_ROOT || path6.join(homedir3(), ".buda", "runtime");
2402
2423
  var runtimePlatformKey = `${process.platform}-${process.arch}-node${process.versions.modules}`;
@@ -2468,10 +2489,10 @@ var installFromBundledRuntime = async (directory, sourceRoot) => {
2468
2489
  if (relativeEntrypoint.startsWith("..") || path6.isAbsolute(relativeEntrypoint)) {
2469
2490
  throw new Error("Bundled Connector entrypoint must be inside its runtime root");
2470
2491
  }
2471
- const relativeNode = path6.relative(sourceRoot, sourceNode);
2492
+ const { copyNode, relativeNode } = resolveBundledNodePlacement(sourceRoot, sourceNode);
2472
2493
  const entrypoint = path6.join(directory, relativeEntrypoint);
2473
- const nodeExecutable = relativeNode.startsWith("..") ? path6.join(directory, "node", path6.basename(sourceNode)) : path6.join(directory, relativeNode);
2474
- if (relativeNode.startsWith("..")) {
2494
+ const nodeExecutable = copyNode ? path6.join(directory, "node", path6.basename(sourceNode)) : path6.join(directory, relativeNode);
2495
+ if (copyNode) {
2475
2496
  await mkdir5(path6.dirname(nodeExecutable), { recursive: true });
2476
2497
  await cp(sourceNode, nodeExecutable, { force: true });
2477
2498
  }
@@ -2545,13 +2566,14 @@ var isProcessAlive2 = (pid) => {
2545
2566
  return !(typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH");
2546
2567
  }
2547
2568
  };
2548
- var getRuntimeCommandArgs = (runtime, mode) => [
2569
+ var getRuntimeCommandArgs = (runtime, mode, options = {}) => [
2549
2570
  ...runtime.nodeArgs ?? [],
2550
2571
  runtime.entrypoint,
2551
2572
  "daemon",
2552
2573
  "--internal-daemon",
2553
2574
  "--daemon-mode",
2554
2575
  mode,
2576
+ ...options.explicitEnrollment ? ["--explicit-enrollment"] : [],
2555
2577
  "--plain"
2556
2578
  ];
2557
2579
  var compareVersions = (left, right) => {
@@ -2578,9 +2600,9 @@ var waitForDaemon = async (launchConfig, deadline) => {
2578
2600
  lastConfig ? "Connector daemon did not expose its control channel in time" : "Connector registration did not create a canonical local identity in time"
2579
2601
  );
2580
2602
  };
2581
- var spawnInternalDaemon = async (launchConfig, mode, preparedRuntime) => {
2603
+ var spawnInternalDaemon = async (launchConfig, mode, preparedRuntime, options = {}) => {
2582
2604
  const runtime = preparedRuntime ?? await ensureStableConnectorRuntime();
2583
- const child = spawn(runtime.nodeExecutable, getRuntimeCommandArgs(runtime, mode), {
2605
+ const child = spawn(runtime.nodeExecutable, getRuntimeCommandArgs(runtime, mode, options), {
2584
2606
  detached: true,
2585
2607
  env: {
2586
2608
  ...process.env,
@@ -2603,7 +2625,7 @@ var stopOlderIdleDaemon = async (config, status) => {
2603
2625
  }
2604
2626
  throw new Error("Older Connector daemon did not stop cleanly; existing identity was preserved");
2605
2627
  };
2606
- async function ensureConnectorDaemon(launchConfig, mode) {
2628
+ async function ensureConnectorDaemon(launchConfig, mode, options = {}) {
2607
2629
  const deviceId = await getOrCreateSystemDeviceId(getConfigRoot());
2608
2630
  const scope = await resolveConnectorScope(deviceId, launchConfig);
2609
2631
  launchConfig = { ...launchConfig, spaceId: scope.spaceId };
@@ -2623,7 +2645,7 @@ async function ensureConnectorDaemon(launchConfig, mode) {
2623
2645
  const status = mode === "persistent" ? await requestDaemonControl(existingConfig, "persist", getConfigRoot()) : existingStatus;
2624
2646
  return { config: existingConfig, status };
2625
2647
  }
2626
- await spawnInternalDaemon(launchConfig, mode, preparedRuntime);
2648
+ await spawnInternalDaemon(launchConfig, mode, preparedRuntime, options);
2627
2649
  return await waitForDaemon(launchConfig, Date.now() + START_TIMEOUT_MS);
2628
2650
  }
2629
2651
  const persistedStatus = await readPersistedDaemonStatus(
@@ -2636,7 +2658,7 @@ async function ensureConnectorDaemon(launchConfig, mode) {
2636
2658
  );
2637
2659
  }
2638
2660
  }
2639
- await spawnInternalDaemon(launchConfig, mode);
2661
+ await spawnInternalDaemon(launchConfig, mode, void 0, options);
2640
2662
  return await waitForDaemon(launchConfig, Date.now() + START_TIMEOUT_MS);
2641
2663
  } finally {
2642
2664
  await bootstrapLock.release();
@@ -2780,7 +2802,9 @@ async function runConnectorDashboard(launchConfig, options = {}) {
2780
2802
  plain: options.plain
2781
2803
  });
2782
2804
  if (!dashboard) {
2783
- const { config } = await ensureConnectorDaemon(launchConfig, "persistent");
2805
+ const { config } = await ensureConnectorDaemon(launchConfig, "persistent", {
2806
+ explicitEnrollment: true
2807
+ });
2784
2808
  const stopLogs2 = streamDaemonLogs({
2785
2809
  connectorId: config.connectorId,
2786
2810
  dashboardActive: false,
@@ -2835,7 +2859,7 @@ async function runConnectorDashboard(launchConfig, options = {}) {
2835
2859
  preferredConnectorId = config.connectorId;
2836
2860
  }).catch(() => void 0).finally(() => refresh());
2837
2861
  const timer = setInterval(() => void refresh(), 1e3);
2838
- void ensureConnectorDaemon(launchConfig, "persistent").then(async ({ config }) => {
2862
+ void ensureConnectorDaemon(launchConfig, "persistent", { explicitEnrollment: true }).then(async ({ config }) => {
2839
2863
  pendingConnector = void 0;
2840
2864
  preferredConnectorId = config.connectorId;
2841
2865
  await refresh();
@@ -3003,13 +3027,12 @@ var createTerminalSession = async (grant, nodePtyLoader) => {
3003
3027
  try {
3004
3028
  nodePty = await nodePtyLoader();
3005
3029
  } catch (error) {
3030
+ const message = serializeErrorMessage(error);
3006
3031
  void writeLog(
3007
3032
  "error",
3008
3033
  `local terminal could not load node-pty: ${serializeErrorMessage(error)}`
3009
3034
  );
3010
- throw new LocalTerminalUnavailableError(
3011
- "Local terminal is unavailable because node-pty could not be loaded. The connector remains available for other capabilities."
3012
- );
3035
+ throw new LocalTerminalUnavailableError(message);
3013
3036
  }
3014
3037
  const shell = process.platform === "win32" ? "powershell.exe" : process.env.SHELL || "/bin/bash";
3015
3038
  const shellArgs = process.platform === "win32" ? [] : ["-l"];
@@ -3199,7 +3222,7 @@ var proxyConnectorTerminalTunnel = async (input) => {
3199
3222
  let bridgeAccepted = false;
3200
3223
  let activityStarted = false;
3201
3224
  let activityEnded = false;
3202
- let cloudCloseAfterOpen = null;
3225
+ let localCloseAfterBridge = null;
3203
3226
  let localCloseAfterOpen = null;
3204
3227
  const endActivity = () => {
3205
3228
  if (!activityStarted || activityEnded) return;
@@ -3224,7 +3247,9 @@ var proxyConnectorTerminalTunnel = async (input) => {
3224
3247
  if (!bridgeAccepted) {
3225
3248
  if (!isBinary && data.toString() === '{"type":"bridge-accepted"}') {
3226
3249
  bridgeAccepted = true;
3227
- local.send(JSON.stringify({ type: "bridge-start" }));
3250
+ if (local.readyState === WebSocket.OPEN) {
3251
+ local.send(JSON.stringify({ type: "bridge-start" }));
3252
+ }
3228
3253
  for (const [frame, binary] of pendingCloudFrames) {
3229
3254
  if (local.readyState === WebSocket.OPEN) local.send(frame, { binary });
3230
3255
  }
@@ -3234,6 +3259,9 @@ var proxyConnectorTerminalTunnel = async (input) => {
3234
3259
  pendingCloudFrames.length = 0;
3235
3260
  pendingLocalFrames.length = 0;
3236
3261
  pendingBytes = 0;
3262
+ if (localCloseAfterBridge && cloud.readyState === WebSocket.OPEN) {
3263
+ cloud.close(localCloseAfterBridge.code, localCloseAfterBridge.reason);
3264
+ }
3237
3265
  return;
3238
3266
  }
3239
3267
  bufferFrame(pendingCloudFrames, data, isBinary);
@@ -3270,15 +3298,10 @@ var proxyConnectorTerminalTunnel = async (input) => {
3270
3298
  code: normalizeTerminalCloseCode(code),
3271
3299
  reason: truncateTerminalCloseReason(reason.toString())
3272
3300
  };
3273
- if (cloud.readyState === WebSocket.OPEN) {
3301
+ if (!bridgeAccepted) {
3302
+ localCloseAfterBridge = normalizedClose;
3303
+ } else if (cloud.readyState === WebSocket.OPEN) {
3274
3304
  cloud.close(normalizedClose.code, normalizedClose.reason);
3275
- } else if (cloud.readyState === WebSocket.CONNECTING) {
3276
- cloudCloseAfterOpen = normalizedClose;
3277
- }
3278
- });
3279
- cloud.once("open", () => {
3280
- if (cloudCloseAfterOpen && cloud.readyState === WebSocket.OPEN) {
3281
- cloud.close(cloudCloseAfterOpen.code, cloudCloseAfterOpen.reason);
3282
3305
  }
3283
3306
  });
3284
3307
  local.once("open", () => {
@@ -3295,9 +3318,11 @@ var proxyConnectorTerminalTunnel = async (input) => {
3295
3318
  local.terminate();
3296
3319
  throw error;
3297
3320
  }
3298
- if (cloud.readyState !== WebSocket.OPEN || local.readyState !== WebSocket.OPEN) return;
3299
- activityStarted = true;
3300
- input.onActivityStart?.();
3321
+ if (cloud.readyState !== WebSocket.OPEN) return;
3322
+ if (local.readyState === WebSocket.OPEN) {
3323
+ activityStarted = true;
3324
+ input.onActivityStart?.();
3325
+ }
3301
3326
  cloud.send(JSON.stringify({ type: "bridge-ready" }));
3302
3327
  await writeLog(
3303
3328
  "info",
@@ -5421,9 +5446,7 @@ async function runOnboard(launchConfig, options = {}) {
5421
5446
  await migrateLegacyWorkspaceRoot(config2.workdirRoot);
5422
5447
  await provisionWorkdirLayout(config2.workdirRoot);
5423
5448
  try {
5424
- const registration = await registerConnector(config2, launchConfig, void 0, {
5425
- recoverMissingProfile: false
5426
- });
5449
+ const registration = await registerConnectorForExplicitEnrollment(config2, launchConfig);
5427
5450
  config2.connectorId = registration.connectorId;
5428
5451
  config2.spaceId = registration.spaceId ?? config2.spaceId;
5429
5452
  relayProtocol = registration.relayProtocol;
@@ -5455,7 +5478,16 @@ async function runOnboard(launchConfig, options = {}) {
5455
5478
  if (!existing) {
5456
5479
  } else {
5457
5480
  try {
5458
- relayProtocol = (await registerConnector(config, launchConfig, bunnyDaemon)).relayProtocol;
5481
+ const registration = await registerConnectorForExplicitEnrollment(
5482
+ config,
5483
+ launchConfig,
5484
+ bunnyDaemon
5485
+ );
5486
+ config.connectorId = registration.connectorId;
5487
+ config.spaceId = registration.spaceId ?? config.spaceId;
5488
+ if (!config.spaceId) throw new Error("Registration did not resolve a Space");
5489
+ relayProtocol = registration.relayProtocol;
5490
+ await writeDeviceConfig(config);
5459
5491
  } catch (error) {
5460
5492
  await stopEmbeddedBunnyDaemon(bunnyDaemon);
5461
5493
  s.stop("Failed to register");
@@ -5543,15 +5575,12 @@ async function stopRecoveredIdleDaemon(config, configRoot) {
5543
5575
  throw new Error(`Recovered Connector ${config.connectorId} did not stop cleanly.`);
5544
5576
  }
5545
5577
  async function runNewConnector(launchConfig) {
5546
- const existing = await readDeviceConfig(launchConfig);
5547
5578
  const config = await ensureDeviceConfig(launchConfig);
5548
5579
  const paths = getConnectorPaths(config.serverUrl);
5549
5580
  await migrateLegacyWorkspaceRoot(config.workdirRoot);
5550
5581
  await provisionWorkdirLayout(config.workdirRoot);
5551
5582
  await LocalWorkspaceRegistry.open(config.workdirRoot);
5552
- const registration = await registerConnector(config, launchConfig, void 0, {
5553
- recoverMissingProfile: shouldRecoverMissingProfile(Boolean(existing), launchConfig)
5554
- });
5583
+ const registration = await registerConnectorForExplicitEnrollment(config, launchConfig);
5555
5584
  config.connectorId = registration.connectorId;
5556
5585
  config.spaceId = registration.spaceId ?? config.spaceId;
5557
5586
  await writeDeviceConfig(config);
@@ -5592,9 +5621,7 @@ async function runConnectorDaemon(launchConfig, options = {}) {
5592
5621
  const workspaceRegistry = await LocalWorkspaceRegistry.open(config.workdirRoot);
5593
5622
  bunnyDaemon = await startEmbeddedBunnyDaemon(config, launchConfig);
5594
5623
  const activeBunnyDaemon = bunnyDaemon;
5595
- const registration = await registerConnector(config, launchConfig, activeBunnyDaemon, {
5596
- recoverMissingProfile: shouldRecoverMissingProfile(Boolean(existing), launchConfig)
5597
- });
5624
+ const registration = options.explicitEnrollment ? await registerConnectorForExplicitEnrollment(config, launchConfig, activeBunnyDaemon) : await registerConnector(config, launchConfig, activeBunnyDaemon);
5598
5625
  const connectorIdChanged = config.connectorId !== registration.connectorId;
5599
5626
  if (connectorIdChanged) {
5600
5627
  const registeredConfig = {
@@ -5703,7 +5730,6 @@ async function runConnectorDaemon(launchConfig, options = {}) {
5703
5730
  throw error;
5704
5731
  }
5705
5732
  }
5706
- var shouldRecoverMissingProfile = (hasExistingProfile, launchConfig) => !hasExistingProfile && Boolean(getConnectorToken(launchConfig)) && !launchConfig?.oauthToken?.trim();
5707
5733
 
5708
5734
  // src/cli.ts
5709
5735
  function printHelp() {
@@ -5795,6 +5821,7 @@ async function main() {
5795
5821
  if (command === "daemon" && process.argv.includes("--internal-daemon")) {
5796
5822
  await runConnectorDaemon(launchConfig, {
5797
5823
  captureConsole: true,
5824
+ explicitEnrollment: process.argv.includes("--explicit-enrollment"),
5798
5825
  mode: getDaemonModeFlag(),
5799
5826
  version: CONNECTOR_RUNTIME_VERSION
5800
5827
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buda-ai/connector",
3
- "version": "0.1.12",
3
+ "version": "0.1.15",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "publishConfig": {