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.
package/dist/index.js CHANGED
@@ -23495,12 +23495,12 @@ var getNodeModulesParentDirs;
23495
23495
  var init_getNodeModulesParentDirs = __esm({
23496
23496
  "node_modules/@aws-sdk/core/dist-es/submodules/client/util-user-agent-node/getNodeModulesParentDirs.js"() {
23497
23497
  "use strict";
23498
- getNodeModulesParentDirs = (dirname18) => {
23498
+ getNodeModulesParentDirs = (dirname19) => {
23499
23499
  const cwd = process.cwd();
23500
- if (!dirname18) {
23500
+ if (!dirname19) {
23501
23501
  return [cwd];
23502
23502
  }
23503
- const normalizedPath = normalize(dirname18);
23503
+ const normalizedPath = normalize(dirname19);
23504
23504
  const parts = normalizedPath.split(sep3);
23505
23505
  const nodeModulesIndex = parts.indexOf("node_modules");
23506
23506
  const parentDir = nodeModulesIndex !== -1 ? parts.slice(0, nodeModulesIndex).join(sep3) : normalizedPath;
@@ -23578,8 +23578,8 @@ var init_getTypeScriptUserAgentPair = __esm({
23578
23578
  tscVersion = null;
23579
23579
  return void 0;
23580
23580
  }
23581
- const dirname18 = typeof __dirname !== "undefined" ? __dirname : void 0;
23582
- const nodeModulesParentDirs = getNodeModulesParentDirs(dirname18);
23581
+ const dirname19 = typeof __dirname !== "undefined" ? __dirname : void 0;
23582
+ const nodeModulesParentDirs = getNodeModulesParentDirs(dirname19);
23583
23583
  let versionFromApp;
23584
23584
  for (const nodeModulesParentDir of nodeModulesParentDirs) {
23585
23585
  try {
@@ -62153,9 +62153,9 @@ init_summarize();
62153
62153
  init_http2();
62154
62154
  import { createServer } from "http";
62155
62155
  import { spawn as spawn2 } from "child_process";
62156
- import { existsSync as existsSync31 } from "fs";
62156
+ import { existsSync as existsSync32 } from "fs";
62157
62157
  import { WebSocketServer, WebSocket } from "ws";
62158
- import { dirname as dirname16, resolve as resolve16 } from "path";
62158
+ import { dirname as dirname17, resolve as resolve16 } from "path";
62159
62159
 
62160
62160
  // src/gui/active-db.ts
62161
62161
  init_adapter();
@@ -64001,12 +64001,16 @@ var tokensCss = `
64001
64001
  surface (a bare input on a modal, the Database wizard, User Config, etc.):
64002
64002
  dark text on a white field with a light border. Placeholders use the
64003
64003
  muted token. Affects every input/select/textarea across the GUI. */
64004
- input, select, textarea {
64004
+ /* Text-like fields only \u2014 radios/checkboxes keep their native rendering
64005
+ (the box/border treatment mangles them). The accent color tints the native
64006
+ controls so checked radios/checkboxes are on-brand blue. */
64007
+ input:not([type='radio']):not([type='checkbox']):not([type='range']), select, textarea {
64005
64008
  color: var(--text);
64006
64009
  background: var(--surface);
64007
64010
  border: 1px solid var(--border);
64008
64011
  border-radius: 6px;
64009
64012
  }
64013
+ input[type='radio'], input[type='checkbox'] { accent-color: var(--accent); }
64010
64014
  input::placeholder, textarea::placeholder {
64011
64015
  color: var(--text-muted);
64012
64016
  opacity: 1;
@@ -64991,7 +64995,7 @@ var teamsCss = ` /* \u2500\u2500 Teams (Project Config + User Config) \u2500\
64991
64995
  color: var(--text); font-weight: 500;
64992
64996
  text-transform: uppercase; letter-spacing: 0.04em;
64993
64997
  }
64994
- .modal .field input, .modal .field textarea {
64998
+ .modal .field input:not([type='radio']):not([type='checkbox']), .modal .field textarea {
64995
64999
  width: 100%; padding: 6px 8px;
64996
65000
  background: var(--surface); color: var(--text);
64997
65001
  border: 1px solid var(--border-strong);
@@ -65001,6 +65005,20 @@ var teamsCss = ` /* \u2500\u2500 Teams (Project Config + User Config) \u2500\
65001
65005
  color: var(--text-muted);
65002
65006
  }
65003
65007
  .modal .field textarea { min-height: 60px; font-family: ui-monospace, monospace; font-size: 12px; }
65008
+ /* New-workspace "Kind" selector \u2014 clean cards, blue-highlighted selection. */
65009
+ .wiz-kind-opts { display: flex; gap: 10px; margin-top: 6px; flex-wrap: wrap; }
65010
+ .wiz-kind-card {
65011
+ flex: 1 1 0; min-width: 132px; display: flex; align-items: center; gap: 9px;
65012
+ padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px;
65013
+ background: var(--surface); cursor: pointer;
65014
+ transition: border-color 0.12s ease, background 0.12s ease;
65015
+ }
65016
+ .wiz-kind-card:hover { border-color: var(--border-strong); }
65017
+ .wiz-kind-card:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
65018
+ .wiz-kind-card input { margin: 0; flex: 0 0 auto; }
65019
+ .wiz-kind-name { font-size: 13px; color: var(--text); text-transform: none; letter-spacing: 0; }
65020
+ .wiz-kind-sub { color: var(--text-muted); font-size: 11px; margin-left: 2px; }
65021
+ .wiz-kind-card:has(input:checked) .wiz-kind-name { color: var(--accent-deep); font-weight: 500; }
65004
65022
  .modal .copy-token {
65005
65023
  padding: 8px 10px; background: var(--surface-2); border: 1px solid var(--border);
65006
65024
  border-radius: 4px; font-family: ui-monospace, monospace; font-size: 12px;
@@ -66246,6 +66264,9 @@ var bootJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
66246
66264
  initRailDragDrop();
66247
66265
  renderComposer();
66248
66266
  initThreadControls();
66267
+ // Warm up on-device voice in the background shortly after boot so dictation
66268
+ // is ready on first use \u2014 no visible model-loading step, ever.
66269
+ if (typeof voicePreload === 'function') setTimeout(voicePreload, 1500);
66249
66270
  checkNativeSetup();
66250
66271
  // App is fully populated \u2014 reveal it (Feature C).
66251
66272
  hideAppLoading();
@@ -70009,9 +70030,14 @@ var dashboardJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
70009
70030
  }
70010
70031
  var d = displayFor(table);
70011
70032
  // The tab shows the open RECORD's name (e.g. an entity row), not the
70012
- // object/table name.
70033
+ // object/table name. Guard: only retitle a RECORD ('item:') tab \u2014 never the
70034
+ // shared Brain Graph ('graph') tab, even if a record render briefly runs
70035
+ // while the hash still resolves to the graph (which would rename \u{1F9E0}).
70013
70036
  if (typeof setTabTitle === 'function') {
70014
- setTabTitle(tabKeyForHash(location.hash), fsDisplayName(row) || d.label);
70037
+ var fsItemKey = tabKeyForHash(location.hash);
70038
+ if (fsItemKey && fsItemKey.indexOf('item:') === 0) {
70039
+ setTabTitle(fsItemKey, fsDisplayName(row) || d.label);
70040
+ }
70015
70041
  }
70016
70042
  // Files + artifacts get the two-view document layout (formatted display +
70017
70043
  // a View Source toggle) with a Version History + Delete dropdown \u2014 not the
@@ -70081,7 +70107,10 @@ var dashboardJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
70081
70107
  // The tab shows the FILE's name (e.g. "Properties Dashboard"), not the
70082
70108
  // object name ("Files").
70083
70109
  if (typeof setTabTitle === 'function') {
70084
- setTabTitle(tabKeyForHash(location.hash), fsDisplayName(row) || d.label);
70110
+ var fsDocKey = tabKeyForHash(location.hash);
70111
+ if (fsDocKey && fsDocKey.indexOf('item:') === 0) {
70112
+ setTabTitle(fsDocKey, fsDisplayName(row) || d.label);
70113
+ }
70085
70114
  }
70086
70115
  var mode = fileViewMode[id] || 'display';
70087
70116
  // Actions live in a dropdown menu next to the title; View source / Version
@@ -72288,15 +72317,18 @@ var dataModelJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
72288
72317
  return '' +
72289
72318
  nameField +
72290
72319
  '<div class="field"><label>Kind</label>' +
72291
- '<div style="display:flex;gap:16px;margin-top:4px;flex-wrap:wrap">' +
72292
- '<label style="display:flex;align-items:center;gap:6px;font-weight:400;text-transform:none;letter-spacing:0">' +
72293
- '<input type="radio" name="wiz-kind" value="local"' + (kind === 'local' ? ' checked' : '') + ' /> New local (SQLite)' +
72320
+ '<div class="wiz-kind-opts">' +
72321
+ '<label class="wiz-kind-card">' +
72322
+ '<input type="radio" name="wiz-kind" value="local"' + (kind === 'local' ? ' checked' : '') + ' />' +
72323
+ '<span class="wiz-kind-name">New local <span class="wiz-kind-sub">SQLite</span></span>' +
72294
72324
  '</label>' +
72295
- '<label style="display:flex;align-items:center;gap:6px;font-weight:400;text-transform:none;letter-spacing:0">' +
72296
- '<input type="radio" name="wiz-kind" value="cloud"' + (kind === 'cloud' ? ' checked' : '') + ' /> New cloud (Postgres)' +
72325
+ '<label class="wiz-kind-card">' +
72326
+ '<input type="radio" name="wiz-kind" value="cloud"' + (kind === 'cloud' ? ' checked' : '') + ' />' +
72327
+ '<span class="wiz-kind-name">New cloud <span class="wiz-kind-sub">Postgres</span></span>' +
72297
72328
  '</label>' +
72298
- '<label style="display:flex;align-items:center;gap:6px;font-weight:400;text-transform:none;letter-spacing:0">' +
72299
- '<input type="radio" name="wiz-kind" value="join"' + (kind === 'join' ? ' checked' : '') + ' /> Join a team (invite)' +
72329
+ '<label class="wiz-kind-card">' +
72330
+ '<input type="radio" name="wiz-kind" value="join"' + (kind === 'join' ? ' checked' : '') + ' />' +
72331
+ '<span class="wiz-kind-name">Join a team <span class="wiz-kind-sub">invite</span></span>' +
72300
72332
  '</label>' +
72301
72333
  '</div>' +
72302
72334
  '<p style="font-size:11px;color:var(--text-muted);margin:6px 0 0">' +
@@ -74441,6 +74473,14 @@ var voiceLocalJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
74441
74473
  return _voiceWorker;
74442
74474
  }
74443
74475
 
74476
+ // Warm up the voice worker + model in the BACKGROUND on launch, so dictation is
74477
+ // ready by the time the user records and any first-run weight fetch happens
74478
+ // silently up front (never mid-recording, never with a visible "downloading"
74479
+ // state). Idempotent + best-effort \u2014 a failure just leaves the mic to lazy-init.
74480
+ function voicePreload() {
74481
+ try { getVoiceWorker(); } catch (_) { /* best-effort */ }
74482
+ }
74483
+
74444
74484
  function voicePreferredDevice() {
74445
74485
  // WebGPU when the browser exposes it, else WASM. The worker downgrades to
74446
74486
  // wasm itself if the runtime can't honor webgpu, so this is just a hint.
@@ -74462,14 +74502,14 @@ var voiceLocalJs = ` // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
74462
74502
  _voiceWorkerReady = false;
74463
74503
  }
74464
74504
 
74465
- // Forward model-download progress to the composer placeholder so the first
74466
- // use shows "Downloading voice model\u2026 N%" (it needs the network ONCE; after
74467
- // that it's cached and offline).
74468
- function onVoiceProgress(file, progress) {
74469
- var inp = document.getElementById('chat-input');
74470
- if (!inp) return;
74471
- var pct = (typeof progress === 'number' && progress > 0) ? (' ' + Math.round(progress) + '%') : '';
74472
- inp.setAttribute('placeholder', 'Downloading voice model\u2026' + pct);
74505
+ // Model loading is SILENT \u2014 the user never sees a "downloading voice model"
74506
+ // state. The worker + model are warmed up in the background on launch (see
74507
+ // voicePreload), and the ORT runtime ships bundled, so by the time anyone
74508
+ // records, dictation is ready. We intentionally surface no loading progress in
74509
+ // the composer; if a first-run weight fetch is still in flight, the existing
74510
+ // "Transcribing\u2026" placeholder covers it.
74511
+ function onVoiceProgress(_file, _progress) {
74512
+ /* intentionally silent \u2014 no visible voice-model loading UI */
74473
74513
  }
74474
74514
 
74475
74515
  // Decode a recorded audio blob to mono 16 kHz PCM (Float32Array), entirely in
@@ -75473,12 +75513,33 @@ var sourcesJs = `
75473
75513
  '<span class="src-name">' + escapeHtml(name) + '</span></div></li>';
75474
75514
  }).join('') + '</ul>'
75475
75515
  : '';
75516
+ // Preserve expanded folders across this re-render so an in-progress
75517
+ // ingest (which re-renders the sidebar) never snaps an open folder shut.
75518
+ // Capture each expanded folder's path + its lazily-loaded children markup,
75519
+ // then re-attach + re-open them after the rebuild (no re-fetch, no flicker).
75520
+ var openFolders = {};
75521
+ host.querySelectorAll('.src-folder[data-loaded="1"]').forEach(function (li) {
75522
+ var ul0 = li.querySelector(':scope > .src-children');
75523
+ if (ul0 && !ul0.hidden) openFolders[li.getAttribute('data-path')] = ul0.innerHTML;
75524
+ });
75476
75525
  if (!rootsHtml && !looseHtml) {
75477
75526
  host.innerHTML = '<div class="src-empty">No files yet.</div>';
75478
75527
  return;
75479
75528
  }
75480
75529
  host.innerHTML = rootsHtml + looseHtml;
75481
75530
  wireSourceTree(host);
75531
+ host.querySelectorAll('.src-folder').forEach(function (li) {
75532
+ var saved = openFolders[li.getAttribute('data-path')];
75533
+ if (saved == null) return;
75534
+ var ul1 = li.querySelector(':scope > .src-children');
75535
+ var caret = li.querySelector(':scope > .src-row > .src-caret');
75536
+ if (!ul1) return;
75537
+ ul1.innerHTML = saved;
75538
+ ul1.hidden = false;
75539
+ li.setAttribute('data-loaded', '1');
75540
+ if (caret) caret.textContent = '\u25BE';
75541
+ wireSourceTree(ul1);
75542
+ });
75482
75543
  })
75483
75544
  .catch(function () { host.innerHTML = ''; });
75484
75545
  }
@@ -79921,8 +79982,16 @@ async function dispatchIngestRoute(req, res, ctx) {
79921
79982
 
79922
79983
  // src/gui/sources-routes.ts
79923
79984
  init_user_config();
79924
- import { statSync as statSync10, readdirSync as readdirSync8, readFileSync as readFileSync24, writeFileSync as writeFileSync9 } from "fs";
79925
- import { resolve as resolve12, join as join30, basename as basename13, sep as sep8 } from "path";
79985
+ import {
79986
+ statSync as statSync10,
79987
+ readdirSync as readdirSync8,
79988
+ readFileSync as readFileSync24,
79989
+ writeFileSync as writeFileSync9,
79990
+ existsSync as existsSync26,
79991
+ mkdirSync as mkdirSync11,
79992
+ rmSync
79993
+ } from "fs";
79994
+ import { resolve as resolve12, join as join30, basename as basename13, sep as sep8, dirname as dirname15 } from "path";
79926
79995
  import { execFile } from "child_process";
79927
79996
  import { randomUUID as randomUUID4 } from "crypto";
79928
79997
  init_http2();
@@ -79930,20 +79999,49 @@ var MAX_LIST_ENTRIES = 2e3;
79930
79999
  var MAX_INGEST_FILES = 500;
79931
80000
  var MAX_INGEST_DEPTH = 8;
79932
80001
  var SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", ".DS_Store", "__pycache__", ".venv", "venv"]);
79933
- function rootsFile() {
79934
- return join30(configDir(), "sources.json");
80002
+ function rootsFile(configPath) {
80003
+ return join30(dirname15(configPath), "sources.json");
80004
+ }
80005
+ function migrateGlobalRootsIfNeeded(configPath) {
80006
+ const wsFile = rootsFile(configPath);
80007
+ if (existsSync26(wsFile)) return;
80008
+ const globalFile = join30(configDir(), "sources.json");
80009
+ if (globalFile === wsFile || !existsSync26(globalFile)) return;
80010
+ let roots;
80011
+ try {
80012
+ const parsed = JSON.parse(readFileSync24(globalFile, "utf8"));
80013
+ if (!Array.isArray(parsed.roots) || parsed.roots.length === 0) return;
80014
+ roots = parsed.roots;
80015
+ } catch {
80016
+ return;
80017
+ }
80018
+ try {
80019
+ mkdirSync11(dirname15(wsFile), { recursive: true });
80020
+ writeFileSync9(wsFile, JSON.stringify({ roots }, null, 2), "utf8");
80021
+ } catch {
80022
+ return;
80023
+ }
80024
+ try {
80025
+ rmSync(globalFile, { force: true });
80026
+ } catch {
80027
+ try {
80028
+ writeFileSync9(globalFile, JSON.stringify({ roots: [] }, null, 2), "utf8");
80029
+ } catch {
80030
+ }
80031
+ }
79935
80032
  }
79936
- function readRoots() {
80033
+ function readRoots(configPath) {
80034
+ migrateGlobalRootsIfNeeded(configPath);
79937
80035
  try {
79938
- const raw = readFileSync24(rootsFile(), "utf8");
80036
+ const raw = readFileSync24(rootsFile(configPath), "utf8");
79939
80037
  const parsed = JSON.parse(raw);
79940
80038
  return Array.isArray(parsed.roots) ? parsed.roots : [];
79941
80039
  } catch {
79942
80040
  return [];
79943
80041
  }
79944
80042
  }
79945
- function writeRoots(roots) {
79946
- writeFileSync9(rootsFile(), JSON.stringify({ roots }, null, 2), "utf8");
80043
+ function writeRoots(configPath, roots) {
80044
+ writeFileSync9(rootsFile(configPath), JSON.stringify({ roots }, null, 2), "utf8");
79947
80045
  }
79948
80046
  function safeResolveInside2(target, roots) {
79949
80047
  const abs = resolve12(target);
@@ -80033,14 +80131,14 @@ async function ingestFolder(abs, ingestFile) {
80033
80131
  return { ingested, skipped };
80034
80132
  }
80035
80133
  async function dispatchSourcesRoute(req, res, deps) {
80036
- const { pathname, method, ingestFile } = deps;
80134
+ const { pathname, method, ingestFile, configPath } = deps;
80037
80135
  if (!pathname.startsWith("/api/sources/")) return false;
80038
80136
  if (!localFileOpenEnabled()) {
80039
80137
  sendJson(res, { enabled: false });
80040
80138
  return true;
80041
80139
  }
80042
80140
  if (pathname === "/api/sources/roots" && method === "GET") {
80043
- sendJson(res, { enabled: true, roots: readRoots() });
80141
+ sendJson(res, { enabled: true, roots: readRoots(configPath) });
80044
80142
  return true;
80045
80143
  }
80046
80144
  if (pathname === "/api/sources/roots" && method === "POST") {
@@ -80066,12 +80164,12 @@ async function dispatchSourcesRoute(req, res, deps) {
80066
80164
  sendJson(res, { error: `path not found: ${abs}` }, 400);
80067
80165
  return true;
80068
80166
  }
80069
- const roots = readRoots();
80167
+ const roots = readRoots(configPath);
80070
80168
  let root6 = roots.find((r6) => resolve12(r6.path) === abs);
80071
80169
  if (!root6) {
80072
80170
  root6 = { id: randomUUID4(), path: abs, kind, name: basename13(abs) || abs };
80073
80171
  roots.push(root6);
80074
- writeRoots(roots);
80172
+ writeRoots(configPath, roots);
80075
80173
  }
80076
80174
  let result;
80077
80175
  if (kind === "folder") result = await ingestFolder(abs, ingestFile);
@@ -80082,8 +80180,8 @@ async function dispatchSourcesRoute(req, res, deps) {
80082
80180
  const delMatch = /^\/api\/sources\/roots\/([^/]+)$/.exec(pathname);
80083
80181
  if (delMatch && method === "DELETE") {
80084
80182
  const id = decodeURIComponent(delMatch[1] ?? "");
80085
- const roots = readRoots().filter((r6) => r6.id !== id);
80086
- writeRoots(roots);
80183
+ const roots = readRoots(configPath).filter((r6) => r6.id !== id);
80184
+ writeRoots(configPath, roots);
80087
80185
  sendJson(res, { ok: true });
80088
80186
  return true;
80089
80187
  }
@@ -80101,7 +80199,7 @@ async function dispatchSourcesRoute(req, res, deps) {
80101
80199
  sendJson(res, { error: "path is required" }, 400);
80102
80200
  return true;
80103
80201
  }
80104
- const abs = safeResolveInside2(target, readRoots());
80202
+ const abs = safeResolveInside2(target, readRoots(configPath));
80105
80203
  if (!abs) {
80106
80204
  sendJson(res, { error: "path is outside any registered source root" }, 403);
80107
80205
  return true;
@@ -80116,7 +80214,7 @@ async function dispatchSourcesRoute(req, res, deps) {
80116
80214
  if (pathname === "/api/sources/ingest-folder" && method === "POST") {
80117
80215
  const body = await readJson(req).catch(() => ({}));
80118
80216
  const target = typeof body.path === "string" ? body.path : "";
80119
- const abs = safeResolveInside2(target, readRoots());
80217
+ const abs = safeResolveInside2(target, readRoots(configPath));
80120
80218
  if (!abs) {
80121
80219
  sendJson(res, { error: "path is outside any registered source root" }, 403);
80122
80220
  return true;
@@ -80130,7 +80228,7 @@ async function dispatchSourcesRoute(req, res, deps) {
80130
80228
  // src/gui/import-routes.ts
80131
80229
  init_adapter();
80132
80230
  init_http2();
80133
- import { existsSync as existsSync26, readFileSync as readFileSync25, statSync as statSync11 } from "fs";
80231
+ import { existsSync as existsSync27, readFileSync as readFileSync25, statSync as statSync11 } from "fs";
80134
80232
  import { isAbsolute as isAbsolute4, join as join31 } from "path";
80135
80233
  init_native_entities();
80136
80234
  function badRequest(message) {
@@ -80164,7 +80262,7 @@ async function readImportSourceFromFile(db, fileId, latticeRoot) {
80164
80262
  );
80165
80263
  if (!row) throw badRequest("Unknown import file: " + fileId);
80166
80264
  const path3 = localPathOf2(row, latticeRoot);
80167
- if (!path3 || !existsSync26(path3)) {
80265
+ if (!path3 || !existsSync27(path3)) {
80168
80266
  throw badRequest("The import file\u2019s bytes are not available locally.");
80169
80267
  }
80170
80268
  const sizeBytes = statSync11(path3).size;
@@ -80459,7 +80557,7 @@ init_dispatch();
80459
80557
  init_column_descriptions();
80460
80558
  init_mutations();
80461
80559
  init_native_entities();
80462
- import { createReadStream as createReadStream3, existsSync as existsSync27, realpathSync as realpathSync2, statSync as statSync12 } from "fs";
80560
+ import { createReadStream as createReadStream3, existsSync as existsSync28, realpathSync as realpathSync2, statSync as statSync12 } from "fs";
80463
80561
  import { extname as extname3, join as join32, normalize as normalize2, sep as sep9 } from "path";
80464
80562
 
80465
80563
  // src/gui/count-many.ts
@@ -80667,7 +80765,7 @@ async function handleReadRoutes(req, res, ctx, deps) {
80667
80765
  const base = deps.guiAssetsDir.replace(/[/\\]+$/, "");
80668
80766
  const target = normalize2(join32(base, rel));
80669
80767
  const within = target === base || target.startsWith(base + sep9);
80670
- if (!within || !existsSync27(target) || !statSync12(target).isFile()) {
80768
+ if (!within || !existsSync28(target) || !statSync12(target).isFile()) {
80671
80769
  sendJson(res, { error: "asset not found" }, 404);
80672
80770
  return true;
80673
80771
  }
@@ -81875,16 +81973,16 @@ async function handleHistoryRoutes(req, res, ctx, deps) {
81875
81973
  // src/gui/workspaces-routes.ts
81876
81974
  init_http2();
81877
81975
  import { resolve as resolve13 } from "path";
81878
- import { existsSync as existsSync28, rmSync } from "fs";
81976
+ import { existsSync as existsSync29, rmSync as rmSync2 } from "fs";
81879
81977
  init_workspace();
81880
81978
  init_lattice_root();
81881
81979
  init_user_config();
81882
81980
  function cleanupWorkspaceFiles(root6, ws) {
81883
81981
  if (!ws.configPath && ws.kind === "local") {
81884
- rmSync(workspaceDir(root6, ws.dir), { recursive: true, force: true });
81982
+ rmSync2(workspaceDir(root6, ws.dir), { recursive: true, force: true });
81885
81983
  } else if (ws.kind === "cloud") {
81886
- if (ws.configPath && existsSync28(ws.configPath)) {
81887
- rmSync(ws.configPath, { force: true });
81984
+ if (ws.configPath && existsSync29(ws.configPath)) {
81985
+ rmSync2(ws.configPath, { force: true });
81888
81986
  }
81889
81987
  const labelMatch = /^\$\{LATTICE_DB:([A-Za-z0-9._-]+)\}$/.exec(ws.db.trim());
81890
81988
  const label = labelMatch?.[1];
@@ -82087,15 +82185,15 @@ async function handleWorkspacesRoutes(req, res, ctx, deps) {
82087
82185
  // src/gui/databases-routes.ts
82088
82186
  init_http2();
82089
82187
  import { basename as basename15, resolve as resolve15 } from "path";
82090
- import { existsSync as existsSync30 } from "fs";
82188
+ import { existsSync as existsSync31 } from "fs";
82091
82189
  init_parser();
82092
82190
 
82093
82191
  // src/gui/config-paths.ts
82094
82192
  init_parser();
82095
- import { basename as basename14, dirname as dirname15, join as join33, resolve as resolve14 } from "path";
82193
+ import { basename as basename14, dirname as dirname16, join as join33, resolve as resolve14 } from "path";
82096
82194
  import {
82097
- existsSync as existsSync29,
82098
- mkdirSync as mkdirSync11,
82195
+ existsSync as existsSync30,
82196
+ mkdirSync as mkdirSync12,
82099
82197
  readFileSync as readFileSync26,
82100
82198
  readdirSync as readdirSync9,
82101
82199
  unlinkSync as unlinkSync5,
@@ -82103,10 +82201,10 @@ import {
82103
82201
  } from "fs";
82104
82202
  import { parseDocument as parseDocument7 } from "yaml";
82105
82203
  function resolveOutputDirForConfig(configPath) {
82106
- const base = dirname15(resolve14(configPath));
82204
+ const base = dirname16(resolve14(configPath));
82107
82205
  for (const dir of ["context", ".", "generated"]) {
82108
82206
  const abs = resolve14(base, dir);
82109
- if (existsSync29(join33(abs, ".lattice", "manifest.json"))) return abs;
82207
+ if (existsSync30(join33(abs, ".lattice", "manifest.json"))) return abs;
82110
82208
  }
82111
82209
  return resolve14(base, "context");
82112
82210
  }
@@ -82115,7 +82213,7 @@ function friendlyConfigName(parsedName, configPath) {
82115
82213
  return basename14(configPath).replace(/\.(ya?ml)$/, "");
82116
82214
  }
82117
82215
  function listConfigs(activeConfigPath) {
82118
- const dir = dirname15(activeConfigPath);
82216
+ const dir = dirname16(activeConfigPath);
82119
82217
  const entries = [];
82120
82218
  for (const fname of readdirSync9(dir)) {
82121
82219
  if (!fname.endsWith(".yml") && !fname.endsWith(".yaml")) continue;
@@ -82144,17 +82242,17 @@ function listConfigs(activeConfigPath) {
82144
82242
  return entries.sort((a6, b6) => a6.label.localeCompare(b6.label));
82145
82243
  }
82146
82244
  function createBlankConfig(activeConfigPath, dbName) {
82147
- const dir = dirname15(activeConfigPath);
82245
+ const dir = dirname16(activeConfigPath);
82148
82246
  const slug = dbName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
82149
82247
  if (!slug) throw new Error("Workspace name must contain at least one alphanumeric character");
82150
82248
  const configPath = join33(dir, `${slug}.config.yml`);
82151
- if (existsSync29(configPath)) throw new Error(`Config already exists: ${slug}.config.yml`);
82249
+ if (existsSync30(configPath)) throw new Error(`Config already exists: ${slug}.config.yml`);
82152
82250
  const yaml = `db: ./data/${slug}.db
82153
82251
 
82154
82252
  entities: {}
82155
82253
  `;
82156
82254
  writeFileSync10(configPath, yaml, "utf8");
82157
- mkdirSync11(join33(dir, "data"), { recursive: true });
82255
+ mkdirSync12(join33(dir, "data"), { recursive: true });
82158
82256
  return configPath;
82159
82257
  }
82160
82258
  function sqliteFileForConfig(configPath) {
@@ -82163,18 +82261,18 @@ function sqliteFileForConfig(configPath) {
82163
82261
  if (!raw) return null;
82164
82262
  if (isPostgresUrl(raw) || raw.startsWith("${LATTICE_DB:")) return null;
82165
82263
  if (raw === ":memory:" || raw.startsWith("file:")) return null;
82166
- return resolve14(dirname15(configPath), raw);
82264
+ return resolve14(dirname16(configPath), raw);
82167
82265
  }
82168
82266
  function deleteDatabaseFiles(targetConfigPath) {
82169
82267
  const sqliteFile = sqliteFileForConfig(targetConfigPath);
82170
82268
  unlinkSync5(targetConfigPath);
82171
82269
  let deletedDbFile = null;
82172
- if (sqliteFile && existsSync29(sqliteFile)) {
82270
+ if (sqliteFile && existsSync30(sqliteFile)) {
82173
82271
  unlinkSync5(sqliteFile);
82174
82272
  deletedDbFile = sqliteFile;
82175
82273
  for (const suffix of ["-wal", "-shm", "-journal"]) {
82176
82274
  const sidecar = sqliteFile + suffix;
82177
- if (existsSync29(sidecar)) unlinkSync5(sidecar);
82275
+ if (existsSync30(sidecar)) unlinkSync5(sidecar);
82178
82276
  }
82179
82277
  }
82180
82278
  return { deletedConfig: basename14(targetConfigPath), deletedDbFile };
@@ -82208,7 +82306,7 @@ async function handleDatabasesRoutes(req, res, ctx, deps) {
82208
82306
  return true;
82209
82307
  }
82210
82308
  const newPath = resolve15(body.path);
82211
- if (!existsSync30(newPath)) {
82309
+ if (!existsSync31(newPath)) {
82212
82310
  sendJson(res, { error: `Config not found: ${newPath}` }, 400);
82213
82311
  return true;
82214
82312
  }
@@ -82314,8 +82412,8 @@ async function handleDatabasesRoutes(req, res, ctx, deps) {
82314
82412
  // src/gui/server.ts
82315
82413
  init_user_config();
82316
82414
  function resolveDefaultGuiAssetsDir() {
82317
- const bundleSibling = process.argv[1] ? resolve16(dirname16(process.argv[1]), "gui-assets") : null;
82318
- if (bundleSibling && existsSync31(bundleSibling)) return bundleSibling;
82415
+ const bundleSibling = process.argv[1] ? resolve16(dirname17(process.argv[1]), "gui-assets") : null;
82416
+ if (bundleSibling && existsSync32(bundleSibling)) return bundleSibling;
82319
82417
  return resolve16(process.cwd(), "dist", "gui-assets");
82320
82418
  }
82321
82419
  function sendText(res, body, status = 200, contentType = "text/plain; charset=utf-8") {
@@ -82372,7 +82470,7 @@ async function startGuiServer(options) {
82372
82470
  const sessionId = crypto.randomUUID();
82373
82471
  let updateService = null;
82374
82472
  let activeRef = bootConfigPath && bootOutputDir ? await openConfig(bootConfigPath, bootOutputDir, autoRender, options.realtimeWatchdogMs) : null;
82375
- const latticeRoot = (bootConfigPath ? findLatticeRoot(dirname16(bootConfigPath)) : null) ?? (options.latticeRoot ? resolve16(options.latticeRoot) : null);
82473
+ const latticeRoot = (bootConfigPath ? findLatticeRoot(dirname17(bootConfigPath)) : null) ?? (options.latticeRoot ? resolve16(options.latticeRoot) : null);
82376
82474
  let currentWorkspaceId = null;
82377
82475
  if (latticeRoot && bootConfigPath) {
82378
82476
  const launched = listWorkspaces(latticeRoot).find(
@@ -82726,7 +82824,7 @@ async function startGuiServer(options) {
82726
82824
  createJunction: (otherTable) => createFileJunction(active, otherTable, sessionId),
82727
82825
  createEntity: (entity, columns) => createUserEntity(active, entity, columns, sessionId),
82728
82826
  aggressiveness: getAggressiveness(),
82729
- latticeRoot: dirname16(active.configPath),
82827
+ latticeRoot: dirname17(active.configPath),
82730
82828
  configPath: active.configPath,
82731
82829
  outputDir: active.outputDir,
82732
82830
  sessionId,
@@ -82751,7 +82849,7 @@ async function startGuiServer(options) {
82751
82849
  createJunction: (otherTable) => createFileJunction(active, otherTable, sessionId),
82752
82850
  createEntity: (entity, columns) => createUserEntity(active, entity, columns, sessionId),
82753
82851
  aggressiveness: getAggressiveness(),
82754
- latticeRoot: dirname16(active.configPath),
82852
+ latticeRoot: dirname17(active.configPath),
82755
82853
  configPath: active.configPath,
82756
82854
  outputDir: active.outputDir,
82757
82855
  sessionId,
@@ -82762,6 +82860,7 @@ async function startGuiServer(options) {
82762
82860
  return await dispatchSourcesRoute(req2, res2, {
82763
82861
  db: active.db,
82764
82862
  ingestFile: (p3) => ingestLocalFile(ingestCtx, mctx, p3, false),
82863
+ configPath: active.configPath,
82765
82864
  pathname,
82766
82865
  method
82767
82866
  });
@@ -82777,7 +82876,7 @@ async function startGuiServer(options) {
82777
82876
  return await dispatchImportRoute(req2, res2, {
82778
82877
  db: active.db,
82779
82878
  configPath: active.configPath,
82780
- latticeRoot: dirname16(active.configPath),
82879
+ latticeRoot: dirname17(active.configPath),
82781
82880
  validTables: active.validTables,
82782
82881
  softDeletable: active.softDeletable
82783
82882
  });
@@ -82806,7 +82905,7 @@ async function startGuiServer(options) {
82806
82905
  if (!pathname.startsWith("/api/files/")) return false;
82807
82906
  return await dispatchFilesRoute(req2, res2, {
82808
82907
  db: active.db,
82809
- latticeRoot: dirname16(active.configPath),
82908
+ latticeRoot: dirname17(active.configPath),
82810
82909
  configPath: active.configPath,
82811
82910
  pathname,
82812
82911
  method
@@ -83017,8 +83116,8 @@ ${e6.stack ?? ""}`
83017
83116
  }
83018
83117
 
83019
83118
  // src/cloud/file-source-key-store.ts
83020
- import { readFileSync as readFileSync27, writeFileSync as writeFileSync11, existsSync as existsSync32, mkdirSync as mkdirSync12, renameSync as renameSync5, chmodSync as chmodSync3 } from "fs";
83021
- import { dirname as dirname17, resolve as resolve17 } from "path";
83119
+ import { readFileSync as readFileSync27, writeFileSync as writeFileSync11, existsSync as existsSync33, mkdirSync as mkdirSync13, renameSync as renameSync5, chmodSync as chmodSync3 } from "fs";
83120
+ import { dirname as dirname18, resolve as resolve17 } from "path";
83022
83121
  import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes9, scryptSync as scryptSync3 } from "crypto";
83023
83122
  var ENC_HEADER = "LATTICE-KMS-v1\n";
83024
83123
  var SCRYPT_N = 1 << 15;
@@ -83069,9 +83168,9 @@ var FileSourceKeyStore = class {
83069
83168
  // ── internals ────────────────────────────────────────────────────────
83070
83169
  load() {
83071
83170
  const out = /* @__PURE__ */ new Map();
83072
- if (!existsSync32(this.path)) {
83073
- const dir = dirname17(this.path);
83074
- if (!existsSync32(dir)) mkdirSync12(dir, { recursive: true, mode: 448 });
83171
+ if (!existsSync33(this.path)) {
83172
+ const dir = dirname18(this.path);
83173
+ if (!existsSync33(dir)) mkdirSync13(dir, { recursive: true, mode: 448 });
83075
83174
  return out;
83076
83175
  }
83077
83176
  const raw = readFileSync27(this.path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latticesql",
3
- "version": "4.3.0",
3
+ "version": "4.3.2",
4
4
  "description": "Persistent structured memory for AI agent systems — pluggable SQLite or Postgres backend, LLM context bridge",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -48,6 +48,7 @@
48
48
  "test:deno": "deno test --no-check -A tests/deno/",
49
49
  "desktop:dev": "npm run build && node scripts/sync-desktop-version.mjs && deno desktop --no-check --allow-all desktop/main.ts",
50
50
  "desktop:build:mac": "npm run build && node scripts/sync-desktop-version.mjs && deno desktop --no-check --allow-env --allow-read --allow-write --allow-net --allow-run --allow-sys --allow-ffi --include dist/gui-assets --output dist-desktop/Lattice.dmg desktop/main.ts",
51
+ "desktop:build:mac:pkg": "npm run build && node scripts/sync-desktop-version.mjs && deno desktop --no-check --allow-env --allow-read --allow-write --allow-net --allow-run --allow-sys --allow-ffi --include dist/gui-assets --output dist-desktop/Lattice.app desktop/main.ts && sh scripts/build-mac-pkg.sh",
51
52
  "desktop:build:win": "npm run build && node scripts/sync-desktop-version.mjs && deno desktop --no-check --allow-env --allow-read --allow-write --allow-net --allow-run --allow-sys --allow-ffi --include dist/gui-assets --output dist-desktop/Lattice.msi desktop/main.ts",
52
53
  "prepublishOnly": "npm run check:generic && npm run build && npm run typecheck && npm test"
53
54
  },