bazilion 0.20.0 → 0.21.0-beta.2
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 +430 -369
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +811 -488
- package/dist/daemon.js.map +1 -1
- package/dist/migrations/0001_init.sql +2 -1
- package/dist/migrations/0002_device_token_scopes.sql +8 -0
- package/dist/migrations/0003_web_pairing_tokens.sql +18 -0
- package/dist/web/client/assets/{ChatPane-CGCtAuD3.js → ChatPane--0BWZYHD.js} +1 -1
- package/dist/web/client/assets/{ConfirmDialog-Br19uXWH.js → ConfirmDialog-D9AiLH_Z.js} +1 -1
- package/dist/web/client/assets/{FieldRow-Csy3_cH5.js → FieldRow-Cd0EUpYd.js} +1 -1
- package/dist/web/client/assets/{ProductionTeamPolicyEditor-DG1x4Cqz.js → ProductionTeamPolicyEditor-BR5_1Wyv.js} +1 -1
- package/dist/web/client/assets/{ProfileCommunicationEditor-C3odNVkK.js → ProfileCommunicationEditor-K2wGbGky.js} +1 -1
- package/dist/web/client/assets/{ResultSourceConversation-5PFWqXTY.js → ResultSourceConversation-Y9VTd-nz.js} +1 -1
- package/dist/web/client/assets/{TeamTabs-BHB_COm0.js → TeamTabs-Yuc_lSZ9.js} +1 -1
- package/dist/web/client/assets/{TemplatesTabs-YyytjW7k.js → TemplatesTabs-Pj00chC7.js} +1 -1
- package/dist/web/client/assets/{UnsavedChangesGuard-CredyC3E.js → UnsavedChangesGuard-BSfJZH7E.js} +1 -1
- package/dist/web/client/assets/{_id-CIkPtQY0.js → _id-B4yPnTNN.js} +1 -1
- package/dist/web/client/assets/{_id-KXX6nuKc.js → _id-CUbb0F4l.js} +1 -1
- package/dist/web/client/assets/{_id-BZ_-4M4s.js → _id-D2l33vb6.js} +1 -1
- package/dist/web/client/assets/{_id-BLm9LVlZ.js → _id-DCFRZAJN.js} +1 -1
- package/dist/web/client/assets/{_id-nDbQY7f_.js → _id-UniNI3bQ.js} +1 -1
- package/dist/web/client/assets/{activity-BE7jG1Mz.js → activity-C5QG0Wgv.js} +1 -1
- package/dist/web/client/assets/{agents-S9lzXrrs.js → agents-CQo9V1lc.js} +1 -1
- package/dist/web/client/assets/{agents-vOPd-upn.js → agents-DVVPYxPM.js} +1 -1
- package/dist/web/client/assets/{approvals-BUfhlUAX.js → approvals-DQz6TJE8.js} +1 -1
- package/dist/web/client/assets/{attention-C3r-2GSp.js → attention-BtCLaWhZ.js} +1 -1
- package/dist/web/client/assets/chevron-right-BGFokHDA.js +1 -0
- package/dist/web/client/assets/{config-AL_EM57n.js → config-DuhKvD0X.js} +1 -1
- package/dist/web/client/assets/{inbox-LlCpJrMH.js → inbox-Cr7iGkrF.js} +1 -1
- package/dist/web/client/assets/{index-CwMw0pnV.js → index-ChXVa4eb.js} +2 -2
- package/dist/web/client/assets/{learning-zvTJ_9vM.js → learning-5eO_SZUP.js} +1 -1
- package/dist/web/client/assets/{login-BpQ54z8Y.js → login-Cn9mf44C.js} +1 -1
- package/dist/web/client/assets/{mcp-BD6VzXg_.js → mcp-0COajQD4.js} +1 -1
- package/dist/web/client/assets/{members-SEDi8SFo.js → members-9eTmy1QM.js} +1 -1
- package/dist/web/client/assets/{memory-zi_dPlMA.js → memory-CExQd_vP.js} +1 -1
- package/dist/web/client/assets/{policy-URjQAAdN.js → policy-B-zDlt_G.js} +1 -1
- package/dist/web/client/assets/{results-Bcuy4Flp.js → results-BUmKkuHo.js} +1 -1
- package/dist/web/client/assets/{review-CVH7X9-d.js → review-BUTz_zRX.js} +1 -1
- package/dist/web/client/assets/{routes-BJEX6yAE.js → routes-b1FscQsH.js} +1 -1
- package/dist/web/client/assets/{services-BTG4F5FL.js → services-D-RdMc8g.js} +1 -1
- package/dist/web/client/assets/{skills-DwiHS7eD.js → skills-CNbkY2ji.js} +1 -1
- package/dist/web/client/assets/{teams-DfpwQu1i.js → teams-Dn9o_-P-.js} +1 -1
- package/dist/web/client/assets/{teams-DcROmSGB.js → teams-H4OTWt8E.js} +1 -1
- package/dist/web/client/assets/{telegram-BLyaaUXE.js → telegram-BnM54CPN.js} +1 -1
- package/dist/web/client/assets/tokens-C-I23fVZ.js +1 -0
- package/dist/web/client/assets/{triggers-CtVhrAGA.js → triggers-DG9YoC7B.js} +1 -1
- package/dist/web/client/assets/{verifications-TC0ccGLY.js → verifications-CzToBSUN.js} +1 -1
- package/dist/web/client/assets/{welcome-DML3X1ha.js → welcome-REp-dEfY.js} +1 -1
- package/dist/web/client/assets/{x-D8yuCam7.js → x-C-BpLdcp.js} +1 -1
- package/dist/web/server/assets/{_tanstack-start-manifest_v-BGSoO6CK.js → _tanstack-start-manifest_v-BfURdqEL.js} +82 -82
- package/dist/web/server/assets/{router-BVhdWkwP.js → router-CyZ-GH8M.js} +1 -1
- package/dist/web/server/assets/{tokens-_2hptHP6.js → tokens-BFhrz5qd.js} +1 -1
- package/dist/web/server/assets/{tokens-DDwtO15P.js → tokens-DO_eDpv_.js} +96 -3
- package/dist/web/server/server.js +2 -2
- package/dist/worker.js +127 -90
- package/dist/worker.js.map +1 -1
- package/package.json +3 -3
- package/dist/web/client/assets/chevron-right-C7P3Z105.js +0 -1
- package/dist/web/client/assets/tokens-Dp9Vwvfx.js +0 -1
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import { defineCommand as defineCommand39, runCommand, showUsage } from "citty";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "bazilion",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.21.0-beta.2",
|
|
10
10
|
description: "Multi-agent runtime CLI \u2014 spawn LLM agents, manage profiles/teams/skills, and run the local daemon.",
|
|
11
11
|
license: "MIT",
|
|
12
12
|
repository: {
|
|
@@ -375,12 +375,29 @@ function readAuthFile(authFile) {
|
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
// src/paths.ts
|
|
378
|
+
import { realpathSync } from "fs";
|
|
378
379
|
import { homedir } from "os";
|
|
379
|
-
import { join } from "path";
|
|
380
|
+
import { basename, dirname, join, resolve } from "path";
|
|
380
381
|
function resolveCliPaths(home) {
|
|
381
|
-
const root = home ?? process.env.BAZILION_HOME ?? join(homedir(), ".bazilion");
|
|
382
|
+
const root = canonicalHome(resolve(home ?? process.env.BAZILION_HOME ?? join(homedir(), ".bazilion")));
|
|
382
383
|
return { home: root, authFile: join(root, "auth.json") };
|
|
383
384
|
}
|
|
385
|
+
function canonicalHome(root) {
|
|
386
|
+
let resolved = root;
|
|
387
|
+
const unresolvedTail = [];
|
|
388
|
+
while (true) {
|
|
389
|
+
try {
|
|
390
|
+
resolved = realpathSync(resolved);
|
|
391
|
+
break;
|
|
392
|
+
} catch {
|
|
393
|
+
const parent = dirname(resolved);
|
|
394
|
+
if (parent === resolved) break;
|
|
395
|
+
unresolvedTail.unshift(basename(resolved));
|
|
396
|
+
resolved = parent;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return join(resolved, ...unresolvedTail);
|
|
400
|
+
}
|
|
384
401
|
|
|
385
402
|
// src/client.ts
|
|
386
403
|
function loadClientConfig() {
|
|
@@ -721,7 +738,7 @@ var questionCommand = defineCommand3({
|
|
|
721
738
|
// src/commands/queue.ts
|
|
722
739
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
723
740
|
import { readFileSync as readFileSync2, statSync } from "fs";
|
|
724
|
-
import { basename, extname } from "path";
|
|
741
|
+
import { basename as basename2, extname } from "path";
|
|
725
742
|
import { defineCommand as defineCommand4 } from "citty";
|
|
726
743
|
var positional4 = { type: "positional", required: true };
|
|
727
744
|
var output3 = (value) => console.log(JSON.stringify(value, null, 2));
|
|
@@ -796,7 +813,7 @@ async function submit(args2, replacement) {
|
|
|
796
813
|
".pdf": "application/pdf"
|
|
797
814
|
};
|
|
798
815
|
return {
|
|
799
|
-
name:
|
|
816
|
+
name: basename2(path),
|
|
800
817
|
mimeType: mime[extname(path).toLowerCase()] ?? "application/octet-stream",
|
|
801
818
|
data: readFileSync2(path).toString("base64")
|
|
802
819
|
};
|
|
@@ -886,7 +903,7 @@ var queueCommand = defineCommand4({
|
|
|
886
903
|
// src/commands/agent.ts
|
|
887
904
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
888
905
|
import { readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
889
|
-
import { basename as
|
|
906
|
+
import { basename as basename3, extname as extname2 } from "path";
|
|
890
907
|
import { stdin, stdout } from "process";
|
|
891
908
|
import { createInterface } from "readline/promises";
|
|
892
909
|
import { defineCommand as defineCommand5 } from "citty";
|
|
@@ -978,7 +995,7 @@ function loadImages(paths) {
|
|
|
978
995
|
return paths.map((p) => {
|
|
979
996
|
const mimeType = IMAGE_MIME[extname2(p).toLowerCase()];
|
|
980
997
|
if (!mimeType) throw new Error(`unsupported image type: ${p} (png/jpg/gif/webp only)`);
|
|
981
|
-
return { name:
|
|
998
|
+
return { name: basename3(p), mimeType, data: readFileSync3(p).toString("base64") };
|
|
982
999
|
});
|
|
983
1000
|
}
|
|
984
1001
|
var FILE_MIME = {
|
|
@@ -992,7 +1009,7 @@ var FILE_MIME = {
|
|
|
992
1009
|
};
|
|
993
1010
|
function loadFiles(paths) {
|
|
994
1011
|
return paths.map((p) => ({
|
|
995
|
-
name:
|
|
1012
|
+
name: basename3(p),
|
|
996
1013
|
mimeType: FILE_MIME[extname2(p).toLowerCase()] ?? "application/octet-stream",
|
|
997
1014
|
data: readFileSync3(p).toString("base64")
|
|
998
1015
|
}));
|
|
@@ -1268,7 +1285,7 @@ function printEvent(e, state) {
|
|
|
1268
1285
|
process.stdout.write("\n");
|
|
1269
1286
|
state.inDeltaStream = false;
|
|
1270
1287
|
}
|
|
1271
|
-
const out =
|
|
1288
|
+
const out = basename3(e.name).replace(/[^\w.-]/g, "_") || "file";
|
|
1272
1289
|
writeFileSync(out, Buffer.from(e.data, "base64"));
|
|
1273
1290
|
console.log(` [file received: saved to ./${out} (${e.mimeType})]`);
|
|
1274
1291
|
break;
|
|
@@ -1387,69 +1404,34 @@ var chatCmd = defineCommand5({
|
|
|
1387
1404
|
}
|
|
1388
1405
|
return;
|
|
1389
1406
|
}
|
|
1407
|
+
if (bashApprovalMode === "interactive") {
|
|
1408
|
+
console.error(
|
|
1409
|
+
`usage: bazilion agent chat ${args2.id} --message "..." (one-shot) \u2014 for a conversational surface, use the web UI`
|
|
1410
|
+
);
|
|
1411
|
+
process.exitCode = 1;
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1390
1414
|
console.log(`chatting with ${resolved.agent.name} (${resolved.model})`);
|
|
1391
|
-
console.log("(type /exit to quit)");
|
|
1415
|
+
console.log("(type /exit to quit; input is piped, commands run with auto_deny)");
|
|
1392
1416
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
1393
1417
|
try {
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
let line;
|
|
1401
|
-
try {
|
|
1402
|
-
const answer = rl.question("> ");
|
|
1403
|
-
if (retryDraft) {
|
|
1404
|
-
rl.write(retryDraft);
|
|
1405
|
-
retryDraft = "";
|
|
1406
|
-
}
|
|
1407
|
-
line = await answer;
|
|
1408
|
-
} catch {
|
|
1409
|
-
break;
|
|
1410
|
-
}
|
|
1411
|
-
const trimmed = line.trim();
|
|
1412
|
-
if (trimmed === "/exit" || trimmed === "/quit") break;
|
|
1413
|
-
if (!trimmed) continue;
|
|
1414
|
-
try {
|
|
1415
|
-
await streamTurn(client, resolved.agent.id, trimmed, void 0, {
|
|
1416
|
-
bashApprovalMode,
|
|
1417
|
-
expectedSelection: observed.selection,
|
|
1418
|
-
questionPrompt: {
|
|
1419
|
-
question: (text2, signal) => rl.question(text2, { signal }),
|
|
1420
|
-
write: (line2) => console.log(line2)
|
|
1421
|
-
},
|
|
1422
|
-
approvalPrompt: {
|
|
1423
|
-
question: (question) => rl.question(question),
|
|
1424
|
-
write: (output4) => console.log(output4)
|
|
1425
|
-
}
|
|
1426
|
-
});
|
|
1427
|
-
} catch (err) {
|
|
1428
|
-
retryDraft = trimmed;
|
|
1429
|
-
console.error(
|
|
1430
|
-
`error: ${err.message}. Review the preserved draft before retrying.`
|
|
1431
|
-
);
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
} else {
|
|
1435
|
-
rl.setPrompt("> ");
|
|
1436
|
-
rl.prompt();
|
|
1437
|
-
for await (const line of rl) {
|
|
1438
|
-
const trimmed = line.trim();
|
|
1439
|
-
if (trimmed === "/exit" || trimmed === "/quit") break;
|
|
1440
|
-
if (!trimmed) {
|
|
1441
|
-
rl.prompt();
|
|
1442
|
-
continue;
|
|
1443
|
-
}
|
|
1444
|
-
try {
|
|
1445
|
-
await streamTurn(client, resolved.agent.id, trimmed, void 0, {
|
|
1446
|
-
bashApprovalMode
|
|
1447
|
-
});
|
|
1448
|
-
} catch (err) {
|
|
1449
|
-
console.error(`error: ${err.message}`);
|
|
1450
|
-
}
|
|
1418
|
+
rl.setPrompt("> ");
|
|
1419
|
+
rl.prompt();
|
|
1420
|
+
for await (const line of rl) {
|
|
1421
|
+
const trimmed = line.trim();
|
|
1422
|
+
if (trimmed === "/exit" || trimmed === "/quit") break;
|
|
1423
|
+
if (!trimmed) {
|
|
1451
1424
|
rl.prompt();
|
|
1425
|
+
continue;
|
|
1426
|
+
}
|
|
1427
|
+
try {
|
|
1428
|
+
await streamTurn(client, resolved.agent.id, trimmed, void 0, {
|
|
1429
|
+
bashApprovalMode
|
|
1430
|
+
});
|
|
1431
|
+
} catch (err) {
|
|
1432
|
+
console.error(`error: ${err.message}`);
|
|
1452
1433
|
}
|
|
1434
|
+
rl.prompt();
|
|
1453
1435
|
}
|
|
1454
1436
|
} finally {
|
|
1455
1437
|
rl.close();
|
|
@@ -1593,8 +1575,8 @@ var chatCompactCmd = defineCommand5({
|
|
|
1593
1575
|
process.stdout.write(
|
|
1594
1576
|
`compact chat history for ${args2.id}? head turns become a summary; tail is preserved. [y/N] `
|
|
1595
1577
|
);
|
|
1596
|
-
const answer = await new Promise((
|
|
1597
|
-
process.stdin.once("data", (d) =>
|
|
1578
|
+
const answer = await new Promise((resolve7) => {
|
|
1579
|
+
process.stdin.once("data", (d) => resolve7(String(d).trim().toLowerCase()));
|
|
1598
1580
|
});
|
|
1599
1581
|
if (answer !== "y" && answer !== "yes") {
|
|
1600
1582
|
console.log("aborted");
|
|
@@ -2121,7 +2103,7 @@ function answerCliOpenAIPrompt(prompt, input = process.stdin, output4 = process.
|
|
|
2121
2103
|
);
|
|
2122
2104
|
}
|
|
2123
2105
|
output4.write(`${prompt.message}: `);
|
|
2124
|
-
return new Promise((
|
|
2106
|
+
return new Promise((resolve7, reject) => {
|
|
2125
2107
|
let settled = false;
|
|
2126
2108
|
const signal = prompt.signal;
|
|
2127
2109
|
let readingInput = true;
|
|
@@ -2142,7 +2124,7 @@ function answerCliOpenAIPrompt(prompt, input = process.stdin, output4 = process.
|
|
|
2142
2124
|
if (settled) return;
|
|
2143
2125
|
settled = true;
|
|
2144
2126
|
cleanup();
|
|
2145
|
-
|
|
2127
|
+
resolve7(String(data).trim());
|
|
2146
2128
|
};
|
|
2147
2129
|
const onAbort = () => {
|
|
2148
2130
|
if (settled || !signal) return;
|
|
@@ -2318,16 +2300,17 @@ import {
|
|
|
2318
2300
|
mkdirSync as mkdirSync2,
|
|
2319
2301
|
mkdtempSync,
|
|
2320
2302
|
openSync as openSync2,
|
|
2321
|
-
readdirSync,
|
|
2322
|
-
readFileSync as
|
|
2303
|
+
readdirSync as readdirSync2,
|
|
2304
|
+
readFileSync as readFileSync6,
|
|
2323
2305
|
readSync,
|
|
2306
|
+
realpathSync as realpathSync3,
|
|
2324
2307
|
renameSync as renameSync2,
|
|
2325
2308
|
rmSync as rmSync2,
|
|
2326
2309
|
writeFileSync as writeFileSync2
|
|
2327
2310
|
} from "fs";
|
|
2328
2311
|
import { tmpdir } from "os";
|
|
2329
|
-
import { basename as
|
|
2330
|
-
import { DatabaseSync as
|
|
2312
|
+
import { basename as basename5, dirname as dirname4, isAbsolute, join as join4, parse, posix, relative, resolve as resolve4 } from "path";
|
|
2313
|
+
import { DatabaseSync as DatabaseSync4, backup as sqliteBackup } from "node:sqlite";
|
|
2331
2314
|
import { Readable } from "stream";
|
|
2332
2315
|
import { pipeline } from "stream/promises";
|
|
2333
2316
|
import { Decrypter, Encrypter } from "age-encryption";
|
|
@@ -2336,7 +2319,7 @@ import { extract, list as list5 } from "tar";
|
|
|
2336
2319
|
|
|
2337
2320
|
// src/backup-coding-recovery.ts
|
|
2338
2321
|
import { lstatSync } from "fs";
|
|
2339
|
-
import { resolve } from "path";
|
|
2322
|
+
import { resolve as resolve2 } from "path";
|
|
2340
2323
|
function invalidateRestoredCodingEvidence(db, payload, targetHome) {
|
|
2341
2324
|
const rows = db.prepare("SELECT id, receipt_json FROM coding_commands").all();
|
|
2342
2325
|
for (const row2 of rows) {
|
|
@@ -2399,8 +2382,8 @@ function invalidateRestoredCodingEvidence(db, payload, targetHome) {
|
|
|
2399
2382
|
const teams = db.prepare("SELECT id FROM teams").all();
|
|
2400
2383
|
const rebase = db.prepare("UPDATE workspace_writers SET root_path = ? WHERE team_id = ?");
|
|
2401
2384
|
for (const team of teams) {
|
|
2402
|
-
if (lstatSync(
|
|
2403
|
-
rebase.run(
|
|
2385
|
+
if (lstatSync(resolve2(payload, "teams", team.id)).isDirectory())
|
|
2386
|
+
rebase.run(resolve2(targetHome, "teams", team.id), team.id);
|
|
2404
2387
|
}
|
|
2405
2388
|
}
|
|
2406
2389
|
|
|
@@ -2475,174 +2458,180 @@ function pauseRestoredUserQueue(database) {
|
|
|
2475
2458
|
|
|
2476
2459
|
// src/backup-schema.ts
|
|
2477
2460
|
import { createHash } from "crypto";
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
["table", "trigger_dispatches"],
|
|
2596
|
-
["table", "web_tokens"],
|
|
2597
|
-
["table", "web_sessions"],
|
|
2598
|
-
["trigger", "create_team_policy"],
|
|
2599
|
-
["trigger", "prevent_detached_team_policy_delete"],
|
|
2600
|
-
["trigger", "validate_source_binding_insert"],
|
|
2601
|
-
["trigger", "validate_team_agent_state_insert"],
|
|
2602
|
-
["trigger", "validate_team_policy_baseline_update"],
|
|
2603
|
-
["trigger", "validate_team_policy_edge_insert"],
|
|
2604
|
-
["trigger", "validate_team_template_edge_insert"],
|
|
2605
|
-
// BAZ-046: one operator-approved publication of a reviewed revision to a code host.
|
|
2606
|
-
["table", "publications"],
|
|
2607
|
-
["index", "publications_team_time"],
|
|
2608
|
-
["index", "publications_packet_published"],
|
|
2609
|
-
["index", "publications_lease"]
|
|
2610
|
-
];
|
|
2461
|
+
|
|
2462
|
+
// ../daemon/src/core/db/migrate.ts
|
|
2463
|
+
import { readdirSync, readFileSync as readFileSync4 } from "fs";
|
|
2464
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
2465
|
+
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
2466
|
+
import { fileURLToPath } from "url";
|
|
2467
|
+
|
|
2468
|
+
// ../daemon/src/core/db/client.ts
|
|
2469
|
+
import { backup, DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
2470
|
+
function wrap(rawDb) {
|
|
2471
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2472
|
+
let transactionDepth = 0;
|
|
2473
|
+
let savepointSequence = 0;
|
|
2474
|
+
function getStmt(sql) {
|
|
2475
|
+
let s = cache.get(sql);
|
|
2476
|
+
if (!s) {
|
|
2477
|
+
s = rawDb.prepare(sql);
|
|
2478
|
+
cache.set(sql, s);
|
|
2479
|
+
}
|
|
2480
|
+
return s;
|
|
2481
|
+
}
|
|
2482
|
+
return {
|
|
2483
|
+
query(sql) {
|
|
2484
|
+
const stmt = getStmt(sql);
|
|
2485
|
+
return {
|
|
2486
|
+
get(...params) {
|
|
2487
|
+
const result = stmt.get(...params);
|
|
2488
|
+
return result ?? null;
|
|
2489
|
+
},
|
|
2490
|
+
all(...params) {
|
|
2491
|
+
return stmt.all(...params);
|
|
2492
|
+
},
|
|
2493
|
+
run(...params) {
|
|
2494
|
+
return stmt.run(...params);
|
|
2495
|
+
}
|
|
2496
|
+
};
|
|
2497
|
+
},
|
|
2498
|
+
run(sql, params) {
|
|
2499
|
+
const stmt = getStmt(sql);
|
|
2500
|
+
return stmt.run(...params ?? []);
|
|
2501
|
+
},
|
|
2502
|
+
exec(sql) {
|
|
2503
|
+
rawDb.exec(sql);
|
|
2504
|
+
},
|
|
2505
|
+
// node:sqlite has no callable `transaction` wrapper; use manual BEGIN/COMMIT/ROLLBACK.
|
|
2506
|
+
transaction(fn) {
|
|
2507
|
+
return () => {
|
|
2508
|
+
const outermost = transactionDepth === 0;
|
|
2509
|
+
const savepoint = outermost ? null : `bazilion_nested_${++savepointSequence}`;
|
|
2510
|
+
if (outermost) rawDb.exec("BEGIN");
|
|
2511
|
+
else rawDb.exec(`SAVEPOINT ${savepoint}`);
|
|
2512
|
+
transactionDepth++;
|
|
2513
|
+
try {
|
|
2514
|
+
const result = fn();
|
|
2515
|
+
if (outermost) rawDb.exec("COMMIT");
|
|
2516
|
+
else rawDb.exec(`RELEASE SAVEPOINT ${savepoint}`);
|
|
2517
|
+
return result;
|
|
2518
|
+
} catch (err) {
|
|
2519
|
+
if (outermost) rawDb.exec("ROLLBACK");
|
|
2520
|
+
else {
|
|
2521
|
+
rawDb.exec(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
2522
|
+
rawDb.exec(`RELEASE SAVEPOINT ${savepoint}`);
|
|
2523
|
+
}
|
|
2524
|
+
throw err;
|
|
2525
|
+
} finally {
|
|
2526
|
+
transactionDepth--;
|
|
2527
|
+
}
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2531
|
+
}
|
|
2532
|
+
function applyPragmas(rawDb, includeWal) {
|
|
2533
|
+
if (includeWal) {
|
|
2534
|
+
try {
|
|
2535
|
+
rawDb.exec("PRAGMA journal_mode = WAL");
|
|
2536
|
+
} catch {
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
rawDb.exec("PRAGMA foreign_keys = ON");
|
|
2540
|
+
}
|
|
2541
|
+
function openInMemoryDb() {
|
|
2542
|
+
const raw = new DatabaseSync2(":memory:");
|
|
2543
|
+
applyPragmas(raw, false);
|
|
2544
|
+
return {
|
|
2545
|
+
raw: wrap(raw),
|
|
2546
|
+
backupTo(path) {
|
|
2547
|
+
return backup(raw, path);
|
|
2548
|
+
},
|
|
2549
|
+
close() {
|
|
2550
|
+
raw.close();
|
|
2551
|
+
}
|
|
2552
|
+
};
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
// ../daemon/src/core/db/migrate.ts
|
|
2556
|
+
var migrationsDir = join2(dirname2(fileURLToPath(import.meta.url)), "migrations");
|
|
2557
|
+
var schemaMigrationsSql = `
|
|
2558
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
2559
|
+
version TEXT PRIMARY KEY,
|
|
2560
|
+
applied_at INTEGER NOT NULL
|
|
2561
|
+
)
|
|
2562
|
+
`;
|
|
2563
|
+
function listMigrations() {
|
|
2564
|
+
return readdirSync(migrationsDir).filter((file) => file.endsWith(".sql")).sort().map((file) => ({
|
|
2565
|
+
version: file.replace(/\.sql$/, ""),
|
|
2566
|
+
sql: readFileSync4(join2(migrationsDir, file), "utf8")
|
|
2567
|
+
}));
|
|
2568
|
+
}
|
|
2569
|
+
var canonicalSchemaObjectsByPrefix = /* @__PURE__ */ new Map();
|
|
2570
|
+
function schemaObjects(db) {
|
|
2571
|
+
return db.raw.query(
|
|
2572
|
+
`SELECT type, name, tbl_name, sql
|
|
2573
|
+
FROM sqlite_schema
|
|
2574
|
+
WHERE sql IS NOT NULL AND substr(name, 1, 7) <> 'sqlite_'
|
|
2575
|
+
ORDER BY type, name`
|
|
2576
|
+
).all();
|
|
2577
|
+
}
|
|
2611
2578
|
function normalizeSql(sql) {
|
|
2612
2579
|
return sql.replace(/\s+/g, " ").trim();
|
|
2613
2580
|
}
|
|
2614
|
-
function
|
|
2615
|
-
const
|
|
2616
|
-
if (
|
|
2581
|
+
function expectedSchema(files, prefixLength) {
|
|
2582
|
+
const cached = canonicalSchemaObjectsByPrefix.get(prefixLength);
|
|
2583
|
+
if (cached) return cached;
|
|
2584
|
+
const canonical = openInMemoryDb();
|
|
2585
|
+
try {
|
|
2586
|
+
canonical.raw.exec(schemaMigrationsSql);
|
|
2587
|
+
for (const file of files.slice(0, prefixLength)) canonical.raw.exec(file.sql);
|
|
2588
|
+
const objects = schemaObjects(canonical);
|
|
2589
|
+
canonicalSchemaObjectsByPrefix.set(prefixLength, objects);
|
|
2590
|
+
return objects;
|
|
2591
|
+
} finally {
|
|
2592
|
+
canonical.close();
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
function assertSchemaMatchesCanonicalChain(raw) {
|
|
2596
|
+
const files = listMigrations();
|
|
2597
|
+
const expectedVersions = files.map((file) => file.version);
|
|
2598
|
+
const applied = raw.prepare("SELECT version FROM schema_migrations ORDER BY version").all().map((row2) => row2.version);
|
|
2599
|
+
if (applied.length !== expectedVersions.length || applied.some((version, index) => version !== expectedVersions[index])) {
|
|
2617
2600
|
throw new Error(
|
|
2618
|
-
`schema_migrations must contain exactly ${
|
|
2601
|
+
`schema_migrations must contain exactly ${expectedVersions.join(", ")}; found ` + (applied.join(", ") || "none")
|
|
2619
2602
|
);
|
|
2620
2603
|
}
|
|
2621
|
-
const rows =
|
|
2604
|
+
const rows = raw.prepare(
|
|
2622
2605
|
`SELECT type, name, tbl_name, sql
|
|
2623
2606
|
FROM sqlite_schema
|
|
2624
|
-
WHERE sql IS NOT NULL AND name
|
|
2607
|
+
WHERE sql IS NOT NULL AND substr(name, 1, 7) <> 'sqlite_'
|
|
2608
|
+
ORDER BY type, name`
|
|
2625
2609
|
).all();
|
|
2626
|
-
const
|
|
2627
|
-
const canonicalKeys = new Set(
|
|
2610
|
+
const canonical = expectedSchema(files, files.length);
|
|
2611
|
+
const canonicalKeys = new Set(canonical.map((row2) => `${row2.type}\0${row2.name}`));
|
|
2612
|
+
const actualKeys = new Map(rows.map((row2) => [`${row2.type}\0${row2.name}`, row2]));
|
|
2613
|
+
for (const row2 of canonical) {
|
|
2614
|
+
if (!actualKeys.has(`${row2.type}\0${row2.name}`)) {
|
|
2615
|
+
throw new Error(`required canonical schema ${row2.type} is missing: ${row2.name}`);
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2628
2618
|
for (const row2 of rows) {
|
|
2629
2619
|
if (!canonicalKeys.has(`${row2.type}\0${row2.name}`)) {
|
|
2630
2620
|
throw new Error(`unexpected schema ${row2.type} is not canonical: ${row2.name}`);
|
|
2631
2621
|
}
|
|
2632
2622
|
}
|
|
2633
|
-
const
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
if (!row2) throw new Error(`required canonical schema ${type} is missing: ${name}`);
|
|
2637
|
-
canonicalRows.push(row2);
|
|
2638
|
-
}
|
|
2639
|
-
const payload = canonicalRows.map((row2) => [row2.type, row2.name, row2.tbl_name, normalizeSql(row2.sql)].join("\0")).join("\n");
|
|
2640
|
-
const actualHash = createHash("sha256").update(payload).digest("hex");
|
|
2641
|
-
if (actualHash !== CANONICAL_SCHEMA_HASH) {
|
|
2623
|
+
const payload = rows.map((row2) => [row2.type, row2.name, row2.tbl_name, normalizeSql(row2.sql)].join("\0")).join("\n");
|
|
2624
|
+
const canonicalPayload = canonical.map((row2) => [row2.type, row2.name, row2.tbl_name, normalizeSql(row2.sql)].join("\0")).join("\n");
|
|
2625
|
+
if (payload !== canonicalPayload) {
|
|
2642
2626
|
throw new Error(
|
|
2643
|
-
"
|
|
2627
|
+
"database schema does not match this release\u2019s canonical migration chain; restore a backup created from the current release"
|
|
2644
2628
|
);
|
|
2645
2629
|
}
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2632
|
+
// src/backup-schema.ts
|
|
2633
|
+
function assertCanonicalBackupSchema(db) {
|
|
2634
|
+
assertSchemaMatchesCanonicalChain(db);
|
|
2646
2635
|
for (const row2 of db.prepare("SELECT id, bytes, byte_length, sha256 FROM agent_results WHERE deleted_at IS NULL").iterate()) {
|
|
2647
2636
|
const bytes = row2.bytes;
|
|
2648
2637
|
if (!(bytes instanceof Uint8Array) || bytes.byteLength !== row2.byte_length || createHash("sha256").update(bytes).digest("hex") !== row2.sha256) {
|
|
@@ -2663,31 +2652,31 @@ import {
|
|
|
2663
2652
|
lstatSync as lstatSync2,
|
|
2664
2653
|
mkdirSync,
|
|
2665
2654
|
openSync,
|
|
2666
|
-
readFileSync as
|
|
2667
|
-
realpathSync,
|
|
2655
|
+
readFileSync as readFileSync5,
|
|
2656
|
+
realpathSync as realpathSync2,
|
|
2668
2657
|
renameSync,
|
|
2669
2658
|
rmSync,
|
|
2670
2659
|
writeSync
|
|
2671
2660
|
} from "fs";
|
|
2672
|
-
import { basename as
|
|
2661
|
+
import { basename as basename4, dirname as dirname3, join as join3, resolve as resolve3 } from "path";
|
|
2673
2662
|
var DAEMON_LIVENESS_FILENAME = "daemon-runtime.json";
|
|
2674
2663
|
var STALE_AFTER_MS = 6e4;
|
|
2675
2664
|
var PROBE_TIMEOUT_MS = 750;
|
|
2676
2665
|
function canonicalHomeIdentity(home) {
|
|
2677
|
-
const absolute =
|
|
2666
|
+
const absolute = resolve3(home);
|
|
2678
2667
|
try {
|
|
2679
|
-
return
|
|
2668
|
+
return realpathSync2.native(absolute);
|
|
2680
2669
|
} catch (error) {
|
|
2681
2670
|
if (errorCode(error) !== "ENOENT") throw error;
|
|
2682
|
-
const parent =
|
|
2671
|
+
const parent = dirname3(absolute);
|
|
2683
2672
|
if (parent === absolute) throw error;
|
|
2684
|
-
return
|
|
2673
|
+
return join3(canonicalHomeIdentity(parent), basename4(absolute));
|
|
2685
2674
|
}
|
|
2686
2675
|
}
|
|
2687
2676
|
function daemonLivenessPath(home) {
|
|
2688
|
-
const
|
|
2689
|
-
const identity = createHash2("sha256").update(
|
|
2690
|
-
return
|
|
2677
|
+
const canonicalHome3 = canonicalHomeIdentity(home);
|
|
2678
|
+
const identity = createHash2("sha256").update(canonicalHome3).digest("hex").slice(0, 24);
|
|
2679
|
+
return join3(dirname3(canonicalHome3), `.bazilion-runtime-${identity}.json`);
|
|
2691
2680
|
}
|
|
2692
2681
|
function errorCode(error) {
|
|
2693
2682
|
return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
@@ -2725,7 +2714,7 @@ function parseRecord(raw) {
|
|
|
2725
2714
|
function readRecord(path) {
|
|
2726
2715
|
try {
|
|
2727
2716
|
const stat = lstatSync2(path);
|
|
2728
|
-
const raw = stat.isFile() ?
|
|
2717
|
+
const raw = stat.isFile() ? readFileSync5(path, "utf8") : "";
|
|
2729
2718
|
return { raw, stat, record: stat.isFile() ? parseRecord(raw) : null };
|
|
2730
2719
|
} catch (error) {
|
|
2731
2720
|
if (errorCode(error) === "ENOENT") return null;
|
|
@@ -2782,7 +2771,7 @@ function writeRecord(fd, record) {
|
|
|
2782
2771
|
function fsyncParentDirectory(path) {
|
|
2783
2772
|
let directoryFd = null;
|
|
2784
2773
|
try {
|
|
2785
|
-
directoryFd = openSync(
|
|
2774
|
+
directoryFd = openSync(dirname3(path), "r");
|
|
2786
2775
|
fsyncSync(directoryFd);
|
|
2787
2776
|
} catch (error) {
|
|
2788
2777
|
if (process.platform !== "win32") throw error;
|
|
@@ -2804,7 +2793,7 @@ function reclaimRecord(path, existing) {
|
|
|
2804
2793
|
return null;
|
|
2805
2794
|
}
|
|
2806
2795
|
try {
|
|
2807
|
-
renameSync(path,
|
|
2796
|
+
renameSync(path, join3(claim, "stale-record.json"));
|
|
2808
2797
|
return claim;
|
|
2809
2798
|
} catch (error) {
|
|
2810
2799
|
if (errorCode(error) === "ENOENT") return null;
|
|
@@ -2812,10 +2801,10 @@ function reclaimRecord(path, existing) {
|
|
|
2812
2801
|
}
|
|
2813
2802
|
}
|
|
2814
2803
|
async function acquireHomeRestoreLock(home, operation = "restoring") {
|
|
2815
|
-
const targetHome =
|
|
2816
|
-
mkdirSync(
|
|
2804
|
+
const targetHome = resolve3(home);
|
|
2805
|
+
mkdirSync(dirname3(targetHome), { recursive: true });
|
|
2817
2806
|
const path = daemonLivenessPath(targetHome);
|
|
2818
|
-
mkdirSync(
|
|
2807
|
+
mkdirSync(dirname3(path), { recursive: true });
|
|
2819
2808
|
const instanceId = randomUUID6();
|
|
2820
2809
|
let fd = null;
|
|
2821
2810
|
let reclaimClaim = null;
|
|
@@ -2941,7 +2930,7 @@ async function acquireHomeRestoreLock(home, operation = "restoring") {
|
|
|
2941
2930
|
markSwapping(recoveryPath, hadPrevious) {
|
|
2942
2931
|
if (released || !stillOwnsPath()) throw new Error("restore ownership was lost");
|
|
2943
2932
|
record.state = "swapping";
|
|
2944
|
-
record.recoveryPath =
|
|
2933
|
+
record.recoveryPath = resolve3(recoveryPath);
|
|
2945
2934
|
record.hadPrevious = hadPrevious;
|
|
2946
2935
|
writeRecord(fd, record);
|
|
2947
2936
|
fsyncParentDirectory(path);
|
|
@@ -2956,7 +2945,7 @@ async function acquireHomeRestoreLock(home, operation = "restoring") {
|
|
|
2956
2945
|
markRecoveryRequired(recoveryPath, hadPrevious) {
|
|
2957
2946
|
if (released || !stillOwnsPath()) throw new Error("restore ownership was lost");
|
|
2958
2947
|
record.state = "recovery-required";
|
|
2959
|
-
record.recoveryPath =
|
|
2948
|
+
record.recoveryPath = resolve3(recoveryPath);
|
|
2960
2949
|
record.hadPrevious = hadPrevious;
|
|
2961
2950
|
writeRecord(fd, record);
|
|
2962
2951
|
},
|
|
@@ -3008,10 +2997,10 @@ var createCmd = defineCommand9({
|
|
|
3008
2997
|
const cfg = loadClientConfig();
|
|
3009
2998
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3010
2999
|
const defaultSuffix = args2.recipient ? ".tar.gz.age" : ".tar.gz";
|
|
3011
|
-
const outAbs =
|
|
3000
|
+
const outAbs = resolve4(args2.output ?? `bazilion-backup-${date}${defaultSuffix}`);
|
|
3012
3001
|
if (existsSync2(outAbs)) throw new Error(`refusing to overwrite existing backup: ${outAbs}`);
|
|
3013
|
-
const configuredHome =
|
|
3014
|
-
const outputFromHome = relative(configuredHome, outAbs);
|
|
3002
|
+
const configuredHome = canonicalHome2(resolveCliPaths().home);
|
|
3003
|
+
const outputFromHome = relative(configuredHome, canonicalHome2(outAbs));
|
|
3015
3004
|
if (!outputFromHome || !outputFromHome.startsWith("..") && !isAbsolute(outputFromHome)) {
|
|
3016
3005
|
throw new Error(
|
|
3017
3006
|
`backup output must be outside BAZILION_HOME (${configuredHome}) to avoid nesting backups`
|
|
@@ -3033,8 +3022,8 @@ var createCmd = defineCommand9({
|
|
|
3033
3022
|
}
|
|
3034
3023
|
throw new Error(`backup failed: ${err}`);
|
|
3035
3024
|
}
|
|
3036
|
-
const downloadDir = mkdtempSync(
|
|
3037
|
-
const partial =
|
|
3025
|
+
const downloadDir = mkdtempSync(resolve4(tmpdir(), "bazilion-download-"));
|
|
3026
|
+
const partial = resolve4(downloadDir, "backup.tar.gz");
|
|
3038
3027
|
try {
|
|
3039
3028
|
if (args2.recipient) {
|
|
3040
3029
|
const [encryptSource, validateSource] = res.body.tee();
|
|
@@ -3059,9 +3048,9 @@ var createCmd = defineCommand9({
|
|
|
3059
3048
|
renameSync2(partial, outAbs);
|
|
3060
3049
|
} catch (error) {
|
|
3061
3050
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "EXDEV") throw error;
|
|
3062
|
-
const installPartial =
|
|
3063
|
-
|
|
3064
|
-
`.${
|
|
3051
|
+
const installPartial = resolve4(
|
|
3052
|
+
dirname4(outAbs),
|
|
3053
|
+
`.${basename5(outAbs)}.${randomUUID7()}.installing`
|
|
3065
3054
|
);
|
|
3066
3055
|
try {
|
|
3067
3056
|
copyFileSync(partial, installPartial);
|
|
@@ -3247,7 +3236,7 @@ function validateArchiveEntries(entries) {
|
|
|
3247
3236
|
function validateAuthFile(path) {
|
|
3248
3237
|
let parsed;
|
|
3249
3238
|
try {
|
|
3250
|
-
parsed = JSON.parse(
|
|
3239
|
+
parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
3251
3240
|
} catch (error) {
|
|
3252
3241
|
const detail = error instanceof Error ? error.message : String(error);
|
|
3253
3242
|
throw new Error(`backup auth.json is invalid: ${detail}`);
|
|
@@ -3260,7 +3249,7 @@ function validateAuthFile(path) {
|
|
|
3260
3249
|
function validateDatabase(path, authToken) {
|
|
3261
3250
|
let db = null;
|
|
3262
3251
|
try {
|
|
3263
|
-
db = new
|
|
3252
|
+
db = new DatabaseSync4(path, { readOnly: true });
|
|
3264
3253
|
const integrity = db.prepare("PRAGMA integrity_check").all();
|
|
3265
3254
|
if (integrity.length !== 1 || integrity[0]?.integrity_check !== "ok") {
|
|
3266
3255
|
const detail = integrity.map((row2) => row2.integrity_check).join("; ") || "no result";
|
|
@@ -3290,6 +3279,22 @@ function validateDatabase(path, authToken) {
|
|
|
3290
3279
|
db?.close();
|
|
3291
3280
|
}
|
|
3292
3281
|
}
|
|
3282
|
+
function canonicalHome2(root) {
|
|
3283
|
+
let resolved = resolve4(root);
|
|
3284
|
+
const unresolvedTail = [];
|
|
3285
|
+
while (true) {
|
|
3286
|
+
try {
|
|
3287
|
+
resolved = realpathSync3(resolved);
|
|
3288
|
+
break;
|
|
3289
|
+
} catch {
|
|
3290
|
+
const parent = dirname4(resolved);
|
|
3291
|
+
if (parent === resolved) break;
|
|
3292
|
+
unresolvedTail.unshift(basename5(resolved));
|
|
3293
|
+
resolved = parent;
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
return join4(resolved, ...unresolvedTail);
|
|
3297
|
+
}
|
|
3293
3298
|
var SLUG_ID = /^[a-z0-9][a-z0-9-]*$/;
|
|
3294
3299
|
var AGENT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
3295
3300
|
function validateEntityId(id, pattern, entity) {
|
|
@@ -3299,7 +3304,7 @@ function validateEntityId(id, pattern, entity) {
|
|
|
3299
3304
|
return id;
|
|
3300
3305
|
}
|
|
3301
3306
|
function containedChildDirectory(root, id, rowLabel) {
|
|
3302
|
-
const child =
|
|
3307
|
+
const child = resolve4(root, id);
|
|
3303
3308
|
const fromRoot = relative(root, child);
|
|
3304
3309
|
if (!fromRoot || fromRoot.startsWith("..") || isAbsolute(fromRoot)) {
|
|
3305
3310
|
throw new Error(`${rowLabel} directory escapes its canonical root: ${JSON.stringify(id)}`);
|
|
@@ -3324,7 +3329,9 @@ function requireExtractedTeamSlot(path, rowLabel) {
|
|
|
3324
3329
|
function rebaseRestoredHomeDirectories(database, payload, targetHome) {
|
|
3325
3330
|
let db = null;
|
|
3326
3331
|
try {
|
|
3327
|
-
|
|
3332
|
+
const canonicalTarget = canonicalHome2(targetHome);
|
|
3333
|
+
const canonicalPayload = realpathSync3(payload);
|
|
3334
|
+
db = new DatabaseSync4(database);
|
|
3328
3335
|
db.exec("PRAGMA foreign_keys = ON");
|
|
3329
3336
|
const profiles = db.prepare("SELECT id FROM profiles ORDER BY id").all();
|
|
3330
3337
|
const agents = db.prepare("SELECT id FROM agents ORDER BY id").all();
|
|
@@ -3335,8 +3342,8 @@ function rebaseRestoredHomeDirectories(database, payload, targetHome) {
|
|
|
3335
3342
|
["agents", agents, AGENT_ID]
|
|
3336
3343
|
]) {
|
|
3337
3344
|
const collection = table;
|
|
3338
|
-
const stagedRoot =
|
|
3339
|
-
const targetRoot =
|
|
3345
|
+
const stagedRoot = resolve4(canonicalPayload, collection);
|
|
3346
|
+
const targetRoot = resolve4(canonicalTarget, collection);
|
|
3340
3347
|
for (const row2 of rows) {
|
|
3341
3348
|
const id = validateEntityId(row2.id, idPattern, `${table} row`);
|
|
3342
3349
|
const rowLabel = `${table} row ${JSON.stringify(id)}`;
|
|
@@ -3349,7 +3356,7 @@ function rebaseRestoredHomeDirectories(database, payload, targetHome) {
|
|
|
3349
3356
|
});
|
|
3350
3357
|
}
|
|
3351
3358
|
}
|
|
3352
|
-
const stagedTeamsRoot =
|
|
3359
|
+
const stagedTeamsRoot = resolve4(canonicalPayload, "teams");
|
|
3353
3360
|
for (const row2 of teams) {
|
|
3354
3361
|
const id = validateEntityId(row2.id, SLUG_ID, "teams row");
|
|
3355
3362
|
const rowLabel = `teams row ${JSON.stringify(id)}`;
|
|
@@ -3399,21 +3406,21 @@ function rebaseRestoredHomeDirectories(database, payload, targetHome) {
|
|
|
3399
3406
|
}
|
|
3400
3407
|
}
|
|
3401
3408
|
function removeRebuildableQmdIndexes(payload) {
|
|
3402
|
-
const teamsDir =
|
|
3409
|
+
const teamsDir = resolve4(payload, "teams");
|
|
3403
3410
|
if (!existsSync2(teamsDir) || !lstatSync3(teamsDir).isDirectory()) return;
|
|
3404
|
-
for (const team of
|
|
3411
|
+
for (const team of readdirSync2(teamsDir, { withFileTypes: true })) {
|
|
3405
3412
|
if (!team.isDirectory() || team.isSymbolicLink()) continue;
|
|
3406
|
-
const memoryDir =
|
|
3413
|
+
const memoryDir = resolve4(teamsDir, team.name, "memory");
|
|
3407
3414
|
if (!existsSync2(memoryDir) || !lstatSync3(memoryDir).isDirectory()) continue;
|
|
3408
|
-
for (const entry3 of
|
|
3415
|
+
for (const entry3 of readdirSync2(memoryDir, { withFileTypes: true })) {
|
|
3409
3416
|
if (entry3.isFile() && entry3.name.startsWith(".qmd-index.sqlite")) {
|
|
3410
|
-
rmSync2(
|
|
3417
|
+
rmSync2(resolve4(memoryDir, entry3.name), { force: true });
|
|
3411
3418
|
}
|
|
3412
3419
|
}
|
|
3413
3420
|
}
|
|
3414
3421
|
}
|
|
3415
3422
|
function revokeRestoredBrowserSessions(database) {
|
|
3416
|
-
const db = new
|
|
3423
|
+
const db = new DatabaseSync4(database);
|
|
3417
3424
|
try {
|
|
3418
3425
|
db.prepare("UPDATE web_sessions SET revoked_at = ? WHERE revoked_at IS NULL").run(Date.now());
|
|
3419
3426
|
} finally {
|
|
@@ -3421,9 +3428,9 @@ function revokeRestoredBrowserSessions(database) {
|
|
|
3421
3428
|
}
|
|
3422
3429
|
}
|
|
3423
3430
|
function installValidatedPayload(payload, targetHome, staging, lifecycle, operations = { rename: renameSync2 }) {
|
|
3424
|
-
const previous =
|
|
3431
|
+
const previous = resolve4(staging, "previous-home");
|
|
3425
3432
|
const hadPrevious = existsSync2(targetHome);
|
|
3426
|
-
const targetParent =
|
|
3433
|
+
const targetParent = dirname4(targetHome);
|
|
3427
3434
|
const syncDirectory = operations.fsyncDirectory ?? fsyncDirectory;
|
|
3428
3435
|
const recoveryError = (message, recoveryPath, cause) => {
|
|
3429
3436
|
let markerError;
|
|
@@ -3534,7 +3541,7 @@ function fsyncDirectory(path) {
|
|
|
3534
3541
|
}
|
|
3535
3542
|
}
|
|
3536
3543
|
function fsyncFile(path) {
|
|
3537
|
-
const fd = openSync2(path, "r");
|
|
3544
|
+
const fd = openSync2(path, "r+");
|
|
3538
3545
|
try {
|
|
3539
3546
|
fsyncSync2(fd);
|
|
3540
3547
|
} finally {
|
|
@@ -3552,13 +3559,13 @@ function isAgeEncrypted(path) {
|
|
|
3552
3559
|
}
|
|
3553
3560
|
}
|
|
3554
3561
|
function readAgeIdentity(rawPath) {
|
|
3555
|
-
const path =
|
|
3562
|
+
const path = resolve4(rawPath);
|
|
3556
3563
|
const entry3 = lstatSync3(path);
|
|
3557
3564
|
if (!entry3.isFile()) throw new Error(`age identity is not a regular file: ${path}`);
|
|
3558
3565
|
if (process.platform !== "win32" && (entry3.mode & 63) !== 0) {
|
|
3559
3566
|
throw new Error(`age identity must be owner-only (chmod 600): ${path}`);
|
|
3560
3567
|
}
|
|
3561
|
-
const identities =
|
|
3568
|
+
const identities = readFileSync6(path, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
3562
3569
|
if (identities.length !== 1 || !identities[0]?.startsWith("AGE-SECRET-KEY-")) {
|
|
3563
3570
|
throw new Error("age identity file must contain exactly one supported AGE-SECRET-KEY entry");
|
|
3564
3571
|
}
|
|
@@ -3586,18 +3593,18 @@ var restoreCmd = defineCommand9({
|
|
|
3586
3593
|
}
|
|
3587
3594
|
},
|
|
3588
3595
|
async run({ args: args2 }) {
|
|
3589
|
-
const file =
|
|
3596
|
+
const file = resolve4(args2.file);
|
|
3590
3597
|
if (!existsSync2(file)) throw new Error(`backup file not found: ${file}`);
|
|
3591
3598
|
const paths = resolveCliPaths(args2.home);
|
|
3592
|
-
const targetHome =
|
|
3599
|
+
const targetHome = resolve4(paths.home);
|
|
3593
3600
|
if (targetHome === parse(targetHome).root) {
|
|
3594
3601
|
throw new Error(`refusing to restore over filesystem root: ${targetHome}`);
|
|
3595
3602
|
}
|
|
3596
|
-
const targetParent =
|
|
3603
|
+
const targetParent = dirname4(targetHome);
|
|
3597
3604
|
mkdirSync2(targetParent, { recursive: true });
|
|
3598
3605
|
const restoreLock = await acquireHomeRestoreLock(targetHome);
|
|
3599
3606
|
try {
|
|
3600
|
-
const targetsConfiguredHome = targetHome ===
|
|
3607
|
+
const targetsConfiguredHome = targetHome === resolve4(resolveCliPaths().home);
|
|
3601
3608
|
if (targetsConfiguredHome) {
|
|
3602
3609
|
for (const serverUrl of configuredLoopbackUrls()) {
|
|
3603
3610
|
if (await probeServerRunning(serverUrl)) {
|
|
@@ -3611,16 +3618,16 @@ var restoreCmd = defineCommand9({
|
|
|
3611
3618
|
if (!lstatSync3(targetHome).isDirectory()) {
|
|
3612
3619
|
throw new Error(`${targetHome} exists and is not a directory`);
|
|
3613
3620
|
}
|
|
3614
|
-
const entries =
|
|
3621
|
+
const entries = readdirSync2(targetHome);
|
|
3615
3622
|
if (entries.length > 0 && !args2.force) {
|
|
3616
3623
|
throw new Error(
|
|
3617
3624
|
`${targetHome} is not empty. Pass --force to overwrite (destroys existing data).`
|
|
3618
3625
|
);
|
|
3619
3626
|
}
|
|
3620
3627
|
}
|
|
3621
|
-
const staging = mkdtempSync(
|
|
3622
|
-
const stagedArchive =
|
|
3623
|
-
const payload =
|
|
3628
|
+
const staging = mkdtempSync(resolve4(targetParent, ".bazilion-restore-"));
|
|
3629
|
+
const stagedArchive = resolve4(staging, "backup.tar.gz");
|
|
3630
|
+
const payload = resolve4(staging, "payload");
|
|
3624
3631
|
let preserveStaging = false;
|
|
3625
3632
|
try {
|
|
3626
3633
|
if (isAgeEncrypted(file)) {
|
|
@@ -3666,8 +3673,8 @@ var restoreCmd = defineCommand9({
|
|
|
3666
3673
|
// payload-relative path by npm-tar.
|
|
3667
3674
|
preservePaths: true
|
|
3668
3675
|
});
|
|
3669
|
-
const database =
|
|
3670
|
-
const authFile =
|
|
3676
|
+
const database = resolve4(payload, "bazilion.db");
|
|
3677
|
+
const authFile = resolve4(payload, "auth.json");
|
|
3671
3678
|
if (!lstatSync3(database).isFile() || !lstatSync3(authFile).isFile()) {
|
|
3672
3679
|
throw new Error("backup required files did not extract as regular files");
|
|
3673
3680
|
}
|
|
@@ -3730,11 +3737,11 @@ function encryptSecretEnvelope(value, password) {
|
|
|
3730
3737
|
});
|
|
3731
3738
|
}
|
|
3732
3739
|
function credentialInventory(home) {
|
|
3733
|
-
const authFile =
|
|
3734
|
-
const database =
|
|
3740
|
+
const authFile = resolve4(home, "auth.json");
|
|
3741
|
+
const database = resolve4(home, "bazilion.db");
|
|
3735
3742
|
const token = validateAuthFile(authFile);
|
|
3736
3743
|
validateDatabase(database, token);
|
|
3737
|
-
const db = new
|
|
3744
|
+
const db = new DatabaseSync4(database, { readOnly: true });
|
|
3738
3745
|
try {
|
|
3739
3746
|
const activeTokens = db.prepare(
|
|
3740
3747
|
"SELECT COUNT(*) AS count FROM web_tokens WHERE revoked_at IS NULL AND kind = 'device' AND expires_at > ?"
|
|
@@ -3749,7 +3756,7 @@ var inventoryCmd = defineCommand9({
|
|
|
3749
3756
|
meta: { name: "inventory", description: "List credential classes captured by a backup/home" },
|
|
3750
3757
|
args: { home: { type: "string", description: "Override BAZILION_HOME" } },
|
|
3751
3758
|
run({ args: args2 }) {
|
|
3752
|
-
const home =
|
|
3759
|
+
const home = resolve4(resolveCliPaths(args2.home).home);
|
|
3753
3760
|
const inventory = credentialInventory(home);
|
|
3754
3761
|
console.log("credential classes present (values are never shown):");
|
|
3755
3762
|
console.log(` bootstrap token: ${inventory.bootstrap ? "present" : "missing"}`);
|
|
@@ -3788,14 +3795,14 @@ var rotateBootstrapCmd = defineCommand9({
|
|
|
3788
3795
|
async run({ args: args2 }) {
|
|
3789
3796
|
if (!args2.yes) throw new Error("--yes is required");
|
|
3790
3797
|
const paths = resolveCliPaths(args2.home);
|
|
3791
|
-
const targetHome =
|
|
3798
|
+
const targetHome = resolve4(paths.home);
|
|
3792
3799
|
if (targetHome === parse(targetHome).root) {
|
|
3793
3800
|
throw new Error(`refusing to rotate filesystem root: ${targetHome}`);
|
|
3794
3801
|
}
|
|
3795
3802
|
const lock = await acquireHomeRestoreLock(targetHome);
|
|
3796
|
-
const parent =
|
|
3797
|
-
const staging = mkdtempSync(
|
|
3798
|
-
const payload =
|
|
3803
|
+
const parent = dirname4(targetHome);
|
|
3804
|
+
const staging = mkdtempSync(resolve4(parent, ".bazilion-rotate-"));
|
|
3805
|
+
const payload = resolve4(staging, "payload");
|
|
3799
3806
|
let preserveStaging = false;
|
|
3800
3807
|
try {
|
|
3801
3808
|
for (const serverUrl of configuredLoopbackUrls()) {
|
|
@@ -3803,20 +3810,20 @@ var rotateBootstrapCmd = defineCommand9({
|
|
|
3803
3810
|
throw new Error(`bazilion server appears to be running at ${serverUrl} \u2014 stop it first.`);
|
|
3804
3811
|
}
|
|
3805
3812
|
}
|
|
3806
|
-
const oldAuth = JSON.parse(
|
|
3813
|
+
const oldAuth = JSON.parse(readFileSync6(paths.authFile, "utf8"));
|
|
3807
3814
|
if (typeof oldAuth.token !== "string" || !oldAuth.token) {
|
|
3808
3815
|
throw new Error("auth.json is missing the bootstrap token");
|
|
3809
3816
|
}
|
|
3810
|
-
validateDatabase(
|
|
3817
|
+
validateDatabase(resolve4(targetHome, "bazilion.db"), oldAuth.token);
|
|
3811
3818
|
cpSync(targetHome, payload, {
|
|
3812
3819
|
recursive: true,
|
|
3813
3820
|
dereference: false,
|
|
3814
3821
|
verbatimSymlinks: true,
|
|
3815
3822
|
preserveTimestamps: true
|
|
3816
3823
|
});
|
|
3817
|
-
const stagedDb =
|
|
3824
|
+
const stagedDb = resolve4(payload, "bazilion.db");
|
|
3818
3825
|
rmSync2(stagedDb, { force: true });
|
|
3819
|
-
const sourceDb = new
|
|
3826
|
+
const sourceDb = new DatabaseSync4(resolve4(targetHome, "bazilion.db"), { readOnly: true });
|
|
3820
3827
|
try {
|
|
3821
3828
|
await sqliteBackup(sourceDb, stagedDb);
|
|
3822
3829
|
} finally {
|
|
@@ -3825,7 +3832,7 @@ var rotateBootstrapCmd = defineCommand9({
|
|
|
3825
3832
|
for (const suffix of ["-wal", "-shm", "-journal"])
|
|
3826
3833
|
rmSync2(`${stagedDb}${suffix}`, { force: true });
|
|
3827
3834
|
const newToken = randomBytes(24).toString("hex");
|
|
3828
|
-
const db = new
|
|
3835
|
+
const db = new DatabaseSync4(stagedDb);
|
|
3829
3836
|
try {
|
|
3830
3837
|
db.exec("PRAGMA foreign_keys = ON; BEGIN IMMEDIATE");
|
|
3831
3838
|
try {
|
|
@@ -3863,8 +3870,8 @@ var rotateBootstrapCmd = defineCommand9({
|
|
|
3863
3870
|
} finally {
|
|
3864
3871
|
db.close();
|
|
3865
3872
|
}
|
|
3866
|
-
const stagedAuth =
|
|
3867
|
-
const authPartial =
|
|
3873
|
+
const stagedAuth = resolve4(payload, "auth.json");
|
|
3874
|
+
const authPartial = resolve4(payload, `.auth.json.${randomUUID7()}.installing`);
|
|
3868
3875
|
writeFileSync2(authPartial, `${JSON.stringify({ ...oldAuth, token: newToken }, null, 2)}
|
|
3869
3876
|
`, {
|
|
3870
3877
|
mode: 384,
|
|
@@ -4122,16 +4129,16 @@ var configCommand = defineCommand11({
|
|
|
4122
4129
|
import { spawn } from "child_process";
|
|
4123
4130
|
import { existsSync as existsSync3 } from "fs";
|
|
4124
4131
|
import { connect } from "net";
|
|
4125
|
-
import { join as
|
|
4132
|
+
import { join as join5 } from "path";
|
|
4126
4133
|
import { defineCommand as defineCommand12 } from "citty";
|
|
4127
|
-
var bundledDaemonEntry =
|
|
4128
|
-
var sourceDaemonEntry =
|
|
4134
|
+
var bundledDaemonEntry = join5(import.meta.dirname, "daemon.js");
|
|
4135
|
+
var sourceDaemonEntry = join5(import.meta.dirname, "..", "..", "..", "daemon", "src", "index.ts");
|
|
4129
4136
|
var daemonEntry = existsSync3(bundledDaemonEntry) ? bundledDaemonEntry : sourceDaemonEntry;
|
|
4130
|
-
var bundledWebServerEntry =
|
|
4131
|
-
var sourceWebServerEntry =
|
|
4137
|
+
var bundledWebServerEntry = join5(import.meta.dirname, "web-server.js");
|
|
4138
|
+
var sourceWebServerEntry = join5(import.meta.dirname, "..", "web-server.ts");
|
|
4132
4139
|
var webServerEntry = existsSync3(bundledWebServerEntry) ? bundledWebServerEntry : sourceWebServerEntry;
|
|
4133
|
-
var bundledWebDist =
|
|
4134
|
-
var sourceWebDist =
|
|
4140
|
+
var bundledWebDist = join5(import.meta.dirname, "web");
|
|
4141
|
+
var sourceWebDist = join5(import.meta.dirname, "..", "..", "..", "web", "dist");
|
|
4135
4142
|
var webDist = existsSync3(bundledWebDist) ? bundledWebDist : sourceWebDist;
|
|
4136
4143
|
function nodeArgs(entry3) {
|
|
4137
4144
|
return entry3.endsWith(".ts") ? ["--import", "tsx/esm", entry3] : [entry3];
|
|
@@ -4150,12 +4157,12 @@ function probeHost(host) {
|
|
|
4150
4157
|
return host;
|
|
4151
4158
|
}
|
|
4152
4159
|
function isTcpPortOpen(host, port) {
|
|
4153
|
-
return new Promise((
|
|
4160
|
+
return new Promise((resolve7) => {
|
|
4154
4161
|
const socket = connect({ host: probeHost(host), port: Number(port) });
|
|
4155
4162
|
const done = (open) => {
|
|
4156
4163
|
socket.removeAllListeners();
|
|
4157
4164
|
socket.destroy();
|
|
4158
|
-
|
|
4165
|
+
resolve7(open);
|
|
4159
4166
|
};
|
|
4160
4167
|
socket.setTimeout(600);
|
|
4161
4168
|
socket.once("connect", () => done(true));
|
|
@@ -4294,7 +4301,7 @@ var dashboardCommand = defineCommand12({
|
|
|
4294
4301
|
`web UI port ${webPort} is already in use. Re-run with --port <free-port>.`
|
|
4295
4302
|
);
|
|
4296
4303
|
}
|
|
4297
|
-
if (!existsSync3(
|
|
4304
|
+
if (!existsSync3(join5(webDist, "server", "server.js"))) {
|
|
4298
4305
|
throw new Error(
|
|
4299
4306
|
`bazilion web UI bundle not found at ${webDist}. Run "pnpm --filter @bazilion/web build" from the repository root of a source checkout, or reinstall the published package.`
|
|
4300
4307
|
);
|
|
@@ -4321,13 +4328,13 @@ var dashboardCommand = defineCommand12({
|
|
|
4321
4328
|
if (children.length === 0) return;
|
|
4322
4329
|
process.on("SIGINT", terminateChildren);
|
|
4323
4330
|
process.on("SIGTERM", terminateChildren);
|
|
4324
|
-
await new Promise((
|
|
4331
|
+
await new Promise((resolve7) => {
|
|
4325
4332
|
let remaining = children.length;
|
|
4326
4333
|
for (const child of children) {
|
|
4327
4334
|
child.on("close", (code) => {
|
|
4328
4335
|
remaining--;
|
|
4329
4336
|
if (!signalled && code && code !== 0) process.exitCode = code;
|
|
4330
|
-
if (remaining === 0)
|
|
4337
|
+
if (remaining === 0) resolve7();
|
|
4331
4338
|
});
|
|
4332
4339
|
}
|
|
4333
4340
|
});
|
|
@@ -4699,7 +4706,7 @@ var inboxCommand = defineCommand15({
|
|
|
4699
4706
|
});
|
|
4700
4707
|
|
|
4701
4708
|
// src/commands/login.ts
|
|
4702
|
-
import { existsSync as existsSync4, readFileSync as
|
|
4709
|
+
import { existsSync as existsSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
4703
4710
|
import { defineCommand as defineCommand16 } from "citty";
|
|
4704
4711
|
function normalizeServer(raw) {
|
|
4705
4712
|
let url;
|
|
@@ -4742,7 +4749,7 @@ var loginCommand = defineCommand16({
|
|
|
4742
4749
|
`${paths.authFile} not found. Start the daemon with "bazilion serve" first \u2014 login stores the remote there.`
|
|
4743
4750
|
);
|
|
4744
4751
|
}
|
|
4745
|
-
const auth = JSON.parse(
|
|
4752
|
+
const auth = JSON.parse(readFileSync7(paths.authFile, "utf8"));
|
|
4746
4753
|
if (args2.clear) {
|
|
4747
4754
|
if (!auth.remote) {
|
|
4748
4755
|
console.log("no remote stored \u2014 nothing to clear");
|
|
@@ -4992,9 +4999,9 @@ var memoryCommand = defineCommand18({
|
|
|
4992
4999
|
// src/commands/profile.ts
|
|
4993
5000
|
import { spawn as spawn2 } from "child_process";
|
|
4994
5001
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
4995
|
-
import { readFileSync as
|
|
5002
|
+
import { readFileSync as readFileSync8, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
4996
5003
|
import { tmpdir as tmpdir2 } from "os";
|
|
4997
|
-
import { join as
|
|
5004
|
+
import { join as join6 } from "path";
|
|
4998
5005
|
|
|
4999
5006
|
// ../../packages/api-types/src/git-review.ts
|
|
5000
5007
|
var REVIEW_LIMITS = {
|
|
@@ -5071,7 +5078,7 @@ var createCmd2 = defineCommand19({
|
|
|
5071
5078
|
},
|
|
5072
5079
|
async run({ args: args2 }) {
|
|
5073
5080
|
const skillsMode = parseSkillsMode(args2["skills-mode"]);
|
|
5074
|
-
const readTemplate = (path) => path ?
|
|
5081
|
+
const readTemplate = (path) => path ? readFileSync8(path, "utf8") : void 0;
|
|
5075
5082
|
const body = {
|
|
5076
5083
|
id: args2.id,
|
|
5077
5084
|
name: args2.name,
|
|
@@ -5146,17 +5153,17 @@ var editCmd2 = defineCommand19({
|
|
|
5146
5153
|
const { content } = await client.get(
|
|
5147
5154
|
`/api/profiles/${args2.id}/files/${file}`
|
|
5148
5155
|
);
|
|
5149
|
-
const tmpPath =
|
|
5156
|
+
const tmpPath = join6(tmpdir2(), `bazilion-${args2.id}-${file}-${randomBytes2(4).toString("hex")}`);
|
|
5150
5157
|
writeFileSync4(tmpPath, content);
|
|
5151
5158
|
try {
|
|
5152
5159
|
const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
|
|
5153
|
-
const code = await new Promise((
|
|
5160
|
+
const code = await new Promise((resolve7, reject) => {
|
|
5154
5161
|
const child = spawn2(editor, [tmpPath], { stdio: "inherit" });
|
|
5155
5162
|
child.on("error", reject);
|
|
5156
|
-
child.on("close", (c) =>
|
|
5163
|
+
child.on("close", (c) => resolve7(c ?? 0));
|
|
5157
5164
|
});
|
|
5158
5165
|
if (code !== 0) throw new Error(`editor exited with code ${code}`);
|
|
5159
|
-
const updated =
|
|
5166
|
+
const updated = readFileSync8(tmpPath, "utf8");
|
|
5160
5167
|
if (updated === content) {
|
|
5161
5168
|
console.log("(no changes)");
|
|
5162
5169
|
return;
|
|
@@ -5502,10 +5509,10 @@ var sendCommand = defineCommand22({
|
|
|
5502
5509
|
// src/commands/serve.ts
|
|
5503
5510
|
import { spawn as spawn3 } from "child_process";
|
|
5504
5511
|
import { existsSync as existsSync5 } from "fs";
|
|
5505
|
-
import { join as
|
|
5512
|
+
import { join as join7 } from "path";
|
|
5506
5513
|
import { defineCommand as defineCommand23 } from "citty";
|
|
5507
|
-
var bundledDaemonEntry2 =
|
|
5508
|
-
var sourceDaemonEntry2 =
|
|
5514
|
+
var bundledDaemonEntry2 = join7(import.meta.dirname, "daemon.js");
|
|
5515
|
+
var sourceDaemonEntry2 = join7(import.meta.dirname, "..", "..", "..", "daemon", "src", "index.ts");
|
|
5509
5516
|
var daemonEntry2 = existsSync5(bundledDaemonEntry2) ? bundledDaemonEntry2 : sourceDaemonEntry2;
|
|
5510
5517
|
var serveCommand = defineCommand23({
|
|
5511
5518
|
meta: {
|
|
@@ -5556,17 +5563,17 @@ var serveCommand = defineCommand23({
|
|
|
5556
5563
|
signalled = true;
|
|
5557
5564
|
});
|
|
5558
5565
|
process.on("SIGTERM", onSigterm);
|
|
5559
|
-
await new Promise((
|
|
5566
|
+
await new Promise((resolve7, reject) => {
|
|
5560
5567
|
proc.on("error", (err) => reject(err));
|
|
5561
5568
|
proc.on("close", (code) => {
|
|
5562
5569
|
if (signalled) {
|
|
5563
5570
|
process.exitCode = 0;
|
|
5564
|
-
|
|
5571
|
+
resolve7();
|
|
5565
5572
|
} else if (code === 0 || code === null) {
|
|
5566
|
-
|
|
5573
|
+
resolve7();
|
|
5567
5574
|
} else {
|
|
5568
5575
|
process.exitCode = code;
|
|
5569
|
-
|
|
5576
|
+
resolve7();
|
|
5570
5577
|
}
|
|
5571
5578
|
});
|
|
5572
5579
|
});
|
|
@@ -5611,8 +5618,8 @@ var sessionCommand = defineCommand24({
|
|
|
5611
5618
|
});
|
|
5612
5619
|
|
|
5613
5620
|
// src/commands/skill.ts
|
|
5614
|
-
import { existsSync as existsSync6, readFileSync as
|
|
5615
|
-
import { basename as
|
|
5621
|
+
import { existsSync as existsSync6, readFileSync as readFileSync9, statSync as statSync2 } from "fs";
|
|
5622
|
+
import { basename as basename6, resolve as resolve5 } from "path";
|
|
5616
5623
|
import { defineCommand as defineCommand25 } from "citty";
|
|
5617
5624
|
function printFindings(findings, prefix = " ") {
|
|
5618
5625
|
for (const f of findings) {
|
|
@@ -5676,13 +5683,13 @@ var importCmd = defineCommand25({
|
|
|
5676
5683
|
},
|
|
5677
5684
|
async run({ args: args2 }) {
|
|
5678
5685
|
const client = createClient2();
|
|
5679
|
-
const absFrom =
|
|
5686
|
+
const absFrom = resolve5(args2.from);
|
|
5680
5687
|
const isLocalZip = args2.from.toLowerCase().endsWith(".zip") && existsSync6(absFrom) && statSync2(absFrom).isFile();
|
|
5681
5688
|
let result;
|
|
5682
5689
|
try {
|
|
5683
5690
|
if (isLocalZip) {
|
|
5684
|
-
const bytes =
|
|
5685
|
-
const file = new File([bytes],
|
|
5691
|
+
const bytes = readFileSync9(absFrom);
|
|
5692
|
+
const file = new File([bytes], basename6(absFrom), { type: "application/zip" });
|
|
5686
5693
|
const fd = new FormData();
|
|
5687
5694
|
fd.set("file", file);
|
|
5688
5695
|
if (args2.force) fd.set("force", "true");
|
|
@@ -5751,7 +5758,7 @@ var skillCommand = defineCommand25({
|
|
|
5751
5758
|
});
|
|
5752
5759
|
|
|
5753
5760
|
// src/commands/team.ts
|
|
5754
|
-
import { readFileSync as
|
|
5761
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
5755
5762
|
import { stdin as stdin2 } from "process";
|
|
5756
5763
|
import { defineCommand as defineCommand33 } from "citty";
|
|
5757
5764
|
|
|
@@ -5813,7 +5820,7 @@ var teamCodingLogCommand = defineCommand26({
|
|
|
5813
5820
|
});
|
|
5814
5821
|
|
|
5815
5822
|
// src/commands/team-environment.ts
|
|
5816
|
-
import { readFileSync as
|
|
5823
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
5817
5824
|
import { defineCommand as defineCommand27 } from "citty";
|
|
5818
5825
|
var args = { id: { type: "positional", required: true, description: "Team slug" } };
|
|
5819
5826
|
var teamEnvironmentCommand = defineCommand27({
|
|
@@ -5839,7 +5846,7 @@ var teamEnvironmentCommand = defineCommand27({
|
|
|
5839
5846
|
},
|
|
5840
5847
|
async run({ args: args2 }) {
|
|
5841
5848
|
const input = JSON.parse(
|
|
5842
|
-
|
|
5849
|
+
readFileSync10(args2.file, "utf8")
|
|
5843
5850
|
);
|
|
5844
5851
|
console.log(
|
|
5845
5852
|
JSON.stringify(await createClient2().codingEnvironment.configure(args2.id, input), null, 2)
|
|
@@ -5850,7 +5857,7 @@ var teamEnvironmentCommand = defineCommand27({
|
|
|
5850
5857
|
});
|
|
5851
5858
|
|
|
5852
5859
|
// src/commands/team-policy.ts
|
|
5853
|
-
import { readFileSync as
|
|
5860
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
5854
5861
|
import { defineCommand as defineCommand28 } from "citty";
|
|
5855
5862
|
|
|
5856
5863
|
// src/team-interchange.ts
|
|
@@ -6067,7 +6074,7 @@ function edgeDiff(before, after) {
|
|
|
6067
6074
|
// src/commands/team-policy.ts
|
|
6068
6075
|
function readJson(path) {
|
|
6069
6076
|
try {
|
|
6070
|
-
return JSON.parse(
|
|
6077
|
+
return JSON.parse(readFileSync11(path, "utf8"));
|
|
6071
6078
|
} catch (error) {
|
|
6072
6079
|
throw new Error(`invalid JSON: ${error.message}`);
|
|
6073
6080
|
}
|
|
@@ -7357,7 +7364,7 @@ var userMdSetCmd = defineCommand33({
|
|
|
7357
7364
|
async run({ args: args2 }) {
|
|
7358
7365
|
let content;
|
|
7359
7366
|
if (args2["from-stdin"]) content = await readStdin();
|
|
7360
|
-
else if (args2.file) content =
|
|
7367
|
+
else if (args2.file) content = readFileSync12(args2.file, "utf8");
|
|
7361
7368
|
else if (args2.text !== void 0) content = args2.text;
|
|
7362
7369
|
else {
|
|
7363
7370
|
console.error("team user-md set: provide --file, --from-stdin, or --text");
|
|
@@ -7503,11 +7510,11 @@ var teamCommand = defineCommand33({
|
|
|
7503
7510
|
});
|
|
7504
7511
|
|
|
7505
7512
|
// src/commands/team-template.ts
|
|
7506
|
-
import { readFileSync as
|
|
7513
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
7507
7514
|
import { defineCommand as defineCommand34 } from "citty";
|
|
7508
7515
|
function jsonFile(path) {
|
|
7509
7516
|
try {
|
|
7510
|
-
return JSON.parse(
|
|
7517
|
+
return JSON.parse(readFileSync13(path, "utf8"));
|
|
7511
7518
|
} catch (error) {
|
|
7512
7519
|
throw new Error(`invalid JSON: ${error.message}`);
|
|
7513
7520
|
}
|
|
@@ -8025,7 +8032,7 @@ function tokenRow(t) {
|
|
|
8025
8032
|
const expired = t.expiresAt !== null && t.expiresAt <= Date.now();
|
|
8026
8033
|
const state = t.revokedAt ? "revoked" : expired ? "expired" : "active";
|
|
8027
8034
|
const expires = t.expiresAt ? new Date(t.expiresAt).toISOString() : "(never)";
|
|
8028
|
-
return [t.id, t.kind, state, t.label, `expires: ${expires}`, `last: ${last}`];
|
|
8035
|
+
return [t.id, t.kind, state, t.label, t.scopes.join(" "), `expires: ${expires}`, `last: ${last}`];
|
|
8029
8036
|
}
|
|
8030
8037
|
function resolveQrServer(override) {
|
|
8031
8038
|
const raw = override ?? loadClientConfig().serverUrl;
|
|
@@ -8062,19 +8069,29 @@ var createCmd6 = defineCommand36({
|
|
|
8062
8069
|
expiresDays: {
|
|
8063
8070
|
type: "string",
|
|
8064
8071
|
description: "Device lifetime in days (default 90, maximum 365)"
|
|
8072
|
+
},
|
|
8073
|
+
scope: {
|
|
8074
|
+
type: "string",
|
|
8075
|
+
description: "Authorization scope; repeat for more (read, write, approvals, admin). Default: all scopes."
|
|
8065
8076
|
}
|
|
8066
8077
|
},
|
|
8067
|
-
async run({ args: args2 }) {
|
|
8078
|
+
async run({ args: args2, rawArgs }) {
|
|
8068
8079
|
const client = createClient2();
|
|
8069
8080
|
const expiresInDays = args2.expiresDays === void 0 ? void 0 : Number(args2.expiresDays);
|
|
8070
8081
|
if (expiresInDays !== void 0 && !Number.isInteger(expiresInDays)) {
|
|
8071
8082
|
throw new Error("--expires-days must be an integer");
|
|
8072
8083
|
}
|
|
8073
|
-
const
|
|
8084
|
+
const scopes = collectFlagValues(rawArgs, "scope");
|
|
8085
|
+
const body = {
|
|
8086
|
+
label: args2.label,
|
|
8087
|
+
expiresInDays,
|
|
8088
|
+
...scopes.length > 0 ? { scopes } : {}
|
|
8089
|
+
};
|
|
8074
8090
|
const res = await client.post("/api/tokens", body);
|
|
8075
|
-
console.log(`id:
|
|
8076
|
-
console.log(`label:
|
|
8077
|
-
console.log(`kind:
|
|
8091
|
+
console.log(`id: ${res.meta.id}`);
|
|
8092
|
+
console.log(`label: ${res.meta.label}`);
|
|
8093
|
+
console.log(`kind: ${res.meta.kind}`);
|
|
8094
|
+
console.log(`scopes: ${res.meta.scopes.join(" ")}`);
|
|
8078
8095
|
console.log(
|
|
8079
8096
|
`expires: ${res.meta.expiresAt ? new Date(res.meta.expiresAt).toISOString() : "(never)"}`
|
|
8080
8097
|
);
|
|
@@ -8090,6 +8107,43 @@ var createCmd6 = defineCommand36({
|
|
|
8090
8107
|
qrcode.generate(pairUrl, { small: true }, (qr) => console.log(qr));
|
|
8091
8108
|
}
|
|
8092
8109
|
});
|
|
8110
|
+
var pairCmd = defineCommand36({
|
|
8111
|
+
meta: {
|
|
8112
|
+
name: "pair",
|
|
8113
|
+
description: "Mint a one-paste pairing setup code for a new device (10 min, single use)"
|
|
8114
|
+
},
|
|
8115
|
+
args: {
|
|
8116
|
+
scope: {
|
|
8117
|
+
type: "string",
|
|
8118
|
+
description: "Authorization scope for the minted device credential; repeat for more. Default: all scopes."
|
|
8119
|
+
},
|
|
8120
|
+
server: {
|
|
8121
|
+
type: "string",
|
|
8122
|
+
description: "Server URL to embed in the setup code (default: detect LAN IP; pass the gateway HTTPS origin for remote devices)"
|
|
8123
|
+
}
|
|
8124
|
+
},
|
|
8125
|
+
async run({ args: args2, rawArgs }) {
|
|
8126
|
+
const client = createClient2();
|
|
8127
|
+
const scopes = collectFlagValues(rawArgs, "scope");
|
|
8128
|
+
const res = await client.post("/api/pair/codes", {
|
|
8129
|
+
...scopes.length > 0 ? { scopes } : {}
|
|
8130
|
+
});
|
|
8131
|
+
let setupUrl = res.setupUrl;
|
|
8132
|
+
if (args2.server) {
|
|
8133
|
+
const serverUrl = resolveQrServer(args2.server);
|
|
8134
|
+
setupUrl = `bazilion-pair://pair?server=${encodeURIComponent(serverUrl)}&code=${encodeURIComponent(res.code)}`;
|
|
8135
|
+
}
|
|
8136
|
+
console.log(`id: ${res.meta.id}`);
|
|
8137
|
+
console.log(`scopes: ${res.meta.scopes.join(" ")}`);
|
|
8138
|
+
console.log(`expires: ${new Date(res.meta.expiresAt).toISOString()} (10 minutes, single use)`);
|
|
8139
|
+
console.log("");
|
|
8140
|
+
console.log(`setup URL (paste or scan on the new device):`);
|
|
8141
|
+
console.log(setupUrl);
|
|
8142
|
+
console.log("");
|
|
8143
|
+
console.log("the code admits exactly one credential exchange; after that it is inert.");
|
|
8144
|
+
qrcode.generate(setupUrl, { small: true }, (qr) => console.log(qr));
|
|
8145
|
+
}
|
|
8146
|
+
});
|
|
8093
8147
|
var listCmd14 = defineCommand36({
|
|
8094
8148
|
meta: { name: "list", description: "List web tokens" },
|
|
8095
8149
|
args: {
|
|
@@ -8131,6 +8185,7 @@ var tokenCommand = defineCommand36({
|
|
|
8131
8185
|
meta: { name: "token", description: "Manage web tokens for API/CLI clients" },
|
|
8132
8186
|
subCommands: {
|
|
8133
8187
|
create: createCmd6,
|
|
8188
|
+
pair: pairCmd,
|
|
8134
8189
|
list: listCmd14,
|
|
8135
8190
|
revoke: revokeCmd2,
|
|
8136
8191
|
"show-local": showLocalCmd
|
|
@@ -8280,9 +8335,9 @@ var triggerCommand = defineCommand37({
|
|
|
8280
8335
|
});
|
|
8281
8336
|
|
|
8282
8337
|
// src/commands/uninstall.ts
|
|
8283
|
-
import { existsSync as existsSync7, lstatSync as lstatSync4, readdirSync as
|
|
8338
|
+
import { existsSync as existsSync7, lstatSync as lstatSync4, readdirSync as readdirSync3, realpathSync as realpathSync4, rmSync as rmSync4 } from "fs";
|
|
8284
8339
|
import { homedir as homedir2 } from "os";
|
|
8285
|
-
import { isAbsolute as isAbsolute2, join as
|
|
8340
|
+
import { isAbsolute as isAbsolute2, join as join8, parse as parse2, relative as relative2, resolve as resolve6, sep } from "path";
|
|
8286
8341
|
import { defineCommand as defineCommand38 } from "citty";
|
|
8287
8342
|
function makeLineReader() {
|
|
8288
8343
|
let buffer = "";
|
|
@@ -8293,8 +8348,8 @@ function makeLineReader() {
|
|
|
8293
8348
|
const nlIdx = buffer.indexOf("\n");
|
|
8294
8349
|
if (nlIdx === -1) {
|
|
8295
8350
|
if (ended) {
|
|
8296
|
-
const
|
|
8297
|
-
|
|
8351
|
+
const resolve7 = queue.shift();
|
|
8352
|
+
resolve7?.(buffer);
|
|
8298
8353
|
buffer = "";
|
|
8299
8354
|
} else {
|
|
8300
8355
|
return;
|
|
@@ -8302,8 +8357,8 @@ function makeLineReader() {
|
|
|
8302
8357
|
} else {
|
|
8303
8358
|
const line = buffer.slice(0, nlIdx);
|
|
8304
8359
|
buffer = buffer.slice(nlIdx + 1);
|
|
8305
|
-
const
|
|
8306
|
-
|
|
8360
|
+
const resolve7 = queue.shift();
|
|
8361
|
+
resolve7?.(line);
|
|
8307
8362
|
}
|
|
8308
8363
|
}
|
|
8309
8364
|
};
|
|
@@ -8316,8 +8371,8 @@ function makeLineReader() {
|
|
|
8316
8371
|
ended = true;
|
|
8317
8372
|
tryDeliver();
|
|
8318
8373
|
});
|
|
8319
|
-
return () => new Promise((
|
|
8320
|
-
queue.push(
|
|
8374
|
+
return () => new Promise((resolve7) => {
|
|
8375
|
+
queue.push(resolve7);
|
|
8321
8376
|
tryDeliver();
|
|
8322
8377
|
});
|
|
8323
8378
|
}
|
|
@@ -8338,10 +8393,10 @@ function removePath(p) {
|
|
|
8338
8393
|
}
|
|
8339
8394
|
function canonicalExistingPath(path) {
|
|
8340
8395
|
try {
|
|
8341
|
-
return
|
|
8396
|
+
return realpathSync4.native(path);
|
|
8342
8397
|
} catch (error) {
|
|
8343
8398
|
if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) throw error;
|
|
8344
|
-
return
|
|
8399
|
+
return resolve6(path);
|
|
8345
8400
|
}
|
|
8346
8401
|
}
|
|
8347
8402
|
function containsPath(container, candidate) {
|
|
@@ -8349,7 +8404,7 @@ function containsPath(container, candidate) {
|
|
|
8349
8404
|
return nested === "" || nested !== ".." && !nested.startsWith(`..${sep}`) && !isAbsolute2(nested);
|
|
8350
8405
|
}
|
|
8351
8406
|
function assertSafeUninstallHome(home) {
|
|
8352
|
-
const target =
|
|
8407
|
+
const target = resolve6(home);
|
|
8353
8408
|
const canonical = canonicalExistingPath(target);
|
|
8354
8409
|
const userHome = canonicalExistingPath(homedir2());
|
|
8355
8410
|
const workingDirectory = canonicalExistingPath(process.cwd());
|
|
@@ -8389,15 +8444,22 @@ var uninstallCommand = defineCommand38({
|
|
|
8389
8444
|
async run({ args: args2 }) {
|
|
8390
8445
|
const paths = resolveCliPaths(args2.home);
|
|
8391
8446
|
const targetHome = assertSafeUninstallHome(paths.home);
|
|
8392
|
-
const
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
const
|
|
8399
|
-
const
|
|
8400
|
-
const
|
|
8447
|
+
const requestedHome = resolve6(args2.home ?? process.env.BAZILION_HOME ?? join8(homedir2(), ".bazilion"));
|
|
8448
|
+
let requestedIsSymlink = false;
|
|
8449
|
+
try {
|
|
8450
|
+
requestedIsSymlink = lstatSync4(requestedHome).isSymbolicLink();
|
|
8451
|
+
} catch {
|
|
8452
|
+
}
|
|
8453
|
+
const homeIsSymlink = requestedIsSymlink;
|
|
8454
|
+
const dbFile = join8(targetHome, "bazilion.db");
|
|
8455
|
+
const profilesDir = join8(targetHome, "profiles");
|
|
8456
|
+
const agentsDir = join8(targetHome, "agents");
|
|
8457
|
+
const teamsDir = join8(targetHome, "teams");
|
|
8458
|
+
const legacyGroupsDir = join8(targetHome, "groups");
|
|
8459
|
+
const skillsDir = join8(targetHome, "skills");
|
|
8460
|
+
const logsDir = join8(targetHome, "logs");
|
|
8461
|
+
const legacyConfigFile = join8(targetHome, "config.json");
|
|
8462
|
+
const legacySecretsFile = join8(targetHome, "secrets.enc");
|
|
8401
8463
|
if (!existsSync7(targetHome)) {
|
|
8402
8464
|
const uninstallLock2 = await acquireHomeRestoreLock(targetHome, "uninstalling");
|
|
8403
8465
|
try {
|
|
@@ -8408,7 +8470,6 @@ var uninstallCommand = defineCommand38({
|
|
|
8408
8470
|
}
|
|
8409
8471
|
return;
|
|
8410
8472
|
}
|
|
8411
|
-
const homeIsSymlink = lstatSync4(targetHome).isSymbolicLink();
|
|
8412
8473
|
console.log(`about to uninstall bazilion at ${targetHome}`);
|
|
8413
8474
|
console.log("");
|
|
8414
8475
|
const resetTargets = [
|
|
@@ -8416,7 +8477,7 @@ var uninstallCommand = defineCommand38({
|
|
|
8416
8477
|
`${dbFile}-wal`,
|
|
8417
8478
|
`${dbFile}-shm`,
|
|
8418
8479
|
`${dbFile}-journal`,
|
|
8419
|
-
|
|
8480
|
+
join8(targetHome, "auth.json"),
|
|
8420
8481
|
legacyConfigFile,
|
|
8421
8482
|
legacySecretsFile,
|
|
8422
8483
|
profilesDir,
|
|
@@ -8450,10 +8511,10 @@ var uninstallCommand = defineCommand38({
|
|
|
8450
8511
|
for (const p of fullWipeTargets) {
|
|
8451
8512
|
if (removePath(p)) console.log(`removed ${p}`);
|
|
8452
8513
|
}
|
|
8453
|
-
if (
|
|
8514
|
+
if (readdirSync3(targetHome).length === 0 && !homeIsSymlink) {
|
|
8454
8515
|
rmSync4(targetHome, { recursive: true, force: true });
|
|
8455
8516
|
console.log(`removed ${targetHome}`);
|
|
8456
|
-
} else if (homeIsSymlink &&
|
|
8517
|
+
} else if (homeIsSymlink && readdirSync3(targetHome).length === 0) {
|
|
8457
8518
|
console.log(`kept ${targetHome}: symlinked BAZILION_HOME root is now empty`);
|
|
8458
8519
|
} else {
|
|
8459
8520
|
console.log(`${targetHome} still has unmanaged files; left in place`);
|