latticesql 4.3.0 → 4.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29043,12 +29043,12 @@ var getNodeModulesParentDirs;
29043
29043
  var init_getNodeModulesParentDirs = __esm({
29044
29044
  "node_modules/@aws-sdk/core/dist-es/submodules/client/util-user-agent-node/getNodeModulesParentDirs.js"() {
29045
29045
  "use strict";
29046
- getNodeModulesParentDirs = (dirname17) => {
29046
+ getNodeModulesParentDirs = (dirname18) => {
29047
29047
  const cwd = process.cwd();
29048
- if (!dirname17) {
29048
+ if (!dirname18) {
29049
29049
  return [cwd];
29050
29050
  }
29051
- const normalizedPath = normalize(dirname17);
29051
+ const normalizedPath = normalize(dirname18);
29052
29052
  const parts = normalizedPath.split(sep6);
29053
29053
  const nodeModulesIndex = parts.indexOf("node_modules");
29054
29054
  const parentDir = nodeModulesIndex !== -1 ? parts.slice(0, nodeModulesIndex).join(sep6) : normalizedPath;
@@ -29126,8 +29126,8 @@ var init_getTypeScriptUserAgentPair = __esm({
29126
29126
  tscVersion = null;
29127
29127
  return void 0;
29128
29128
  }
29129
- const dirname17 = typeof __dirname !== "undefined" ? __dirname : void 0;
29130
- const nodeModulesParentDirs = getNodeModulesParentDirs(dirname17);
29129
+ const dirname18 = typeof __dirname !== "undefined" ? __dirname : void 0;
29130
+ const nodeModulesParentDirs = getNodeModulesParentDirs(dirname18);
29131
29131
  let versionFromApp;
29132
29132
  for (const nodeModulesParentDir of nodeModulesParentDirs) {
29133
29133
  try {
@@ -57916,9 +57916,9 @@ var init_dist_es22 = __esm({
57916
57916
  init_http();
57917
57917
  import { createServer } from "http";
57918
57918
  import { spawn as spawn2 } from "child_process";
57919
- import { existsSync as existsSync31 } from "fs";
57919
+ import { existsSync as existsSync32 } from "fs";
57920
57920
  import { WebSocketServer, WebSocket } from "ws";
57921
- import { dirname as dirname16, resolve as resolve15 } from "path";
57921
+ import { dirname as dirname17, resolve as resolve15 } from "path";
57922
57922
 
57923
57923
  // src/gui/active-db.ts
57924
57924
  init_adapter();
@@ -60123,12 +60123,16 @@ var tokensCss = `
60123
60123
  surface (a bare input on a modal, the Database wizard, User Config, etc.):
60124
60124
  dark text on a white field with a light border. Placeholders use the
60125
60125
  muted token. Affects every input/select/textarea across the GUI. */
60126
- input, select, textarea {
60126
+ /* Text-like fields only \u2014 radios/checkboxes keep their native rendering
60127
+ (the box/border treatment mangles them). The accent color tints the native
60128
+ controls so checked radios/checkboxes are on-brand blue. */
60129
+ input:not([type='radio']):not([type='checkbox']):not([type='range']), select, textarea {
60127
60130
  color: var(--text);
60128
60131
  background: var(--surface);
60129
60132
  border: 1px solid var(--border);
60130
60133
  border-radius: 6px;
60131
60134
  }
60135
+ input[type='radio'], input[type='checkbox'] { accent-color: var(--accent); }
60132
60136
  input::placeholder, textarea::placeholder {
60133
60137
  color: var(--text-muted);
60134
60138
  opacity: 1;
@@ -61113,7 +61117,7 @@ var teamsCss = ` /* \u2500\u2500 Teams (Project Config + User Config) \u2500\
61113
61117
  color: var(--text); font-weight: 500;
61114
61118
  text-transform: uppercase; letter-spacing: 0.04em;
61115
61119
  }
61116
- .modal .field input, .modal .field textarea {
61120
+ .modal .field input:not([type='radio']):not([type='checkbox']), .modal .field textarea {
61117
61121
  width: 100%; padding: 6px 8px;
61118
61122
  background: var(--surface); color: var(--text);
61119
61123
  border: 1px solid var(--border-strong);
@@ -61123,6 +61127,20 @@ var teamsCss = ` /* \u2500\u2500 Teams (Project Config + User Config) \u2500\
61123
61127
  color: var(--text-muted);
61124
61128
  }
61125
61129
  .modal .field textarea { min-height: 60px; font-family: ui-monospace, monospace; font-size: 12px; }
61130
+ /* New-workspace "Kind" selector \u2014 clean cards, blue-highlighted selection. */
61131
+ .wiz-kind-opts { display: flex; gap: 10px; margin-top: 6px; flex-wrap: wrap; }
61132
+ .wiz-kind-card {
61133
+ flex: 1 1 0; min-width: 132px; display: flex; align-items: center; gap: 9px;
61134
+ padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px;
61135
+ background: var(--surface); cursor: pointer;
61136
+ transition: border-color 0.12s ease, background 0.12s ease;
61137
+ }
61138
+ .wiz-kind-card:hover { border-color: var(--border-strong); }
61139
+ .wiz-kind-card:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
61140
+ .wiz-kind-card input { margin: 0; flex: 0 0 auto; }
61141
+ .wiz-kind-name { font-size: 13px; color: var(--text); text-transform: none; letter-spacing: 0; }
61142
+ .wiz-kind-sub { color: var(--text-muted); font-size: 11px; margin-left: 2px; }
61143
+ .wiz-kind-card:has(input:checked) .wiz-kind-name { color: var(--accent-deep); font-weight: 500; }
61126
61144
  .modal .copy-token {
61127
61145
  padding: 8px 10px; background: var(--surface-2); border: 1px solid var(--border);
61128
61146
  border-radius: 4px; font-family: ui-monospace, monospace; font-size: 12px;
@@ -62368,6 +62386,9 @@ var bootJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
62368
62386
  initRailDragDrop();
62369
62387
  renderComposer();
62370
62388
  initThreadControls();
62389
+ // Warm up on-device voice in the background shortly after boot so dictation
62390
+ // is ready on first use \u2014 no visible model-loading step, ever.
62391
+ if (typeof voicePreload === 'function') setTimeout(voicePreload, 1500);
62371
62392
  checkNativeSetup();
62372
62393
  // App is fully populated \u2014 reveal it (Feature C).
62373
62394
  hideAppLoading();
@@ -66131,9 +66152,14 @@ var dashboardJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
66131
66152
  }
66132
66153
  var d = displayFor(table);
66133
66154
  // The tab shows the open RECORD's name (e.g. an entity row), not the
66134
- // object/table name.
66155
+ // object/table name. Guard: only retitle a RECORD ('item:') tab \u2014 never the
66156
+ // shared Brain Graph ('graph') tab, even if a record render briefly runs
66157
+ // while the hash still resolves to the graph (which would rename \u{1F9E0}).
66135
66158
  if (typeof setTabTitle === 'function') {
66136
- setTabTitle(tabKeyForHash(location.hash), fsDisplayName(row) || d.label);
66159
+ var fsItemKey = tabKeyForHash(location.hash);
66160
+ if (fsItemKey && fsItemKey.indexOf('item:') === 0) {
66161
+ setTabTitle(fsItemKey, fsDisplayName(row) || d.label);
66162
+ }
66137
66163
  }
66138
66164
  // Files + artifacts get the two-view document layout (formatted display +
66139
66165
  // a View Source toggle) with a Version History + Delete dropdown \u2014 not the
@@ -66203,7 +66229,10 @@ var dashboardJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
66203
66229
  // The tab shows the FILE's name (e.g. "Properties Dashboard"), not the
66204
66230
  // object name ("Files").
66205
66231
  if (typeof setTabTitle === 'function') {
66206
- setTabTitle(tabKeyForHash(location.hash), fsDisplayName(row) || d.label);
66232
+ var fsDocKey = tabKeyForHash(location.hash);
66233
+ if (fsDocKey && fsDocKey.indexOf('item:') === 0) {
66234
+ setTabTitle(fsDocKey, fsDisplayName(row) || d.label);
66235
+ }
66207
66236
  }
66208
66237
  var mode = fileViewMode[id] || 'display';
66209
66238
  // Actions live in a dropdown menu next to the title; View source / Version
@@ -68410,15 +68439,18 @@ var dataModelJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
68410
68439
  return '' +
68411
68440
  nameField +
68412
68441
  '<div class="field"><label>Kind</label>' +
68413
- '<div style="display:flex;gap:16px;margin-top:4px;flex-wrap:wrap">' +
68414
- '<label style="display:flex;align-items:center;gap:6px;font-weight:400;text-transform:none;letter-spacing:0">' +
68415
- '<input type="radio" name="wiz-kind" value="local"' + (kind === 'local' ? ' checked' : '') + ' /> New local (SQLite)' +
68442
+ '<div class="wiz-kind-opts">' +
68443
+ '<label class="wiz-kind-card">' +
68444
+ '<input type="radio" name="wiz-kind" value="local"' + (kind === 'local' ? ' checked' : '') + ' />' +
68445
+ '<span class="wiz-kind-name">New local <span class="wiz-kind-sub">SQLite</span></span>' +
68416
68446
  '</label>' +
68417
- '<label style="display:flex;align-items:center;gap:6px;font-weight:400;text-transform:none;letter-spacing:0">' +
68418
- '<input type="radio" name="wiz-kind" value="cloud"' + (kind === 'cloud' ? ' checked' : '') + ' /> New cloud (Postgres)' +
68447
+ '<label class="wiz-kind-card">' +
68448
+ '<input type="radio" name="wiz-kind" value="cloud"' + (kind === 'cloud' ? ' checked' : '') + ' />' +
68449
+ '<span class="wiz-kind-name">New cloud <span class="wiz-kind-sub">Postgres</span></span>' +
68419
68450
  '</label>' +
68420
- '<label style="display:flex;align-items:center;gap:6px;font-weight:400;text-transform:none;letter-spacing:0">' +
68421
- '<input type="radio" name="wiz-kind" value="join"' + (kind === 'join' ? ' checked' : '') + ' /> Join a team (invite)' +
68451
+ '<label class="wiz-kind-card">' +
68452
+ '<input type="radio" name="wiz-kind" value="join"' + (kind === 'join' ? ' checked' : '') + ' />' +
68453
+ '<span class="wiz-kind-name">Join a team <span class="wiz-kind-sub">invite</span></span>' +
68422
68454
  '</label>' +
68423
68455
  '</div>' +
68424
68456
  '<p style="font-size:11px;color:var(--text-muted);margin:6px 0 0">' +
@@ -70563,6 +70595,14 @@ var voiceLocalJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
70563
70595
  return _voiceWorker;
70564
70596
  }
70565
70597
 
70598
+ // Warm up the voice worker + model in the BACKGROUND on launch, so dictation is
70599
+ // ready by the time the user records and any first-run weight fetch happens
70600
+ // silently up front (never mid-recording, never with a visible "downloading"
70601
+ // state). Idempotent + best-effort \u2014 a failure just leaves the mic to lazy-init.
70602
+ function voicePreload() {
70603
+ try { getVoiceWorker(); } catch (_) { /* best-effort */ }
70604
+ }
70605
+
70566
70606
  function voicePreferredDevice() {
70567
70607
  // WebGPU when the browser exposes it, else WASM. The worker downgrades to
70568
70608
  // wasm itself if the runtime can't honor webgpu, so this is just a hint.
@@ -70584,14 +70624,14 @@ var voiceLocalJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
70584
70624
  _voiceWorkerReady = false;
70585
70625
  }
70586
70626
 
70587
- // Forward model-download progress to the composer placeholder so the first
70588
- // use shows "Downloading voice model\u2026 N%" (it needs the network ONCE; after
70589
- // that it's cached and offline).
70590
- function onVoiceProgress(file, progress) {
70591
- var inp = document.getElementById('chat-input');
70592
- if (!inp) return;
70593
- var pct = (typeof progress === 'number' && progress > 0) ? (' ' + Math.round(progress) + '%') : '';
70594
- inp.setAttribute('placeholder', 'Downloading voice model\u2026' + pct);
70627
+ // Model loading is SILENT \u2014 the user never sees a "downloading voice model"
70628
+ // state. The worker + model are warmed up in the background on launch (see
70629
+ // voicePreload), and the ORT runtime ships bundled, so by the time anyone
70630
+ // records, dictation is ready. We intentionally surface no loading progress in
70631
+ // the composer; if a first-run weight fetch is still in flight, the existing
70632
+ // "Transcribing\u2026" placeholder covers it.
70633
+ function onVoiceProgress(_file, _progress) {
70634
+ /* intentionally silent \u2014 no visible voice-model loading UI */
70595
70635
  }
70596
70636
 
70597
70637
  // Decode a recorded audio blob to mono 16 kHz PCM (Float32Array), entirely in
@@ -71595,12 +71635,33 @@ var sourcesJs = `
71595
71635
  '<span class="src-name">' + escapeHtml(name) + '</span></div></li>';
71596
71636
  }).join('') + '</ul>'
71597
71637
  : '';
71638
+ // Preserve expanded folders across this re-render so an in-progress
71639
+ // ingest (which re-renders the sidebar) never snaps an open folder shut.
71640
+ // Capture each expanded folder's path + its lazily-loaded children markup,
71641
+ // then re-attach + re-open them after the rebuild (no re-fetch, no flicker).
71642
+ var openFolders = {};
71643
+ host.querySelectorAll('.src-folder[data-loaded="1"]').forEach(function (li) {
71644
+ var ul0 = li.querySelector(':scope > .src-children');
71645
+ if (ul0 && !ul0.hidden) openFolders[li.getAttribute('data-path')] = ul0.innerHTML;
71646
+ });
71598
71647
  if (!rootsHtml && !looseHtml) {
71599
71648
  host.innerHTML = '<div class="src-empty">No files yet.</div>';
71600
71649
  return;
71601
71650
  }
71602
71651
  host.innerHTML = rootsHtml + looseHtml;
71603
71652
  wireSourceTree(host);
71653
+ host.querySelectorAll('.src-folder').forEach(function (li) {
71654
+ var saved = openFolders[li.getAttribute('data-path')];
71655
+ if (saved == null) return;
71656
+ var ul1 = li.querySelector(':scope > .src-children');
71657
+ var caret = li.querySelector(':scope > .src-row > .src-caret');
71658
+ if (!ul1) return;
71659
+ ul1.innerHTML = saved;
71660
+ ul1.hidden = false;
71661
+ li.setAttribute('data-loaded', '1');
71662
+ if (caret) caret.textContent = '\u25BE';
71663
+ wireSourceTree(ul1);
71664
+ });
71604
71665
  })
71605
71666
  .catch(function () { host.innerHTML = ''; });
71606
71667
  }
@@ -76557,8 +76618,16 @@ async function dispatchIngestRoute(req, res, ctx) {
76557
76618
 
76558
76619
  // src/gui/sources-routes.ts
76559
76620
  init_user_config();
76560
- import { statSync as statSync9, readdirSync as readdirSync8, readFileSync as readFileSync23, writeFileSync as writeFileSync9 } from "fs";
76561
- import { resolve as resolve11, join as join28, basename as basename12, sep as sep8 } from "path";
76621
+ import {
76622
+ statSync as statSync9,
76623
+ readdirSync as readdirSync8,
76624
+ readFileSync as readFileSync23,
76625
+ writeFileSync as writeFileSync9,
76626
+ existsSync as existsSync26,
76627
+ mkdirSync as mkdirSync11,
76628
+ rmSync
76629
+ } from "fs";
76630
+ import { resolve as resolve11, join as join28, basename as basename12, sep as sep8, dirname as dirname15 } from "path";
76562
76631
  import { execFile } from "child_process";
76563
76632
  import { randomUUID as randomUUID4 } from "crypto";
76564
76633
  init_http();
@@ -76566,20 +76635,49 @@ var MAX_LIST_ENTRIES = 2e3;
76566
76635
  var MAX_INGEST_FILES = 500;
76567
76636
  var MAX_INGEST_DEPTH = 8;
76568
76637
  var SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", ".DS_Store", "__pycache__", ".venv", "venv"]);
76569
- function rootsFile() {
76570
- return join28(configDir(), "sources.json");
76638
+ function rootsFile(configPath) {
76639
+ return join28(dirname15(configPath), "sources.json");
76640
+ }
76641
+ function migrateGlobalRootsIfNeeded(configPath) {
76642
+ const wsFile = rootsFile(configPath);
76643
+ if (existsSync26(wsFile)) return;
76644
+ const globalFile = join28(configDir(), "sources.json");
76645
+ if (globalFile === wsFile || !existsSync26(globalFile)) return;
76646
+ let roots;
76647
+ try {
76648
+ const parsed = JSON.parse(readFileSync23(globalFile, "utf8"));
76649
+ if (!Array.isArray(parsed.roots) || parsed.roots.length === 0) return;
76650
+ roots = parsed.roots;
76651
+ } catch {
76652
+ return;
76653
+ }
76654
+ try {
76655
+ mkdirSync11(dirname15(wsFile), { recursive: true });
76656
+ writeFileSync9(wsFile, JSON.stringify({ roots }, null, 2), "utf8");
76657
+ } catch {
76658
+ return;
76659
+ }
76660
+ try {
76661
+ rmSync(globalFile, { force: true });
76662
+ } catch {
76663
+ try {
76664
+ writeFileSync9(globalFile, JSON.stringify({ roots: [] }, null, 2), "utf8");
76665
+ } catch {
76666
+ }
76667
+ }
76571
76668
  }
76572
- function readRoots() {
76669
+ function readRoots(configPath) {
76670
+ migrateGlobalRootsIfNeeded(configPath);
76573
76671
  try {
76574
- const raw = readFileSync23(rootsFile(), "utf8");
76672
+ const raw = readFileSync23(rootsFile(configPath), "utf8");
76575
76673
  const parsed = JSON.parse(raw);
76576
76674
  return Array.isArray(parsed.roots) ? parsed.roots : [];
76577
76675
  } catch {
76578
76676
  return [];
76579
76677
  }
76580
76678
  }
76581
- function writeRoots(roots) {
76582
- writeFileSync9(rootsFile(), JSON.stringify({ roots }, null, 2), "utf8");
76679
+ function writeRoots(configPath, roots) {
76680
+ writeFileSync9(rootsFile(configPath), JSON.stringify({ roots }, null, 2), "utf8");
76583
76681
  }
76584
76682
  function safeResolveInside2(target, roots) {
76585
76683
  const abs = resolve11(target);
@@ -76669,14 +76767,14 @@ async function ingestFolder(abs, ingestFile) {
76669
76767
  return { ingested, skipped };
76670
76768
  }
76671
76769
  async function dispatchSourcesRoute(req, res, deps) {
76672
- const { pathname, method, ingestFile } = deps;
76770
+ const { pathname, method, ingestFile, configPath } = deps;
76673
76771
  if (!pathname.startsWith("/api/sources/")) return false;
76674
76772
  if (!localFileOpenEnabled()) {
76675
76773
  sendJson(res, { enabled: false });
76676
76774
  return true;
76677
76775
  }
76678
76776
  if (pathname === "/api/sources/roots" && method === "GET") {
76679
- sendJson(res, { enabled: true, roots: readRoots() });
76777
+ sendJson(res, { enabled: true, roots: readRoots(configPath) });
76680
76778
  return true;
76681
76779
  }
76682
76780
  if (pathname === "/api/sources/roots" && method === "POST") {
@@ -76702,12 +76800,12 @@ async function dispatchSourcesRoute(req, res, deps) {
76702
76800
  sendJson(res, { error: `path not found: ${abs}` }, 400);
76703
76801
  return true;
76704
76802
  }
76705
- const roots = readRoots();
76803
+ const roots = readRoots(configPath);
76706
76804
  let root6 = roots.find((r6) => resolve11(r6.path) === abs);
76707
76805
  if (!root6) {
76708
76806
  root6 = { id: randomUUID4(), path: abs, kind, name: basename12(abs) || abs };
76709
76807
  roots.push(root6);
76710
- writeRoots(roots);
76808
+ writeRoots(configPath, roots);
76711
76809
  }
76712
76810
  let result;
76713
76811
  if (kind === "folder") result = await ingestFolder(abs, ingestFile);
@@ -76718,8 +76816,8 @@ async function dispatchSourcesRoute(req, res, deps) {
76718
76816
  const delMatch = /^\/api\/sources\/roots\/([^/]+)$/.exec(pathname);
76719
76817
  if (delMatch && method === "DELETE") {
76720
76818
  const id = decodeURIComponent(delMatch[1] ?? "");
76721
- const roots = readRoots().filter((r6) => r6.id !== id);
76722
- writeRoots(roots);
76819
+ const roots = readRoots(configPath).filter((r6) => r6.id !== id);
76820
+ writeRoots(configPath, roots);
76723
76821
  sendJson(res, { ok: true });
76724
76822
  return true;
76725
76823
  }
@@ -76737,7 +76835,7 @@ async function dispatchSourcesRoute(req, res, deps) {
76737
76835
  sendJson(res, { error: "path is required" }, 400);
76738
76836
  return true;
76739
76837
  }
76740
- const abs = safeResolveInside2(target, readRoots());
76838
+ const abs = safeResolveInside2(target, readRoots(configPath));
76741
76839
  if (!abs) {
76742
76840
  sendJson(res, { error: "path is outside any registered source root" }, 403);
76743
76841
  return true;
@@ -76752,7 +76850,7 @@ async function dispatchSourcesRoute(req, res, deps) {
76752
76850
  if (pathname === "/api/sources/ingest-folder" && method === "POST") {
76753
76851
  const body = await readJson(req).catch(() => ({}));
76754
76852
  const target = typeof body.path === "string" ? body.path : "";
76755
- const abs = safeResolveInside2(target, readRoots());
76853
+ const abs = safeResolveInside2(target, readRoots(configPath));
76756
76854
  if (!abs) {
76757
76855
  sendJson(res, { error: "path is outside any registered source root" }, 403);
76758
76856
  return true;
@@ -76766,7 +76864,7 @@ async function dispatchSourcesRoute(req, res, deps) {
76766
76864
  // src/gui/import-routes.ts
76767
76865
  init_adapter();
76768
76866
  init_http();
76769
- import { existsSync as existsSync26, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
76867
+ import { existsSync as existsSync27, readFileSync as readFileSync24, statSync as statSync10 } from "fs";
76770
76868
  import { isAbsolute as isAbsolute4, join as join29 } from "path";
76771
76869
  init_native_entities();
76772
76870
  function badRequest(message) {
@@ -76800,7 +76898,7 @@ async function readImportSourceFromFile(db, fileId, latticeRoot) {
76800
76898
  );
76801
76899
  if (!row) throw badRequest("Unknown import file: " + fileId);
76802
76900
  const path3 = localPathOf2(row, latticeRoot);
76803
- if (!path3 || !existsSync26(path3)) {
76901
+ if (!path3 || !existsSync27(path3)) {
76804
76902
  throw badRequest("The import file\u2019s bytes are not available locally.");
76805
76903
  }
76806
76904
  const sizeBytes = statSync10(path3).size;
@@ -78941,7 +79039,7 @@ init_dispatch();
78941
79039
  init_column_descriptions();
78942
79040
  init_mutations();
78943
79041
  init_native_entities();
78944
- import { createReadStream as createReadStream3, existsSync as existsSync27, realpathSync as realpathSync2, statSync as statSync11 } from "fs";
79042
+ import { createReadStream as createReadStream3, existsSync as existsSync28, realpathSync as realpathSync2, statSync as statSync11 } from "fs";
78945
79043
  import { extname as extname3, join as join30, normalize as normalize2, sep as sep9 } from "path";
78946
79044
 
78947
79045
  // src/gui/count-many.ts
@@ -79149,7 +79247,7 @@ async function handleReadRoutes(req, res, ctx, deps) {
79149
79247
  const base = deps.guiAssetsDir.replace(/[/\\]+$/, "");
79150
79248
  const target = normalize2(join30(base, rel));
79151
79249
  const within = target === base || target.startsWith(base + sep9);
79152
- if (!within || !existsSync27(target) || !statSync11(target).isFile()) {
79250
+ if (!within || !existsSync28(target) || !statSync11(target).isFile()) {
79153
79251
  sendJson(res, { error: "asset not found" }, 404);
79154
79252
  return true;
79155
79253
  }
@@ -80357,16 +80455,16 @@ async function handleHistoryRoutes(req, res, ctx, deps) {
80357
80455
  // src/gui/workspaces-routes.ts
80358
80456
  init_http();
80359
80457
  import { resolve as resolve12 } from "path";
80360
- import { existsSync as existsSync28, rmSync } from "fs";
80458
+ import { existsSync as existsSync29, rmSync as rmSync2 } from "fs";
80361
80459
  init_workspace();
80362
80460
  init_lattice_root();
80363
80461
  init_user_config();
80364
80462
  function cleanupWorkspaceFiles(root6, ws) {
80365
80463
  if (!ws.configPath && ws.kind === "local") {
80366
- rmSync(workspaceDir(root6, ws.dir), { recursive: true, force: true });
80464
+ rmSync2(workspaceDir(root6, ws.dir), { recursive: true, force: true });
80367
80465
  } else if (ws.kind === "cloud") {
80368
- if (ws.configPath && existsSync28(ws.configPath)) {
80369
- rmSync(ws.configPath, { force: true });
80466
+ if (ws.configPath && existsSync29(ws.configPath)) {
80467
+ rmSync2(ws.configPath, { force: true });
80370
80468
  }
80371
80469
  const labelMatch = /^\$\{LATTICE_DB:([A-Za-z0-9._-]+)\}$/.exec(ws.db.trim());
80372
80470
  const label = labelMatch?.[1];
@@ -80569,15 +80667,15 @@ async function handleWorkspacesRoutes(req, res, ctx, deps) {
80569
80667
  // src/gui/databases-routes.ts
80570
80668
  init_http();
80571
80669
  import { basename as basename14, resolve as resolve14 } from "path";
80572
- import { existsSync as existsSync30 } from "fs";
80670
+ import { existsSync as existsSync31 } from "fs";
80573
80671
  init_parser();
80574
80672
 
80575
80673
  // src/gui/config-paths.ts
80576
80674
  init_parser();
80577
- import { basename as basename13, dirname as dirname15, join as join31, resolve as resolve13 } from "path";
80675
+ import { basename as basename13, dirname as dirname16, join as join31, resolve as resolve13 } from "path";
80578
80676
  import {
80579
- existsSync as existsSync29,
80580
- mkdirSync as mkdirSync11,
80677
+ existsSync as existsSync30,
80678
+ mkdirSync as mkdirSync12,
80581
80679
  readFileSync as readFileSync25,
80582
80680
  readdirSync as readdirSync9,
80583
80681
  unlinkSync as unlinkSync5,
@@ -80585,10 +80683,10 @@ import {
80585
80683
  } from "fs";
80586
80684
  import { parseDocument as parseDocument7 } from "yaml";
80587
80685
  function resolveOutputDirForConfig(configPath) {
80588
- const base = dirname15(resolve13(configPath));
80686
+ const base = dirname16(resolve13(configPath));
80589
80687
  for (const dir of ["context", ".", "generated"]) {
80590
80688
  const abs = resolve13(base, dir);
80591
- if (existsSync29(join31(abs, ".lattice", "manifest.json"))) return abs;
80689
+ if (existsSync30(join31(abs, ".lattice", "manifest.json"))) return abs;
80592
80690
  }
80593
80691
  return resolve13(base, "context");
80594
80692
  }
@@ -80597,7 +80695,7 @@ function friendlyConfigName(parsedName, configPath) {
80597
80695
  return basename13(configPath).replace(/\.(ya?ml)$/, "");
80598
80696
  }
80599
80697
  function listConfigs(activeConfigPath) {
80600
- const dir = dirname15(activeConfigPath);
80698
+ const dir = dirname16(activeConfigPath);
80601
80699
  const entries = [];
80602
80700
  for (const fname of readdirSync9(dir)) {
80603
80701
  if (!fname.endsWith(".yml") && !fname.endsWith(".yaml")) continue;
@@ -80626,17 +80724,17 @@ function listConfigs(activeConfigPath) {
80626
80724
  return entries.sort((a6, b6) => a6.label.localeCompare(b6.label));
80627
80725
  }
80628
80726
  function createBlankConfig(activeConfigPath, dbName) {
80629
- const dir = dirname15(activeConfigPath);
80727
+ const dir = dirname16(activeConfigPath);
80630
80728
  const slug = dbName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
80631
80729
  if (!slug) throw new Error("Workspace name must contain at least one alphanumeric character");
80632
80730
  const configPath = join31(dir, `${slug}.config.yml`);
80633
- if (existsSync29(configPath)) throw new Error(`Config already exists: ${slug}.config.yml`);
80731
+ if (existsSync30(configPath)) throw new Error(`Config already exists: ${slug}.config.yml`);
80634
80732
  const yaml = `db: ./data/${slug}.db
80635
80733
 
80636
80734
  entities: {}
80637
80735
  `;
80638
80736
  writeFileSync10(configPath, yaml, "utf8");
80639
- mkdirSync11(join31(dir, "data"), { recursive: true });
80737
+ mkdirSync12(join31(dir, "data"), { recursive: true });
80640
80738
  return configPath;
80641
80739
  }
80642
80740
  function sqliteFileForConfig(configPath) {
@@ -80645,18 +80743,18 @@ function sqliteFileForConfig(configPath) {
80645
80743
  if (!raw) return null;
80646
80744
  if (isPostgresUrl(raw) || raw.startsWith("${LATTICE_DB:")) return null;
80647
80745
  if (raw === ":memory:" || raw.startsWith("file:")) return null;
80648
- return resolve13(dirname15(configPath), raw);
80746
+ return resolve13(dirname16(configPath), raw);
80649
80747
  }
80650
80748
  function deleteDatabaseFiles(targetConfigPath) {
80651
80749
  const sqliteFile = sqliteFileForConfig(targetConfigPath);
80652
80750
  unlinkSync5(targetConfigPath);
80653
80751
  let deletedDbFile = null;
80654
- if (sqliteFile && existsSync29(sqliteFile)) {
80752
+ if (sqliteFile && existsSync30(sqliteFile)) {
80655
80753
  unlinkSync5(sqliteFile);
80656
80754
  deletedDbFile = sqliteFile;
80657
80755
  for (const suffix of ["-wal", "-shm", "-journal"]) {
80658
80756
  const sidecar = sqliteFile + suffix;
80659
- if (existsSync29(sidecar)) unlinkSync5(sidecar);
80757
+ if (existsSync30(sidecar)) unlinkSync5(sidecar);
80660
80758
  }
80661
80759
  }
80662
80760
  return { deletedConfig: basename13(targetConfigPath), deletedDbFile };
@@ -80690,7 +80788,7 @@ async function handleDatabasesRoutes(req, res, ctx, deps) {
80690
80788
  return true;
80691
80789
  }
80692
80790
  const newPath = resolve14(body.path);
80693
- if (!existsSync30(newPath)) {
80791
+ if (!existsSync31(newPath)) {
80694
80792
  sendJson(res, { error: `Config not found: ${newPath}` }, 400);
80695
80793
  return true;
80696
80794
  }
@@ -80796,8 +80894,8 @@ async function handleDatabasesRoutes(req, res, ctx, deps) {
80796
80894
  // src/gui/server.ts
80797
80895
  init_user_config();
80798
80896
  function resolveDefaultGuiAssetsDir() {
80799
- const bundleSibling = process.argv[1] ? resolve15(dirname16(process.argv[1]), "gui-assets") : null;
80800
- if (bundleSibling && existsSync31(bundleSibling)) return bundleSibling;
80897
+ const bundleSibling = process.argv[1] ? resolve15(dirname17(process.argv[1]), "gui-assets") : null;
80898
+ if (bundleSibling && existsSync32(bundleSibling)) return bundleSibling;
80801
80899
  return resolve15(process.cwd(), "dist", "gui-assets");
80802
80900
  }
80803
80901
  function sendText(res, body, status = 200, contentType = "text/plain; charset=utf-8") {
@@ -80854,7 +80952,7 @@ async function startGuiServer(options) {
80854
80952
  const sessionId = crypto.randomUUID();
80855
80953
  let updateService = null;
80856
80954
  let activeRef = bootConfigPath && bootOutputDir ? await openConfig(bootConfigPath, bootOutputDir, autoRender, options.realtimeWatchdogMs) : null;
80857
- const latticeRoot = (bootConfigPath ? findLatticeRoot(dirname16(bootConfigPath)) : null) ?? (options.latticeRoot ? resolve15(options.latticeRoot) : null);
80955
+ const latticeRoot = (bootConfigPath ? findLatticeRoot(dirname17(bootConfigPath)) : null) ?? (options.latticeRoot ? resolve15(options.latticeRoot) : null);
80858
80956
  let currentWorkspaceId = null;
80859
80957
  if (latticeRoot && bootConfigPath) {
80860
80958
  const launched = listWorkspaces(latticeRoot).find(
@@ -81208,7 +81306,7 @@ async function startGuiServer(options) {
81208
81306
  createJunction: (otherTable) => createFileJunction(active, otherTable, sessionId),
81209
81307
  createEntity: (entity, columns) => createUserEntity(active, entity, columns, sessionId),
81210
81308
  aggressiveness: getAggressiveness(),
81211
- latticeRoot: dirname16(active.configPath),
81309
+ latticeRoot: dirname17(active.configPath),
81212
81310
  configPath: active.configPath,
81213
81311
  outputDir: active.outputDir,
81214
81312
  sessionId,
@@ -81233,7 +81331,7 @@ async function startGuiServer(options) {
81233
81331
  createJunction: (otherTable) => createFileJunction(active, otherTable, sessionId),
81234
81332
  createEntity: (entity, columns) => createUserEntity(active, entity, columns, sessionId),
81235
81333
  aggressiveness: getAggressiveness(),
81236
- latticeRoot: dirname16(active.configPath),
81334
+ latticeRoot: dirname17(active.configPath),
81237
81335
  configPath: active.configPath,
81238
81336
  outputDir: active.outputDir,
81239
81337
  sessionId,
@@ -81244,6 +81342,7 @@ async function startGuiServer(options) {
81244
81342
  return await dispatchSourcesRoute(req2, res2, {
81245
81343
  db: active.db,
81246
81344
  ingestFile: (p3) => ingestLocalFile(ingestCtx, mctx, p3, false),
81345
+ configPath: active.configPath,
81247
81346
  pathname,
81248
81347
  method
81249
81348
  });
@@ -81259,7 +81358,7 @@ async function startGuiServer(options) {
81259
81358
  return await dispatchImportRoute(req2, res2, {
81260
81359
  db: active.db,
81261
81360
  configPath: active.configPath,
81262
- latticeRoot: dirname16(active.configPath),
81361
+ latticeRoot: dirname17(active.configPath),
81263
81362
  validTables: active.validTables,
81264
81363
  softDeletable: active.softDeletable
81265
81364
  });
@@ -81288,7 +81387,7 @@ async function startGuiServer(options) {
81288
81387
  if (!pathname.startsWith("/api/files/")) return false;
81289
81388
  return await dispatchFilesRoute(req2, res2, {
81290
81389
  db: active.db,
81291
- latticeRoot: dirname16(active.configPath),
81390
+ latticeRoot: dirname17(active.configPath),
81292
81391
  configPath: active.configPath,
81293
81392
  pathname,
81294
81393
  method
@@ -81499,7 +81598,7 @@ ${e6.stack ?? ""}`
81499
81598
  }
81500
81599
 
81501
81600
  // src/desktop-entry.ts
81502
- var VERSION2 = true ? "4.3.0" : "unknown";
81601
+ var VERSION2 = true ? "4.3.2" : "unknown";
81503
81602
  export {
81504
81603
  VERSION2 as VERSION,
81505
81604
  ensureRootForGui,