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.
Files changed (59) hide show
  1. package/dist/cli.js +430 -369
  2. package/dist/cli.js.map +1 -1
  3. package/dist/daemon.js +811 -488
  4. package/dist/daemon.js.map +1 -1
  5. package/dist/migrations/0001_init.sql +2 -1
  6. package/dist/migrations/0002_device_token_scopes.sql +8 -0
  7. package/dist/migrations/0003_web_pairing_tokens.sql +18 -0
  8. package/dist/web/client/assets/{ChatPane-CGCtAuD3.js → ChatPane--0BWZYHD.js} +1 -1
  9. package/dist/web/client/assets/{ConfirmDialog-Br19uXWH.js → ConfirmDialog-D9AiLH_Z.js} +1 -1
  10. package/dist/web/client/assets/{FieldRow-Csy3_cH5.js → FieldRow-Cd0EUpYd.js} +1 -1
  11. package/dist/web/client/assets/{ProductionTeamPolicyEditor-DG1x4Cqz.js → ProductionTeamPolicyEditor-BR5_1Wyv.js} +1 -1
  12. package/dist/web/client/assets/{ProfileCommunicationEditor-C3odNVkK.js → ProfileCommunicationEditor-K2wGbGky.js} +1 -1
  13. package/dist/web/client/assets/{ResultSourceConversation-5PFWqXTY.js → ResultSourceConversation-Y9VTd-nz.js} +1 -1
  14. package/dist/web/client/assets/{TeamTabs-BHB_COm0.js → TeamTabs-Yuc_lSZ9.js} +1 -1
  15. package/dist/web/client/assets/{TemplatesTabs-YyytjW7k.js → TemplatesTabs-Pj00chC7.js} +1 -1
  16. package/dist/web/client/assets/{UnsavedChangesGuard-CredyC3E.js → UnsavedChangesGuard-BSfJZH7E.js} +1 -1
  17. package/dist/web/client/assets/{_id-CIkPtQY0.js → _id-B4yPnTNN.js} +1 -1
  18. package/dist/web/client/assets/{_id-KXX6nuKc.js → _id-CUbb0F4l.js} +1 -1
  19. package/dist/web/client/assets/{_id-BZ_-4M4s.js → _id-D2l33vb6.js} +1 -1
  20. package/dist/web/client/assets/{_id-BLm9LVlZ.js → _id-DCFRZAJN.js} +1 -1
  21. package/dist/web/client/assets/{_id-nDbQY7f_.js → _id-UniNI3bQ.js} +1 -1
  22. package/dist/web/client/assets/{activity-BE7jG1Mz.js → activity-C5QG0Wgv.js} +1 -1
  23. package/dist/web/client/assets/{agents-S9lzXrrs.js → agents-CQo9V1lc.js} +1 -1
  24. package/dist/web/client/assets/{agents-vOPd-upn.js → agents-DVVPYxPM.js} +1 -1
  25. package/dist/web/client/assets/{approvals-BUfhlUAX.js → approvals-DQz6TJE8.js} +1 -1
  26. package/dist/web/client/assets/{attention-C3r-2GSp.js → attention-BtCLaWhZ.js} +1 -1
  27. package/dist/web/client/assets/chevron-right-BGFokHDA.js +1 -0
  28. package/dist/web/client/assets/{config-AL_EM57n.js → config-DuhKvD0X.js} +1 -1
  29. package/dist/web/client/assets/{inbox-LlCpJrMH.js → inbox-Cr7iGkrF.js} +1 -1
  30. package/dist/web/client/assets/{index-CwMw0pnV.js → index-ChXVa4eb.js} +2 -2
  31. package/dist/web/client/assets/{learning-zvTJ_9vM.js → learning-5eO_SZUP.js} +1 -1
  32. package/dist/web/client/assets/{login-BpQ54z8Y.js → login-Cn9mf44C.js} +1 -1
  33. package/dist/web/client/assets/{mcp-BD6VzXg_.js → mcp-0COajQD4.js} +1 -1
  34. package/dist/web/client/assets/{members-SEDi8SFo.js → members-9eTmy1QM.js} +1 -1
  35. package/dist/web/client/assets/{memory-zi_dPlMA.js → memory-CExQd_vP.js} +1 -1
  36. package/dist/web/client/assets/{policy-URjQAAdN.js → policy-B-zDlt_G.js} +1 -1
  37. package/dist/web/client/assets/{results-Bcuy4Flp.js → results-BUmKkuHo.js} +1 -1
  38. package/dist/web/client/assets/{review-CVH7X9-d.js → review-BUTz_zRX.js} +1 -1
  39. package/dist/web/client/assets/{routes-BJEX6yAE.js → routes-b1FscQsH.js} +1 -1
  40. package/dist/web/client/assets/{services-BTG4F5FL.js → services-D-RdMc8g.js} +1 -1
  41. package/dist/web/client/assets/{skills-DwiHS7eD.js → skills-CNbkY2ji.js} +1 -1
  42. package/dist/web/client/assets/{teams-DfpwQu1i.js → teams-Dn9o_-P-.js} +1 -1
  43. package/dist/web/client/assets/{teams-DcROmSGB.js → teams-H4OTWt8E.js} +1 -1
  44. package/dist/web/client/assets/{telegram-BLyaaUXE.js → telegram-BnM54CPN.js} +1 -1
  45. package/dist/web/client/assets/tokens-C-I23fVZ.js +1 -0
  46. package/dist/web/client/assets/{triggers-CtVhrAGA.js → triggers-DG9YoC7B.js} +1 -1
  47. package/dist/web/client/assets/{verifications-TC0ccGLY.js → verifications-CzToBSUN.js} +1 -1
  48. package/dist/web/client/assets/{welcome-DML3X1ha.js → welcome-REp-dEfY.js} +1 -1
  49. package/dist/web/client/assets/{x-D8yuCam7.js → x-C-BpLdcp.js} +1 -1
  50. package/dist/web/server/assets/{_tanstack-start-manifest_v-BGSoO6CK.js → _tanstack-start-manifest_v-BfURdqEL.js} +82 -82
  51. package/dist/web/server/assets/{router-BVhdWkwP.js → router-CyZ-GH8M.js} +1 -1
  52. package/dist/web/server/assets/{tokens-_2hptHP6.js → tokens-BFhrz5qd.js} +1 -1
  53. package/dist/web/server/assets/{tokens-DDwtO15P.js → tokens-DO_eDpv_.js} +96 -3
  54. package/dist/web/server/server.js +2 -2
  55. package/dist/worker.js +127 -90
  56. package/dist/worker.js.map +1 -1
  57. package/package.json +3 -3
  58. package/dist/web/client/assets/chevron-right-C7P3Z105.js +0 -1
  59. 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.20.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: basename(path),
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 basename2, extname as extname2 } from "path";
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: basename2(p), mimeType, data: readFileSync3(p).toString("base64") };
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: basename2(p),
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 = basename2(e.name).replace(/[^\w.-]/g, "_") || "file";
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
- if (bashApprovalMode === "interactive") {
1395
- let retryDraft = "";
1396
- while (true) {
1397
- const observed = await client.get(
1398
- `/api/agents/${resolved.agent.id}/sessions/head`
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((resolve6) => {
1597
- process.stdin.once("data", (d) => resolve6(String(d).trim().toLowerCase()));
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((resolve6, reject) => {
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
- resolve6(String(data).trim());
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 readFileSync5,
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 basename4, dirname as dirname2, isAbsolute, parse, posix, relative, resolve as resolve3 } from "path";
2330
- import { DatabaseSync as DatabaseSync2, backup as sqliteBackup } from "node:sqlite";
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(resolve(payload, "teams", team.id)).isDirectory())
2403
- rebase.run(resolve(targetHome, "teams", team.id), team.id);
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
- var CANONICAL_MIGRATION = "0001_init";
2479
- var CANONICAL_SCHEMA_HASH = "469e6610e0f1030aa9e699bff1083a54305a77bc48f573eeae908d96a48d5396";
2480
- var CANONICAL_OBJECTS = [
2481
- ["table", "team_coding_environments"],
2482
- ["table", "workspace_writers"],
2483
- ["table", "workspace_resources"],
2484
- ["table", "coding_commands"],
2485
- ["index", "coding_command_history"],
2486
- ["table", "coding_command_logs"],
2487
- ["index", "coding_command_logs_retention"],
2488
- ["index", "coding_command_logs_team_time"],
2489
- ["table", "source_snapshots"],
2490
- ["index", "source_snapshots_retention"],
2491
- ["index", "source_snapshots_team_time"],
2492
- ["table", "review_packets"],
2493
- ["index", "review_packets_team_time"],
2494
- ["index", "review_packets_reviewer_dispatch"],
2495
- ["index", "review_packets_retention"],
2496
- ["table", "review_findings"],
2497
- ["index", "review_findings_packet"],
2498
- ["index", "review_findings_unresolved"],
2499
- ["table", "review_conclusions"],
2500
- ["index", "review_conclusions_packet"],
2501
- ["table", "review_attempts"],
2502
- ["index", "review_attempts_one_open_per_packet"],
2503
- ["index", "review_attempts_lease"],
2504
- ["table", "verification_requests"],
2505
- ["index", "verification_requests_team_time"],
2506
- ["index", "verification_requests_recipient_dispatch"],
2507
- ["index", "verification_requests_retention"],
2508
- ["table", "verification_checks"],
2509
- ["table", "verification_attempts"],
2510
- ["index", "verification_attempts_one_open_per_request"],
2511
- ["index", "verification_attempts_lease"],
2512
- ["table", "verification_check_outcomes"],
2513
- ["index", "verification_check_outcomes_command"],
2514
- ["table", "notification_settings"],
2515
- ["table", "notification_receipts"],
2516
- ["index", "notification_receipts_state"],
2517
- ["index", "notification_receipts_time"],
2518
- ["table", "agent_questions"],
2519
- ["table", "question_receipt_key"],
2520
- ["index", "agent_questions_one_pending"],
2521
- ["index", "agent_questions_agent_time"],
2522
- ["table", "user_queue_controls"],
2523
- ["table", "user_queue_items"],
2524
- ["table", "user_queue_attachments"],
2525
- ["index", "user_queue_agent_order"],
2526
- ["index", "user_queue_status"],
2527
- ["index", "agent_conversations_agent_time"],
2528
- ["table", "agent_conversations"],
2529
- ["table", "agent_conversation_selection"],
2530
- ["index", "agent_results_team_time"],
2531
- ["index", "agent_results_session_source"],
2532
- ["index", "agent_results_packet_source"],
2533
- ["index", "agent_triggers_agent"],
2534
- ["index", "agent_triggers_enabled"],
2535
- ["index", "agent_loop_break_events_agent_time"],
2536
- ["index", "agent_loop_break_events_team_time"],
2537
- ["index", "agent_lesson_proposals_agent_status_time"],
2538
- ["index", "agent_lesson_proposals_review"],
2539
- ["index", "agent_reviews_agent_time"],
2540
- ["index", "agent_reviews_claimable"],
2541
- ["index", "agent_reviews_one_open_per_agent"],
2542
- ["index", "communication_approval_events_attempt"],
2543
- ["index", "communication_approvals_queue"],
2544
- ["index", "communication_approvals_teams"],
2545
- ["index", "idx_agents_telegram_topic_id"],
2546
- ["index", "idx_provider_models_provider"],
2547
- ["index", "messages_policy_delivery_queue"],
2548
- ["index", "messages_causal_chain"],
2549
- ["index", "messages_to_unread"],
2550
- ["index", "team_policy_baseline_owner"],
2551
- ["index", "team_policy_blocks_team_time"],
2552
- ["index", "team_template_active_position"],
2553
- ["index", "trigger_dispatches_claimable"],
2554
- ["index", "trigger_dispatches_trigger_time"],
2555
- ["index", "web_tokens_active"],
2556
- ["index", "web_sessions_active"],
2557
- ["index", "web_sessions_device"],
2558
- ["table", "agent_results"],
2559
- ["table", "agent_skills"],
2560
- ["table", "agent_loop_break_events"],
2561
- ["table", "agent_lesson_proposals"],
2562
- ["table", "agent_reviews"],
2563
- ["table", "agent_triggers"],
2564
- ["table", "agents"],
2565
- ["table", "attention_acknowledgements"],
2566
- ["table", "communication_approval_events"],
2567
- ["table", "communication_approval_message_grants"],
2568
- ["table", "communication_approvals"],
2569
- ["table", "config"],
2570
- ["table", "mcp_servers"],
2571
- ["table", "messages"],
2572
- ["table", "profile_communication_defaults"],
2573
- ["table", "profile_default_skills"],
2574
- ["table", "profiles"],
2575
- ["table", "provider_models"],
2576
- ["table", "provider_state"],
2577
- ["table", "schema_migrations"],
2578
- ["table", "secrets"],
2579
- ["table", "skill_meta"],
2580
- ["table", "source_slot_bindings"],
2581
- ["table", "team_agent_state"],
2582
- ["table", "team_policies"],
2583
- ["table", "team_policy_block_events"],
2584
- ["table", "team_policy_edges"],
2585
- ["table", "team_template_edges"],
2586
- ["table", "team_template_revision_edges"],
2587
- ["table", "team_template_revision_slots"],
2588
- ["table", "team_template_revisions"],
2589
- ["table", "team_template_slots"],
2590
- ["table", "team_templates"],
2591
- ["table", "teams"],
2592
- ["table", "telegram_allowed_users"],
2593
- ["table", "telegram_pairing_challenge"],
2594
- ["table", "template_instantiations"],
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 assertCanonicalBackupSchema(db) {
2615
- const migrations = db.prepare("SELECT version FROM schema_migrations ORDER BY version").all();
2616
- if (migrations.length !== 1 || migrations[0]?.version !== CANONICAL_MIGRATION) {
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 ${CANONICAL_MIGRATION}; found ` + (migrations.map((row2) => row2.version).join(", ") || "none")
2601
+ `schema_migrations must contain exactly ${expectedVersions.join(", ")}; found ` + (applied.join(", ") || "none")
2619
2602
  );
2620
2603
  }
2621
- const rows = db.prepare(
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 NOT LIKE 'sqlite_%'`
2607
+ WHERE sql IS NOT NULL AND substr(name, 1, 7) <> 'sqlite_'
2608
+ ORDER BY type, name`
2625
2609
  ).all();
2626
- const byKey = new Map(rows.map((row2) => [`${row2.type}\0${row2.name}`, row2]));
2627
- const canonicalKeys = new Set(CANONICAL_OBJECTS.map(([type, name]) => `${type}\0${name}`));
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 canonicalRows = [];
2634
- for (const [type, name] of CANONICAL_OBJECTS) {
2635
- const row2 = byKey.get(`${type}\0${name}`);
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
- "canonical schema fingerprint does not match this Bazilion release; restore a backup created from the current clean-install schema"
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 readFileSync4,
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 basename3, dirname, join as join2, resolve as resolve2 } from "path";
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 = resolve2(home);
2666
+ const absolute = resolve3(home);
2678
2667
  try {
2679
- return realpathSync.native(absolute);
2668
+ return realpathSync2.native(absolute);
2680
2669
  } catch (error) {
2681
2670
  if (errorCode(error) !== "ENOENT") throw error;
2682
- const parent = dirname(absolute);
2671
+ const parent = dirname3(absolute);
2683
2672
  if (parent === absolute) throw error;
2684
- return join2(canonicalHomeIdentity(parent), basename3(absolute));
2673
+ return join3(canonicalHomeIdentity(parent), basename4(absolute));
2685
2674
  }
2686
2675
  }
2687
2676
  function daemonLivenessPath(home) {
2688
- const canonicalHome = canonicalHomeIdentity(home);
2689
- const identity = createHash2("sha256").update(canonicalHome).digest("hex").slice(0, 24);
2690
- return join2(dirname(canonicalHome), `.bazilion-runtime-${identity}.json`);
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() ? readFileSync4(path, "utf8") : "";
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(dirname(path), "r");
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, join2(claim, "stale-record.json"));
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 = resolve2(home);
2816
- mkdirSync(dirname(targetHome), { recursive: true });
2804
+ const targetHome = resolve3(home);
2805
+ mkdirSync(dirname3(targetHome), { recursive: true });
2817
2806
  const path = daemonLivenessPath(targetHome);
2818
- mkdirSync(dirname(path), { recursive: true });
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 = resolve2(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 = resolve2(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 = resolve3(args2.output ?? `bazilion-backup-${date}${defaultSuffix}`);
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 = resolve3(resolveCliPaths().home);
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(resolve3(tmpdir(), "bazilion-download-"));
3037
- const partial = resolve3(downloadDir, "backup.tar.gz");
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 = resolve3(
3063
- dirname2(outAbs),
3064
- `.${basename4(outAbs)}.${randomUUID7()}.installing`
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(readFileSync5(path, "utf8"));
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 DatabaseSync2(path, { readOnly: true });
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 = resolve3(root, id);
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
- db = new DatabaseSync2(database);
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 = resolve3(payload, collection);
3339
- const targetRoot = resolve3(targetHome, collection);
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 = resolve3(payload, "teams");
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 = resolve3(payload, "teams");
3409
+ const teamsDir = resolve4(payload, "teams");
3403
3410
  if (!existsSync2(teamsDir) || !lstatSync3(teamsDir).isDirectory()) return;
3404
- for (const team of readdirSync(teamsDir, { withFileTypes: true })) {
3411
+ for (const team of readdirSync2(teamsDir, { withFileTypes: true })) {
3405
3412
  if (!team.isDirectory() || team.isSymbolicLink()) continue;
3406
- const memoryDir = resolve3(teamsDir, team.name, "memory");
3413
+ const memoryDir = resolve4(teamsDir, team.name, "memory");
3407
3414
  if (!existsSync2(memoryDir) || !lstatSync3(memoryDir).isDirectory()) continue;
3408
- for (const entry3 of readdirSync(memoryDir, { withFileTypes: true })) {
3415
+ for (const entry3 of readdirSync2(memoryDir, { withFileTypes: true })) {
3409
3416
  if (entry3.isFile() && entry3.name.startsWith(".qmd-index.sqlite")) {
3410
- rmSync2(resolve3(memoryDir, entry3.name), { force: true });
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 DatabaseSync2(database);
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 = resolve3(staging, "previous-home");
3431
+ const previous = resolve4(staging, "previous-home");
3425
3432
  const hadPrevious = existsSync2(targetHome);
3426
- const targetParent = dirname2(targetHome);
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 = resolve3(rawPath);
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 = readFileSync5(path, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
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 = resolve3(args2.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 = resolve3(paths.home);
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 = dirname2(targetHome);
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 === resolve3(resolveCliPaths().home);
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 = readdirSync(targetHome);
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(resolve3(targetParent, ".bazilion-restore-"));
3622
- const stagedArchive = resolve3(staging, "backup.tar.gz");
3623
- const payload = resolve3(staging, "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 = resolve3(payload, "bazilion.db");
3670
- const authFile = resolve3(payload, "auth.json");
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 = resolve3(home, "auth.json");
3734
- const database = resolve3(home, "bazilion.db");
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 DatabaseSync2(database, { readOnly: true });
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 = resolve3(resolveCliPaths(args2.home).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 = resolve3(paths.home);
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 = dirname2(targetHome);
3797
- const staging = mkdtempSync(resolve3(parent, ".bazilion-rotate-"));
3798
- const payload = resolve3(staging, "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(readFileSync5(paths.authFile, "utf8"));
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(resolve3(targetHome, "bazilion.db"), oldAuth.token);
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 = resolve3(payload, "bazilion.db");
3824
+ const stagedDb = resolve4(payload, "bazilion.db");
3818
3825
  rmSync2(stagedDb, { force: true });
3819
- const sourceDb = new DatabaseSync2(resolve3(targetHome, "bazilion.db"), { readOnly: true });
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 DatabaseSync2(stagedDb);
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 = resolve3(payload, "auth.json");
3867
- const authPartial = resolve3(payload, `.auth.json.${randomUUID7()}.installing`);
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 join3 } from "path";
4132
+ import { join as join5 } from "path";
4126
4133
  import { defineCommand as defineCommand12 } from "citty";
4127
- var bundledDaemonEntry = join3(import.meta.dirname, "daemon.js");
4128
- var sourceDaemonEntry = join3(import.meta.dirname, "..", "..", "..", "daemon", "src", "index.ts");
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 = join3(import.meta.dirname, "web-server.js");
4131
- var sourceWebServerEntry = join3(import.meta.dirname, "..", "web-server.ts");
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 = join3(import.meta.dirname, "web");
4134
- var sourceWebDist = join3(import.meta.dirname, "..", "..", "..", "web", "dist");
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((resolve6) => {
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
- resolve6(open);
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(join3(webDist, "server", "server.js"))) {
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((resolve6) => {
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) resolve6();
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 readFileSync6, writeFileSync as writeFileSync3 } from "fs";
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(readFileSync6(paths.authFile, "utf8"));
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 readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
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 join4 } from "path";
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 ? readFileSync7(path, "utf8") : void 0;
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 = join4(tmpdir2(), `bazilion-${args2.id}-${file}-${randomBytes2(4).toString("hex")}`);
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((resolve6, reject) => {
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) => resolve6(c ?? 0));
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 = readFileSync7(tmpPath, "utf8");
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 join5 } from "path";
5512
+ import { join as join7 } from "path";
5506
5513
  import { defineCommand as defineCommand23 } from "citty";
5507
- var bundledDaemonEntry2 = join5(import.meta.dirname, "daemon.js");
5508
- var sourceDaemonEntry2 = join5(import.meta.dirname, "..", "..", "..", "daemon", "src", "index.ts");
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((resolve6, reject) => {
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
- resolve6();
5571
+ resolve7();
5565
5572
  } else if (code === 0 || code === null) {
5566
- resolve6();
5573
+ resolve7();
5567
5574
  } else {
5568
5575
  process.exitCode = code;
5569
- resolve6();
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 readFileSync8, statSync as statSync2 } from "fs";
5615
- import { basename as basename5, resolve as resolve4 } from "path";
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 = resolve4(args2.from);
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 = readFileSync8(absFrom);
5685
- const file = new File([bytes], basename5(absFrom), { type: "application/zip" });
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 readFileSync11 } from "fs";
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 readFileSync9 } from "fs";
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
- readFileSync9(args2.file, "utf8")
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 readFileSync10 } from "fs";
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(readFileSync10(path, "utf8"));
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 = readFileSync11(args2.file, "utf8");
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 readFileSync12 } from "fs";
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(readFileSync12(path, "utf8"));
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 body = { label: args2.label, expiresInDays };
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: ${res.meta.id}`);
8076
- console.log(`label: ${res.meta.label}`);
8077
- console.log(`kind: ${res.meta.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 readdirSync2, realpathSync as realpathSync2, rmSync as rmSync4 } from "fs";
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 join6, parse as parse2, relative as relative2, resolve as resolve5, sep } from "path";
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 resolve6 = queue.shift();
8297
- resolve6?.(buffer);
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 resolve6 = queue.shift();
8306
- resolve6?.(line);
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((resolve6) => {
8320
- queue.push(resolve6);
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 realpathSync2.native(path);
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 resolve5(path);
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 = resolve5(home);
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 dbFile = join6(targetHome, "bazilion.db");
8393
- const profilesDir = join6(targetHome, "profiles");
8394
- const agentsDir = join6(targetHome, "agents");
8395
- const teamsDir = join6(targetHome, "teams");
8396
- const legacyGroupsDir = join6(targetHome, "groups");
8397
- const skillsDir = join6(targetHome, "skills");
8398
- const logsDir = join6(targetHome, "logs");
8399
- const legacyConfigFile = join6(targetHome, "config.json");
8400
- const legacySecretsFile = join6(targetHome, "secrets.enc");
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
- join6(targetHome, "auth.json"),
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 (readdirSync2(targetHome).length === 0 && !homeIsSymlink) {
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 && readdirSync2(targetHome).length === 0) {
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`);