bazilion 0.20.0 → 0.21.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/cli.js +307 -288
  2. package/dist/cli.js.map +1 -1
  3. package/dist/daemon.js +567 -300
  4. package/dist/daemon.js.map +1 -1
  5. package/dist/migrations/0002_device_token_scopes.sql +8 -0
  6. package/dist/migrations/0003_web_pairing_tokens.sql +18 -0
  7. package/dist/web/client/assets/{ChatPane-CGCtAuD3.js → ChatPane--0BWZYHD.js} +1 -1
  8. package/dist/web/client/assets/{ConfirmDialog-Br19uXWH.js → ConfirmDialog-D9AiLH_Z.js} +1 -1
  9. package/dist/web/client/assets/{FieldRow-Csy3_cH5.js → FieldRow-Cd0EUpYd.js} +1 -1
  10. package/dist/web/client/assets/{ProductionTeamPolicyEditor-DG1x4Cqz.js → ProductionTeamPolicyEditor-BR5_1Wyv.js} +1 -1
  11. package/dist/web/client/assets/{ProfileCommunicationEditor-C3odNVkK.js → ProfileCommunicationEditor-K2wGbGky.js} +1 -1
  12. package/dist/web/client/assets/{ResultSourceConversation-5PFWqXTY.js → ResultSourceConversation-Y9VTd-nz.js} +1 -1
  13. package/dist/web/client/assets/{TeamTabs-BHB_COm0.js → TeamTabs-Yuc_lSZ9.js} +1 -1
  14. package/dist/web/client/assets/{TemplatesTabs-YyytjW7k.js → TemplatesTabs-Pj00chC7.js} +1 -1
  15. package/dist/web/client/assets/{UnsavedChangesGuard-CredyC3E.js → UnsavedChangesGuard-BSfJZH7E.js} +1 -1
  16. package/dist/web/client/assets/{_id-CIkPtQY0.js → _id-B4yPnTNN.js} +1 -1
  17. package/dist/web/client/assets/{_id-KXX6nuKc.js → _id-CUbb0F4l.js} +1 -1
  18. package/dist/web/client/assets/{_id-BZ_-4M4s.js → _id-D2l33vb6.js} +1 -1
  19. package/dist/web/client/assets/{_id-BLm9LVlZ.js → _id-DCFRZAJN.js} +1 -1
  20. package/dist/web/client/assets/{_id-nDbQY7f_.js → _id-UniNI3bQ.js} +1 -1
  21. package/dist/web/client/assets/{activity-BE7jG1Mz.js → activity-C5QG0Wgv.js} +1 -1
  22. package/dist/web/client/assets/{agents-S9lzXrrs.js → agents-CQo9V1lc.js} +1 -1
  23. package/dist/web/client/assets/{agents-vOPd-upn.js → agents-DVVPYxPM.js} +1 -1
  24. package/dist/web/client/assets/{approvals-BUfhlUAX.js → approvals-DQz6TJE8.js} +1 -1
  25. package/dist/web/client/assets/{attention-C3r-2GSp.js → attention-BtCLaWhZ.js} +1 -1
  26. package/dist/web/client/assets/chevron-right-BGFokHDA.js +1 -0
  27. package/dist/web/client/assets/{config-AL_EM57n.js → config-DuhKvD0X.js} +1 -1
  28. package/dist/web/client/assets/{inbox-LlCpJrMH.js → inbox-Cr7iGkrF.js} +1 -1
  29. package/dist/web/client/assets/{index-CwMw0pnV.js → index-ChXVa4eb.js} +2 -2
  30. package/dist/web/client/assets/{learning-zvTJ_9vM.js → learning-5eO_SZUP.js} +1 -1
  31. package/dist/web/client/assets/{login-BpQ54z8Y.js → login-Cn9mf44C.js} +1 -1
  32. package/dist/web/client/assets/{mcp-BD6VzXg_.js → mcp-0COajQD4.js} +1 -1
  33. package/dist/web/client/assets/{members-SEDi8SFo.js → members-9eTmy1QM.js} +1 -1
  34. package/dist/web/client/assets/{memory-zi_dPlMA.js → memory-CExQd_vP.js} +1 -1
  35. package/dist/web/client/assets/{policy-URjQAAdN.js → policy-B-zDlt_G.js} +1 -1
  36. package/dist/web/client/assets/{results-Bcuy4Flp.js → results-BUmKkuHo.js} +1 -1
  37. package/dist/web/client/assets/{review-CVH7X9-d.js → review-BUTz_zRX.js} +1 -1
  38. package/dist/web/client/assets/{routes-BJEX6yAE.js → routes-b1FscQsH.js} +1 -1
  39. package/dist/web/client/assets/{services-BTG4F5FL.js → services-D-RdMc8g.js} +1 -1
  40. package/dist/web/client/assets/{skills-DwiHS7eD.js → skills-CNbkY2ji.js} +1 -1
  41. package/dist/web/client/assets/{teams-DfpwQu1i.js → teams-Dn9o_-P-.js} +1 -1
  42. package/dist/web/client/assets/{teams-DcROmSGB.js → teams-H4OTWt8E.js} +1 -1
  43. package/dist/web/client/assets/{telegram-BLyaaUXE.js → telegram-BnM54CPN.js} +1 -1
  44. package/dist/web/client/assets/tokens-C-I23fVZ.js +1 -0
  45. package/dist/web/client/assets/{triggers-CtVhrAGA.js → triggers-DG9YoC7B.js} +1 -1
  46. package/dist/web/client/assets/{verifications-TC0ccGLY.js → verifications-CzToBSUN.js} +1 -1
  47. package/dist/web/client/assets/{welcome-DML3X1ha.js → welcome-REp-dEfY.js} +1 -1
  48. package/dist/web/client/assets/{x-D8yuCam7.js → x-C-BpLdcp.js} +1 -1
  49. package/dist/web/server/assets/{_tanstack-start-manifest_v-BGSoO6CK.js → _tanstack-start-manifest_v-BfURdqEL.js} +82 -82
  50. package/dist/web/server/assets/{router-BVhdWkwP.js → router-CyZ-GH8M.js} +1 -1
  51. package/dist/web/server/assets/{tokens-_2hptHP6.js → tokens-BFhrz5qd.js} +1 -1
  52. package/dist/web/server/assets/{tokens-DDwtO15P.js → tokens-DO_eDpv_.js} +96 -3
  53. package/dist/web/server/server.js +2 -2
  54. package/dist/worker.js +34 -19
  55. package/dist/worker.js.map +1 -1
  56. package/package.json +3 -3
  57. package/dist/web/client/assets/chevron-right-C7P3Z105.js +0 -1
  58. 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.1",
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: {
@@ -1387,69 +1387,34 @@ var chatCmd = defineCommand5({
1387
1387
  }
1388
1388
  return;
1389
1389
  }
1390
+ if (bashApprovalMode === "interactive") {
1391
+ console.error(
1392
+ `usage: bazilion agent chat ${args2.id} --message "..." (one-shot) \u2014 for a conversational surface, use the web UI`
1393
+ );
1394
+ process.exitCode = 1;
1395
+ return;
1396
+ }
1390
1397
  console.log(`chatting with ${resolved.agent.name} (${resolved.model})`);
1391
- console.log("(type /exit to quit)");
1398
+ console.log("(type /exit to quit; input is piped, commands run with auto_deny)");
1392
1399
  const rl = createInterface({ input: stdin, output: stdout });
1393
1400
  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
- }
1401
+ rl.setPrompt("> ");
1402
+ rl.prompt();
1403
+ for await (const line of rl) {
1404
+ const trimmed = line.trim();
1405
+ if (trimmed === "/exit" || trimmed === "/quit") break;
1406
+ if (!trimmed) {
1451
1407
  rl.prompt();
1408
+ continue;
1452
1409
  }
1410
+ try {
1411
+ await streamTurn(client, resolved.agent.id, trimmed, void 0, {
1412
+ bashApprovalMode
1413
+ });
1414
+ } catch (err) {
1415
+ console.error(`error: ${err.message}`);
1416
+ }
1417
+ rl.prompt();
1453
1418
  }
1454
1419
  } finally {
1455
1420
  rl.close();
@@ -2318,16 +2283,16 @@ import {
2318
2283
  mkdirSync as mkdirSync2,
2319
2284
  mkdtempSync,
2320
2285
  openSync as openSync2,
2321
- readdirSync,
2322
- readFileSync as readFileSync5,
2286
+ readdirSync as readdirSync2,
2287
+ readFileSync as readFileSync6,
2323
2288
  readSync,
2324
2289
  renameSync as renameSync2,
2325
2290
  rmSync as rmSync2,
2326
2291
  writeFileSync as writeFileSync2
2327
2292
  } from "fs";
2328
2293
  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";
2294
+ import { basename as basename4, dirname as dirname3, isAbsolute, parse, posix, relative, resolve as resolve3 } from "path";
2295
+ import { DatabaseSync as DatabaseSync4, backup as sqliteBackup } from "node:sqlite";
2331
2296
  import { Readable } from "stream";
2332
2297
  import { pipeline } from "stream/promises";
2333
2298
  import { Decrypter, Encrypter } from "age-encryption";
@@ -2475,174 +2440,180 @@ function pauseRestoredUserQueue(database) {
2475
2440
 
2476
2441
  // src/backup-schema.ts
2477
2442
  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
- ];
2443
+
2444
+ // ../daemon/src/core/db/migrate.ts
2445
+ import { readdirSync, readFileSync as readFileSync4 } from "fs";
2446
+ import { dirname, join as join2 } from "path";
2447
+ import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
2448
+ import { fileURLToPath } from "url";
2449
+
2450
+ // ../daemon/src/core/db/client.ts
2451
+ import { backup, DatabaseSync as DatabaseSync2 } from "node:sqlite";
2452
+ function wrap(rawDb) {
2453
+ const cache = /* @__PURE__ */ new Map();
2454
+ let transactionDepth = 0;
2455
+ let savepointSequence = 0;
2456
+ function getStmt(sql) {
2457
+ let s = cache.get(sql);
2458
+ if (!s) {
2459
+ s = rawDb.prepare(sql);
2460
+ cache.set(sql, s);
2461
+ }
2462
+ return s;
2463
+ }
2464
+ return {
2465
+ query(sql) {
2466
+ const stmt = getStmt(sql);
2467
+ return {
2468
+ get(...params) {
2469
+ const result = stmt.get(...params);
2470
+ return result ?? null;
2471
+ },
2472
+ all(...params) {
2473
+ return stmt.all(...params);
2474
+ },
2475
+ run(...params) {
2476
+ return stmt.run(...params);
2477
+ }
2478
+ };
2479
+ },
2480
+ run(sql, params) {
2481
+ const stmt = getStmt(sql);
2482
+ return stmt.run(...params ?? []);
2483
+ },
2484
+ exec(sql) {
2485
+ rawDb.exec(sql);
2486
+ },
2487
+ // node:sqlite has no callable `transaction` wrapper; use manual BEGIN/COMMIT/ROLLBACK.
2488
+ transaction(fn) {
2489
+ return () => {
2490
+ const outermost = transactionDepth === 0;
2491
+ const savepoint = outermost ? null : `bazilion_nested_${++savepointSequence}`;
2492
+ if (outermost) rawDb.exec("BEGIN");
2493
+ else rawDb.exec(`SAVEPOINT ${savepoint}`);
2494
+ transactionDepth++;
2495
+ try {
2496
+ const result = fn();
2497
+ if (outermost) rawDb.exec("COMMIT");
2498
+ else rawDb.exec(`RELEASE SAVEPOINT ${savepoint}`);
2499
+ return result;
2500
+ } catch (err) {
2501
+ if (outermost) rawDb.exec("ROLLBACK");
2502
+ else {
2503
+ rawDb.exec(`ROLLBACK TO SAVEPOINT ${savepoint}`);
2504
+ rawDb.exec(`RELEASE SAVEPOINT ${savepoint}`);
2505
+ }
2506
+ throw err;
2507
+ } finally {
2508
+ transactionDepth--;
2509
+ }
2510
+ };
2511
+ }
2512
+ };
2513
+ }
2514
+ function applyPragmas(rawDb, includeWal) {
2515
+ if (includeWal) {
2516
+ try {
2517
+ rawDb.exec("PRAGMA journal_mode = WAL");
2518
+ } catch {
2519
+ }
2520
+ }
2521
+ rawDb.exec("PRAGMA foreign_keys = ON");
2522
+ }
2523
+ function openInMemoryDb() {
2524
+ const raw = new DatabaseSync2(":memory:");
2525
+ applyPragmas(raw, false);
2526
+ return {
2527
+ raw: wrap(raw),
2528
+ backupTo(path) {
2529
+ return backup(raw, path);
2530
+ },
2531
+ close() {
2532
+ raw.close();
2533
+ }
2534
+ };
2535
+ }
2536
+
2537
+ // ../daemon/src/core/db/migrate.ts
2538
+ var migrationsDir = join2(dirname(fileURLToPath(import.meta.url)), "migrations");
2539
+ var schemaMigrationsSql = `
2540
+ CREATE TABLE IF NOT EXISTS schema_migrations (
2541
+ version TEXT PRIMARY KEY,
2542
+ applied_at INTEGER NOT NULL
2543
+ )
2544
+ `;
2545
+ function listMigrations() {
2546
+ return readdirSync(migrationsDir).filter((file) => file.endsWith(".sql")).sort().map((file) => ({
2547
+ version: file.replace(/\.sql$/, ""),
2548
+ sql: readFileSync4(join2(migrationsDir, file), "utf8")
2549
+ }));
2550
+ }
2551
+ var canonicalSchemaObjectsByPrefix = /* @__PURE__ */ new Map();
2552
+ function schemaObjects(db) {
2553
+ return db.raw.query(
2554
+ `SELECT type, name, tbl_name, sql
2555
+ FROM sqlite_schema
2556
+ WHERE sql IS NOT NULL AND substr(name, 1, 7) <> 'sqlite_'
2557
+ ORDER BY type, name`
2558
+ ).all();
2559
+ }
2611
2560
  function normalizeSql(sql) {
2612
2561
  return sql.replace(/\s+/g, " ").trim();
2613
2562
  }
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) {
2563
+ function expectedSchema(files, prefixLength) {
2564
+ const cached = canonicalSchemaObjectsByPrefix.get(prefixLength);
2565
+ if (cached) return cached;
2566
+ const canonical = openInMemoryDb();
2567
+ try {
2568
+ canonical.raw.exec(schemaMigrationsSql);
2569
+ for (const file of files.slice(0, prefixLength)) canonical.raw.exec(file.sql);
2570
+ const objects = schemaObjects(canonical);
2571
+ canonicalSchemaObjectsByPrefix.set(prefixLength, objects);
2572
+ return objects;
2573
+ } finally {
2574
+ canonical.close();
2575
+ }
2576
+ }
2577
+ function assertSchemaMatchesCanonicalChain(raw) {
2578
+ const files = listMigrations();
2579
+ const expectedVersions = files.map((file) => file.version);
2580
+ const applied = raw.prepare("SELECT version FROM schema_migrations ORDER BY version").all().map((row2) => row2.version);
2581
+ if (applied.length !== expectedVersions.length || applied.some((version, index) => version !== expectedVersions[index])) {
2617
2582
  throw new Error(
2618
- `schema_migrations must contain exactly ${CANONICAL_MIGRATION}; found ` + (migrations.map((row2) => row2.version).join(", ") || "none")
2583
+ `schema_migrations must contain exactly ${expectedVersions.join(", ")}; found ` + (applied.join(", ") || "none")
2619
2584
  );
2620
2585
  }
2621
- const rows = db.prepare(
2586
+ const rows = raw.prepare(
2622
2587
  `SELECT type, name, tbl_name, sql
2623
2588
  FROM sqlite_schema
2624
- WHERE sql IS NOT NULL AND name NOT LIKE 'sqlite_%'`
2589
+ WHERE sql IS NOT NULL AND substr(name, 1, 7) <> 'sqlite_'
2590
+ ORDER BY type, name`
2625
2591
  ).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}`));
2592
+ const canonical = expectedSchema(files, files.length);
2593
+ const canonicalKeys = new Set(canonical.map((row2) => `${row2.type}\0${row2.name}`));
2594
+ const actualKeys = new Map(rows.map((row2) => [`${row2.type}\0${row2.name}`, row2]));
2595
+ for (const row2 of canonical) {
2596
+ if (!actualKeys.has(`${row2.type}\0${row2.name}`)) {
2597
+ throw new Error(`required canonical schema ${row2.type} is missing: ${row2.name}`);
2598
+ }
2599
+ }
2628
2600
  for (const row2 of rows) {
2629
2601
  if (!canonicalKeys.has(`${row2.type}\0${row2.name}`)) {
2630
2602
  throw new Error(`unexpected schema ${row2.type} is not canonical: ${row2.name}`);
2631
2603
  }
2632
2604
  }
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) {
2605
+ const payload = rows.map((row2) => [row2.type, row2.name, row2.tbl_name, normalizeSql(row2.sql)].join("\0")).join("\n");
2606
+ const canonicalPayload = canonical.map((row2) => [row2.type, row2.name, row2.tbl_name, normalizeSql(row2.sql)].join("\0")).join("\n");
2607
+ if (payload !== canonicalPayload) {
2642
2608
  throw new Error(
2643
- "canonical schema fingerprint does not match this Bazilion release; restore a backup created from the current clean-install schema"
2609
+ "database schema does not match this release\u2019s canonical migration chain; restore a backup created from the current release"
2644
2610
  );
2645
2611
  }
2612
+ }
2613
+
2614
+ // src/backup-schema.ts
2615
+ function assertCanonicalBackupSchema(db) {
2616
+ assertSchemaMatchesCanonicalChain(db);
2646
2617
  for (const row2 of db.prepare("SELECT id, bytes, byte_length, sha256 FROM agent_results WHERE deleted_at IS NULL").iterate()) {
2647
2618
  const bytes = row2.bytes;
2648
2619
  if (!(bytes instanceof Uint8Array) || bytes.byteLength !== row2.byte_length || createHash("sha256").update(bytes).digest("hex") !== row2.sha256) {
@@ -2663,13 +2634,13 @@ import {
2663
2634
  lstatSync as lstatSync2,
2664
2635
  mkdirSync,
2665
2636
  openSync,
2666
- readFileSync as readFileSync4,
2637
+ readFileSync as readFileSync5,
2667
2638
  realpathSync,
2668
2639
  renameSync,
2669
2640
  rmSync,
2670
2641
  writeSync
2671
2642
  } from "fs";
2672
- import { basename as basename3, dirname, join as join2, resolve as resolve2 } from "path";
2643
+ import { basename as basename3, dirname as dirname2, join as join3, resolve as resolve2 } from "path";
2673
2644
  var DAEMON_LIVENESS_FILENAME = "daemon-runtime.json";
2674
2645
  var STALE_AFTER_MS = 6e4;
2675
2646
  var PROBE_TIMEOUT_MS = 750;
@@ -2679,15 +2650,15 @@ function canonicalHomeIdentity(home) {
2679
2650
  return realpathSync.native(absolute);
2680
2651
  } catch (error) {
2681
2652
  if (errorCode(error) !== "ENOENT") throw error;
2682
- const parent = dirname(absolute);
2653
+ const parent = dirname2(absolute);
2683
2654
  if (parent === absolute) throw error;
2684
- return join2(canonicalHomeIdentity(parent), basename3(absolute));
2655
+ return join3(canonicalHomeIdentity(parent), basename3(absolute));
2685
2656
  }
2686
2657
  }
2687
2658
  function daemonLivenessPath(home) {
2688
2659
  const canonicalHome = canonicalHomeIdentity(home);
2689
2660
  const identity = createHash2("sha256").update(canonicalHome).digest("hex").slice(0, 24);
2690
- return join2(dirname(canonicalHome), `.bazilion-runtime-${identity}.json`);
2661
+ return join3(dirname2(canonicalHome), `.bazilion-runtime-${identity}.json`);
2691
2662
  }
2692
2663
  function errorCode(error) {
2693
2664
  return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
@@ -2725,7 +2696,7 @@ function parseRecord(raw) {
2725
2696
  function readRecord(path) {
2726
2697
  try {
2727
2698
  const stat = lstatSync2(path);
2728
- const raw = stat.isFile() ? readFileSync4(path, "utf8") : "";
2699
+ const raw = stat.isFile() ? readFileSync5(path, "utf8") : "";
2729
2700
  return { raw, stat, record: stat.isFile() ? parseRecord(raw) : null };
2730
2701
  } catch (error) {
2731
2702
  if (errorCode(error) === "ENOENT") return null;
@@ -2782,7 +2753,7 @@ function writeRecord(fd, record) {
2782
2753
  function fsyncParentDirectory(path) {
2783
2754
  let directoryFd = null;
2784
2755
  try {
2785
- directoryFd = openSync(dirname(path), "r");
2756
+ directoryFd = openSync(dirname2(path), "r");
2786
2757
  fsyncSync(directoryFd);
2787
2758
  } catch (error) {
2788
2759
  if (process.platform !== "win32") throw error;
@@ -2804,7 +2775,7 @@ function reclaimRecord(path, existing) {
2804
2775
  return null;
2805
2776
  }
2806
2777
  try {
2807
- renameSync(path, join2(claim, "stale-record.json"));
2778
+ renameSync(path, join3(claim, "stale-record.json"));
2808
2779
  return claim;
2809
2780
  } catch (error) {
2810
2781
  if (errorCode(error) === "ENOENT") return null;
@@ -2813,9 +2784,9 @@ function reclaimRecord(path, existing) {
2813
2784
  }
2814
2785
  async function acquireHomeRestoreLock(home, operation = "restoring") {
2815
2786
  const targetHome = resolve2(home);
2816
- mkdirSync(dirname(targetHome), { recursive: true });
2787
+ mkdirSync(dirname2(targetHome), { recursive: true });
2817
2788
  const path = daemonLivenessPath(targetHome);
2818
- mkdirSync(dirname(path), { recursive: true });
2789
+ mkdirSync(dirname2(path), { recursive: true });
2819
2790
  const instanceId = randomUUID6();
2820
2791
  let fd = null;
2821
2792
  let reclaimClaim = null;
@@ -3060,7 +3031,7 @@ var createCmd = defineCommand9({
3060
3031
  } catch (error) {
3061
3032
  if (!(error instanceof Error) || !("code" in error) || error.code !== "EXDEV") throw error;
3062
3033
  const installPartial = resolve3(
3063
- dirname2(outAbs),
3034
+ dirname3(outAbs),
3064
3035
  `.${basename4(outAbs)}.${randomUUID7()}.installing`
3065
3036
  );
3066
3037
  try {
@@ -3247,7 +3218,7 @@ function validateArchiveEntries(entries) {
3247
3218
  function validateAuthFile(path) {
3248
3219
  let parsed;
3249
3220
  try {
3250
- parsed = JSON.parse(readFileSync5(path, "utf8"));
3221
+ parsed = JSON.parse(readFileSync6(path, "utf8"));
3251
3222
  } catch (error) {
3252
3223
  const detail = error instanceof Error ? error.message : String(error);
3253
3224
  throw new Error(`backup auth.json is invalid: ${detail}`);
@@ -3260,7 +3231,7 @@ function validateAuthFile(path) {
3260
3231
  function validateDatabase(path, authToken) {
3261
3232
  let db = null;
3262
3233
  try {
3263
- db = new DatabaseSync2(path, { readOnly: true });
3234
+ db = new DatabaseSync4(path, { readOnly: true });
3264
3235
  const integrity = db.prepare("PRAGMA integrity_check").all();
3265
3236
  if (integrity.length !== 1 || integrity[0]?.integrity_check !== "ok") {
3266
3237
  const detail = integrity.map((row2) => row2.integrity_check).join("; ") || "no result";
@@ -3324,7 +3295,7 @@ function requireExtractedTeamSlot(path, rowLabel) {
3324
3295
  function rebaseRestoredHomeDirectories(database, payload, targetHome) {
3325
3296
  let db = null;
3326
3297
  try {
3327
- db = new DatabaseSync2(database);
3298
+ db = new DatabaseSync4(database);
3328
3299
  db.exec("PRAGMA foreign_keys = ON");
3329
3300
  const profiles = db.prepare("SELECT id FROM profiles ORDER BY id").all();
3330
3301
  const agents = db.prepare("SELECT id FROM agents ORDER BY id").all();
@@ -3401,11 +3372,11 @@ function rebaseRestoredHomeDirectories(database, payload, targetHome) {
3401
3372
  function removeRebuildableQmdIndexes(payload) {
3402
3373
  const teamsDir = resolve3(payload, "teams");
3403
3374
  if (!existsSync2(teamsDir) || !lstatSync3(teamsDir).isDirectory()) return;
3404
- for (const team of readdirSync(teamsDir, { withFileTypes: true })) {
3375
+ for (const team of readdirSync2(teamsDir, { withFileTypes: true })) {
3405
3376
  if (!team.isDirectory() || team.isSymbolicLink()) continue;
3406
3377
  const memoryDir = resolve3(teamsDir, team.name, "memory");
3407
3378
  if (!existsSync2(memoryDir) || !lstatSync3(memoryDir).isDirectory()) continue;
3408
- for (const entry3 of readdirSync(memoryDir, { withFileTypes: true })) {
3379
+ for (const entry3 of readdirSync2(memoryDir, { withFileTypes: true })) {
3409
3380
  if (entry3.isFile() && entry3.name.startsWith(".qmd-index.sqlite")) {
3410
3381
  rmSync2(resolve3(memoryDir, entry3.name), { force: true });
3411
3382
  }
@@ -3413,7 +3384,7 @@ function removeRebuildableQmdIndexes(payload) {
3413
3384
  }
3414
3385
  }
3415
3386
  function revokeRestoredBrowserSessions(database) {
3416
- const db = new DatabaseSync2(database);
3387
+ const db = new DatabaseSync4(database);
3417
3388
  try {
3418
3389
  db.prepare("UPDATE web_sessions SET revoked_at = ? WHERE revoked_at IS NULL").run(Date.now());
3419
3390
  } finally {
@@ -3423,7 +3394,7 @@ function revokeRestoredBrowserSessions(database) {
3423
3394
  function installValidatedPayload(payload, targetHome, staging, lifecycle, operations = { rename: renameSync2 }) {
3424
3395
  const previous = resolve3(staging, "previous-home");
3425
3396
  const hadPrevious = existsSync2(targetHome);
3426
- const targetParent = dirname2(targetHome);
3397
+ const targetParent = dirname3(targetHome);
3427
3398
  const syncDirectory = operations.fsyncDirectory ?? fsyncDirectory;
3428
3399
  const recoveryError = (message, recoveryPath, cause) => {
3429
3400
  let markerError;
@@ -3558,7 +3529,7 @@ function readAgeIdentity(rawPath) {
3558
3529
  if (process.platform !== "win32" && (entry3.mode & 63) !== 0) {
3559
3530
  throw new Error(`age identity must be owner-only (chmod 600): ${path}`);
3560
3531
  }
3561
- const identities = readFileSync5(path, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
3532
+ const identities = readFileSync6(path, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
3562
3533
  if (identities.length !== 1 || !identities[0]?.startsWith("AGE-SECRET-KEY-")) {
3563
3534
  throw new Error("age identity file must contain exactly one supported AGE-SECRET-KEY entry");
3564
3535
  }
@@ -3593,7 +3564,7 @@ var restoreCmd = defineCommand9({
3593
3564
  if (targetHome === parse(targetHome).root) {
3594
3565
  throw new Error(`refusing to restore over filesystem root: ${targetHome}`);
3595
3566
  }
3596
- const targetParent = dirname2(targetHome);
3567
+ const targetParent = dirname3(targetHome);
3597
3568
  mkdirSync2(targetParent, { recursive: true });
3598
3569
  const restoreLock = await acquireHomeRestoreLock(targetHome);
3599
3570
  try {
@@ -3611,7 +3582,7 @@ var restoreCmd = defineCommand9({
3611
3582
  if (!lstatSync3(targetHome).isDirectory()) {
3612
3583
  throw new Error(`${targetHome} exists and is not a directory`);
3613
3584
  }
3614
- const entries = readdirSync(targetHome);
3585
+ const entries = readdirSync2(targetHome);
3615
3586
  if (entries.length > 0 && !args2.force) {
3616
3587
  throw new Error(
3617
3588
  `${targetHome} is not empty. Pass --force to overwrite (destroys existing data).`
@@ -3734,7 +3705,7 @@ function credentialInventory(home) {
3734
3705
  const database = resolve3(home, "bazilion.db");
3735
3706
  const token = validateAuthFile(authFile);
3736
3707
  validateDatabase(database, token);
3737
- const db = new DatabaseSync2(database, { readOnly: true });
3708
+ const db = new DatabaseSync4(database, { readOnly: true });
3738
3709
  try {
3739
3710
  const activeTokens = db.prepare(
3740
3711
  "SELECT COUNT(*) AS count FROM web_tokens WHERE revoked_at IS NULL AND kind = 'device' AND expires_at > ?"
@@ -3793,7 +3764,7 @@ var rotateBootstrapCmd = defineCommand9({
3793
3764
  throw new Error(`refusing to rotate filesystem root: ${targetHome}`);
3794
3765
  }
3795
3766
  const lock = await acquireHomeRestoreLock(targetHome);
3796
- const parent = dirname2(targetHome);
3767
+ const parent = dirname3(targetHome);
3797
3768
  const staging = mkdtempSync(resolve3(parent, ".bazilion-rotate-"));
3798
3769
  const payload = resolve3(staging, "payload");
3799
3770
  let preserveStaging = false;
@@ -3803,7 +3774,7 @@ var rotateBootstrapCmd = defineCommand9({
3803
3774
  throw new Error(`bazilion server appears to be running at ${serverUrl} \u2014 stop it first.`);
3804
3775
  }
3805
3776
  }
3806
- const oldAuth = JSON.parse(readFileSync5(paths.authFile, "utf8"));
3777
+ const oldAuth = JSON.parse(readFileSync6(paths.authFile, "utf8"));
3807
3778
  if (typeof oldAuth.token !== "string" || !oldAuth.token) {
3808
3779
  throw new Error("auth.json is missing the bootstrap token");
3809
3780
  }
@@ -3816,7 +3787,7 @@ var rotateBootstrapCmd = defineCommand9({
3816
3787
  });
3817
3788
  const stagedDb = resolve3(payload, "bazilion.db");
3818
3789
  rmSync2(stagedDb, { force: true });
3819
- const sourceDb = new DatabaseSync2(resolve3(targetHome, "bazilion.db"), { readOnly: true });
3790
+ const sourceDb = new DatabaseSync4(resolve3(targetHome, "bazilion.db"), { readOnly: true });
3820
3791
  try {
3821
3792
  await sqliteBackup(sourceDb, stagedDb);
3822
3793
  } finally {
@@ -3825,7 +3796,7 @@ var rotateBootstrapCmd = defineCommand9({
3825
3796
  for (const suffix of ["-wal", "-shm", "-journal"])
3826
3797
  rmSync2(`${stagedDb}${suffix}`, { force: true });
3827
3798
  const newToken = randomBytes(24).toString("hex");
3828
- const db = new DatabaseSync2(stagedDb);
3799
+ const db = new DatabaseSync4(stagedDb);
3829
3800
  try {
3830
3801
  db.exec("PRAGMA foreign_keys = ON; BEGIN IMMEDIATE");
3831
3802
  try {
@@ -4122,16 +4093,16 @@ var configCommand = defineCommand11({
4122
4093
  import { spawn } from "child_process";
4123
4094
  import { existsSync as existsSync3 } from "fs";
4124
4095
  import { connect } from "net";
4125
- import { join as join3 } from "path";
4096
+ import { join as join4 } from "path";
4126
4097
  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");
4098
+ var bundledDaemonEntry = join4(import.meta.dirname, "daemon.js");
4099
+ var sourceDaemonEntry = join4(import.meta.dirname, "..", "..", "..", "daemon", "src", "index.ts");
4129
4100
  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");
4101
+ var bundledWebServerEntry = join4(import.meta.dirname, "web-server.js");
4102
+ var sourceWebServerEntry = join4(import.meta.dirname, "..", "web-server.ts");
4132
4103
  var webServerEntry = existsSync3(bundledWebServerEntry) ? bundledWebServerEntry : sourceWebServerEntry;
4133
- var bundledWebDist = join3(import.meta.dirname, "web");
4134
- var sourceWebDist = join3(import.meta.dirname, "..", "..", "..", "web", "dist");
4104
+ var bundledWebDist = join4(import.meta.dirname, "web");
4105
+ var sourceWebDist = join4(import.meta.dirname, "..", "..", "..", "web", "dist");
4135
4106
  var webDist = existsSync3(bundledWebDist) ? bundledWebDist : sourceWebDist;
4136
4107
  function nodeArgs(entry3) {
4137
4108
  return entry3.endsWith(".ts") ? ["--import", "tsx/esm", entry3] : [entry3];
@@ -4294,7 +4265,7 @@ var dashboardCommand = defineCommand12({
4294
4265
  `web UI port ${webPort} is already in use. Re-run with --port <free-port>.`
4295
4266
  );
4296
4267
  }
4297
- if (!existsSync3(join3(webDist, "server", "server.js"))) {
4268
+ if (!existsSync3(join4(webDist, "server", "server.js"))) {
4298
4269
  throw new Error(
4299
4270
  `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
4271
  );
@@ -4699,7 +4670,7 @@ var inboxCommand = defineCommand15({
4699
4670
  });
4700
4671
 
4701
4672
  // src/commands/login.ts
4702
- import { existsSync as existsSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
4673
+ import { existsSync as existsSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
4703
4674
  import { defineCommand as defineCommand16 } from "citty";
4704
4675
  function normalizeServer(raw) {
4705
4676
  let url;
@@ -4742,7 +4713,7 @@ var loginCommand = defineCommand16({
4742
4713
  `${paths.authFile} not found. Start the daemon with "bazilion serve" first \u2014 login stores the remote there.`
4743
4714
  );
4744
4715
  }
4745
- const auth = JSON.parse(readFileSync6(paths.authFile, "utf8"));
4716
+ const auth = JSON.parse(readFileSync7(paths.authFile, "utf8"));
4746
4717
  if (args2.clear) {
4747
4718
  if (!auth.remote) {
4748
4719
  console.log("no remote stored \u2014 nothing to clear");
@@ -4992,9 +4963,9 @@ var memoryCommand = defineCommand18({
4992
4963
  // src/commands/profile.ts
4993
4964
  import { spawn as spawn2 } from "child_process";
4994
4965
  import { randomBytes as randomBytes2 } from "crypto";
4995
- import { readFileSync as readFileSync7, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
4966
+ import { readFileSync as readFileSync8, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
4996
4967
  import { tmpdir as tmpdir2 } from "os";
4997
- import { join as join4 } from "path";
4968
+ import { join as join5 } from "path";
4998
4969
 
4999
4970
  // ../../packages/api-types/src/git-review.ts
5000
4971
  var REVIEW_LIMITS = {
@@ -5071,7 +5042,7 @@ var createCmd2 = defineCommand19({
5071
5042
  },
5072
5043
  async run({ args: args2 }) {
5073
5044
  const skillsMode = parseSkillsMode(args2["skills-mode"]);
5074
- const readTemplate = (path) => path ? readFileSync7(path, "utf8") : void 0;
5045
+ const readTemplate = (path) => path ? readFileSync8(path, "utf8") : void 0;
5075
5046
  const body = {
5076
5047
  id: args2.id,
5077
5048
  name: args2.name,
@@ -5146,7 +5117,7 @@ var editCmd2 = defineCommand19({
5146
5117
  const { content } = await client.get(
5147
5118
  `/api/profiles/${args2.id}/files/${file}`
5148
5119
  );
5149
- const tmpPath = join4(tmpdir2(), `bazilion-${args2.id}-${file}-${randomBytes2(4).toString("hex")}`);
5120
+ const tmpPath = join5(tmpdir2(), `bazilion-${args2.id}-${file}-${randomBytes2(4).toString("hex")}`);
5150
5121
  writeFileSync4(tmpPath, content);
5151
5122
  try {
5152
5123
  const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
@@ -5156,7 +5127,7 @@ var editCmd2 = defineCommand19({
5156
5127
  child.on("close", (c) => resolve6(c ?? 0));
5157
5128
  });
5158
5129
  if (code !== 0) throw new Error(`editor exited with code ${code}`);
5159
- const updated = readFileSync7(tmpPath, "utf8");
5130
+ const updated = readFileSync8(tmpPath, "utf8");
5160
5131
  if (updated === content) {
5161
5132
  console.log("(no changes)");
5162
5133
  return;
@@ -5502,10 +5473,10 @@ var sendCommand = defineCommand22({
5502
5473
  // src/commands/serve.ts
5503
5474
  import { spawn as spawn3 } from "child_process";
5504
5475
  import { existsSync as existsSync5 } from "fs";
5505
- import { join as join5 } from "path";
5476
+ import { join as join6 } from "path";
5506
5477
  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");
5478
+ var bundledDaemonEntry2 = join6(import.meta.dirname, "daemon.js");
5479
+ var sourceDaemonEntry2 = join6(import.meta.dirname, "..", "..", "..", "daemon", "src", "index.ts");
5509
5480
  var daemonEntry2 = existsSync5(bundledDaemonEntry2) ? bundledDaemonEntry2 : sourceDaemonEntry2;
5510
5481
  var serveCommand = defineCommand23({
5511
5482
  meta: {
@@ -5611,7 +5582,7 @@ var sessionCommand = defineCommand24({
5611
5582
  });
5612
5583
 
5613
5584
  // src/commands/skill.ts
5614
- import { existsSync as existsSync6, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
5585
+ import { existsSync as existsSync6, readFileSync as readFileSync9, statSync as statSync2 } from "fs";
5615
5586
  import { basename as basename5, resolve as resolve4 } from "path";
5616
5587
  import { defineCommand as defineCommand25 } from "citty";
5617
5588
  function printFindings(findings, prefix = " ") {
@@ -5681,7 +5652,7 @@ var importCmd = defineCommand25({
5681
5652
  let result;
5682
5653
  try {
5683
5654
  if (isLocalZip) {
5684
- const bytes = readFileSync8(absFrom);
5655
+ const bytes = readFileSync9(absFrom);
5685
5656
  const file = new File([bytes], basename5(absFrom), { type: "application/zip" });
5686
5657
  const fd = new FormData();
5687
5658
  fd.set("file", file);
@@ -5751,7 +5722,7 @@ var skillCommand = defineCommand25({
5751
5722
  });
5752
5723
 
5753
5724
  // src/commands/team.ts
5754
- import { readFileSync as readFileSync11 } from "fs";
5725
+ import { readFileSync as readFileSync12 } from "fs";
5755
5726
  import { stdin as stdin2 } from "process";
5756
5727
  import { defineCommand as defineCommand33 } from "citty";
5757
5728
 
@@ -5813,7 +5784,7 @@ var teamCodingLogCommand = defineCommand26({
5813
5784
  });
5814
5785
 
5815
5786
  // src/commands/team-environment.ts
5816
- import { readFileSync as readFileSync9 } from "fs";
5787
+ import { readFileSync as readFileSync10 } from "fs";
5817
5788
  import { defineCommand as defineCommand27 } from "citty";
5818
5789
  var args = { id: { type: "positional", required: true, description: "Team slug" } };
5819
5790
  var teamEnvironmentCommand = defineCommand27({
@@ -5839,7 +5810,7 @@ var teamEnvironmentCommand = defineCommand27({
5839
5810
  },
5840
5811
  async run({ args: args2 }) {
5841
5812
  const input = JSON.parse(
5842
- readFileSync9(args2.file, "utf8")
5813
+ readFileSync10(args2.file, "utf8")
5843
5814
  );
5844
5815
  console.log(
5845
5816
  JSON.stringify(await createClient2().codingEnvironment.configure(args2.id, input), null, 2)
@@ -5850,7 +5821,7 @@ var teamEnvironmentCommand = defineCommand27({
5850
5821
  });
5851
5822
 
5852
5823
  // src/commands/team-policy.ts
5853
- import { readFileSync as readFileSync10 } from "fs";
5824
+ import { readFileSync as readFileSync11 } from "fs";
5854
5825
  import { defineCommand as defineCommand28 } from "citty";
5855
5826
 
5856
5827
  // src/team-interchange.ts
@@ -6067,7 +6038,7 @@ function edgeDiff(before, after) {
6067
6038
  // src/commands/team-policy.ts
6068
6039
  function readJson(path) {
6069
6040
  try {
6070
- return JSON.parse(readFileSync10(path, "utf8"));
6041
+ return JSON.parse(readFileSync11(path, "utf8"));
6071
6042
  } catch (error) {
6072
6043
  throw new Error(`invalid JSON: ${error.message}`);
6073
6044
  }
@@ -7357,7 +7328,7 @@ var userMdSetCmd = defineCommand33({
7357
7328
  async run({ args: args2 }) {
7358
7329
  let content;
7359
7330
  if (args2["from-stdin"]) content = await readStdin();
7360
- else if (args2.file) content = readFileSync11(args2.file, "utf8");
7331
+ else if (args2.file) content = readFileSync12(args2.file, "utf8");
7361
7332
  else if (args2.text !== void 0) content = args2.text;
7362
7333
  else {
7363
7334
  console.error("team user-md set: provide --file, --from-stdin, or --text");
@@ -7503,11 +7474,11 @@ var teamCommand = defineCommand33({
7503
7474
  });
7504
7475
 
7505
7476
  // src/commands/team-template.ts
7506
- import { readFileSync as readFileSync12 } from "fs";
7477
+ import { readFileSync as readFileSync13 } from "fs";
7507
7478
  import { defineCommand as defineCommand34 } from "citty";
7508
7479
  function jsonFile(path) {
7509
7480
  try {
7510
- return JSON.parse(readFileSync12(path, "utf8"));
7481
+ return JSON.parse(readFileSync13(path, "utf8"));
7511
7482
  } catch (error) {
7512
7483
  throw new Error(`invalid JSON: ${error.message}`);
7513
7484
  }
@@ -8025,7 +7996,7 @@ function tokenRow(t) {
8025
7996
  const expired = t.expiresAt !== null && t.expiresAt <= Date.now();
8026
7997
  const state = t.revokedAt ? "revoked" : expired ? "expired" : "active";
8027
7998
  const expires = t.expiresAt ? new Date(t.expiresAt).toISOString() : "(never)";
8028
- return [t.id, t.kind, state, t.label, `expires: ${expires}`, `last: ${last}`];
7999
+ return [t.id, t.kind, state, t.label, t.scopes.join(" "), `expires: ${expires}`, `last: ${last}`];
8029
8000
  }
8030
8001
  function resolveQrServer(override) {
8031
8002
  const raw = override ?? loadClientConfig().serverUrl;
@@ -8062,19 +8033,29 @@ var createCmd6 = defineCommand36({
8062
8033
  expiresDays: {
8063
8034
  type: "string",
8064
8035
  description: "Device lifetime in days (default 90, maximum 365)"
8036
+ },
8037
+ scope: {
8038
+ type: "string",
8039
+ description: "Authorization scope; repeat for more (read, write, approvals, admin). Default: all scopes."
8065
8040
  }
8066
8041
  },
8067
- async run({ args: args2 }) {
8042
+ async run({ args: args2, rawArgs }) {
8068
8043
  const client = createClient2();
8069
8044
  const expiresInDays = args2.expiresDays === void 0 ? void 0 : Number(args2.expiresDays);
8070
8045
  if (expiresInDays !== void 0 && !Number.isInteger(expiresInDays)) {
8071
8046
  throw new Error("--expires-days must be an integer");
8072
8047
  }
8073
- const body = { label: args2.label, expiresInDays };
8048
+ const scopes = collectFlagValues(rawArgs, "scope");
8049
+ const body = {
8050
+ label: args2.label,
8051
+ expiresInDays,
8052
+ ...scopes.length > 0 ? { scopes } : {}
8053
+ };
8074
8054
  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}`);
8055
+ console.log(`id: ${res.meta.id}`);
8056
+ console.log(`label: ${res.meta.label}`);
8057
+ console.log(`kind: ${res.meta.kind}`);
8058
+ console.log(`scopes: ${res.meta.scopes.join(" ")}`);
8078
8059
  console.log(
8079
8060
  `expires: ${res.meta.expiresAt ? new Date(res.meta.expiresAt).toISOString() : "(never)"}`
8080
8061
  );
@@ -8090,6 +8071,43 @@ var createCmd6 = defineCommand36({
8090
8071
  qrcode.generate(pairUrl, { small: true }, (qr) => console.log(qr));
8091
8072
  }
8092
8073
  });
8074
+ var pairCmd = defineCommand36({
8075
+ meta: {
8076
+ name: "pair",
8077
+ description: "Mint a one-paste pairing setup code for a new device (10 min, single use)"
8078
+ },
8079
+ args: {
8080
+ scope: {
8081
+ type: "string",
8082
+ description: "Authorization scope for the minted device credential; repeat for more. Default: all scopes."
8083
+ },
8084
+ server: {
8085
+ type: "string",
8086
+ description: "Server URL to embed in the setup code (default: detect LAN IP; pass the gateway HTTPS origin for remote devices)"
8087
+ }
8088
+ },
8089
+ async run({ args: args2, rawArgs }) {
8090
+ const client = createClient2();
8091
+ const scopes = collectFlagValues(rawArgs, "scope");
8092
+ const res = await client.post("/api/pair/codes", {
8093
+ ...scopes.length > 0 ? { scopes } : {}
8094
+ });
8095
+ let setupUrl = res.setupUrl;
8096
+ if (args2.server) {
8097
+ const serverUrl = resolveQrServer(args2.server);
8098
+ setupUrl = `bazilion-pair://pair?server=${encodeURIComponent(serverUrl)}&code=${encodeURIComponent(res.code)}`;
8099
+ }
8100
+ console.log(`id: ${res.meta.id}`);
8101
+ console.log(`scopes: ${res.meta.scopes.join(" ")}`);
8102
+ console.log(`expires: ${new Date(res.meta.expiresAt).toISOString()} (10 minutes, single use)`);
8103
+ console.log("");
8104
+ console.log(`setup URL (paste or scan on the new device):`);
8105
+ console.log(setupUrl);
8106
+ console.log("");
8107
+ console.log("the code admits exactly one credential exchange; after that it is inert.");
8108
+ qrcode.generate(setupUrl, { small: true }, (qr) => console.log(qr));
8109
+ }
8110
+ });
8093
8111
  var listCmd14 = defineCommand36({
8094
8112
  meta: { name: "list", description: "List web tokens" },
8095
8113
  args: {
@@ -8131,6 +8149,7 @@ var tokenCommand = defineCommand36({
8131
8149
  meta: { name: "token", description: "Manage web tokens for API/CLI clients" },
8132
8150
  subCommands: {
8133
8151
  create: createCmd6,
8152
+ pair: pairCmd,
8134
8153
  list: listCmd14,
8135
8154
  revoke: revokeCmd2,
8136
8155
  "show-local": showLocalCmd
@@ -8280,9 +8299,9 @@ var triggerCommand = defineCommand37({
8280
8299
  });
8281
8300
 
8282
8301
  // src/commands/uninstall.ts
8283
- import { existsSync as existsSync7, lstatSync as lstatSync4, readdirSync as readdirSync2, realpathSync as realpathSync2, rmSync as rmSync4 } from "fs";
8302
+ import { existsSync as existsSync7, lstatSync as lstatSync4, readdirSync as readdirSync3, realpathSync as realpathSync2, rmSync as rmSync4 } from "fs";
8284
8303
  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";
8304
+ import { isAbsolute as isAbsolute2, join as join7, parse as parse2, relative as relative2, resolve as resolve5, sep } from "path";
8286
8305
  import { defineCommand as defineCommand38 } from "citty";
8287
8306
  function makeLineReader() {
8288
8307
  let buffer = "";
@@ -8389,15 +8408,15 @@ var uninstallCommand = defineCommand38({
8389
8408
  async run({ args: args2 }) {
8390
8409
  const paths = resolveCliPaths(args2.home);
8391
8410
  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");
8411
+ const dbFile = join7(targetHome, "bazilion.db");
8412
+ const profilesDir = join7(targetHome, "profiles");
8413
+ const agentsDir = join7(targetHome, "agents");
8414
+ const teamsDir = join7(targetHome, "teams");
8415
+ const legacyGroupsDir = join7(targetHome, "groups");
8416
+ const skillsDir = join7(targetHome, "skills");
8417
+ const logsDir = join7(targetHome, "logs");
8418
+ const legacyConfigFile = join7(targetHome, "config.json");
8419
+ const legacySecretsFile = join7(targetHome, "secrets.enc");
8401
8420
  if (!existsSync7(targetHome)) {
8402
8421
  const uninstallLock2 = await acquireHomeRestoreLock(targetHome, "uninstalling");
8403
8422
  try {
@@ -8416,7 +8435,7 @@ var uninstallCommand = defineCommand38({
8416
8435
  `${dbFile}-wal`,
8417
8436
  `${dbFile}-shm`,
8418
8437
  `${dbFile}-journal`,
8419
- join6(targetHome, "auth.json"),
8438
+ join7(targetHome, "auth.json"),
8420
8439
  legacyConfigFile,
8421
8440
  legacySecretsFile,
8422
8441
  profilesDir,
@@ -8450,10 +8469,10 @@ var uninstallCommand = defineCommand38({
8450
8469
  for (const p of fullWipeTargets) {
8451
8470
  if (removePath(p)) console.log(`removed ${p}`);
8452
8471
  }
8453
- if (readdirSync2(targetHome).length === 0 && !homeIsSymlink) {
8472
+ if (readdirSync3(targetHome).length === 0 && !homeIsSymlink) {
8454
8473
  rmSync4(targetHome, { recursive: true, force: true });
8455
8474
  console.log(`removed ${targetHome}`);
8456
- } else if (homeIsSymlink && readdirSync2(targetHome).length === 0) {
8475
+ } else if (homeIsSymlink && readdirSync3(targetHome).length === 0) {
8457
8476
  console.log(`kept ${targetHome}: symlinked BAZILION_HOME root is now empty`);
8458
8477
  } else {
8459
8478
  console.log(`${targetHome} still has unmanaged files; left in place`);