@cabane/companion 0.6.172 → 0.6.173
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 +6176 -6405
- package/dist/pairing-config.js +38 -100
- package/dist/runtime.js +1 -0
- package/package.json +1 -1
package/dist/pairing-config.js
CHANGED
|
@@ -432,114 +432,53 @@ function saveConfig(cfg) {
|
|
|
432
432
|
}
|
|
433
433
|
|
|
434
434
|
// src/enrollment.ts
|
|
435
|
-
|
|
436
|
-
constructor() {
|
|
437
|
-
super("this pairing code expired before it was confirmed.");
|
|
438
|
-
this.name = "EnrollmentExpiredError";
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
var EnrollmentCancelledError = class extends CompanionError {
|
|
442
|
-
constructor() {
|
|
443
|
-
super("pairing was cancelled.");
|
|
444
|
-
this.name = "EnrollmentCancelledError";
|
|
445
|
-
}
|
|
446
|
-
};
|
|
447
|
-
function trimBase(baseUrl) {
|
|
448
|
-
return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
449
|
-
}
|
|
450
|
-
async function postJson(baseUrl, path, body) {
|
|
435
|
+
async function claimSetupCode(baseUrl, input) {
|
|
451
436
|
let res;
|
|
452
437
|
try {
|
|
453
|
-
res = await fetch(`${
|
|
438
|
+
res = await fetch(`${baseUrl.replace(/\/$/, "")}/api/device-enrollment/claim`, {
|
|
454
439
|
method: "POST",
|
|
455
|
-
headers: {
|
|
456
|
-
|
|
440
|
+
headers: {
|
|
441
|
+
"content-type": "application/json",
|
|
442
|
+
...input.deviceToken ? { authorization: `Bearer ${input.deviceToken}` } : {}
|
|
443
|
+
},
|
|
444
|
+
body: JSON.stringify({
|
|
445
|
+
userCode: input.userCode,
|
|
446
|
+
label: input.label,
|
|
447
|
+
platform: process.platform,
|
|
448
|
+
arch: process.arch,
|
|
449
|
+
nodeMajor: Number.parseInt(process.versions.node.split(".")[0], 10)
|
|
450
|
+
})
|
|
457
451
|
});
|
|
458
|
-
} catch
|
|
452
|
+
} catch {
|
|
459
453
|
throw new CompanionError(
|
|
460
|
-
`
|
|
454
|
+
`Couldn't reach Cabane at ${baseUrl}. Check the server URL and your connection.`
|
|
461
455
|
);
|
|
462
456
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
return parsed;
|
|
482
|
-
}
|
|
483
|
-
function requestEnrollmentCode(baseUrl, opts = {}) {
|
|
484
|
-
return postJson(baseUrl, "/api/device-enrollment/code", {
|
|
485
|
-
...opts.label ? { label: opts.label } : {},
|
|
486
|
-
...hostFacts()
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
function hostFacts() {
|
|
490
|
-
const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "", 10);
|
|
457
|
+
if (res.status === 429)
|
|
458
|
+
throw new CompanionError(
|
|
459
|
+
"Too many attempts from this network. Wait a few minutes and paste the setup line again."
|
|
460
|
+
);
|
|
461
|
+
if (res.status === 404 && input.deviceToken)
|
|
462
|
+
throw new CompanionError(
|
|
463
|
+
"The setup code or saved device credential is unavailable. If this device was removed, run cabane logout, then take a fresh setup line from your workspace\u2019s Settings \u2192 Devices."
|
|
464
|
+
);
|
|
465
|
+
if (res.status === 404 || res.status === 410)
|
|
466
|
+
throw new CompanionError(
|
|
467
|
+
"That setup code is unavailable. Take a fresh setup line from your workspace\u2019s Settings \u2192 Devices."
|
|
468
|
+
);
|
|
469
|
+
if (!res.ok) throw new ApiError(res.status, `Setup failed (${res.status}).`);
|
|
470
|
+
const body = await res.json();
|
|
471
|
+
if (!body || typeof body !== "object" || !("baseUrl" in body) || typeof body.baseUrl !== "string" || !("deviceId" in body) || typeof body.deviceId !== "string")
|
|
472
|
+
throw new CompanionError("Cabane returned an incomplete setup response.");
|
|
473
|
+
const token = "deviceToken" in body && typeof body.deviceToken === "string" ? body.deviceToken : input.deviceToken;
|
|
474
|
+
if (!token) throw new CompanionError("Cabane returned no device credential.");
|
|
491
475
|
return {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
476
|
+
baseUrl: body.baseUrl,
|
|
477
|
+
deviceToken: token,
|
|
478
|
+
deviceId: body.deviceId,
|
|
479
|
+
..."deviceLabel" in body && typeof body.deviceLabel === "string" ? { deviceLabel: body.deviceLabel } : {}
|
|
495
480
|
};
|
|
496
481
|
}
|
|
497
|
-
function pollOnce(baseUrl, deviceCode) {
|
|
498
|
-
return postJson(baseUrl, "/api/device-enrollment/poll", { deviceCode });
|
|
499
|
-
}
|
|
500
|
-
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
501
|
-
async function runDeviceFlow(baseUrl, print, opts = {}) {
|
|
502
|
-
if (opts.signal?.aborted) throw new EnrollmentCancelledError();
|
|
503
|
-
const code = await requestEnrollmentCode(baseUrl, {
|
|
504
|
-
...opts.label ? { label: opts.label } : {}
|
|
505
|
-
});
|
|
506
|
-
if (opts.onCode) await opts.onCode(code);
|
|
507
|
-
print("");
|
|
508
|
-
print(` Enter this code at ${code.verificationUri}`);
|
|
509
|
-
print("");
|
|
510
|
-
print(` ${code.userCode}`);
|
|
511
|
-
print("");
|
|
512
|
-
print(` or open: ${code.verificationUriComplete}`);
|
|
513
|
-
print("");
|
|
514
|
-
print("Waiting for you to confirm it in Cabane\u2026");
|
|
515
|
-
return awaitEnrollment(baseUrl, code, opts);
|
|
516
|
-
}
|
|
517
|
-
async function awaitEnrollment(baseUrl, code, opts = {}) {
|
|
518
|
-
const now = opts.now ?? (() => Date.now());
|
|
519
|
-
const wait = opts.sleepMs ?? sleep;
|
|
520
|
-
const deadline = now() + code.expiresIn * 1e3;
|
|
521
|
-
let intervalMs = Math.max(1, code.interval) * 1e3;
|
|
522
|
-
while (now() < deadline) {
|
|
523
|
-
await wait(intervalMs);
|
|
524
|
-
if (opts.signal?.aborted) throw new EnrollmentCancelledError();
|
|
525
|
-
const res = await pollOnce(baseUrl, code.deviceCode);
|
|
526
|
-
if (res.status === "complete") {
|
|
527
|
-
if (!res.deviceToken || !res.baseUrl) {
|
|
528
|
-
throw new CompanionError("the server reported the pairing complete but returned no token.");
|
|
529
|
-
}
|
|
530
|
-
return {
|
|
531
|
-
baseUrl: res.baseUrl,
|
|
532
|
-
deviceToken: res.deviceToken,
|
|
533
|
-
...res.deviceId ? { deviceId: res.deviceId } : {},
|
|
534
|
-
...res.deviceLabel ? { deviceLabel: res.deviceLabel } : {},
|
|
535
|
-
...res.ownerName ? { ownerName: res.ownerName } : {}
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
if (res.status === "expired") throw new EnrollmentExpiredError();
|
|
539
|
-
if (res.status === "slow_down") intervalMs += 1e3;
|
|
540
|
-
}
|
|
541
|
-
throw new EnrollmentExpiredError();
|
|
542
|
-
}
|
|
543
482
|
|
|
544
483
|
// src/pairing-config.ts
|
|
545
484
|
var DEFAULT_BASE_URL = "https://app.cabane.ai";
|
|
@@ -574,9 +513,8 @@ function isDevicePaired() {
|
|
|
574
513
|
export {
|
|
575
514
|
ApiError,
|
|
576
515
|
CompanionError,
|
|
516
|
+
claimSetupCode,
|
|
577
517
|
isDevicePaired,
|
|
578
|
-
requestEnrollmentCode,
|
|
579
518
|
resolvePairBaseUrl,
|
|
580
|
-
runDeviceFlow,
|
|
581
519
|
writePairedConfig
|
|
582
520
|
};
|
package/dist/runtime.js
CHANGED
|
@@ -14270,6 +14270,7 @@ var CompanionSupervisor = class {
|
|
|
14270
14270
|
async sendHeartbeat() {
|
|
14271
14271
|
if (!this.deviceApi) return;
|
|
14272
14272
|
try {
|
|
14273
|
+
if (!this.detection || advertisedRuntimes(this.detection).length === 0) await this.detect();
|
|
14273
14274
|
const store = loadSecretStoreTolerant(
|
|
14274
14275
|
(m) => this.log.warn({ err: m }, "Could not read the secrets file. Check ~/.cabane/secrets.json.")
|
|
14275
14276
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cabane/companion",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.173",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The Cabane Companion (headless): connect an agent on your machine to your Cabane workspace as a responder — drive work against your own codebase, files, and MCP servers without putting any of it in Cabane.",
|
|
6
6
|
"license": "UNLICENSED",
|