austere-axi 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -492,7 +492,7 @@ var require_ci_info = __commonJS({
492
492
  }
493
493
  });
494
494
 
495
- // src/cli/artifact.js
495
+ // src/cli/artifact.ts
496
496
  function readArtifact(html) {
497
497
  const text = String(html);
498
498
  const m = PROGRAM_RE.exec(text);
@@ -544,28 +544,30 @@ function rewriteRuntime(html, replacement) {
544
544
  return rep + "\n" + text;
545
545
  }
546
546
  function escapeHtml(s) {
547
- return String(s).replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
547
+ return String(s).replace(/[&<>"']/g, (c) => ENTITIES[c]);
548
548
  }
549
549
  function decodeEntities(s) {
550
550
  return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
551
551
  }
552
- var CDN_RUNTIME_URL, PROGRAM_RE, RUNTIME_RE, TITLE_RE;
552
+ var CDN_RUNTIME_URL, PROGRAM_RE, RUNTIME_RE, TITLE_RE, ENTITIES;
553
553
  var init_artifact = __esm({
554
- "src/cli/artifact.js"() {
554
+ "src/cli/artifact.ts"() {
555
+ "use strict";
555
556
  CDN_RUNTIME_URL = "https://cdn.jsdelivr.net/npm/austere-axi@0/dist/austere.js";
556
557
  PROGRAM_RE = /(<script\b[^>]*\btype\s*=\s*["']text\/openui(?:-lang)?["'][^>]*>)([\s\S]*?)(<\/script\s*>)/i;
557
558
  RUNTIME_RE = /<script\b[^>]*\bsrc\s*=\s*["']([^"']*\/austere(?:\.min)?\.js(?:\?[^"']*)?|austere(?:\.min)?\.js)["'][^>]*>\s*<\/script\s*>/i;
558
559
  TITLE_RE = /<title[^>]*>([\s\S]*?)<\/title\s*>/i;
560
+ ENTITIES = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
559
561
  }
560
562
  });
561
563
 
562
- // src/cli/paths.js
564
+ // src/cli/paths.ts
563
565
  import fs from "node:fs";
564
566
  import os from "node:os";
565
567
  import path from "node:path";
566
568
  import { fileURLToPath } from "node:url";
567
569
  function packKitPath() {
568
- return BUNDLED ? path.join(HERE, "pack-kit.mjs") : path.resolve(HERE, "../pack-kit/index.js");
570
+ return BUNDLED ? path.join(HERE, "pack-kit.mjs") : path.resolve(HERE, "../pack-kit/index.ts");
569
571
  }
570
572
  function assetPath(name) {
571
573
  return path.join(ASSET_DIR, name);
@@ -611,17 +613,18 @@ function versionGt(a, b) {
611
613
  }
612
614
  var HERE, BUNDLED, ASSET_DIR, VERSION, CLI_ENTRY, securedDir;
613
615
  var init_paths = __esm({
614
- "src/cli/paths.js"() {
616
+ "src/cli/paths.ts"() {
617
+ "use strict";
615
618
  HERE = path.dirname(fileURLToPath(import.meta.url));
616
619
  BUNDLED = true;
617
620
  ASSET_DIR = BUNDLED ? HERE : path.resolve(HERE, "../../dist");
618
- VERSION = true ? "0.5.2" : JSON.parse(fs.readFileSync(path.resolve(HERE, "../../package.json"), "utf8")).version;
619
- CLI_ENTRY = BUNDLED ? fileURLToPath(import.meta.url) : path.resolve(HERE, "main.js");
621
+ VERSION = true ? "0.6.0" : packageVersion();
622
+ CLI_ENTRY = BUNDLED ? fileURLToPath(import.meta.url) : path.resolve(HERE, "main.ts");
620
623
  securedDir = null;
621
624
  }
622
625
  });
623
626
 
624
- // src/shared/packs-meta.js
627
+ // src/shared/packs-meta.ts
625
628
  function splitSpec(spec) {
626
629
  const at2 = spec.lastIndexOf("@");
627
630
  if (at2 <= 0) return { name: spec, version: "" };
@@ -650,18 +653,16 @@ function isValidVersion(version2) {
650
653
  }
651
654
  var PACKS_META_RE, NAME_RE, VERSION_RE;
652
655
  var init_packs_meta = __esm({
653
- "src/shared/packs-meta.js"() {
656
+ "src/shared/packs-meta.ts"() {
657
+ "use strict";
654
658
  PACKS_META_RE = /<meta\s+name=["']austere-packs["']\s+content=["']([^"']*)["']\s*\/?>/i;
655
659
  NAME_RE = /^(@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
656
660
  VERSION_RE = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/;
657
661
  }
658
662
  });
659
663
 
660
- // src/shared/catalog.js
661
- function searchCatalog(entries, query, { notesOf = (
662
- /** @type {(entry: any) => string[]} */
663
- (() => [])
664
- ), limit = 8 } = {}) {
664
+ // src/shared/catalog.ts
665
+ function searchCatalog(entries, query, { notesOf = () => [], limit = 8 } = {}) {
665
666
  const q2 = String(query || "").trim().toLowerCase();
666
667
  const terms = words(q2);
667
668
  if (!terms.length) return [];
@@ -688,13 +689,14 @@ function searchCatalog(entries, query, { notesOf = (
688
689
  }
689
690
  var CATALOG_FORMAT, words;
690
691
  var init_catalog = __esm({
691
- "src/shared/catalog.js"() {
692
+ "src/shared/catalog.ts"() {
693
+ "use strict";
692
694
  CATALOG_FORMAT = 1;
693
695
  words = (text) => String(text || "").toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length > 1);
694
696
  }
695
697
  });
696
698
 
697
- // src/cli/packs.js
699
+ // src/cli/packs.ts
698
700
  import fs2 from "node:fs";
699
701
  import path2 from "node:path";
700
702
  function isFirstParty(name) {
@@ -754,7 +756,7 @@ function installedPacks() {
754
756
  return Object.entries(lock.packs).map(([name, e]) => {
755
757
  const dir = path2.join(packsDir(), packDirName(name, e.version));
756
758
  return { name, ...e, dir, catalog: readJson(path2.join(dir, "catalog.json"), null) };
757
- }).filter((p) => p.catalog).sort((a, b) => a.name.localeCompare(b.name));
759
+ }).filter((p) => !!p.catalog).sort((a, b) => a.name.localeCompare(b.name));
758
760
  }
759
761
  function findInstalled(name) {
760
762
  return installedPacks().find((p) => p.name === name) || null;
@@ -852,7 +854,8 @@ function mergePackSchemas(schema, catalogs) {
852
854
  }
853
855
  var PACK_API, TRUSTED_SCOPE, core, bundled;
854
856
  var init_packs = __esm({
855
- "src/cli/packs.js"() {
857
+ "src/cli/packs.ts"() {
858
+ "use strict";
856
859
  init_paths();
857
860
  init_packs_meta();
858
861
  init_catalog();
@@ -863,10 +866,15 @@ var init_packs = __esm({
863
866
  }
864
867
  });
865
868
 
866
- // src/cli/invites.js
869
+ // src/cli/invites.ts
867
870
  import crypto from "node:crypto";
868
871
  import fs4 from "node:fs";
869
872
  import path3 from "node:path";
873
+ function isInvite(i) {
874
+ if (!i || typeof i !== "object") return false;
875
+ const o = i;
876
+ return typeof o.token === "string" && o.token.length >= 22 && Boolean(o.name) && Boolean(o.sessionId);
877
+ }
870
878
  function safeEqual(a, b) {
871
879
  const x = crypto.createHash("sha256").update(String(a)).digest();
872
880
  const y = crypto.createHash("sha256").update(String(b)).digest();
@@ -923,18 +931,21 @@ function ownerKey(dir) {
923
931
  }
924
932
  var COOKIE, RESERVED, InviteStore, OWNER_COOKIE, LoginCodes, hashCode;
925
933
  var init_invites = __esm({
926
- "src/cli/invites.js"() {
934
+ "src/cli/invites.ts"() {
935
+ "use strict";
927
936
  COOKIE = "austere_rv";
928
937
  RESERVED = /* @__PURE__ */ new Set(["owner", "you", "agent", "me"]);
929
938
  InviteStore = class {
930
- /** @param {string} dir state dir */
939
+ file;
940
+ invites;
941
+ /** @param dir state dir */
931
942
  constructor(dir) {
932
943
  this.file = path3.join(dir, "invites.json");
933
944
  this.invites = [];
934
945
  try {
935
946
  const raw = JSON.parse(fs4.readFileSync(this.file, "utf8"));
936
947
  if (Array.isArray(raw.invites)) {
937
- this.invites = raw.invites.filter((i) => i && typeof i.token === "string" && i.token.length >= 22 && i.name && i.sessionId);
948
+ this.invites = raw.invites.filter(isInvite);
938
949
  }
939
950
  } catch {
940
951
  }
@@ -944,7 +955,6 @@ var init_invites = __esm({
944
955
  fs4.writeFileSync(tmp, JSON.stringify({ invites: this.invites }, null, 2) + "\n", { mode: 384 });
945
956
  fs4.renameSync(tmp, this.file);
946
957
  }
947
- /** @returns {Invite} */
948
958
  add({ name, sessionId: sessionId2, file: file3, auto = false }) {
949
959
  const clean = cleanName(name);
950
960
  if (this.invites.some((i) => i.sessionId === sessionId2 && i.name.toLowerCase() === clean.toLowerCase())) {
@@ -979,7 +989,10 @@ var init_invites = __esm({
979
989
  };
980
990
  OWNER_COOKIE = "austere_owner";
981
991
  LoginCodes = class {
982
- /** @param {number} ttlMs @param {() => number} [now] */
992
+ ttlMs;
993
+ now;
994
+ /** sha256(code) -> expiry */
995
+ codes;
983
996
  constructor(ttlMs, now = Date.now) {
984
997
  this.ttlMs = ttlMs;
985
998
  this.now = now;
@@ -1005,7 +1018,7 @@ var init_invites = __esm({
1005
1018
  }
1006
1019
  });
1007
1020
 
1008
- // src/cli/client.js
1021
+ // src/cli/client.ts
1009
1022
  import { spawn } from "node:child_process";
1010
1023
  import crypto2 from "node:crypto";
1011
1024
  import fs5 from "node:fs";
@@ -1091,7 +1104,8 @@ async function ensureServer() {
1091
1104
  throw new Error(`port ${port2} is served by an austere-axi with another state dir (${h.stateDir}); set AUSTERE_AXI_PORT`);
1092
1105
  }
1093
1106
  if (h && (h.legacy || versionGt(VERSION, h.version))) {
1094
- const keep = (h.listen || []).filter((x) => x !== "127.0.0.1" && (!h.tailnet || x !== h.tailnet.ip));
1107
+ const { tailnet } = h;
1108
+ const keep = (h.listen || []).filter((x) => x !== "127.0.0.1" && (!tailnet || x !== tailnet.ip));
1095
1109
  const persist = !!h.persist;
1096
1110
  await shutdownServer(h, port2);
1097
1111
  for (let i = 0; i < 40 && await health(port2); i++) await sleep(100);
@@ -1163,7 +1177,8 @@ async function openBrowser(url2) {
1163
1177
  }
1164
1178
  var sleep, START_TIMEOUT_MS;
1165
1179
  var init_client = __esm({
1166
- "src/cli/client.js"() {
1180
+ "src/cli/client.ts"() {
1181
+ "use strict";
1167
1182
  init_paths();
1168
1183
  init_invites();
1169
1184
  sleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -1171,7 +1186,7 @@ var init_client = __esm({
1171
1186
  }
1172
1187
  });
1173
1188
 
1174
- // src/cli/hub.js
1189
+ // src/cli/hub.ts
1175
1190
  import fs6 from "node:fs";
1176
1191
  import path5 from "node:path";
1177
1192
  function hubConfigFile() {
@@ -1194,7 +1209,7 @@ async function loadSqlite() {
1194
1209
  if (DatabaseSync) return DatabaseSync;
1195
1210
  const emit2 = process.emitWarning;
1196
1211
  process.emitWarning = function(warning, ...rest) {
1197
- if (/sqlite/i.test(String(warning && warning.message ? warning.message : warning))) return;
1212
+ if (/sqlite/i.test(String(typeof warning !== "string" && warning && warning.message ? warning.message : warning))) return;
1198
1213
  return emit2.call(process, warning, ...rest);
1199
1214
  };
1200
1215
  try {
@@ -1252,7 +1267,8 @@ async function registerWithHub(file3, title, id) {
1252
1267
  }
1253
1268
  var DatabaseSync, SCHEMA, NOTES, Hub;
1254
1269
  var init_hub = __esm({
1255
- "src/cli/hub.js"() {
1270
+ "src/cli/hub.ts"() {
1271
+ "use strict";
1256
1272
  init_paths();
1257
1273
  DatabaseSync = null;
1258
1274
  SCHEMA = `
@@ -1308,10 +1324,12 @@ CREATE TABLE IF NOT EXISTS notes (
1308
1324
  CREATE INDEX IF NOT EXISTS notes_artifact ON notes(artifact_id, at);
1309
1325
  `;
1310
1326
  Hub = class _Hub {
1327
+ db;
1328
+ q;
1311
1329
  static async open(file3 = hubDbFile()) {
1312
1330
  return new _Hub(await openDatabase(file3));
1313
1331
  }
1314
- /** @param {any} db an open hub.db (openDatabase) */
1332
+ /** @param db an open hub.db (openDatabase) */
1315
1333
  constructor(db) {
1316
1334
  this.db = db;
1317
1335
  this.q = {
@@ -1350,13 +1368,15 @@ CREATE INDEX IF NOT EXISTS notes_artifact ON notes(artifact_id, at);
1350
1368
  WHERE (? = '' OR a.title LIKE ? ESCAPE '\\' OR a.file LIKE ? ESCAPE '\\' OR a.project LIKE ? ESCAPE '\\')
1351
1369
  AND (? = '' OR a.project = ?)
1352
1370
  GROUP BY a.id ORDER BY a.updated_at DESC LIMIT ?`
1353
- ).all(q2, like, like, like, project, project, limit).map((r) => ({ ...r, open: r.open || 0, received: r.received || 0, addressed: r.addressed || 0, held: r.held || 0 }));
1371
+ ).all(q2, like, like, like, project, project, limit).map((row) => {
1372
+ const r = row;
1373
+ return { ...r, open: r.open || 0, received: r.received || 0, addressed: r.addressed || 0, held: r.held || 0 };
1374
+ });
1354
1375
  }
1355
1376
  /**
1356
1377
  * Notes (annotations and messages) across all pages, newest first.
1357
1378
  * `q` matches note text, target and page title. `status`: "unanswered" (held, open and received), "answered", or "" for all.
1358
1379
  * `author`: a reviewer's name, "owner" for the owner's own notes, or "" for everyone. Discarded notes are left out.
1359
- * @param {{ q?: string, status?: string, project?: string, author?: string, limit?: number }} [o]
1360
1380
  */
1361
1381
  notes({ q: q2 = "", status = "", project = "", author = "", limit = 200 } = {}) {
1362
1382
  const anyAuthor = author === "" ? "all" : "one";
@@ -1388,7 +1408,7 @@ CREATE INDEX IF NOT EXISTS notes_artifact ON notes(artifact_id, at);
1388
1408
  }
1389
1409
  });
1390
1410
 
1391
- // src/cli/lock.js
1411
+ // src/cli/lock.ts
1392
1412
  import fs7 from "node:fs";
1393
1413
  import path6 from "node:path";
1394
1414
  async function lockStateDir(dir, { port: port2 = null, wait = 0 } = {}) {
@@ -1445,8 +1465,8 @@ async function lockHolder(text, dir) {
1445
1465
  }
1446
1466
  if (typeof lock === "number") lock = { pid: lock };
1447
1467
  const pid = Number(lock?.pid);
1448
- if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return null;
1449
- const port2 = Number.isInteger(lock.port) && lock.port > 0 ? lock.port : void 0;
1468
+ if (!lock || !Number.isInteger(pid) || pid <= 0 || pid === process.pid) return null;
1469
+ const port2 = typeof lock.port === "number" && Number.isInteger(lock.port) && lock.port > 0 ? lock.port : void 0;
1450
1470
  if (port2 && await serves(port2, pid, dir)) return { pid, port: port2, serving: true };
1451
1471
  if (!processAlive(pid)) return null;
1452
1472
  if (lock.at == null) return { pid, port: port2, serving: false };
@@ -1466,14 +1486,15 @@ function processAlive(pid) {
1466
1486
  }
1467
1487
  var STARTING_MS, sleep2;
1468
1488
  var init_lock = __esm({
1469
- "src/cli/lock.js"() {
1489
+ "src/cli/lock.ts"() {
1490
+ "use strict";
1470
1491
  init_client();
1471
1492
  STARTING_MS = 6e4;
1472
1493
  sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
1473
1494
  }
1474
1495
  });
1475
1496
 
1476
- // src/cli/sessions.js
1497
+ // src/cli/sessions.ts
1477
1498
  import crypto3 from "node:crypto";
1478
1499
  import fs8 from "node:fs";
1479
1500
  import path7 from "node:path";
@@ -1486,7 +1507,7 @@ function newId(prefix) {
1486
1507
  function noteStatus(e, ackedSeq) {
1487
1508
  if (e.discarded) return "discarded";
1488
1509
  if (e.held) return "held";
1489
- if (e.seq > ackedSeq) return "open";
1510
+ if (Number(e.seq) > ackedSeq) return "open";
1490
1511
  if (e.doneAt) return "addressed";
1491
1512
  return "received";
1492
1513
  }
@@ -1523,7 +1544,6 @@ function hydrate(row) {
1523
1544
  endedAt: row.ended_at || null,
1524
1545
  closedAt: row.closed_at || null,
1525
1546
  ackedSeq: Number(row.acked_seq || 0),
1526
- /** @type {Record<string, any>[]} */
1527
1547
  transcript: [],
1528
1548
  // runtime-only
1529
1549
  deliveredSeq: Number(row.acked_seq || 0),
@@ -1534,18 +1554,22 @@ function hydrate(row) {
1534
1554
  }
1535
1555
  var counter, deliverable, SessionStore;
1536
1556
  var init_sessions = __esm({
1537
- "src/cli/sessions.js"() {
1557
+ "src/cli/sessions.ts"() {
1558
+ "use strict";
1538
1559
  init_hub();
1539
1560
  counter = 0;
1540
1561
  deliverable = (e) => e.role === "user" && e.seq != null && !e.held && !e.discarded;
1541
1562
  SessionStore = class _SessionStore {
1563
+ db;
1564
+ sessions;
1565
+ q;
1542
1566
  /** Open the store in a state dir: hub.db, after importing any session files from before it. */
1543
1567
  static async open(dir) {
1544
1568
  return new _SessionStore(await openDatabase(path7.join(dir, "hub.db")), dir);
1545
1569
  }
1546
1570
  /**
1547
- * @param {any} db hub.db, opened with openDatabase
1548
- * @param {string} dir the state dir
1571
+ * @param db hub.db, opened with openDatabase
1572
+ * @param dir the state dir
1549
1573
  */
1550
1574
  constructor(db, dir) {
1551
1575
  this.db = db;
@@ -1684,7 +1708,7 @@ var init_sessions = __esm({
1684
1708
  }
1685
1709
  /** Held entries, oldest first. */
1686
1710
  heldEntries(s) {
1687
- return s.transcript.filter((e) => e.role === "user" && e.held);
1711
+ return s.transcript.filter((e) => e.role === "user" && Boolean(e.held));
1688
1712
  }
1689
1713
  /**
1690
1714
  * The owner sends the held notes named by `ids` on to the agent. A released note gets
@@ -1740,7 +1764,7 @@ var init_sessions = __esm({
1740
1764
  const now = Date.now();
1741
1765
  this.updateNotes(s, entries.filter((e) => !e.seenAt).map((e) => [e, { seenAt: now }]));
1742
1766
  s.lastDeliveredAt = now;
1743
- s.deliveredSeq = Math.max(s.deliveredSeq, ...entries.map((e) => e.seq));
1767
+ s.deliveredSeq = Math.max(s.deliveredSeq, ...entries.map((e) => Number(e.seq)));
1744
1768
  }
1745
1769
  /**
1746
1770
  * The agent acknowledges every note up to `cursor`. A cursor past the last note in the
@@ -1775,10 +1799,9 @@ var init_sessions = __esm({
1775
1799
  * Feedback no agent has acted on (`feedback <file>`): notes not yet acknowledged,
1776
1800
  * plus acknowledged ones with no agent reply since; `all` adds the addressed ones.
1777
1801
  * Unless `peek`, reading acknowledges them, so a later poll does not deliver them again.
1778
- * @returns {{ entries: { id: string, at: number, author?: string, items: any[], status: string }[], fresh: any[] }}
1779
1802
  */
1780
1803
  feedback(s, { all = false, peek = false } = {}) {
1781
- const picked = s.transcript.filter((e) => deliverable(e) && (e.items || []).length && (all || e.seq > s.ackedSeq || !e.doneAt));
1804
+ const picked = s.transcript.filter((e) => deliverable(e) && (e.items || []).length > 0 && (all || e.seq > s.ackedSeq || !e.doneAt));
1782
1805
  const entries = picked.map((e) => ({
1783
1806
  id: e.id,
1784
1807
  at: e.at,
@@ -1845,10 +1868,10 @@ var init_sessions = __esm({
1845
1868
  }
1846
1869
  importSession(d) {
1847
1870
  const now = Date.now();
1848
- const known = !!this.q.hasNotes.get(d.id);
1871
+ const known2 = !!this.q.hasNotes.get(d.id);
1849
1872
  this.q.ensure.run(d.id, d.file, projectOf(d.file), d.title || path7.basename(d.file), d.createdAt || now, d.updatedAt || now);
1850
1873
  const s = hydrate(this.q.session.get(d.id));
1851
- if (!known) {
1874
+ if (!known2) {
1852
1875
  Object.assign(s, {
1853
1876
  title: d.title || s.title,
1854
1877
  updatedAt: Math.max(s.updatedAt, d.updatedAt || 0),
@@ -1859,10 +1882,10 @@ var init_sessions = __esm({
1859
1882
  }
1860
1883
  const transcript = Array.isArray(d.transcript) ? d.transcript : [];
1861
1884
  const pending = new Set(Array.isArray(d.pending) ? d.pending : []);
1862
- const users = transcript.filter((e) => e && e.role === "user" && e.id && !this.q.note.get(e.id));
1885
+ const users = transcript.filter((e) => Boolean(e && e.role === "user" && e.id && !this.q.note.get(e.id)));
1863
1886
  const open2 = (e) => !e.held && !e.discarded;
1864
1887
  const delivered = users.filter((e) => open2(e) && !pending.has(e.id));
1865
- const waiting = [...pending].map((id) => users.find((e) => e.id === id)).filter((e) => e && open2(e));
1888
+ const waiting = [...pending].map((id) => users.find((e) => e.id === id)).filter((e) => Boolean(e && open2(e)));
1866
1889
  const rest = users.filter((e) => !open2(e));
1867
1890
  const save = (e, seq) => {
1868
1891
  const entry = { ...e, items: Array.isArray(e.items) ? e.items : [], seq };
@@ -1871,7 +1894,7 @@ var init_sessions = __esm({
1871
1894
  };
1872
1895
  const saved = [];
1873
1896
  for (const e of delivered) saved.push(save(e, this.nextSeq()));
1874
- if (delivered.length) s.ackedSeq = Math.max(s.ackedSeq, saved[saved.length - 1].seq);
1897
+ if (delivered.length) s.ackedSeq = Math.max(s.ackedSeq, Number(saved[saved.length - 1].seq));
1875
1898
  for (const e of waiting) saved.push(save(e, this.nextSeq()));
1876
1899
  for (const e of rest) saved.push(save(e, null));
1877
1900
  for (const e of saved) this.indexNote(s, e);
@@ -1884,7 +1907,7 @@ var init_sessions = __esm({
1884
1907
  }
1885
1908
  });
1886
1909
 
1887
- // src/cli/export.js
1910
+ // src/cli/export.ts
1888
1911
  import fs9 from "node:fs";
1889
1912
  import path8 from "node:path";
1890
1913
  function inlineScript(code) {
@@ -1911,14 +1934,15 @@ function exportHtml(html) {
1911
1934
  return { html: out, notices };
1912
1935
  }
1913
1936
  var init_export = __esm({
1914
- "src/cli/export.js"() {
1937
+ "src/cli/export.ts"() {
1938
+ "use strict";
1915
1939
  init_artifact();
1916
1940
  init_paths();
1917
1941
  init_packs();
1918
1942
  }
1919
1943
  });
1920
1944
 
1921
- // src/cli/install.js
1945
+ // src/cli/install.ts
1922
1946
  var install_exports = {};
1923
1947
  __export(install_exports, {
1924
1948
  TRUSTED_SCOPE: () => TRUSTED_SCOPE,
@@ -2011,7 +2035,8 @@ async function fetchBuffer(url2, accept) {
2011
2035
  let res;
2012
2036
  try {
2013
2037
  res = await fetch(url2, { headers: accept ? { accept } : {}, redirect: "follow" });
2014
- } catch (err) {
2038
+ } catch (caught) {
2039
+ const err = caught;
2015
2040
  const e = Object.assign(new Error(`could not reach ${url2} (${err.cause?.code || err.message})`), { network: true });
2016
2041
  throw e;
2017
2042
  }
@@ -2033,7 +2058,7 @@ async function fromRegistry(spec) {
2033
2058
  try {
2034
2059
  meta3 = JSON.parse((await fetchBuffer(metaUrl, "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8")).toString("utf8"));
2035
2060
  } catch (err) {
2036
- if (err.status === 404) throw new Error(`no package ${name} on ${registryUrl()}`);
2061
+ if (err instanceof Error && "status" in err && err.status === 404) throw new Error(`no package ${name} on ${registryUrl()}`);
2037
2062
  throw err;
2038
2063
  }
2039
2064
  const version2 = pickVersion(meta3, range);
@@ -2056,7 +2081,7 @@ function readTarball(tgz, label) {
2056
2081
  try {
2057
2082
  files = untar(zlib.gunzipSync(tgz));
2058
2083
  } catch (err) {
2059
- throw new Error(`${label}: not a gzipped tarball (${err.message})`);
2084
+ throw new Error(`${label}: not a gzipped tarball (${err instanceof Error ? err.message : void 0})`);
2060
2085
  }
2061
2086
  const packJs = files.get("dist/pack.js");
2062
2087
  const catalog = files.get("dist/catalog.json");
@@ -2174,7 +2199,8 @@ function removePack(name) {
2174
2199
  }
2175
2200
  var MAX_TARBALL, MAX_PACK_JS;
2176
2201
  var init_install = __esm({
2177
- "src/cli/install.js"() {
2202
+ "src/cli/install.ts"() {
2203
+ "use strict";
2178
2204
  init_packs();
2179
2205
  init_packs_meta();
2180
2206
  init_catalog();
@@ -2183,7 +2209,7 @@ var init_install = __esm({
2183
2209
  }
2184
2210
  });
2185
2211
 
2186
- // src/cli/pack-dev.js
2212
+ // src/cli/pack-dev.ts
2187
2213
  var pack_dev_exports = {};
2188
2214
  __export(pack_dev_exports, {
2189
2215
  buildPackDir: () => buildPackDir,
@@ -2247,7 +2273,8 @@ async function findEsbuild(dir) {
2247
2273
  for (const base of [path10.join(dir, "package.json"), path10.join(process.cwd(), "package.json"), import.meta.url]) {
2248
2274
  try {
2249
2275
  const resolved = createRequire(base).resolve("esbuild");
2250
- return await import(pathToFileURL(resolved).href);
2276
+ const esbuild = await import(pathToFileURL(resolved).href);
2277
+ return esbuild;
2251
2278
  } catch {
2252
2279
  }
2253
2280
  }
@@ -2276,7 +2303,8 @@ async function buildPackDir(dir = ".") {
2276
2303
  }
2277
2304
  var TEMPLATE;
2278
2305
  var init_pack_dev = __esm({
2279
- "src/cli/pack-dev.js"() {
2306
+ "src/cli/pack-dev.ts"() {
2307
+ "use strict";
2280
2308
  init_paths();
2281
2309
  init_packs();
2282
2310
  init_packs_meta();
@@ -2376,7 +2404,7 @@ export default austereComponent({
2376
2404
  }
2377
2405
  });
2378
2406
 
2379
- // src/cli/net.js
2407
+ // src/cli/net.ts
2380
2408
  import { execFile } from "node:child_process";
2381
2409
  import fs12 from "node:fs";
2382
2410
  function run(bin, args) {
@@ -2436,7 +2464,8 @@ function isLoopback(addr) {
2436
2464
  }
2437
2465
  var CANDIDATES, cache;
2438
2466
  var init_net = __esm({
2439
- "src/cli/net.js"() {
2467
+ "src/cli/net.ts"() {
2468
+ "use strict";
2440
2469
  CANDIDATES = [
2441
2470
  "tailscale",
2442
2471
  "/usr/bin/tailscale",
@@ -2448,13 +2477,14 @@ var init_net = __esm({
2448
2477
  }
2449
2478
  });
2450
2479
 
2451
- // src/cli/items.js
2480
+ // src/cli/items.ts
2452
2481
  function defined(o) {
2453
- return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
2482
+ const out = Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
2483
+ return out;
2454
2484
  }
2455
2485
  function detailOf(d) {
2456
- if (!d || typeof d !== "object") return void 0;
2457
- const out = defined({ part: str2(d.part), row: str2(d.row), column: str2(d.column), rowIndex: Number.isInteger(d.rowIndex) ? d.rowIndex : void 0 });
2486
+ if (!isRecord(d)) return void 0;
2487
+ const out = defined({ part: str2(d.part), row: str2(d.row), column: str2(d.column), rowIndex: typeof d.rowIndex === "number" && Number.isInteger(d.rowIndex) ? d.rowIndex : void 0 });
2458
2488
  return Object.keys(out).length ? out : void 0;
2459
2489
  }
2460
2490
  function reviewerItem(x) {
@@ -2470,18 +2500,20 @@ function reviewerItem(x) {
2470
2500
  detail: detailOf(x.detail)
2471
2501
  });
2472
2502
  }
2473
- var INVISIBLE, str2, ID, COMPONENT, match;
2503
+ var INVISIBLE, str2, ID, COMPONENT, match, isRecord;
2474
2504
  var init_items = __esm({
2475
- "src/cli/items.js"() {
2505
+ "src/cli/items.ts"() {
2506
+ "use strict";
2476
2507
  INVISIBLE = /[\u{E0000}-\u{E007F}\u200B\u200E\u200F\u202A-\u202E\u2066-\u2069]/gu;
2477
2508
  str2 = (v) => typeof v === "string" ? v.replace(INVISIBLE, "") : void 0;
2478
2509
  ID = /^[A-Za-z_$][\w$]{0,99}$/;
2479
2510
  COMPONENT = /^[A-Za-z_][\w.-]{0,99}$/;
2480
2511
  match = (re2, v) => typeof v === "string" && re2.test(v) ? v : void 0;
2512
+ isRecord = (v) => !!v && typeof v === "object";
2481
2513
  }
2482
2514
  });
2483
2515
 
2484
- // src/cli/hub-page.js
2516
+ // src/cli/hub-page.ts
2485
2517
  import os2 from "node:os";
2486
2518
  import path11 from "node:path";
2487
2519
  function day(ms) {
@@ -2519,15 +2551,17 @@ function state(a) {
2519
2551
  function hubPage(rows, { version: version2, q: q2, project, stats }) {
2520
2552
  const byProject = /* @__PURE__ */ new Map();
2521
2553
  for (const r of rows) {
2522
- if (!byProject.has(r.project)) byProject.set(r.project, []);
2523
- byProject.get(r.project).push(r);
2554
+ let list = byProject.get(r.project);
2555
+ if (!list) byProject.set(r.project, list = []);
2556
+ list.push(r);
2524
2557
  }
2525
2558
  const sections = [...byProject.entries()].map(([proj, list]) => {
2526
2559
  const days = /* @__PURE__ */ new Map();
2527
2560
  for (const r of list) {
2528
2561
  const k = day(r.updated_at);
2529
- if (!days.has(k)) days.set(k, []);
2530
- days.get(k).push(r);
2562
+ let items = days.get(k);
2563
+ if (!items) days.set(k, items = []);
2564
+ items.push(r);
2531
2565
  }
2532
2566
  const body = [...days.entries()].map(
2533
2567
  ([d, items]) => `<h3>${escapeHtml(d)}</h3><ul>${items.map(
@@ -2580,7 +2614,8 @@ ${filter}${items ? `<ul>${items}</ul>` : `<p class="empty">${empty}</p>`}
2580
2614
  }
2581
2615
  var STYLE, STATUS_LABEL;
2582
2616
  var init_hub_page = __esm({
2583
- "src/cli/hub-page.js"() {
2617
+ "src/cli/hub-page.ts"() {
2618
+ "use strict";
2584
2619
  init_artifact();
2585
2620
  STYLE = `body{margin:0;background:#0b0b0d;color:#e8e8ec;font:14px/1.5 ui-sans-serif,system-ui,-apple-system,sans-serif}
2586
2621
  main{max-width:860px;margin:0 auto;padding:32px 16px 64px}
@@ -2609,7 +2644,7 @@ b.by{color:#e8e8ec}
2609
2644
  }
2610
2645
  });
2611
2646
 
2612
- // src/cli/server.js
2647
+ // src/cli/server.ts
2613
2648
  var server_exports = {};
2614
2649
  __export(server_exports, {
2615
2650
  persistEnv: () => persistEnv,
@@ -2622,7 +2657,12 @@ import crypto5 from "node:crypto";
2622
2657
  function persistEnv() {
2623
2658
  return /^(1|true|yes)$/i.test(process.env.AUSTERE_AXI_PERSIST || "");
2624
2659
  }
2625
- async function runServer({ port: port2, verbose = false, alsoListen = [], persist = false }) {
2660
+ async function runServer({
2661
+ port: port2,
2662
+ verbose = false,
2663
+ alsoListen = [],
2664
+ persist = false
2665
+ }) {
2626
2666
  const log = (...a) => {
2627
2667
  const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${a.join(" ")}`;
2628
2668
  if (verbose) process.stderr.write(line + "\n");
@@ -2817,7 +2857,7 @@ data: ${JSON.stringify({ state: "revoked" })}
2817
2857
  if (watchers.has(s.id)) return;
2818
2858
  const html = readFileSafe(s.file);
2819
2859
  const art = html == null ? null : readArtifact(html);
2820
- const w = { html, program: art?.program ?? null, shell: art?.shell ?? null, timer: null };
2860
+ const w = { html, program: art?.program ?? null, shell: art?.shell ?? null, timer: void 0 };
2821
2861
  watchers.set(s.id, w);
2822
2862
  if (art?.title) s.title = art.title;
2823
2863
  fs13.watchFile(s.file, { interval: 300 }, () => {
@@ -2841,7 +2881,7 @@ data: ${JSON.stringify({ state: "revoked" })}
2841
2881
  s.revision += 1;
2842
2882
  if (art.title) s.title = art.title;
2843
2883
  log("change", s.id, `rev=${s.revision}`, shellChanged ? "shell" : "program");
2844
- const touched = s.transcript.filter((e) => e.role === "user" && e.seenAt && !e.doneAt && !e.workAt);
2884
+ const touched = s.transcript.filter((e) => e.role === "user" && Boolean(e.seenAt) && !e.doneAt && !e.workAt);
2845
2885
  if (touched.length) {
2846
2886
  store.markWorking(s, touched);
2847
2887
  broadcastTranscript(s, touched);
@@ -3303,7 +3343,7 @@ data: ${JSON.stringify({ state: "revoked" })}
3303
3343
  <body><main><h1>austere-axi <small style="color:#777;font-weight:400">${VERSION}</small></h1><ul>${rows || "<li>No sessions yet.</li>"}</ul></main></body></html>`;
3304
3344
  }
3305
3345
  async function handle(req, res) {
3306
- const url2 = new URL(req.url, "http://x");
3346
+ const url2 = new URL(String(req.url), "http://x");
3307
3347
  const host = hostOnly(req.headers.host);
3308
3348
  if (!hostsAllowed().has(host) && process.env.AUSTERE_AXI_ALLOWED_HOSTS !== "*") {
3309
3349
  return send(res, 403, "host not allowed");
@@ -3420,8 +3460,9 @@ data: ${JSON.stringify(snapshot)}
3420
3460
 
3421
3461
  `);
3422
3462
  const client = { res, viewer: who };
3423
- if (!clients.has(s.id)) clients.set(s.id, /* @__PURE__ */ new Set());
3424
- clients.get(s.id).add(client);
3463
+ let set2 = clients.get(s.id);
3464
+ if (!set2) clients.set(s.id, set2 = /* @__PURE__ */ new Set());
3465
+ set2.add(client);
3425
3466
  browserSeen.add(s.id);
3426
3467
  clearTimeout(graceTimers.get(s.id));
3427
3468
  graceTimers.delete(s.id);
@@ -3519,7 +3560,7 @@ data: ${JSON.stringify(snapshot)}
3519
3560
  if (listeners.has(host)) return resolve(true);
3520
3561
  const server = http2.createServer((req, res) => {
3521
3562
  handle(req, res).catch((err) => {
3522
- log("error", req.method, req.url.split("?")[0], String(err?.stack || err));
3563
+ log("error", req.method, String(req.url).split("?")[0], String(err?.stack || err));
3523
3564
  if (!res.headersSent) send(res, err.status || 500, { error: err.status ? String(err.message) : "internal error" });
3524
3565
  else res.end();
3525
3566
  });
@@ -3528,12 +3569,7 @@ data: ${JSON.stringify(snapshot)}
3528
3569
  server.requestTimeout = 0;
3529
3570
  server.headersTimeout = 6e4;
3530
3571
  server.once("error", (err) => {
3531
- log(
3532
- "listen-failed",
3533
- host,
3534
- /** @type {NodeJS.ErrnoException} */
3535
- err.code || err.message
3536
- );
3572
+ log("listen-failed", host, err.code || err.message);
3537
3573
  resolve(false);
3538
3574
  });
3539
3575
  server.listen(port2, host, () => {
@@ -3601,7 +3637,8 @@ data: ${JSON.stringify({ state: "stopped", reason })}
3601
3637
  }
3602
3638
  var MIME, SHORT_GRACE_MS, LOGIN_TTL_MS, OWNER, REVIEWER_KINDS, PAGE, SSE_MAX_BUFFER, SSE_STALL_MS, SSE_HARD_MAX, SSE_MAX_PER_REVIEWER, MAX_HELD_PER_REVIEWER, SSE_MAX_PER_SESSION;
3603
3639
  var init_server = __esm({
3604
- "src/cli/server.js"() {
3640
+ "src/cli/server.ts"() {
3641
+ "use strict";
3605
3642
  init_artifact();
3606
3643
  init_export();
3607
3644
  init_net();
@@ -3654,7 +3691,7 @@ var init_server = __esm({
3654
3691
  }
3655
3692
  });
3656
3693
 
3657
- // src/cli/mcp.js
3694
+ // src/cli/mcp.ts
3658
3695
  var mcp_exports = {};
3659
3696
  __export(mcp_exports, {
3660
3697
  runMcp: () => runMcp
@@ -3687,12 +3724,13 @@ error: ${err.message}
3687
3724
  }
3688
3725
  function validate2(tool, a) {
3689
3726
  for (const key2 of tool.required || []) {
3690
- if (typeof a[key2] !== "string" || !a[key2].trim()) return `${key2} is required`;
3727
+ const v = a[key2];
3728
+ if (typeof v !== "string" || !v.trim()) return `${key2} is required`;
3691
3729
  }
3692
3730
  for (const [key2, v] of Object.entries(a)) {
3693
3731
  const p = tool.properties[key2];
3694
3732
  if (!p) return `unknown argument: ${key2}`;
3695
- const ok = p.type === "array" ? Array.isArray(v) && v.every((x) => typeof x === "string") : p.type === "integer" ? Number.isInteger(v) && v >= 0 : typeof v === p.type;
3733
+ const ok = p.type === "array" ? Array.isArray(v) && v.every((x) => typeof x === "string") : p.type === "integer" ? typeof v === "number" && Number.isInteger(v) && v >= 0 : typeof v === p.type;
3696
3734
  if (!ok) return `${key2} must be ${p.type === "integer" ? "a non-negative integer" : `a ${p.type}`}`;
3697
3735
  }
3698
3736
  return null;
@@ -3703,9 +3741,10 @@ async function callTool(name, a, signal) {
3703
3741
  if (bad) return { content: [{ type: "text", text: `status: error
3704
3742
  error: ${bad}` }], isError: true };
3705
3743
  if (typeof a.file === "string") a = { ...a, file: path13.resolve(a.file) };
3744
+ const args = a;
3706
3745
  let text = "";
3707
3746
  let isError = false;
3708
- for (const run2 of tool.run(a)) {
3747
+ for (const run2 of tool.run(args)) {
3709
3748
  const r = await runCli(run2, signal);
3710
3749
  text += r.text;
3711
3750
  if (r.code !== 0) {
@@ -3731,7 +3770,7 @@ function runMcp() {
3731
3770
  async function handle(msg) {
3732
3771
  const { id, method, params = {} } = msg;
3733
3772
  if (id === void 0 || id === null) {
3734
- if (method === "notifications/cancelled") inflight.get(params.requestId)?.abort();
3773
+ if (method === "notifications/cancelled" && params.requestId !== void 0) inflight.get(params.requestId)?.abort();
3735
3774
  return;
3736
3775
  }
3737
3776
  switch (method) {
@@ -3740,7 +3779,7 @@ function runMcp() {
3740
3779
  return send({
3741
3780
  id,
3742
3781
  result: {
3743
- protocolVersion: PROTOCOLS.includes(asked) ? asked : PROTOCOLS[0],
3782
+ protocolVersion: asked !== void 0 && PROTOCOLS.includes(asked) ? asked : PROTOCOLS[0],
3744
3783
  capabilities: { tools: { listChanged: false } },
3745
3784
  serverInfo: { name: "austere-axi", title: "austere-axi", version: VERSION },
3746
3785
  instructions: INSTRUCTIONS
@@ -3752,9 +3791,9 @@ function runMcp() {
3752
3791
  case "tools/list":
3753
3792
  return send({ id, result: { tools: listTools() } });
3754
3793
  case "tools/call": {
3755
- if (!Object.hasOwn(TOOLS, params.name)) return error62(id, -32602, `unknown tool: ${params.name}`);
3794
+ if (typeof params.name !== "string" || !Object.hasOwn(TOOLS, params.name)) return error62(id, -32602, `unknown tool: ${params.name}`);
3756
3795
  const args = params.arguments ?? {};
3757
- if (typeof args !== "object" || Array.isArray(args)) return error62(id, -32602, "arguments must be an object");
3796
+ if (!isRecord2(args) || Array.isArray(args)) return error62(id, -32602, "arguments must be an object");
3758
3797
  const ctl = new AbortController();
3759
3798
  inflight.set(id, ctl);
3760
3799
  try {
@@ -3779,12 +3818,13 @@ function runMcp() {
3779
3818
  return error62(null, -32700, "parse error");
3780
3819
  }
3781
3820
  if (Array.isArray(msg)) return error62(null, -32600, "batch not supported");
3782
- if (!msg || typeof msg !== "object" || typeof msg.method !== "string") {
3783
- if (msg && typeof msg === "object" && "id" in msg && !("result" in msg || "error" in msg)) error62(msg.id ?? null, -32600, "invalid request");
3821
+ if (!isRecord2(msg) || typeof msg.method !== "string") {
3822
+ if (isRecord2(msg) && "id" in msg && !("result" in msg || "error" in msg)) error62(msg.id ?? null, -32600, "invalid request");
3784
3823
  return;
3785
3824
  }
3786
- handle(msg).catch((err) => {
3787
- if (msg.id !== void 0 && msg.id !== null) error62(msg.id, -32603, String(err?.message || err));
3825
+ const req = msg;
3826
+ handle(req).catch((err) => {
3827
+ if (req.id !== void 0 && req.id !== null) error62(req.id, -32603, String((isRecord2(err) ? err.message : void 0) || err));
3788
3828
  });
3789
3829
  });
3790
3830
  return new Promise((resolve) => {
@@ -3794,10 +3834,12 @@ function runMcp() {
3794
3834
  });
3795
3835
  });
3796
3836
  }
3797
- var PROTOCOLS, POLL_TIMEOUT_MS, INSTRUCTIONS, file2, TOOLS;
3837
+ var isRecord2, PROTOCOLS, POLL_TIMEOUT_MS, INSTRUCTIONS, file2, TOOLS;
3798
3838
  var init_mcp = __esm({
3799
- "src/cli/mcp.js"() {
3839
+ "src/cli/mcp.ts"() {
3840
+ "use strict";
3800
3841
  init_paths();
3842
+ isRecord2 = (v) => !!v && typeof v === "object";
3801
3843
  PROTOCOLS = ["2025-11-25", "2025-06-18", "2024-11-05"];
3802
3844
  POLL_TIMEOUT_MS = 5e4;
3803
3845
  INSTRUCTIONS = `austere-axi turns plans, comparisons, decisions, code reviews and reports into review pages the user annotates in the browser. Call \`spec\` once per session for the workflow, the file skeleton and the component reference. Results are the CLI's output: where a \`next:\` hint names an \`austere-axi <command>\`, call the tool of that name instead. Pass absolute file paths.`;
@@ -3878,7 +3920,7 @@ var init_mcp = __esm({
3878
3920
  }
3879
3921
  });
3880
3922
 
3881
- // src/cli/main.js
3923
+ // src/cli/main.ts
3882
3924
  import fs14 from "node:fs";
3883
3925
  import path14 from "node:path";
3884
3926
 
@@ -26090,16 +26132,16 @@ function mergeStatements(existing, patch, rootId = "root") {
26090
26132
  return order.filter((id) => merged.has(id)).map((id) => merged.get(id)).join("\n");
26091
26133
  }
26092
26134
 
26093
- // src/cli/main.js
26135
+ // src/cli/main.ts
26094
26136
  init_artifact();
26095
26137
 
26096
- // src/cli/check.js
26138
+ // src/cli/check.ts
26097
26139
  import fs3 from "node:fs";
26098
26140
  init_artifact();
26099
26141
  init_paths();
26100
26142
  init_packs();
26101
26143
 
26102
- // src/shared/statements.js
26144
+ // src/shared/statements.ts
26103
26145
  var IDENT_START = /[A-Za-z_$]/;
26104
26146
  function splitStatements(source) {
26105
26147
  const out = [];
@@ -28078,7 +28120,8 @@ function Ce(e) {
28078
28120
  var xr = { graphlib: ie, version: ue, layout: Oe, debug: Ce, util: { time: le, notime: q } };
28079
28121
  var Uo = xr;
28080
28122
 
28081
- // src/runtime/components/_architecture-lanes.js
28123
+ // src/runtime/components/_architecture-lanes.ts
28124
+ var known = (map2, key2) => map2.get(key2);
28082
28125
  var LANES = {
28083
28126
  margin: 16,
28084
28127
  // around the drawing
@@ -28116,7 +28159,8 @@ function lanesPlanWidth(model) {
28116
28159
  }
28117
28160
  var plans = /* @__PURE__ */ new WeakMap();
28118
28161
  function planColumns(model) {
28119
- if (plans.has(model)) return plans.get(model);
28162
+ const cached2 = plans.get(model);
28163
+ if (cached2 !== void 0) return cached2;
28120
28164
  const lanes = prepareLanes(model);
28121
28165
  if (!lanes) {
28122
28166
  plans.set(model, null);
@@ -28185,9 +28229,10 @@ function assignLanes(model) {
28185
28229
  const top = model.groups.filter((g) => !g.parent);
28186
28230
  if (!top.length) return null;
28187
28231
  const laneOf = /* @__PURE__ */ new Map();
28188
- const lanes = top.map((group) => ({ group, nodes: [] }));
28232
+ const newLane = (group, nodes) => ({ group, nodes, index: 0, laneOf, rows: [], phys: /* @__PURE__ */ new Map(), inner: 0, headLine: "", frame: { x: 0, y: 0, w: 0, h: 0 } });
28233
+ const lanes = top.map((group) => newLane(group, []));
28189
28234
  for (const lane of lanes) {
28190
- for (const m of lane.group.members) {
28235
+ for (const m of lane.group?.members ?? []) {
28191
28236
  if (laneOf.has(m)) continue;
28192
28237
  laneOf.set(m, lane);
28193
28238
  lane.nodes.push(m);
@@ -28202,7 +28247,7 @@ function assignLanes(model) {
28202
28247
  if (isLoose.has(e.from) && !isLoose.has(e.to)) out++;
28203
28248
  if (!isLoose.has(e.from) && isLoose.has(e.to)) inn++;
28204
28249
  }
28205
- const lane = { group: null, nodes: loose };
28250
+ const lane = newLane(null, loose);
28206
28251
  for (const id of loose) laneOf.set(id, lane);
28207
28252
  if (out >= inn) lanes.unshift(lane);
28208
28253
  else lanes.push(lane);
@@ -28221,14 +28266,14 @@ function laneRows(lane, edges) {
28221
28266
  const parent = new Map(ids.map((id) => [id, id]));
28222
28267
  const find = (x) => {
28223
28268
  while (parent.get(x) !== x) {
28224
- parent.set(x, parent.get(parent.get(x)));
28225
- x = parent.get(x);
28269
+ parent.set(x, known(parent, known(parent, x)));
28270
+ x = known(parent, x);
28226
28271
  }
28227
28272
  return x;
28228
28273
  };
28229
28274
  for (const e of intra) parent.set(find(e.from), find(e.to));
28230
28275
  const adj = new Map(ids.map((id) => [id, []]));
28231
- for (const e of intra) adj.get(e.from).push(e.to);
28276
+ for (const e of intra) known(adj, e.from).push(e.to);
28232
28277
  const state2 = /* @__PURE__ */ new Map();
28233
28278
  const kept = [];
28234
28279
  for (const root of ids) {
@@ -28238,7 +28283,7 @@ function laneRows(lane, edges) {
28238
28283
  while (stack.length) {
28239
28284
  const top = stack[stack.length - 1];
28240
28285
  const [u, k] = top;
28241
- const next = adj.get(u)[k];
28286
+ const next = known(adj, u)[k];
28242
28287
  if (next === void 0) {
28243
28288
  state2.set(u, 2);
28244
28289
  stack.pop();
@@ -28257,8 +28302,8 @@ function laneRows(lane, edges) {
28257
28302
  for (let changed = true, guard = 0; changed && guard <= ids.length; guard++) {
28258
28303
  changed = false;
28259
28304
  for (const [u, v] of kept) {
28260
- if (rank.get(v) < rank.get(u) + 1) {
28261
- rank.set(v, rank.get(u) + 1);
28305
+ if (known(rank, v) < known(rank, u) + 1) {
28306
+ rank.set(v, known(rank, u) + 1);
28262
28307
  changed = true;
28263
28308
  }
28264
28309
  }
@@ -28267,20 +28312,20 @@ function laneRows(lane, edges) {
28267
28312
  for (const id of ids) {
28268
28313
  const root = find(id);
28269
28314
  if (!blocks.has(root)) blocks.set(root, []);
28270
- blocks.get(root).push(id);
28315
+ known(blocks, root).push(id);
28271
28316
  }
28272
28317
  const rows = [];
28273
- for (const members2 of [...blocks.values()].sort((a, b) => pos.get(a[0]) - pos.get(b[0]))) {
28318
+ for (const members2 of [...blocks.values()].sort((a, b) => known(pos, a[0]) - known(pos, b[0]))) {
28274
28319
  const byRank = /* @__PURE__ */ new Map();
28275
28320
  for (const id of members2) {
28276
- const r = rank.get(id);
28321
+ const r = known(rank, id);
28277
28322
  if (!byRank.has(r)) byRank.set(r, []);
28278
- byRank.get(r).push(id);
28323
+ known(byRank, r).push(id);
28279
28324
  }
28280
28325
  for (const r of [...byRank.keys()].sort((a, b) => a - b)) {
28281
- const ids2 = byRank.get(r);
28282
- if (ids2.length <= 2) rows.push({ ids: ids2, pin: null });
28283
- else for (const id of ids2) rows.push({ ids: [id], pin: null });
28326
+ const ids2 = known(byRank, r);
28327
+ if (ids2.length <= 2) rows.push({ ids: ids2, pin: null, g: 0 });
28328
+ else for (const id of ids2) rows.push({ ids: [id], pin: null, g: 0 });
28284
28329
  }
28285
28330
  }
28286
28331
  return rows;
@@ -28297,13 +28342,13 @@ function applyPins(rows, byId) {
28297
28342
  continue;
28298
28343
  }
28299
28344
  if (!pinned.has(pin)) {
28300
- const pr2 = { ids: [], pin };
28345
+ const pr2 = { ids: [], pin, g: 0 };
28301
28346
  pinned.set(pin, pr2);
28302
28347
  out.push(pr2);
28303
28348
  }
28304
- pinned.get(pin).ids.push(id);
28349
+ known(pinned, pin).ids.push(id);
28305
28350
  }
28306
- if (free.length) out.push({ ids: free, pin: null });
28351
+ if (free.length) out.push({ ids: free, pin: null, g: 0 });
28307
28352
  }
28308
28353
  return out;
28309
28354
  }
@@ -28332,7 +28377,7 @@ function assignGlobalRows(lanes, edges) {
28332
28377
  const neighbors = /* @__PURE__ */ new Map();
28333
28378
  const link = (a, b) => {
28334
28379
  if (!neighbors.has(a)) neighbors.set(a, []);
28335
- neighbors.get(a).push(b);
28380
+ known(neighbors, a).push(b);
28336
28381
  };
28337
28382
  for (const e of edges) {
28338
28383
  const a = rowOf.get(e.from);
@@ -28368,9 +28413,9 @@ function assignGlobalRows(lanes, edges) {
28368
28413
  for (const lane of lanes) {
28369
28414
  lane.phys = /* @__PURE__ */ new Map();
28370
28415
  for (const r of lane.rows) {
28371
- const g = index.get(r.g);
28416
+ const g = known(index, r.g);
28372
28417
  if (!lane.phys.has(g)) lane.phys.set(g, []);
28373
- lane.phys.get(g).push(...r.ids);
28418
+ known(lane.phys, g).push(...r.ids);
28374
28419
  }
28375
28420
  }
28376
28421
  return used.length;
@@ -28411,7 +28456,7 @@ function placeColumns(lanes, byId, rowCount, sizes, model) {
28411
28456
  for (const lane of lanes) {
28412
28457
  let inner = L.laneMinW;
28413
28458
  for (const ids of lane.phys.values()) {
28414
- const w = ids.reduce((sum, id) => sum + natural.get(id).width, 0) + L.colGap * (ids.length - 1);
28459
+ const w = ids.reduce((sum, id) => sum + known(natural, id).width, 0) + L.colGap * (ids.length - 1);
28415
28460
  inner = Math.max(inner, w);
28416
28461
  }
28417
28462
  const label = lane.group?.label || "";
@@ -28422,13 +28467,13 @@ function placeColumns(lanes, byId, rowCount, sizes, model) {
28422
28467
  const sized = /* @__PURE__ */ new Map();
28423
28468
  for (const lane of lanes) {
28424
28469
  for (const ids of lane.phys.values()) {
28425
- const sum = ids.reduce((acc, id) => acc + natural.get(id).width, 0);
28470
+ const sum = ids.reduce((acc, id) => acc + known(natural, id).width, 0);
28426
28471
  const extra = (lane.inner - sum - L.colGap * (ids.length - 1)) / ids.length;
28427
- for (const id of ids) sized.set(id, sizeNode(byId.get(id), Math.floor(natural.get(id).width + extra)));
28472
+ for (const id of ids) sized.set(id, sizeNode(known(byId, id), Math.floor(known(natural, id).width + extra)));
28428
28473
  }
28429
28474
  }
28430
28475
  const rowH = new Array(rowCount).fill(0);
28431
- for (const lane of lanes) for (const [g, ids] of lane.phys) for (const id of ids) rowH[g] = Math.max(rowH[g], sized.get(id).height);
28476
+ for (const lane of lanes) for (const [g, ids] of lane.phys) for (const id of ids) rowH[g] = Math.max(rowH[g], known(sized, id).height);
28432
28477
  const rowTop = [];
28433
28478
  let y = L.margin + headH + L.lanePad;
28434
28479
  for (let g = 0; g < rowCount; g++) {
@@ -28446,7 +28491,7 @@ function placeColumns(lanes, byId, rowCount, sizes, model) {
28446
28491
  for (const [g, ids] of lane.phys) {
28447
28492
  let bx = x + L.lanePad;
28448
28493
  for (const id of ids) {
28449
- const b = sized.get(id);
28494
+ const b = known(sized, id);
28450
28495
  boxes.set(id, { ...b, x: bx, y: Math.round(rowTop[g] + (rowH[g] - b.height) / 2), rowIndex: g, laneIndex: lane.index });
28451
28496
  bx += b.width + L.colGap;
28452
28497
  }
@@ -28465,8 +28510,8 @@ function placeColumns(lanes, byId, rowCount, sizes, model) {
28465
28510
  channels.push({ key: "outB", axis: "y", lo: frameBottom, hi: height, fixed: true });
28466
28511
  const frameLines = { xs: lanes.flatMap((l) => [l.frame.x, l.frame.x + l.frame.w]), ys: [frameTop, frameBottom] };
28467
28512
  const sides = (e) => {
28468
- const a = boxes.get(e.from);
28469
- const b = boxes.get(e.to);
28513
+ const a = known(boxes, e.from);
28514
+ const b = known(boxes, e.to);
28470
28515
  if (a.laneIndex !== b.laneIndex) return b.laneIndex > a.laneIndex ? ["right", "left"] : ["left", "right"];
28471
28516
  if (b.rowIndex > a.rowIndex) return ["bottom", "top"];
28472
28517
  if (b.rowIndex < a.rowIndex) return ["top", "bottom"];
@@ -28476,8 +28521,8 @@ function placeColumns(lanes, byId, rowCount, sizes, model) {
28476
28521
  }
28477
28522
  function placeBands(lanes, byId, sizes, model, targetWidth) {
28478
28523
  const L = LANES;
28479
- const left = sizes.get("left");
28480
- const right = sizes.get("right");
28524
+ const left = known(sizes, "left");
28525
+ const right = known(sizes, "right");
28481
28526
  const target = (targetWidth || 360) / 0.85;
28482
28527
  const room = Math.max(180, Math.min(720, target - left - right - L.lanePad * 2 - 4));
28483
28528
  sizeLaneHeads(lanes, () => room);
@@ -28495,7 +28540,7 @@ function placeBands(lanes, byId, sizes, model, targetWidth) {
28495
28540
  if (prevBottom !== null) channels.push({ key: `band${lane.index}`, axis: "y", lo: prevBottom, hi: top, fixed: true });
28496
28541
  let first = true;
28497
28542
  for (const row of lane.rows) {
28498
- const natural = row.ids.map((id) => sizeNode(byId.get(id)));
28543
+ const natural = row.ids.map((id) => sizeNode(known(byId, id)));
28499
28544
  const fits = natural.reduce((sum, n) => sum + n.width, 0) + L.colGap * (row.ids.length - 1) <= room;
28500
28545
  const lines = fits ? [row.ids] : row.ids.map((id) => [id]);
28501
28546
  for (const ids of lines) {
@@ -28512,7 +28557,7 @@ function placeBands(lanes, byId, sizes, model, targetWidth) {
28512
28557
  }
28513
28558
  first = false;
28514
28559
  const w = (room - L.colGap * (ids.length - 1)) / ids.length;
28515
- const sized = ids.map((id) => sizeNode(byId.get(id), Math.floor(w)));
28560
+ const sized = ids.map((id) => sizeNode(known(byId, id), Math.floor(w)));
28516
28561
  const h = Math.max(...sized.map((b) => b.height));
28517
28562
  let bx = x0;
28518
28563
  ids.forEach((id, k) => {
@@ -28534,8 +28579,8 @@ function placeBands(lanes, byId, sizes, model, targetWidth) {
28534
28579
  channels.push({ key: "left", axis: "x", lo: 0, hi: left }, { key: "right", axis: "x", lo: width - right, hi: width });
28535
28580
  const frameLines = { xs: [left, width - right], ys: lanes.flatMap((l) => [l.frame.y, l.frame.y + l.frame.h]) };
28536
28581
  const sides = (e) => {
28537
- const a = boxes.get(e.from);
28538
- const b = boxes.get(e.to);
28582
+ const a = known(boxes, e.from);
28583
+ const b = known(boxes, e.to);
28539
28584
  if (a.rowIndex === b.rowIndex) return b.x > a.x ? ["right", "left"] : ["left", "right"];
28540
28585
  if (b.rowIndex === a.rowIndex + 1 && b.x < a.x + a.width && a.x < b.x + b.width) return ["bottom", "top"];
28541
28586
  return b.rowIndex > a.rowIndex ? ["right", "right"] : ["left", "left"];
@@ -28560,8 +28605,8 @@ function routeAll(geo, model) {
28560
28605
  continue;
28561
28606
  }
28562
28607
  const [fromSide, toSide] = geo.sides(e);
28563
- const a = boxes.get(e.from);
28564
- const b = boxes.get(e.to);
28608
+ const a = known(boxes, e.from);
28609
+ const b = known(boxes, e.to);
28565
28610
  edges.push({ id: e.id, from: e.from, to: e.to, fromSide: openSide(a, fromSide, b, boxes), toSide: openSide(b, toSide, a, boxes) });
28566
28611
  }
28567
28612
  const xs = [];
@@ -28576,7 +28621,7 @@ function routeAll(geo, model) {
28576
28621
  bounds: { x0: 1, y0: 1, x1: geo.width - 1, y1: geo.height - 1 }
28577
28622
  });
28578
28623
  for (const e of loops) {
28579
- const b = boxes.get(e.from);
28624
+ const b = known(boxes, e.from);
28580
28625
  const r = b.x + b.width;
28581
28626
  const bottom = b.y + b.height;
28582
28627
  routes.set(e.id, [
@@ -28635,19 +28680,19 @@ function placePorts(boxes, edges) {
28635
28680
  const add = (node2, side, other, edge, end) => {
28636
28681
  const key2 = `${node2}\0${side}`;
28637
28682
  if (!sides.has(key2)) sides.set(key2, { node: node2, side, items: [] });
28638
- sides.get(key2).items.push({ other, edge, end });
28683
+ known(sides, key2).items.push({ other, edge, end, want: 0, pos: 0 });
28639
28684
  };
28640
28685
  for (const e of edges) {
28641
28686
  add(e.from, e.fromSide, e.to, e, "fromPort");
28642
28687
  add(e.to, e.toSide, e.from, e, "toPort");
28643
28688
  }
28644
28689
  for (const { node: node2, side, items } of sides.values()) {
28645
- const b = boxes.get(node2);
28690
+ const b = known(boxes, node2);
28646
28691
  const horizontal = side === "left" || side === "right";
28647
28692
  const lo = horizontal ? b.y + 9 : b.x + 12;
28648
28693
  const hi = horizontal ? b.y + b.height - 9 : b.x + b.width - 12;
28649
28694
  for (const it2 of items) {
28650
- const o = boxes.get(it2.other);
28695
+ const o = known(boxes, it2.other);
28651
28696
  const oLo = horizontal ? o.y : o.x;
28652
28697
  const oHi = horizontal ? o.y + o.height : o.x + o.width;
28653
28698
  const sLo = horizontal ? b.y : b.x;
@@ -28728,10 +28773,11 @@ var Heap = class {
28728
28773
  };
28729
28774
  var COST = { bend: 36, overlap: 8, cross: 22, hug: 0.6 };
28730
28775
  var SEARCH = { weight: 1.5, maxSteps: 12e4, maxTracks: 14 };
28731
- function routeOrthogonal({ boxes, edges, xLines = [], yLines = [], avoid = { xs: [], ys: [] }, bounds }) {
28776
+ function routeOrthogonal({ boxes, edges: input2, xLines = [], yLines = [], avoid = { xs: [], ys: [] }, bounds }) {
28732
28777
  const C = LANES.clear;
28733
28778
  const S2 = LANES.stub;
28734
- placePorts(boxes, edges);
28779
+ placePorts(boxes, input2);
28780
+ const edges = input2;
28735
28781
  const stubOf = (p, side) => ({ x: p.x + NORMAL[side][0] * S2, y: p.y + NORMAL[side][1] * S2 });
28736
28782
  const rnd = (v) => Math.round(v * 2) / 2;
28737
28783
  const hugXs = /* @__PURE__ */ new Set();
@@ -28831,7 +28877,7 @@ function routeOrthogonal({ boxes, edges, xLines = [], yLines = [], avoid = { xs:
28831
28877
  const [i0, j0, i1, j1] = [ix(a.x), iy(a.y), ix(b.x), iy(b.y)];
28832
28878
  if (j0 === j1) for (let i = Math.min(i0, i1); i <= Math.max(i0, i1); i++) path16.push([i, j0]);
28833
28879
  else for (let j = Math.min(j0, j1); j <= Math.max(j0, j1); j++) path16.push([i0, j]);
28834
- if (path16.every(([i, j]) => i !== void 0 && j !== void 0)) mark(path16);
28880
+ if (path16.every((pt2) => pt2[0] !== void 0 && pt2[1] !== void 0)) mark(path16);
28835
28881
  continue;
28836
28882
  }
28837
28883
  }
@@ -29003,7 +29049,7 @@ function placeLabels(edges, routes, geo) {
29003
29049
  segs.push({ a, b, vertical, score });
29004
29050
  }
29005
29051
  segs.sort((p, q2) => q2.score - p.score);
29006
- const sizesToTry = [full, ...[GUTTER_LABEL_W, 76].filter((w) => w < full.width).map((w) => narrowLabel(e.label, w)).filter(Boolean)];
29052
+ const sizesToTry = [full, ...[GUTTER_LABEL_W, 76].filter((w) => w < full.width).map((w) => narrowLabel(e.label, w)).filter((lb) => !!lb)];
29007
29053
  let choice = null;
29008
29054
  let best = null;
29009
29055
  for (const lb of sizesToTry) {
@@ -29048,9 +29094,9 @@ function placeLabels(edges, routes, geo) {
29048
29094
  }
29049
29095
  function finish({ geo, routed }, model) {
29050
29096
  const { boxes, lanes } = geo;
29051
- const nodes = model.nodes.filter((n) => boxes.has(n.id)).map((n) => ({ ...n, ...boxes.get(n.id) }));
29097
+ const nodes = model.nodes.filter((n) => boxes.has(n.id)).map((n) => ({ ...n, ...known(boxes, n.id) }));
29052
29098
  const labels = placeLabels(model.edges, routed, geo);
29053
- const edges = model.edges.filter((e) => routed.has(e.id)).map((e) => ({ ...e, orthogonal: true, points: routed.get(e.id), labelBox: labels.get(e.id) || null }));
29099
+ const edges = model.edges.filter((e) => routed.has(e.id)).map((e) => ({ ...e, orthogonal: true, points: known(routed, e.id), labelBox: labels.get(e.id) || null }));
29054
29100
  const groups = [];
29055
29101
  for (const lane of lanes) {
29056
29102
  if (!lane.group) continue;
@@ -29059,7 +29105,7 @@ function finish({ geo, routed }, model) {
29059
29105
  }
29060
29106
  for (const g of model.groups) {
29061
29107
  if (!g.parent) continue;
29062
- const ms = g.members.map((id) => boxes.get(id)).filter(Boolean);
29108
+ const ms = g.members.map((id) => boxes.get(id)).filter((b) => !!b);
29063
29109
  if (!ms.length) continue;
29064
29110
  const pad = 9;
29065
29111
  const x0 = Math.min(...ms.map((b) => b.x)) - pad;
@@ -29084,7 +29130,7 @@ function finish({ geo, routed }, model) {
29084
29130
  return { rankdir: "lanes", nodes, edges, groups, width, height };
29085
29131
  }
29086
29132
 
29087
- // src/runtime/components/_architecture-model.js
29133
+ // src/runtime/components/_architecture-model.ts
29088
29134
  var NODE_KINDS = ["frontend", "backend", "database", "messagebus", "cloud", "security", "external"];
29089
29135
  var EDGE_STYLES = ["solid", "dashed", "emphasis", "security"];
29090
29136
  var GROUP_KINDS = ["region", "security", "plain"];
@@ -29156,8 +29202,9 @@ function wrapText(text, size, maxWidth, maxLines = 2, mono = false) {
29156
29202
  kept[maxLines - 1] = `${last.join("").trimEnd()}\u2026`;
29157
29203
  return kept;
29158
29204
  }
29159
- var isElement = (v) => v && typeof v === "object" && v.props && typeof v.props === "object";
29205
+ var isElement = (v) => !!v && typeof v === "object" && "props" in v && !!v.props && typeof v.props === "object";
29160
29206
  var str = (v) => typeof v === "string" ? v : v == null ? "" : String(v);
29207
+ var oneOf = (list, v) => list.includes(v);
29161
29208
  function buildModel(props) {
29162
29209
  const problems = [];
29163
29210
  const nodes = /* @__PURE__ */ new Map();
@@ -29165,7 +29212,8 @@ function buildModel(props) {
29165
29212
  let anon = 0;
29166
29213
  const addNode = (el) => {
29167
29214
  if (!isElement(el)) return null;
29168
- if (seenEls.has(el)) return seenEls.get(el);
29215
+ const seen = seenEls.get(el);
29216
+ if (seen !== void 0) return seen;
29169
29217
  const id = el.statementId || `_node${anon++}`;
29170
29218
  if (!nodes.has(id)) {
29171
29219
  const p = el.props;
@@ -29174,11 +29222,11 @@ function buildModel(props) {
29174
29222
  id,
29175
29223
  named: !!el.statementId,
29176
29224
  label,
29177
- kind: NODE_KINDS.includes(p.kind) ? p.kind : "backend",
29225
+ kind: oneOf(NODE_KINDS, p.kind) ? p.kind : "backend",
29178
29226
  detail: str(p.detail).trim(),
29179
29227
  tag: str(p.tag).trim(),
29180
- tone: NODE_TONES.includes(p.tone) ? p.tone : "",
29181
- row: Number.isInteger(p.row) && p.row > 0 ? Math.min(p.row, 200) : null
29228
+ tone: oneOf(NODE_TONES, p.tone) ? p.tone : "",
29229
+ row: typeof p.row === "number" && Number.isInteger(p.row) && p.row > 0 ? Math.min(p.row, 200) : null
29182
29230
  });
29183
29231
  }
29184
29232
  seenEls.set(el, id);
@@ -29201,8 +29249,8 @@ function buildModel(props) {
29201
29249
  from,
29202
29250
  to,
29203
29251
  label: str(el.props.label).trim(),
29204
- style: EDGE_STYLES.includes(el.props.style) ? el.props.style : "solid",
29205
- tone: EDGE_TONES.includes(el.props.tone) ? el.props.tone : ""
29252
+ style: oneOf(EDGE_STYLES, el.props.style) ? el.props.style : "solid",
29253
+ tone: oneOf(EDGE_TONES, el.props.tone) ? el.props.tone : ""
29206
29254
  });
29207
29255
  }
29208
29256
  const groups = [];
@@ -29211,19 +29259,19 @@ function buildModel(props) {
29211
29259
  if (!isElement(el)) continue;
29212
29260
  const id = el.statementId || `_group${anon++}`;
29213
29261
  if (groupIds.has(id)) continue;
29214
- const members2 = [...new Set((Array.isArray(el.props.members) ? el.props.members : []).map(addNode).filter(Boolean))];
29262
+ const members2 = [...new Set((Array.isArray(el.props.members) ? el.props.members : []).map(addNode).filter((m) => !!m))];
29215
29263
  if (!members2.length) continue;
29216
29264
  groupIds.add(id);
29217
29265
  groups.push({
29218
29266
  id,
29219
29267
  named: !!el.statementId,
29220
29268
  label: str(el.props.label).trim(),
29221
- kind: GROUP_KINDS.includes(el.props.kind) ? el.props.kind : "region",
29269
+ kind: oneOf(GROUP_KINDS, el.props.kind) ? el.props.kind : "region",
29222
29270
  members: members2
29223
29271
  });
29224
29272
  }
29225
29273
  nestGroups(groups, problems);
29226
- const direction = DIRECTIONS.includes(props?.direction) ? props.direction : "auto";
29274
+ const direction = oneOf(DIRECTIONS, props?.direction) ? props.direction : "auto";
29227
29275
  return { nodes: [...nodes.values()], edges, groups, direction, problems };
29228
29276
  }
29229
29277
  function nestGroups(groups, problems) {
@@ -29240,8 +29288,9 @@ function nestGroups(groups, problems) {
29240
29288
  else {
29241
29289
  let first = groups.find((x) => x.id === owner.get(m));
29242
29290
  if (!isAncestor(groups, g.id, first.id)) {
29243
- for (let up = groups.find((x) => x.id === first.parent); up; up = groups.find((x) => x.id === up.parent)) {
29244
- if (g.members.every((x) => up.memberSet.has(x))) break;
29291
+ for (let up = groups.find((x) => x.id === first.parent); up; up = groups.find((x) => x.id === up?.parent)) {
29292
+ const set2 = up.memberSet;
29293
+ if (g.members.every((x) => set2.has(x))) break;
29245
29294
  first = up;
29246
29295
  }
29247
29296
  problems.push(
@@ -29257,7 +29306,8 @@ function isAncestor(groups, ancestorId, id) {
29257
29306
  let cur = groups.find((g) => g.id === id);
29258
29307
  while (cur?.parent) {
29259
29308
  if (cur.parent === ancestorId) return true;
29260
- cur = groups.find((g) => g.id === cur.parent);
29309
+ const parent = cur.parent;
29310
+ cur = groups.find((g) => g.id === parent);
29261
29311
  }
29262
29312
  return false;
29263
29313
  }
@@ -29267,7 +29317,7 @@ function detailLinesFor(detail, width) {
29267
29317
  const lines = [];
29268
29318
  for (let i = 0; i < parts.length; i++) {
29269
29319
  if (lines.length === 2) {
29270
- const last = lines.pop().replace(/…$/, "");
29320
+ const last = (lines.pop() ?? "").replace(/…$/, "");
29271
29321
  lines.push(wrapText(`${last} ${parts.slice(i).join(" ")}`, SIZES.detail, width, 1, true)[0]);
29272
29322
  break;
29273
29323
  }
@@ -29311,7 +29361,7 @@ function runLayout(model, rankdir) {
29311
29361
  for (const grp of model.groups) g.setNode(`group:${grp.id}`, {});
29312
29362
  for (const grp of model.groups) {
29313
29363
  if (grp.parent) g.setParent(`group:${grp.id}`, `group:${grp.parent}`);
29314
- for (const m of grp.directMembers) g.setParent(m, `group:${grp.id}`);
29364
+ for (const m of grp.directMembers ?? []) g.setParent(m, `group:${grp.id}`);
29315
29365
  }
29316
29366
  const labels = new Map(model.edges.map((e) => [e.id, sizeEdgeLabel(e.label)]));
29317
29367
  for (const e of model.edges) {
@@ -29351,8 +29401,10 @@ function runLayout(model, rankdir) {
29351
29401
  const cx = n.x + n.width / 2;
29352
29402
  const cy = n.y + n.height / 2;
29353
29403
  const placed = Number.isFinite(d.x) && Number.isFinite(d.y);
29404
+ const dx = d.x;
29405
+ const dy = d.y;
29354
29406
  if (rankdir === "TB") {
29355
- const lx = placed ? d.x : r + 30 + (e.labelBox ? e.labelBox.width / 2 : 0);
29407
+ const lx = placed ? dx : r + 30 + (e.labelBox ? e.labelBox.width / 2 : 0);
29356
29408
  const reach = Math.max(r + 18, e.labelBox ? lx - e.labelBox.width / 2 - 3 : lx);
29357
29409
  const y1 = cy - n.height * 0.22;
29358
29410
  const y2 = cy + n.height * 0.22;
@@ -29364,7 +29416,7 @@ function runLayout(model, rankdir) {
29364
29416
  ];
29365
29417
  if (e.labelBox) e.labelBox = { ...e.labelBox, cx: Math.max(lx, reach + 3 + e.labelBox.width / 2), cy };
29366
29418
  } else {
29367
- const ly = placed ? d.y : b + 30 + (e.labelBox ? e.labelBox.height / 2 : 0);
29419
+ const ly = placed ? dy : b + 30 + (e.labelBox ? e.labelBox.height / 2 : 0);
29368
29420
  const reach = Math.max(b + 16, e.labelBox ? ly - e.labelBox.height / 2 - 3 : ly);
29369
29421
  const spread = Math.min(30, n.width * 0.3);
29370
29422
  e.points = [
@@ -29431,7 +29483,7 @@ function architectureNotes(props) {
29431
29483
  return notes;
29432
29484
  }
29433
29485
 
29434
- // src/shared/check-program.js
29486
+ // src/shared/check-program.ts
29435
29487
  function elementsOf(root, typeName) {
29436
29488
  const out = [];
29437
29489
  const seen = /* @__PURE__ */ new Set();
@@ -29440,8 +29492,9 @@ function elementsOf(root, typeName) {
29440
29492
  const v = stack.pop();
29441
29493
  if (!v || typeof v !== "object" || seen.has(v)) continue;
29442
29494
  seen.add(v);
29443
- if (v.typeName === typeName && v.props) out.push(v);
29444
- for (const child of Array.isArray(v) ? v : Object.values(v.props || {})) stack.push(child);
29495
+ const node2 = v;
29496
+ if (node2.typeName === typeName && node2.props) out.push(node2);
29497
+ for (const child of Array.isArray(v) ? v : Object.values(node2.props || {})) stack.push(child);
29445
29498
  }
29446
29499
  return out;
29447
29500
  }
@@ -29452,10 +29505,7 @@ function checkProgram(program, { parser, lineOf = () => void 0, decorate = (entr
29452
29505
  try {
29453
29506
  parsed = parser().parse(program);
29454
29507
  } catch (err) {
29455
- errors.push({ code: "parse-failed", message: String(
29456
- /** @type {any} */
29457
- err?.message || err
29458
- ) });
29508
+ errors.push({ code: "parse-failed", message: String((err && typeof err === "object" && "message" in err ? err.message : void 0) || err) });
29459
29509
  return { statements: 0, errors, warnings };
29460
29510
  }
29461
29511
  const seen = /* @__PURE__ */ new Set();
@@ -29513,22 +29563,24 @@ function checkProgram(program, { parser, lineOf = () => void 0, decorate = (entr
29513
29563
  return { statements: parsed.meta.statementCount, errors, warnings };
29514
29564
  }
29515
29565
 
29516
- // src/cli/check.js
29566
+ // src/cli/check.ts
29517
29567
  var coreSpec = null;
29518
29568
  var packParsers = /* @__PURE__ */ new Map();
29519
29569
  var customParsers = /* @__PURE__ */ new WeakMap();
29520
29570
  function getParser(schema, packs = []) {
29521
29571
  if (schema) {
29522
- if (!customParsers.has(schema)) customParsers.set(schema, createParser(schema, schema.root || "Stack"));
29523
- return customParsers.get(schema);
29572
+ let custom2 = customParsers.get(schema);
29573
+ if (!custom2) customParsers.set(schema, custom2 = createParser(schema, schema.root || "Stack"));
29574
+ return custom2;
29524
29575
  }
29525
29576
  const key2 = packs.map((p) => `${p.name}@${p.version}:${p.integrity || ""}`).join(",");
29526
- if (!packParsers.has(key2)) {
29527
- coreSpec ||= JSON.parse(fs3.readFileSync(assetPath("spec.json"), "utf8"));
29528
- const spec = mergePackSchemas(coreSpec, packs.map((p) => p.catalog));
29529
- packParsers.set(key2, createParser(spec, spec.root || "Stack"));
29577
+ let parser = packParsers.get(key2);
29578
+ if (!parser) {
29579
+ const core2 = coreSpec ||= JSON.parse(fs3.readFileSync(assetPath("spec.json"), "utf8"));
29580
+ const spec = mergePackSchemas(core2, packs.map((p) => p.catalog));
29581
+ packParsers.set(key2, parser = createParser(spec, spec.root || "Stack"));
29530
29582
  }
29531
- return packParsers.get(key2);
29583
+ return parser;
29532
29584
  }
29533
29585
  function unknownComponent(entry, packs, file3) {
29534
29586
  const name = entry.component;
@@ -29561,7 +29613,7 @@ function statementLines(html) {
29561
29613
  }
29562
29614
  function checkHtml(html, { schema, file: file3 = "<file>" } = {}) {
29563
29615
  const art = readArtifact(html);
29564
- const packs = schema ? { installed: [], missing: [], mismatched: [], stale: [], declared: [] } : pagePacks(html);
29616
+ const packs = schema ? { installed: [], missing: [], mismatched: [], stale: [], declared: [], thirdParty: [] } : pagePacks(html);
29565
29617
  const result = { ok: true, errors: [], warnings: [], statements: 0, title: art.title, hasMermaid: false };
29566
29618
  if (art.program == null) {
29567
29619
  result.ok = false;
@@ -29609,7 +29661,7 @@ function checkHtml(html, { schema, file: file3 = "<file>" } = {}) {
29609
29661
  return result;
29610
29662
  }
29611
29663
 
29612
- // src/cli/main.js
29664
+ // src/cli/main.ts
29613
29665
  init_client();
29614
29666
  init_hub();
29615
29667
  init_invites();
@@ -29617,7 +29669,7 @@ init_lock();
29617
29669
  init_sessions();
29618
29670
  init_export();
29619
29671
 
29620
- // src/cli/output.js
29672
+ // src/cli/output.ts
29621
29673
  var PLAIN = /^[A-Za-z0-9_./@:+-][A-Za-z0-9 _./@:+(),=<>*#%?!'-]*$/;
29622
29674
  var json2 = (v) => JSON.stringify(v).replace(/[\u0085\u2028\u2029]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
29623
29675
  function scalar(v) {
@@ -29629,13 +29681,14 @@ function scalar(v) {
29629
29681
  return json2(s);
29630
29682
  }
29631
29683
  function isPlainObject2(v) {
29632
- return v && typeof v === "object" && !Array.isArray(v);
29684
+ return !!v && typeof v === "object" && !Array.isArray(v);
29633
29685
  }
29686
+ var isList = (v) => Array.isArray(v);
29634
29687
  var KEY = /^[A-Za-z_][A-Za-z0-9_.-]*$/;
29635
29688
  var key = (k) => KEY.test(k) ? k : json2(k);
29636
29689
  function emit(value, indent, lines) {
29637
29690
  const pad = " ".repeat(indent);
29638
- if (Array.isArray(value)) {
29691
+ if (isList(value)) {
29639
29692
  if (!value.length) return;
29640
29693
  for (const item of value) {
29641
29694
  if (isPlainObject2(item)) {
@@ -29655,7 +29708,7 @@ function emit(value, indent, lines) {
29655
29708
  }
29656
29709
  for (const [k, v] of Object.entries(value)) {
29657
29710
  if (v === void 0) continue;
29658
- if (Array.isArray(v)) {
29711
+ if (isList(v)) {
29659
29712
  if (!v.length) continue;
29660
29713
  if (v.every((x) => !isPlainObject2(x) && !Array.isArray(x)) && v.join(", ").length < 100) {
29661
29714
  lines.push(`${pad}${key(k)}: [${v.map(scalar).join(", ")}]`);
@@ -29694,10 +29747,10 @@ function print(obj) {
29694
29747
  process.stdout.write(format(obj) + "\n");
29695
29748
  }
29696
29749
 
29697
- // src/shared/feedback.js
29750
+ // src/shared/feedback.ts
29698
29751
  function locator(lines) {
29699
29752
  return (id) => {
29700
- const l = lines.get(id);
29753
+ const l = id === void 0 ? void 0 : lines.get(id);
29701
29754
  if (!l) return {};
29702
29755
  const first = l.text.split("\n")[0];
29703
29756
  return { line: l.line, source: first.length > 110 ? first.slice(0, 109) + "\u2026" : first };
@@ -29726,10 +29779,10 @@ function describeItem(it2, at2) {
29726
29779
  return { message: it2.text ?? it2.note ?? "" };
29727
29780
  }
29728
29781
 
29729
- // src/cli/main.js
29782
+ // src/cli/main.ts
29730
29783
  init_paths();
29731
29784
 
29732
- // src/cli/components.js
29785
+ // src/cli/components.ts
29733
29786
  init_packs();
29734
29787
  init_catalog();
29735
29788
  var BIN = "austere-axi";
@@ -29826,9 +29879,13 @@ function showComponents(names) {
29826
29879
  return out;
29827
29880
  }
29828
29881
 
29829
- // src/cli/main.js
29882
+ // src/cli/main.ts
29830
29883
  init_packs();
29831
29884
  process.env.OPENUI_TELEMETRY_DISABLED = process.env.OPENUI_TELEMETRY_DISABLED || "1";
29885
+ function messageOf(err) {
29886
+ const e = err;
29887
+ return e.message;
29888
+ }
29832
29889
  var BIN2 = "austere-axi";
29833
29890
  var HELP = `${BIN2} ${VERSION} \u2014 review artifacts written in OpenUI Lang. You write a short
29834
29891
  program instead of a whole HTML page; the reviewer annotates it in the browser;
@@ -30043,7 +30100,7 @@ function parseArgs(argv) {
30043
30100
  if (i + 1 >= argv.length) return { flags, pos, error: `--${key2} needs a value` };
30044
30101
  val = argv[++i];
30045
30102
  }
30046
- if (key2 === "also-listen") (flags[key2] ||= []).push(val);
30103
+ if (key2 === "also-listen") (flags["also-listen"] ||= []).push(String(val));
30047
30104
  else flags[key2] = val;
30048
30105
  } else if (a === "-h") flags.help = true;
30049
30106
  else if (a === "-v" || a === "-V") flags.version = true;
@@ -30133,7 +30190,7 @@ async function cmdHome() {
30133
30190
  }
30134
30191
  async function cmdOpen(file3, flags) {
30135
30192
  const abs = needFile(file3, "open");
30136
- if (!abs) return;
30193
+ if (!abs || file3 === void 0) return;
30137
30194
  const html = fs14.readFileSync(abs, "utf8");
30138
30195
  const check2 = checkHtml(html, { file: quote(file3) });
30139
30196
  await ensureServer();
@@ -30180,7 +30237,8 @@ function describeItems(abs, items) {
30180
30237
  return items.map((it2) => {
30181
30238
  let o;
30182
30239
  try {
30183
- o = describeItem(it2, at2);
30240
+ const item = it2;
30241
+ o = describeItem(item, at2);
30184
30242
  } catch {
30185
30243
  o = { malformed: `could not read this ${typeof it2?.kind === "string" ? it2.kind : "feedback"} item` };
30186
30244
  }
@@ -30204,11 +30262,12 @@ var NEXT = {
30204
30262
  timeout: (f) => `No feedback yet. Run \`${BIN2} poll ${f}\` again.`
30205
30263
  };
30206
30264
  function seqFlag(flags, name) {
30207
- return typeof flags[name] === "string" ? flags[name] : void 0;
30265
+ const v = flags[name];
30266
+ return typeof v === "string" ? v : void 0;
30208
30267
  }
30209
30268
  async function cmdPoll(file3, flags) {
30210
30269
  const abs = needFile(file3, "poll");
30211
- if (!abs) return;
30270
+ if (!abs || file3 === void 0) return;
30212
30271
  await ensureServer();
30213
30272
  const reply = await replyText(flags);
30214
30273
  if (!reply && (flags["agent-reply"] !== void 0 || flags["agent-reply-file"] !== void 0)) {
@@ -30229,7 +30288,7 @@ async function cmdPoll(file3, flags) {
30229
30288
  takeover: !!flags.takeover,
30230
30289
  timeoutMs: flags["timeout-ms"] ? Number(flags["timeout-ms"]) : void 0
30231
30290
  });
30232
- } catch (err) {
30291
+ } catch {
30233
30292
  if (ticker) clearInterval(ticker);
30234
30293
  return print({ status: "interrupted", file: abs, next: NEXT.interrupted(quote(file3)) });
30235
30294
  }
@@ -30261,7 +30320,7 @@ async function cmdPoll(file3, flags) {
30261
30320
  const out = { status: d.status || "unknown", file: abs };
30262
30321
  if (d.endedBy) out.ended_by = d.endedBy;
30263
30322
  if (d.closed) out.closed = "by the owner";
30264
- if (NEXT[d.status]) out.next = NEXT[d.status](f);
30323
+ if (d.status && NEXT[d.status]) out.next = NEXT[d.status](f);
30265
30324
  print(out);
30266
30325
  }
30267
30326
  async function cmdReply(file3, flags) {
@@ -30285,7 +30344,7 @@ async function cmdEnd(file3) {
30285
30344
  }
30286
30345
  async function cmdLock(file3, route) {
30287
30346
  const abs = needFile(file3, route);
30288
- if (!abs) return;
30347
+ if (!abs || file3 === void 0) return;
30289
30348
  await ensureServer();
30290
30349
  const r = await request("POST", `/api/${route}`, { file: abs }, { timeoutMs: 1e4 });
30291
30350
  if (r.status === 404) return fail(`no review session for this file; open it first: ${BIN2} ${quote(file3)}`);
@@ -30316,7 +30375,7 @@ function fixPacks(abs, html) {
30316
30375
  }
30317
30376
  async function cmdCheck(file3, flags = {}) {
30318
30377
  const abs = needFile(file3, "check");
30319
- if (!abs) return;
30378
+ if (!abs || file3 === void 0) return;
30320
30379
  let html = fs14.readFileSync(abs, "utf8");
30321
30380
  let fixed = [];
30322
30381
  if (flags.fix) ({ html, changes: fixed } = fixPacks(abs, html));
@@ -30332,7 +30391,7 @@ async function cmdCheck(file3, flags = {}) {
30332
30391
  }
30333
30392
  async function cmdPatch(file3) {
30334
30393
  const abs = needFile(file3, "patch");
30335
- if (!abs) return;
30394
+ if (!abs || file3 === void 0) return;
30336
30395
  if (process.stdin.isTTY) return usage(`pipe the changed statements on stdin: ${BIN2} patch ${quote(file3)} <<'EOF' ... EOF`, "patch");
30337
30396
  const patch = await readStdin();
30338
30397
  if (!patch.trim()) return fail("stdin was empty");
@@ -30400,7 +30459,7 @@ function cmdExport(file3, flags) {
30400
30459
  }
30401
30460
  function printResult(out) {
30402
30461
  print(out);
30403
- if (out && out.status === "error") process.exitCode = 1;
30462
+ if (out && "status" in out && out.status === "error") process.exitCode = 1;
30404
30463
  }
30405
30464
  async function cmdComponents(sub, args, flags) {
30406
30465
  switch (sub) {
@@ -30417,7 +30476,8 @@ async function cmdComponents(sub, args, flags) {
30417
30476
  let r;
30418
30477
  try {
30419
30478
  r = await addPack2(args[0], { trust: !!flags.trust });
30420
- } catch (err) {
30479
+ } catch (caught) {
30480
+ const err = caught;
30421
30481
  const out = { status: err.code === "untrusted" ? "needs --trust" : "error", error: err.message };
30422
30482
  if (err.network) out.next = `Offline or behind a proxy? \`npm pack ${args[0]}\` downloads it; then \`${BIN2} components add ./<file>.tgz\`.`;
30423
30483
  print(out);
@@ -30457,7 +30517,7 @@ async function cmdComponents(sub, args, flags) {
30457
30517
  next: `cd ${quote(path14.relative(process.cwd(), r.dir) || ".")} && npm install && npm run build, then \`${BIN2} components add .\``
30458
30518
  });
30459
30519
  } catch (err) {
30460
- return fail(err.message);
30520
+ return fail(messageOf(err));
30461
30521
  }
30462
30522
  }
30463
30523
  case "build": {
@@ -30474,7 +30534,7 @@ async function cmdComponents(sub, args, flags) {
30474
30534
  next: `\`${BIN2} components add ${quote(args[0] || ".")}\` to use it here (again after each build), then \`${BIN2} check --fix <file>\` on pages that use it.`
30475
30535
  });
30476
30536
  } catch (err) {
30477
- return fail(err.message);
30537
+ return fail(messageOf(err));
30478
30538
  }
30479
30539
  }
30480
30540
  default: {
@@ -30491,7 +30551,7 @@ function shortDate(ms) {
30491
30551
  }
30492
30552
  async function cmdFeedback(file3, flags) {
30493
30553
  const abs = needFile(file3, "feedback");
30494
- if (!abs) return;
30554
+ if (!abs || file3 === void 0) return;
30495
30555
  const opts = { all: !!flags.all, peek: !!flags.peek };
30496
30556
  let entries = null;
30497
30557
  let status = null;
@@ -30574,7 +30634,7 @@ async function cmdHub(sub, args, flags) {
30574
30634
  hub.close();
30575
30635
  }
30576
30636
  } catch (err) {
30577
- out.index = `${hubDbFile()} cannot be opened: ${err.message}`;
30637
+ out.index = `${hubDbFile()} cannot be opened: ${messageOf(err)}`;
30578
30638
  }
30579
30639
  }
30580
30640
  if (!hubEnabled()) out.next = `\`${BIN2} hub on\` shows a home page with every artifact and note.`;
@@ -30587,7 +30647,7 @@ async function cmdHub(sub, args, flags) {
30587
30647
  try {
30588
30648
  hub = await Hub.open();
30589
30649
  } catch (err) {
30590
- return fail(`${hubDbFile()} cannot be opened: ${err.message}`);
30650
+ return fail(`${hubDbFile()} cannot be opened: ${messageOf(err)}`);
30591
30651
  }
30592
30652
  let rows;
30593
30653
  try {
@@ -30613,7 +30673,7 @@ async function cmdHub(sub, args, flags) {
30613
30673
  try {
30614
30674
  hub = await Hub.open();
30615
30675
  } catch (err) {
30616
- return fail(`${hubDbFile()} cannot be opened: ${err.message}`);
30676
+ return fail(`${hubDbFile()} cannot be opened: ${messageOf(err)}`);
30617
30677
  }
30618
30678
  let rows;
30619
30679
  try {
@@ -30721,7 +30781,7 @@ async function cmdLogin(file3) {
30721
30781
  if (!abs) return;
30722
30782
  }
30723
30783
  await ensureServer();
30724
- if (abs) {
30784
+ if (abs && file3) {
30725
30785
  const r = await request("GET", "/api/sessions");
30726
30786
  if (r.status !== 200) return fail(r.data?.error || `login failed (${r.status})`);
30727
30787
  const s = (r.data.sessions || []).find((x) => x.file === abs);
@@ -30814,8 +30874,9 @@ async function main() {
30814
30874
  return cmdOpen(cmd, flags);
30815
30875
  }
30816
30876
  }
30817
- main().catch((err) => {
30818
- process.stdout.write(format({ status: "error", error: String(err?.message || err) }) + "\n");
30877
+ main().catch((caught) => {
30878
+ const err = caught;
30879
+ process.stdout.write(format({ status: "error", error: String(err?.message || caught) }) + "\n");
30819
30880
  process.exitCode = 1;
30820
30881
  });
30821
30882
  /*! Bundled license information: