@brainbase-labs/cli 0.18.0 → 0.19.1
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/index.js +293 -130
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32012,7 +32012,7 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
32012
32012
|
urnComponent.nss = (uuidComponent.uuid || "").toLowerCase();
|
|
32013
32013
|
return urnComponent;
|
|
32014
32014
|
}
|
|
32015
|
-
var
|
|
32015
|
+
var http = {
|
|
32016
32016
|
scheme: "http",
|
|
32017
32017
|
domainHost: true,
|
|
32018
32018
|
parse: httpParse,
|
|
@@ -32020,7 +32020,7 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
32020
32020
|
};
|
|
32021
32021
|
var https = {
|
|
32022
32022
|
scheme: "https",
|
|
32023
|
-
domainHost:
|
|
32023
|
+
domainHost: http.domainHost,
|
|
32024
32024
|
parse: httpParse,
|
|
32025
32025
|
serialize: httpSerialize
|
|
32026
32026
|
};
|
|
@@ -32049,7 +32049,7 @@ var require_schemes = __commonJS((exports, module) => {
|
|
|
32049
32049
|
skipNormalize: true
|
|
32050
32050
|
};
|
|
32051
32051
|
var SCHEMES = {
|
|
32052
|
-
http
|
|
32052
|
+
http,
|
|
32053
32053
|
https,
|
|
32054
32054
|
ws: ws2,
|
|
32055
32055
|
wss,
|
|
@@ -36008,7 +36008,7 @@ function padStart(s, n) {
|
|
|
36008
36008
|
// package.json
|
|
36009
36009
|
var package_default = {
|
|
36010
36010
|
name: "@brainbase-labs/cli",
|
|
36011
|
-
version: "0.
|
|
36011
|
+
version: "0.19.1",
|
|
36012
36012
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36013
36013
|
type: "module",
|
|
36014
36014
|
bin: {
|
|
@@ -61156,12 +61156,183 @@ function printSkillHelp() {
|
|
|
61156
61156
|
}
|
|
61157
61157
|
|
|
61158
61158
|
// src/cli/login.ts
|
|
61159
|
-
import http from "node:http";
|
|
61160
|
-
import net from "node:net";
|
|
61161
|
-
import { randomBytes } from "node:crypto";
|
|
61162
61159
|
import { spawn } from "node:child_process";
|
|
61163
61160
|
var import_picocolors21 = __toESM(require_picocolors(), 1);
|
|
61164
61161
|
|
|
61162
|
+
// src/core/login-poll.ts
|
|
61163
|
+
var DEFAULT_LOGIN_TIMEOUT_MS = 10 * 60 * 1000;
|
|
61164
|
+
var MIN_LOGIN_TIMEOUT_MS = 30000;
|
|
61165
|
+
var DEFAULT_POLL_INTERVAL_MS = 2000;
|
|
61166
|
+
var MIN_POLL_INTERVAL_MS = 500;
|
|
61167
|
+
var REQUEST_TIMEOUT_MS = 1e4;
|
|
61168
|
+
var MAX_CONSECUTIVE_FAILURES = 20;
|
|
61169
|
+
|
|
61170
|
+
class LoginTimeoutError extends Error {
|
|
61171
|
+
constructor(timeoutMs, lastError) {
|
|
61172
|
+
super(`Login timed out after ${Math.round(timeoutMs / 1000)}s` + (lastError ? ` (last error: ${lastError})` : ""));
|
|
61173
|
+
this.name = "LoginTimeoutError";
|
|
61174
|
+
}
|
|
61175
|
+
}
|
|
61176
|
+
function sleep(ms2) {
|
|
61177
|
+
return new Promise((resolve) => setTimeout(resolve, ms2));
|
|
61178
|
+
}
|
|
61179
|
+
var MAX_POLL_INTERVAL_MS = 60000;
|
|
61180
|
+
function backoffInterval(res, current) {
|
|
61181
|
+
const header = Number(res.headers.get("Retry-After"));
|
|
61182
|
+
const suggested = Number.isFinite(header) && header > 0 ? header * 1000 : current * 2;
|
|
61183
|
+
return Math.min(Math.max(suggested, current), MAX_POLL_INTERVAL_MS);
|
|
61184
|
+
}
|
|
61185
|
+
function clamp2(value, min2, max2) {
|
|
61186
|
+
if (!Number.isFinite(value))
|
|
61187
|
+
return min2;
|
|
61188
|
+
return Math.min(Math.max(value, min2), max2);
|
|
61189
|
+
}
|
|
61190
|
+
function unsupportedDeployment(webBase) {
|
|
61191
|
+
return new Error(`${webBase} does not support device login. Update the Brainbase console, or point at another deployment with \`brainbase login --web <url>\`.`);
|
|
61192
|
+
}
|
|
61193
|
+
var UNSAFE_URI_CHARS = /[\s"'`$&|;<>^(){}\\!*]/;
|
|
61194
|
+
function resolveVerificationUri(webBase, uri) {
|
|
61195
|
+
const fallback = `${webBase}/cli/auth`;
|
|
61196
|
+
let base2;
|
|
61197
|
+
try {
|
|
61198
|
+
base2 = new URL(`${webBase}/`);
|
|
61199
|
+
} catch {
|
|
61200
|
+
return fallback;
|
|
61201
|
+
}
|
|
61202
|
+
let resolved;
|
|
61203
|
+
try {
|
|
61204
|
+
resolved = new URL(uri, base2);
|
|
61205
|
+
} catch {
|
|
61206
|
+
return fallback;
|
|
61207
|
+
}
|
|
61208
|
+
if (resolved.origin !== base2.origin)
|
|
61209
|
+
return fallback;
|
|
61210
|
+
if (resolved.protocol !== "http:" && resolved.protocol !== "https:") {
|
|
61211
|
+
return fallback;
|
|
61212
|
+
}
|
|
61213
|
+
const path73 = `${resolved.pathname}${resolved.search}${resolved.hash}`;
|
|
61214
|
+
if (UNSAFE_URI_CHARS.test(path73))
|
|
61215
|
+
return fallback;
|
|
61216
|
+
return resolved.toString();
|
|
61217
|
+
}
|
|
61218
|
+
async function readJson2(res) {
|
|
61219
|
+
try {
|
|
61220
|
+
const body = await res.json();
|
|
61221
|
+
return body && typeof body === "object" ? body : null;
|
|
61222
|
+
} catch {
|
|
61223
|
+
return null;
|
|
61224
|
+
}
|
|
61225
|
+
}
|
|
61226
|
+
var JSON_HEADERS = {
|
|
61227
|
+
"Content-Type": "application/json",
|
|
61228
|
+
Accept: "application/json"
|
|
61229
|
+
};
|
|
61230
|
+
async function startDeviceAuthorization(options) {
|
|
61231
|
+
const { webBase, fetchImpl = fetch } = options;
|
|
61232
|
+
const url = `${webBase}/api/cli/auth/device`;
|
|
61233
|
+
let res;
|
|
61234
|
+
try {
|
|
61235
|
+
res = await fetchImpl(url, {
|
|
61236
|
+
method: "POST",
|
|
61237
|
+
headers: JSON_HEADERS,
|
|
61238
|
+
body: "{}",
|
|
61239
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
61240
|
+
});
|
|
61241
|
+
} catch (err) {
|
|
61242
|
+
throw new Error(`Could not reach ${url}: ${err.message}`);
|
|
61243
|
+
}
|
|
61244
|
+
if (res.status === 404)
|
|
61245
|
+
throw unsupportedDeployment(webBase);
|
|
61246
|
+
if (!res.ok) {
|
|
61247
|
+
throw new Error(`Could not start login (${webBase} returned ${res.status}).`);
|
|
61248
|
+
}
|
|
61249
|
+
const body = await readJson2(res);
|
|
61250
|
+
if (!body?.device_code || !body.user_code) {
|
|
61251
|
+
throw unsupportedDeployment(webBase);
|
|
61252
|
+
}
|
|
61253
|
+
return {
|
|
61254
|
+
deviceCode: body.device_code,
|
|
61255
|
+
userCode: body.user_code,
|
|
61256
|
+
verificationUri: resolveVerificationUri(webBase, body.verification_uri ?? "/cli/auth"),
|
|
61257
|
+
intervalMs: clamp2(body.interval ? body.interval * 1000 : DEFAULT_POLL_INTERVAL_MS, MIN_POLL_INTERVAL_MS, MAX_POLL_INTERVAL_MS),
|
|
61258
|
+
expiresInMs: clamp2(body.expires_in ? body.expires_in * 1000 : DEFAULT_LOGIN_TIMEOUT_MS, MIN_LOGIN_TIMEOUT_MS, DEFAULT_LOGIN_TIMEOUT_MS)
|
|
61259
|
+
};
|
|
61260
|
+
}
|
|
61261
|
+
async function awaitDeviceSession(options) {
|
|
61262
|
+
const {
|
|
61263
|
+
webBase,
|
|
61264
|
+
authorization,
|
|
61265
|
+
timeoutMs = Math.min(authorization.expiresInMs, DEFAULT_LOGIN_TIMEOUT_MS),
|
|
61266
|
+
now: now2 = Date.now,
|
|
61267
|
+
wait = sleep,
|
|
61268
|
+
fetchImpl = fetch
|
|
61269
|
+
} = options;
|
|
61270
|
+
const url = `${webBase}/api/cli/auth/device/token`;
|
|
61271
|
+
const deadline = now2() + timeoutMs;
|
|
61272
|
+
let consecutiveFailures = 0;
|
|
61273
|
+
let intervalMs = authorization.intervalMs;
|
|
61274
|
+
let lastError;
|
|
61275
|
+
while (now2() < deadline) {
|
|
61276
|
+
let res;
|
|
61277
|
+
try {
|
|
61278
|
+
res = await fetchImpl(url, {
|
|
61279
|
+
method: "POST",
|
|
61280
|
+
headers: JSON_HEADERS,
|
|
61281
|
+
body: JSON.stringify({ device_code: authorization.deviceCode }),
|
|
61282
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
61283
|
+
});
|
|
61284
|
+
} catch (err) {
|
|
61285
|
+
lastError = err.message;
|
|
61286
|
+
if (++consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
|
|
61287
|
+
throw new Error(`Could not reach ${url}: ${lastError}`);
|
|
61288
|
+
}
|
|
61289
|
+
await wait(intervalMs);
|
|
61290
|
+
continue;
|
|
61291
|
+
}
|
|
61292
|
+
if (res.status === 410) {
|
|
61293
|
+
throw new Error("This login expired. Run `brainbase login` again.");
|
|
61294
|
+
}
|
|
61295
|
+
if (res.status === 409) {
|
|
61296
|
+
throw new Error("This login was already completed on another device. Run `brainbase login` again.");
|
|
61297
|
+
}
|
|
61298
|
+
if (res.status === 404)
|
|
61299
|
+
throw unsupportedDeployment(webBase);
|
|
61300
|
+
if (res.status === 429) {
|
|
61301
|
+
consecutiveFailures = 0;
|
|
61302
|
+
intervalMs = backoffInterval(res, intervalMs);
|
|
61303
|
+
lastError = "the server asked us to slow down";
|
|
61304
|
+
await wait(intervalMs);
|
|
61305
|
+
continue;
|
|
61306
|
+
}
|
|
61307
|
+
if (!res.ok) {
|
|
61308
|
+
lastError = `poll returned ${res.status}`;
|
|
61309
|
+
if (res.status >= 400 && res.status < 500) {
|
|
61310
|
+
const detail = (await readJson2(res))?.error;
|
|
61311
|
+
throw new Error(typeof detail === "string" ? detail : `The server rejected this login (${res.status}). Run \`brainbase login\` again.`);
|
|
61312
|
+
}
|
|
61313
|
+
if (++consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
|
|
61314
|
+
throw new Error(`Could not reach ${url}: ${lastError}`);
|
|
61315
|
+
}
|
|
61316
|
+
await wait(intervalMs);
|
|
61317
|
+
continue;
|
|
61318
|
+
}
|
|
61319
|
+
consecutiveFailures = 0;
|
|
61320
|
+
const body = await readJson2(res);
|
|
61321
|
+
if (!body) {
|
|
61322
|
+
throw unsupportedDeployment(webBase);
|
|
61323
|
+
}
|
|
61324
|
+
if (body.status === "ready") {
|
|
61325
|
+
const session = body.session;
|
|
61326
|
+
if (!session) {
|
|
61327
|
+
throw new Error("The server said the login was ready but sent no session. Run `brainbase login` again.");
|
|
61328
|
+
}
|
|
61329
|
+
return session;
|
|
61330
|
+
}
|
|
61331
|
+
await wait(intervalMs);
|
|
61332
|
+
}
|
|
61333
|
+
throw new LoginTimeoutError(timeoutMs, lastError);
|
|
61334
|
+
}
|
|
61335
|
+
|
|
61165
61336
|
// src/ui/ink/WelcomeCard.tsx
|
|
61166
61337
|
var jsx_dev_runtime14 = __toESM(require_jsx_dev_runtime(), 1);
|
|
61167
61338
|
function WelcomeCard(props) {
|
|
@@ -61240,143 +61411,135 @@ async function showWelcomeCard(props) {
|
|
|
61240
61411
|
|
|
61241
61412
|
// src/cli/login.ts
|
|
61242
61413
|
var DEFAULT_WEB_URL = "https://app.brainbaselabs.com";
|
|
61243
|
-
var LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
61244
61414
|
function resolveLoginWebBase(web, envWeb = process.env.BRAINBASE_WEB_URL) {
|
|
61245
61415
|
const override = web?.trim() || envWeb?.trim() || DEFAULT_WEB_URL;
|
|
61246
61416
|
return override.replace(/\/+$/, "");
|
|
61247
61417
|
}
|
|
61418
|
+
function isInsecureWebBase(webBase) {
|
|
61419
|
+
let url;
|
|
61420
|
+
try {
|
|
61421
|
+
url = new URL(webBase);
|
|
61422
|
+
} catch {
|
|
61423
|
+
return false;
|
|
61424
|
+
}
|
|
61425
|
+
if (url.protocol !== "http:")
|
|
61426
|
+
return false;
|
|
61427
|
+
return !["127.0.0.1", "localhost", "[::1]", "::1"].includes(url.hostname);
|
|
61428
|
+
}
|
|
61248
61429
|
function openInBrowser(url) {
|
|
61249
|
-
|
|
61250
|
-
|
|
61251
|
-
const args =
|
|
61252
|
-
|
|
61253
|
-
|
|
61254
|
-
|
|
61255
|
-
|
|
61256
|
-
const srv = net.createServer();
|
|
61257
|
-
srv.unref();
|
|
61258
|
-
srv.on("error", reject2);
|
|
61259
|
-
srv.listen(0, "127.0.0.1", () => {
|
|
61260
|
-
const addr = srv.address();
|
|
61261
|
-
if (typeof addr === "object" && addr) {
|
|
61262
|
-
const port = addr.port;
|
|
61263
|
-
srv.close(() => resolve(port));
|
|
61264
|
-
} else {
|
|
61265
|
-
srv.close();
|
|
61266
|
-
reject2(new Error("no port"));
|
|
61267
|
-
}
|
|
61430
|
+
if (process.env.BRAINBASE_NON_INTERACTIVE)
|
|
61431
|
+
return;
|
|
61432
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["rundll32.exe", ["url.dll,FileProtocolHandler", url]] : ["xdg-open", [url]];
|
|
61433
|
+
try {
|
|
61434
|
+
const child = spawn(cmd, args, {
|
|
61435
|
+
stdio: "ignore",
|
|
61436
|
+
detached: true
|
|
61268
61437
|
});
|
|
61269
|
-
|
|
61438
|
+
child.on("error", () => {});
|
|
61439
|
+
child.unref();
|
|
61440
|
+
} catch {}
|
|
61270
61441
|
}
|
|
61271
|
-
|
|
61272
|
-
return
|
|
61273
|
-
|
|
61274
|
-
|
|
61275
|
-
|
|
61276
|
-
|
|
61277
|
-
|
|
61442
|
+
function displayUserCode(code) {
|
|
61443
|
+
return code.replace(/[^A-Za-z0-9-]/g, "");
|
|
61444
|
+
}
|
|
61445
|
+
function isLoopbackUrl(url) {
|
|
61446
|
+
return ["127.0.0.1", "localhost", "[::1]", "::1"].includes(url.hostname);
|
|
61447
|
+
}
|
|
61448
|
+
function assertNoTransportDowngrade(session, webBase) {
|
|
61449
|
+
let base2;
|
|
61450
|
+
try {
|
|
61451
|
+
base2 = new URL(webBase);
|
|
61452
|
+
} catch {
|
|
61453
|
+
return;
|
|
61454
|
+
}
|
|
61455
|
+
if (base2.protocol !== "https:")
|
|
61456
|
+
return;
|
|
61457
|
+
for (const [field, value] of [
|
|
61458
|
+
["server", session.server],
|
|
61459
|
+
["control_plane_url", session.control_plane_url],
|
|
61460
|
+
["supabase_url", session.supabase_url]
|
|
61461
|
+
]) {
|
|
61462
|
+
if (!value)
|
|
61463
|
+
continue;
|
|
61464
|
+
let url;
|
|
61465
|
+
try {
|
|
61466
|
+
url = new URL(value);
|
|
61467
|
+
} catch {
|
|
61468
|
+
throw new Error(`The server returned an unusable ${field} (${value}).`);
|
|
61469
|
+
}
|
|
61470
|
+
if (url.protocol !== "https:" && !isLoopbackUrl(url)) {
|
|
61471
|
+
throw new Error(`${webBase} returned a plaintext ${field} (${value}). Refusing to store it — every later command would send your token over an unencrypted connection.`);
|
|
61472
|
+
}
|
|
61473
|
+
}
|
|
61474
|
+
}
|
|
61475
|
+
function toAuthSession(session, webBase) {
|
|
61476
|
+
if (!session.access_token || !session.user_id) {
|
|
61477
|
+
throw new Error("The server returned an incomplete session.");
|
|
61478
|
+
}
|
|
61479
|
+
assertNoTransportDowngrade(session, webBase);
|
|
61480
|
+
const optional = (value) => value ?? undefined;
|
|
61481
|
+
const stored = {
|
|
61482
|
+
schemaVersion: 1,
|
|
61483
|
+
access_token: session.access_token,
|
|
61484
|
+
refresh_token: optional(session.refresh_token),
|
|
61485
|
+
expires_at: optional(session.expires_at),
|
|
61486
|
+
user_id: session.user_id,
|
|
61487
|
+
email: optional(session.email),
|
|
61488
|
+
server: optional(session.server),
|
|
61489
|
+
control_plane_url: normalizeControlPlaneUrl(optional(session.control_plane_url)),
|
|
61490
|
+
supabase_url: optional(session.supabase_url),
|
|
61491
|
+
supabase_anon_key: optional(session.supabase_anon_key),
|
|
61492
|
+
authedAt: new Date().toISOString()
|
|
61493
|
+
};
|
|
61494
|
+
const parsed = AuthSessionSchema.safeParse(stored);
|
|
61495
|
+
if (!parsed.success) {
|
|
61496
|
+
throw new Error(`The server returned a session this CLI cannot store (${parsed.error.issues[0]?.path.join(".") || "unknown field"}).`);
|
|
61497
|
+
}
|
|
61498
|
+
return parsed.data;
|
|
61499
|
+
}
|
|
61500
|
+
async function withCancelOnInterrupt(body) {
|
|
61501
|
+
const onInterrupt = () => {
|
|
61502
|
+
f2.warn("Cancelled. Nothing was saved.");
|
|
61503
|
+
process.exit(130);
|
|
61504
|
+
};
|
|
61505
|
+
process.prependListener("SIGINT", onInterrupt);
|
|
61506
|
+
try {
|
|
61507
|
+
return await body();
|
|
61508
|
+
} finally {
|
|
61509
|
+
process.removeListener("SIGINT", onInterrupt);
|
|
61510
|
+
}
|
|
61278
61511
|
}
|
|
61279
61512
|
async function runLogin(_cwd, args) {
|
|
61280
61513
|
banner("login — connect this device to brainbase");
|
|
61281
61514
|
const webBase = resolveLoginWebBase(args.web);
|
|
61282
|
-
const expectedState = randomBytes(16).toString("hex");
|
|
61283
|
-
const port = await getFreePort();
|
|
61284
|
-
const callback = `http://127.0.0.1:${port}/cb`;
|
|
61285
|
-
const url = `${webBase}/cli/auth?callback=${encodeURIComponent(callback)}&state=${expectedState}`;
|
|
61286
|
-
let resolveResult;
|
|
61287
|
-
let rejectResult;
|
|
61288
|
-
const result2 = new Promise((res, rej) => {
|
|
61289
|
-
resolveResult = res;
|
|
61290
|
-
rejectResult = rej;
|
|
61291
|
-
});
|
|
61292
|
-
const corsOrigin = webBase;
|
|
61293
|
-
const server = http.createServer(async (req, res) => {
|
|
61294
|
-
const reqOrigin = req.headers.origin ?? corsOrigin;
|
|
61295
|
-
res.setHeader("Access-Control-Allow-Origin", reqOrigin);
|
|
61296
|
-
res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
|
|
61297
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
61298
|
-
res.setHeader("Vary", "Origin");
|
|
61299
|
-
if (req.method === "OPTIONS") {
|
|
61300
|
-
res.writeHead(204).end();
|
|
61301
|
-
return;
|
|
61302
|
-
}
|
|
61303
|
-
if (req.method === "GET" && (req.url === "/" || req.url === "/cb")) {
|
|
61304
|
-
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
61305
|
-
res.end("brainbase login server is alive. Complete sign-in in your browser.");
|
|
61306
|
-
return;
|
|
61307
|
-
}
|
|
61308
|
-
if (req.method === "POST" && req.url === "/cb") {
|
|
61309
|
-
try {
|
|
61310
|
-
const body = await readBody(req);
|
|
61311
|
-
const payload = JSON.parse(body);
|
|
61312
|
-
if (payload.state !== expectedState) {
|
|
61313
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
61314
|
-
res.end(JSON.stringify({ error: "state mismatch" }));
|
|
61315
|
-
return;
|
|
61316
|
-
}
|
|
61317
|
-
if (!payload.access_token || !payload.user_id) {
|
|
61318
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
61319
|
-
res.end(JSON.stringify({ error: "missing fields" }));
|
|
61320
|
-
return;
|
|
61321
|
-
}
|
|
61322
|
-
const session = {
|
|
61323
|
-
schemaVersion: 1,
|
|
61324
|
-
access_token: payload.access_token,
|
|
61325
|
-
refresh_token: payload.refresh_token,
|
|
61326
|
-
expires_at: payload.expires_at,
|
|
61327
|
-
user_id: payload.user_id,
|
|
61328
|
-
email: payload.email,
|
|
61329
|
-
server: payload.server,
|
|
61330
|
-
control_plane_url: normalizeControlPlaneUrl(payload.control_plane_url),
|
|
61331
|
-
supabase_url: payload.supabase_url,
|
|
61332
|
-
supabase_anon_key: payload.supabase_anon_key,
|
|
61333
|
-
authedAt: new Date().toISOString()
|
|
61334
|
-
};
|
|
61335
|
-
writeAuth(session);
|
|
61336
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
61337
|
-
res.end(JSON.stringify({ ok: true }));
|
|
61338
|
-
resolveResult(session);
|
|
61339
|
-
} catch (err) {
|
|
61340
|
-
res.writeHead(500, { "Content-Type": "application/json" });
|
|
61341
|
-
res.end(JSON.stringify({ error: err.message }));
|
|
61342
|
-
rejectResult(err);
|
|
61343
|
-
}
|
|
61344
|
-
return;
|
|
61345
|
-
}
|
|
61346
|
-
res.writeHead(404).end();
|
|
61347
|
-
});
|
|
61348
|
-
await new Promise((resolve, reject2) => {
|
|
61349
|
-
server.once("error", reject2);
|
|
61350
|
-
server.listen(port, "127.0.0.1", () => resolve());
|
|
61351
|
-
});
|
|
61352
|
-
f2.info(`Opening ${import_picocolors21.default.cyan(`${webBase}/cli/auth`)} in your browser…`);
|
|
61353
|
-
f2.info(import_picocolors21.default.dim(`If it doesn't open, visit:`));
|
|
61354
|
-
console.log(import_picocolors21.default.dim(" ") + url);
|
|
61355
|
-
openInBrowser(url);
|
|
61356
61515
|
const spinner = de();
|
|
61357
|
-
|
|
61358
|
-
|
|
61359
|
-
|
|
61360
|
-
|
|
61361
|
-
rejectResult(new Error(`Login timed out after ${LOGIN_TIMEOUT_MS / 1000}s`));
|
|
61362
|
-
}, LOGIN_TIMEOUT_MS);
|
|
61516
|
+
let spinning = false;
|
|
61517
|
+
if (isInsecureWebBase(webBase)) {
|
|
61518
|
+
f2.warn(import_picocolors21.default.yellow(`${webBase} is not HTTPS — your session would cross the network in the clear.`));
|
|
61519
|
+
}
|
|
61363
61520
|
try {
|
|
61364
|
-
const
|
|
61365
|
-
|
|
61366
|
-
|
|
61521
|
+
const authorization = await startDeviceAuthorization({ webBase });
|
|
61522
|
+
f2.step(`Your code: ${import_picocolors21.default.bold(import_picocolors21.default.cyan(displayUserCode(authorization.userCode)))}`);
|
|
61523
|
+
f2.info(`Enter it at ${import_picocolors21.default.cyan(authorization.verificationUri)}`);
|
|
61524
|
+
f2.info(import_picocolors21.default.dim("Opening your browser…"));
|
|
61525
|
+
openInBrowser(authorization.verificationUri);
|
|
61526
|
+
spinner.start("Waiting for you to approve in the browser (Ctrl-C to cancel)");
|
|
61527
|
+
spinning = true;
|
|
61528
|
+
const session = await withCancelOnInterrupt(() => awaitDeviceSession({ webBase, authorization }));
|
|
61529
|
+
const stored = toAuthSession(session, webBase);
|
|
61530
|
+
writeAuth(stored);
|
|
61367
61531
|
spinner.stop("Authorized.");
|
|
61532
|
+
spinning = false;
|
|
61368
61533
|
$e("Welcome to brainbase.");
|
|
61369
|
-
|
|
61370
|
-
|
|
61371
|
-
|
|
61372
|
-
|
|
61373
|
-
|
|
61374
|
-
|
|
61375
|
-
});
|
|
61376
|
-
}
|
|
61534
|
+
await showWelcomeCard({
|
|
61535
|
+
email: stored.email ?? stored.user_id,
|
|
61536
|
+
controlPlaneUrl: controlPlaneBaseUrl(stored),
|
|
61537
|
+
expiresAt: stored.expires_at,
|
|
61538
|
+
hint: "brainbase template pack — bundle your first agent"
|
|
61539
|
+
});
|
|
61377
61540
|
} catch (err) {
|
|
61378
|
-
|
|
61379
|
-
|
|
61541
|
+
if (spinning)
|
|
61542
|
+
spinner.stop("Login failed.");
|
|
61380
61543
|
f2.error(err.message);
|
|
61381
61544
|
process.exit(1);
|
|
61382
61545
|
}
|
|
@@ -74746,8 +74909,8 @@ async function random2(size2) {
|
|
|
74746
74909
|
const evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % mask.length;
|
|
74747
74910
|
let result2 = "";
|
|
74748
74911
|
while (result2.length < size2) {
|
|
74749
|
-
const
|
|
74750
|
-
for (const randomByte of
|
|
74912
|
+
const randomBytes = await getRandomValues(size2 - result2.length);
|
|
74913
|
+
for (const randomByte of randomBytes) {
|
|
74751
74914
|
if (randomByte < evenDistCutoff) {
|
|
74752
74915
|
result2 += mask[randomByte % mask.length];
|
|
74753
74916
|
}
|