@alook/cli 0.0.121 → 0.0.122
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 +166 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16986,6 +16986,7 @@ function loadCLIConfigForProfile(profile) {
|
|
|
16986
16986
|
}
|
|
16987
16987
|
const result = {
|
|
16988
16988
|
server_url: cfg.server_url || "",
|
|
16989
|
+
session_token: cfg.session_token,
|
|
16989
16990
|
watched_workspaces: cfg.watched_workspaces || []
|
|
16990
16991
|
};
|
|
16991
16992
|
const legacy = cfg.machine_token;
|
|
@@ -17010,6 +17011,7 @@ function saveCLIConfigForProfile(profile, profileConfig) {
|
|
|
17010
17011
|
cfg.profiles[profile] = profileConfig;
|
|
17011
17012
|
} else {
|
|
17012
17013
|
cfg.server_url = profileConfig.server_url;
|
|
17014
|
+
cfg.session_token = profileConfig.session_token;
|
|
17013
17015
|
cfg.watched_workspaces = profileConfig.watched_workspaces;
|
|
17014
17016
|
delete cfg.machine_token;
|
|
17015
17017
|
}
|
|
@@ -17429,6 +17431,30 @@ function openBrowser(url2) {
|
|
|
17429
17431
|
function sleep(ms) {
|
|
17430
17432
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
17431
17433
|
}
|
|
17434
|
+
function syncWorkspacesToConfig(serverWorkspaces, profile, sessionToken) {
|
|
17435
|
+
const cfg = loadCLIConfigForProfile(profile);
|
|
17436
|
+
const watched = cfg.watched_workspaces || [];
|
|
17437
|
+
const serverIds = new Set(serverWorkspaces.map((w) => w.id));
|
|
17438
|
+
for (const sw of serverWorkspaces) {
|
|
17439
|
+
const existing = watched.find((w) => w.id === sw.id);
|
|
17440
|
+
if (existing) {
|
|
17441
|
+
existing.status = "active";
|
|
17442
|
+
existing.name = sw.name;
|
|
17443
|
+
} else {
|
|
17444
|
+
watched.push({ id: sw.id, name: sw.name, token: "", status: "active", agent_ids: [] });
|
|
17445
|
+
}
|
|
17446
|
+
}
|
|
17447
|
+
for (const w of watched) {
|
|
17448
|
+
if (w.id && !serverIds.has(w.id) && w.status !== "registered") {
|
|
17449
|
+
w.status = "deleted";
|
|
17450
|
+
}
|
|
17451
|
+
}
|
|
17452
|
+
saveCLIConfigForProfile(profile, {
|
|
17453
|
+
server_url: cfg.server_url,
|
|
17454
|
+
session_token: sessionToken ?? cfg.session_token,
|
|
17455
|
+
watched_workspaces: watched
|
|
17456
|
+
});
|
|
17457
|
+
}
|
|
17432
17458
|
async function pollAndActivate(opts) {
|
|
17433
17459
|
const { deviceCode, expiresIn, serverUrl, profile } = opts;
|
|
17434
17460
|
let interval = opts.interval;
|
|
@@ -17479,13 +17505,12 @@ async function pollAndActivate(opts) {
|
|
|
17479
17505
|
const me = await client.getJSON("/api/me");
|
|
17480
17506
|
email3 = me.email;
|
|
17481
17507
|
} catch {}
|
|
17482
|
-
let
|
|
17508
|
+
let serverWorkspaces = [];
|
|
17483
17509
|
try {
|
|
17484
|
-
|
|
17485
|
-
if (workspaces.length > 0) {
|
|
17486
|
-
existingWorkspaceId = workspaces[0].id;
|
|
17487
|
-
}
|
|
17510
|
+
serverWorkspaces = await client.getJSON("/api/workspaces");
|
|
17488
17511
|
} catch {}
|
|
17512
|
+
syncWorkspacesToConfig(serverWorkspaces, profile, sessionToken);
|
|
17513
|
+
const existingWorkspaceId = serverWorkspaces.length > 0 ? serverWorkspaces[0].id : "";
|
|
17489
17514
|
const mtUrl = existingWorkspaceId ? `/api/machine-tokens?workspace_id=${existingWorkspaceId}` : "/api/machine-tokens";
|
|
17490
17515
|
let machineToken2;
|
|
17491
17516
|
try {
|
|
@@ -17515,32 +17540,37 @@ if (process.argv.includes("--__login-poll")) {
|
|
|
17515
17540
|
}
|
|
17516
17541
|
async function checkExistingAuth(serverUrl, profile) {
|
|
17517
17542
|
const config2 = loadCLIConfigForProfile(profile);
|
|
17543
|
+
const sessionToken = config2.session_token;
|
|
17518
17544
|
const workspaces = config2.watched_workspaces || [];
|
|
17519
|
-
if (workspaces.length === 0) {
|
|
17520
|
-
return { valid: false };
|
|
17521
|
-
}
|
|
17522
17545
|
const ws = workspaces[0];
|
|
17523
|
-
|
|
17546
|
+
const authToken = sessionToken || ws?.token;
|
|
17547
|
+
if (!authToken) {
|
|
17524
17548
|
return { valid: false };
|
|
17525
17549
|
}
|
|
17526
17550
|
try {
|
|
17527
17551
|
const res = await fetch(`${serverUrl}/api/workspaces`, {
|
|
17528
|
-
headers: { Authorization: `Bearer ${
|
|
17552
|
+
headers: { Authorization: `Bearer ${authToken}` }
|
|
17529
17553
|
});
|
|
17530
17554
|
if (!res.ok) {
|
|
17531
17555
|
return { valid: false };
|
|
17532
17556
|
}
|
|
17557
|
+
const serverWorkspaces = await res.json();
|
|
17558
|
+
const hasValidWorkspace = workspaces.some((w) => w.id && w.status !== "deleted");
|
|
17559
|
+
if (!hasValidWorkspace && serverWorkspaces.length > 0) {
|
|
17560
|
+
syncWorkspacesToConfig(serverWorkspaces, profile);
|
|
17561
|
+
}
|
|
17533
17562
|
let email3;
|
|
17534
17563
|
try {
|
|
17535
17564
|
const meRes = await fetch(`${serverUrl}/api/me`, {
|
|
17536
|
-
headers: { Authorization: `Bearer ${
|
|
17565
|
+
headers: { Authorization: `Bearer ${authToken}` }
|
|
17537
17566
|
});
|
|
17538
17567
|
if (meRes.ok) {
|
|
17539
17568
|
const me = await meRes.json();
|
|
17540
17569
|
email3 = me.email;
|
|
17541
17570
|
}
|
|
17542
17571
|
} catch {}
|
|
17543
|
-
|
|
17572
|
+
const workspaceName = (serverWorkspaces.length > 0 ? serverWorkspaces[0].name : undefined) || ws?.name || undefined;
|
|
17573
|
+
return { valid: true, email: email3, workspaceName };
|
|
17544
17574
|
} catch {
|
|
17545
17575
|
return { valid: false };
|
|
17546
17576
|
}
|
|
@@ -22175,6 +22205,14 @@ function getRootOpts(command) {
|
|
|
22175
22205
|
|
|
22176
22206
|
// lib/resolve-client.ts
|
|
22177
22207
|
function resolveClientOpts(command, opts = {}) {
|
|
22208
|
+
const result = resolveClientOptsPartial(command, opts);
|
|
22209
|
+
if (!result.workspaceId) {
|
|
22210
|
+
console.error("Error: cannot determine workspace. Set ALOOK_WORKSPACE_ID env var or use --workspace flag.");
|
|
22211
|
+
process.exit(1);
|
|
22212
|
+
}
|
|
22213
|
+
return result;
|
|
22214
|
+
}
|
|
22215
|
+
function resolveClientOptsPartial(command, opts = {}) {
|
|
22178
22216
|
const parentOpts = getRootOpts(command);
|
|
22179
22217
|
const cfg = loadCLIConfigForProfile(parentOpts.profile);
|
|
22180
22218
|
const serverUrl = parentOpts.server || process.env.ALOOK_SERVER_URL || cfg.server_url;
|
|
@@ -22206,16 +22244,12 @@ function resolveClientOpts(command, opts = {}) {
|
|
|
22206
22244
|
ws = workspaces[0];
|
|
22207
22245
|
}
|
|
22208
22246
|
const envToken = process.env.ALOOK_TOKEN;
|
|
22209
|
-
const token = envToken || ws?.token;
|
|
22247
|
+
const token = envToken || ws?.token || cfg.session_token;
|
|
22210
22248
|
if (!token) {
|
|
22211
22249
|
console.error(`Error: not registered. Run '${cmdPrefix()} register --token <token>' first.`);
|
|
22212
22250
|
process.exit(1);
|
|
22213
22251
|
}
|
|
22214
|
-
const workspaceId = ws?.id || envWorkspaceId;
|
|
22215
|
-
if (!workspaceId) {
|
|
22216
|
-
console.error("Error: cannot determine workspace. Set ALOOK_WORKSPACE_ID env var or use --workspace flag.");
|
|
22217
|
-
process.exit(1);
|
|
22218
|
-
}
|
|
22252
|
+
const workspaceId = ws?.id || envWorkspaceId || undefined;
|
|
22219
22253
|
return { serverUrl, token, workspaceId };
|
|
22220
22254
|
}
|
|
22221
22255
|
|
|
@@ -23231,11 +23265,40 @@ import { readFileSync as readFileSync14 } from "fs";
|
|
|
23231
23265
|
function slugify2(name) {
|
|
23232
23266
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
23233
23267
|
}
|
|
23268
|
+
function sleep4(ms) {
|
|
23269
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
23270
|
+
}
|
|
23271
|
+
async function resolveWorkspaceId(client, configName) {
|
|
23272
|
+
let workspaces;
|
|
23273
|
+
try {
|
|
23274
|
+
workspaces = await client.getJSON("/api/workspaces");
|
|
23275
|
+
} catch (err) {
|
|
23276
|
+
console.error(`Error: failed to fetch workspaces: ${err instanceof Error ? err.message : err}`);
|
|
23277
|
+
process.exit(1);
|
|
23278
|
+
}
|
|
23279
|
+
for (const ws of workspaces) {
|
|
23280
|
+
try {
|
|
23281
|
+
const agents = await client.getJSON(`/api/agents?workspace_id=${ws.id}`);
|
|
23282
|
+
if (agents.length === 0) {
|
|
23283
|
+
return { workspaceId: ws.id, created: false };
|
|
23284
|
+
}
|
|
23285
|
+
} catch {}
|
|
23286
|
+
}
|
|
23287
|
+
const wsName = configName || "Personal";
|
|
23288
|
+
try {
|
|
23289
|
+
const newWs = await client.postJSON("/api/workspaces", { name: wsName, slug: slugify2(wsName) });
|
|
23290
|
+
console.log(`Created workspace: ${newWs.name} (${newWs.id})`);
|
|
23291
|
+
return { workspaceId: newWs.id, created: true };
|
|
23292
|
+
} catch (err) {
|
|
23293
|
+
console.error(`Error: failed to create workspace: ${err instanceof Error ? err.message : err}`);
|
|
23294
|
+
process.exit(1);
|
|
23295
|
+
}
|
|
23296
|
+
}
|
|
23234
23297
|
function workspaceCommand() {
|
|
23235
23298
|
const cmd = new Command13("workspace").description("Manage workspaces");
|
|
23236
23299
|
cmd.command("init").description("Initialize a workspace from a JSON configuration file").requiredOption("--json-file <path>", "Path to the JSON configuration file").option("--name <name>", "Workspace name (overrides JSON)").option("--json", "Output as JSON").action(async (opts, command) => {
|
|
23237
|
-
const { serverUrl, token, workspaceId } =
|
|
23238
|
-
const client = new APIClient(serverUrl, token,
|
|
23300
|
+
const { serverUrl, token, workspaceId: resolvedWorkspaceId } = resolveClientOptsPartial(command);
|
|
23301
|
+
const client = new APIClient(serverUrl, token, resolvedWorkspaceId);
|
|
23239
23302
|
let configJson;
|
|
23240
23303
|
try {
|
|
23241
23304
|
configJson = readFileSync14(opts.jsonFile, "utf-8");
|
|
@@ -23254,9 +23317,89 @@ function workspaceCommand() {
|
|
|
23254
23317
|
console.error("Error: JSON must contain a 'members' array with at least one member");
|
|
23255
23318
|
process.exit(1);
|
|
23256
23319
|
}
|
|
23320
|
+
let targetWorkspaceId = resolvedWorkspaceId;
|
|
23321
|
+
if (!targetWorkspaceId) {
|
|
23322
|
+
const resolved = await resolveWorkspaceId(client, opts.name || config2.name);
|
|
23323
|
+
targetWorkspaceId = resolved.workspaceId;
|
|
23324
|
+
const parentOpts = getRootOpts(command);
|
|
23325
|
+
const cfg = loadCLIConfigForProfile(parentOpts.profile);
|
|
23326
|
+
const registeredWs = cfg.watched_workspaces?.find((w) => w.status === "registered" && !w.id);
|
|
23327
|
+
if (registeredWs) {
|
|
23328
|
+
try {
|
|
23329
|
+
await client.postJSON("/api/machine-tokens/bind-workspace", { workspace_id: targetWorkspaceId });
|
|
23330
|
+
console.log("Machine token bound to workspace. Waiting for runtime registration...");
|
|
23331
|
+
} catch (err) {
|
|
23332
|
+
console.warn(`Warning: bind-workspace failed: ${err instanceof Error ? err.message : err}`);
|
|
23333
|
+
}
|
|
23334
|
+
}
|
|
23335
|
+
let runtimes2 = [];
|
|
23336
|
+
const wsClient = new APIClient(serverUrl, token, targetWorkspaceId);
|
|
23337
|
+
for (let attempt = 0;attempt < 15; attempt++) {
|
|
23338
|
+
try {
|
|
23339
|
+
runtimes2 = await wsClient.getJSON("/api/runtimes");
|
|
23340
|
+
if (runtimes2.length > 0)
|
|
23341
|
+
break;
|
|
23342
|
+
} catch {}
|
|
23343
|
+
await sleep4(1000);
|
|
23344
|
+
}
|
|
23345
|
+
if (runtimes2.length === 0) {
|
|
23346
|
+
console.error(`Error: No daemon registered after waiting. Run '${cmdPrefix()} daemon start' first.`);
|
|
23347
|
+
process.exit(1);
|
|
23348
|
+
}
|
|
23349
|
+
const OFFLINE_THRESHOLD_MS3 = 5 * 60 * 1000;
|
|
23350
|
+
const now2 = Date.now();
|
|
23351
|
+
const onlineRuntime2 = runtimes2.find((r) => {
|
|
23352
|
+
if (!r.machineLastSeenAt)
|
|
23353
|
+
return false;
|
|
23354
|
+
const lastSeen = new Date(r.machineLastSeenAt.includes("Z") ? r.machineLastSeenAt : r.machineLastSeenAt + "Z").getTime();
|
|
23355
|
+
return now2 - lastSeen < OFFLINE_THRESHOLD_MS3;
|
|
23356
|
+
});
|
|
23357
|
+
const runtime2 = onlineRuntime2 || runtimes2[0];
|
|
23358
|
+
const members2 = config2.members.map((m) => ({
|
|
23359
|
+
...m,
|
|
23360
|
+
runtime_id: runtime2.id
|
|
23361
|
+
}));
|
|
23362
|
+
const payload2 = {
|
|
23363
|
+
name: opts.name || config2.name,
|
|
23364
|
+
scenario: config2.scenario,
|
|
23365
|
+
members: members2
|
|
23366
|
+
};
|
|
23367
|
+
try {
|
|
23368
|
+
const res = await wsClient.postJSON("/api/studios", payload2);
|
|
23369
|
+
try {
|
|
23370
|
+
const freshCfg = loadCLIConfigForProfile(parentOpts.profile);
|
|
23371
|
+
const watched = freshCfg.watched_workspaces || [];
|
|
23372
|
+
const existing = watched.find((w) => w.id === targetWorkspaceId);
|
|
23373
|
+
if (existing) {
|
|
23374
|
+
existing.status = "active";
|
|
23375
|
+
existing.name = res.workspace.name;
|
|
23376
|
+
} else {
|
|
23377
|
+
watched.push({ id: targetWorkspaceId, name: res.workspace.name, token, status: "active", agent_ids: [] });
|
|
23378
|
+
}
|
|
23379
|
+
freshCfg.watched_workspaces = watched;
|
|
23380
|
+
saveCLIConfigForProfile(parentOpts.profile, freshCfg);
|
|
23381
|
+
} catch {}
|
|
23382
|
+
if (opts.json)
|
|
23383
|
+
return printJSON(res);
|
|
23384
|
+
console.log(`
|
|
23385
|
+
Workspace initialized: ${res.studio.name || res.workspace.name}`);
|
|
23386
|
+
console.log("Agents created:");
|
|
23387
|
+
for (const agent2 of res.agents) {
|
|
23388
|
+
const email3 = agent2.email_handle ? toAlookAddress(agent2.email_handle) : "no email";
|
|
23389
|
+
console.log(` - ${agent2.name} (${email3})`);
|
|
23390
|
+
}
|
|
23391
|
+
console.log(`
|
|
23392
|
+
Open: ${serverUrl}/w/${res.workspace.slug}`);
|
|
23393
|
+
} catch (err) {
|
|
23394
|
+
console.error(`Error: failed to create workspace: ${err instanceof Error ? err.message : err}`);
|
|
23395
|
+
process.exit(1);
|
|
23396
|
+
}
|
|
23397
|
+
return;
|
|
23398
|
+
}
|
|
23399
|
+
let targetClient = new APIClient(serverUrl, token, targetWorkspaceId);
|
|
23257
23400
|
let runtimes;
|
|
23258
23401
|
try {
|
|
23259
|
-
runtimes = await
|
|
23402
|
+
runtimes = await targetClient.getJSON("/api/runtimes");
|
|
23260
23403
|
} catch (err) {
|
|
23261
23404
|
console.error(`Error: failed to fetch runtimes: ${err instanceof Error ? err.message : err}`);
|
|
23262
23405
|
process.exit(1);
|
|
@@ -23274,14 +23417,12 @@ function workspaceCommand() {
|
|
|
23274
23417
|
return now - lastSeen < OFFLINE_THRESHOLD_MS2;
|
|
23275
23418
|
});
|
|
23276
23419
|
let runtime = onlineRuntime || runtimes[0];
|
|
23277
|
-
let targetWorkspaceId = workspaceId;
|
|
23278
|
-
let targetClient = client;
|
|
23279
23420
|
try {
|
|
23280
|
-
const agents = await
|
|
23421
|
+
const agents = await targetClient.getJSON(`/api/agents?workspace_id=${targetWorkspaceId}`);
|
|
23281
23422
|
if (agents.length > 0) {
|
|
23282
23423
|
console.log("Current workspace has existing agents. Creating a new workspace...");
|
|
23283
23424
|
const wsName = opts.name || config2.name || "New Workspace";
|
|
23284
|
-
const newWs = await
|
|
23425
|
+
const newWs = await targetClient.postJSON("/api/workspaces", { name: wsName, slug: slugify2(wsName) });
|
|
23285
23426
|
targetWorkspaceId = newWs.id;
|
|
23286
23427
|
targetClient = new APIClient(serverUrl, token, targetWorkspaceId);
|
|
23287
23428
|
console.log(`Created workspace: ${newWs.name} (${newWs.id})`);
|