latticesql 2.2.1 → 2.2.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/cli.js CHANGED
@@ -7584,20 +7584,6 @@ var css = `
7584
7584
  .grants-panel .grants-title { font-weight: 600; margin-bottom: 6px; }
7585
7585
  .grants-panel .grants-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; cursor: pointer; }
7586
7586
  .grants-panel .grants-row input { accent-color: var(--accent); }
7587
- /* Deprecation banner: shown when the workspace holds a grandfathered
7588
- direct database cloud connection (no row-level security). Amber so
7589
- it reads as a warning, not an error. */
7590
- .deprecation-banner {
7591
- display: flex; align-items: center; gap: 12px;
7592
- padding: 8px 16px; font-size: 13px;
7593
- background: rgba(234, 179, 8, 0.12); color: var(--text);
7594
- border-bottom: 1px solid rgba(234, 179, 8, 0.45);
7595
- }
7596
- .deprecation-banner button {
7597
- margin-left: auto; background: transparent; border: none; cursor: pointer;
7598
- color: var(--text-muted); font-size: 13px; padding: 2px 6px; border-radius: 4px;
7599
- }
7600
- .deprecation-banner button:hover { background: rgba(234, 179, 8, 0.18); }
7601
7587
 
7602
7588
  /* Inline create-row at the bottom of every table */
7603
7589
  tr.create-row td { background: var(--surface-2); }
@@ -9088,27 +9074,6 @@ var appJs = `
9088
9074
 
9089
9075
  window.addEventListener('hashchange', renderRoute);
9090
9076
 
9091
- // Deprecation banner: a grandfathered direct database cloud connection
9092
- // bypasses the hosted server's row security entirely \u2014 say so up front.
9093
- // Dismiss hides it for this browser session only.
9094
- function initDeprecationBanner() {
9095
- if (sessionStorage.getItem('lattice-direct-banner-dismissed')) return;
9096
- fetchJson('/api/dbconfig').then(function (d) {
9097
- if (!d || !d.directCloud) return;
9098
- var banner = document.getElementById('deprecation-banner');
9099
- var text = document.getElementById('deprecation-banner-text');
9100
- if (!banner || !text) return;
9101
- text.textContent = "Direct database cloud connections are deprecated and don't support row-level security. Migrate to a hosted workspace.";
9102
- banner.hidden = false;
9103
- var dismiss = document.getElementById('deprecation-banner-dismiss');
9104
- if (dismiss) dismiss.addEventListener('click', function () {
9105
- banner.hidden = true;
9106
- sessionStorage.setItem('lattice-direct-banner-dismissed', '1');
9107
- });
9108
- }).catch(function () { /* dbconfig unavailable (e.g. team-cloud server mode) \u2014 no banner */ });
9109
- }
9110
- initDeprecationBanner();
9111
-
9112
9077
  // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
9113
9078
  // Sidebar
9114
9079
  // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
@@ -11509,9 +11474,11 @@ var appJs = `
11509
11474
  headers: { 'content-type': 'application/json' },
11510
11475
  body: JSON.stringify({ share: !isShared }),
11511
11476
  }).then(function () {
11512
- // The server updated team visibility in place (no DB re-open),
11513
- // so a light in-place refresh reflects it without a full reload.
11514
- return dmRefreshPanel(tableName, false);
11477
+ // Rebuild the graph (not just the panel) so the node's share-status
11478
+ // colour (gnode-shared/gnode-private) recolours immediately from the
11479
+ // refreshed entities \u2014 otherwise the swatch stayed stale until a
11480
+ // manual reload. The editor re-shows for the same table.
11481
+ return dmRefreshPanel(tableName, true);
11515
11482
  }).then(function () {
11516
11483
  showToast(isShared ? 'Unshared "' + tableName + '" from workspace' : 'Shared "' + tableName + '" with workspace', {});
11517
11484
  }).catch(function (e) { showToast('Share update failed: ' + e.message, {}); });
@@ -14231,10 +14198,6 @@ var guiAppHtml = `<!doctype html>
14231
14198
  </svg>
14232
14199
  </button>
14233
14200
  </header>
14234
- <div class="deprecation-banner" id="deprecation-banner" hidden>
14235
- <span id="deprecation-banner-text"></span>
14236
- <button id="deprecation-banner-dismiss" title="Dismiss for this session" aria-label="Dismiss">\u2715</button>
14237
- </div>
14238
14201
  <div class="layout">
14239
14202
  <nav class="sidebar">
14240
14203
  <label class="sidebar-advanced toggle" title="Advanced mode \u2014 row/table editor instead of the file workspace">
@@ -15406,19 +15369,12 @@ async function destroyTeamDirect(db) {
15406
15369
  }
15407
15370
  await db.delete("__lattice_team_identity", "singleton");
15408
15371
  }
15409
- var directDeprecationWarned = false;
15410
15372
  async function openCloud(cloudUrl) {
15411
15373
  if (!isPostgresUrl(cloudUrl)) {
15412
15374
  throw new Error(
15413
15375
  `direct-ops: cloudUrl must be a postgres:// URL (got ${cloudUrl.slice(0, 12)}\u2026)`
15414
15376
  );
15415
15377
  }
15416
- if (!directDeprecationWarned) {
15417
- directDeprecationWarned = true;
15418
- console.warn(
15419
- "[teams] Direct postgres:// team-cloud connection is deprecated and does NOT enforce 2.2 row-level security. Migrate to a hosted Lattice Teams server."
15420
- );
15421
- }
15422
15378
  const db = new Lattice(cloudUrl);
15423
15379
  await db.init();
15424
15380
  for (const [table, def] of Object.entries(CLOUD_INTERNAL_TABLE_DEFS)) {
@@ -15583,7 +15539,7 @@ async function resolveUserIdByEmail(db, email) {
15583
15539
  function isVisibleInTeam(tableName, ctx) {
15584
15540
  if (ctx.shared.has(tableName)) return true;
15585
15541
  const owner = ctx.owners.get(tableName);
15586
- if (owner === void 0) return true;
15542
+ if (owner === void 0) return ctx.isCreator;
15587
15543
  return owner === ctx.myUserId;
15588
15544
  }
15589
15545
  async function listTeamUsers(db) {
@@ -19403,10 +19359,7 @@ async function dispatchDbConfigRoute(req, res, ctx) {
19403
19359
  // without a local `__lattice_team_connections` row (which doesn't
19404
19360
  // exist when the team cloud itself is the active database).
19405
19361
  teamId: ctx.teamMembership?.teamId ?? null,
19406
- myUserId: ctx.teamMembership?.myUserId ?? null,
19407
- // Deprecated direct postgres:// team connection present → the SPA
19408
- // shows the migrate-to-hosted deprecation banner.
19409
- directCloud: ctx.directCloud
19362
+ myUserId: ctx.teamMembership?.myUserId ?? null
19410
19363
  });
19411
19364
  });
19412
19365
  return true;
@@ -20865,8 +20818,12 @@ async function buildSchemaContext(d) {
20865
20818
  }
20866
20819
  return lines.join("\n");
20867
20820
  }
20868
- function buildSystemPrompt(schema) {
20869
- return `${BASE_SYSTEM_PROMPT}
20821
+ function buildSystemPrompt(schema, operatorName) {
20822
+ const who = operatorName && operatorName.trim().length > 0 ? `
20823
+
20824
+ # Who you are assisting
20825
+ You are assisting ${operatorName.trim()}. When the user says "me" / "my", they mean ${operatorName.trim()}; never ask the user for their own name.` : "";
20826
+ return `${BASE_SYSTEM_PROMPT}${who}
20870
20827
 
20871
20828
  # Current database
20872
20829
  ${schema}`;
@@ -20881,7 +20838,7 @@ async function* runChat(opts) {
20881
20838
  ...opts.history ?? [],
20882
20839
  { role: "user", content: opts.userMessage }
20883
20840
  ];
20884
- const system = buildSystemPrompt(await buildSchemaContext(opts.dispatch));
20841
+ const system = buildSystemPrompt(await buildSchemaContext(opts.dispatch), opts.operatorName);
20885
20842
  let loop = 0;
20886
20843
  try {
20887
20844
  for (; loop < MAX_TOOL_LOOPS; loop++) {
@@ -21492,6 +21449,9 @@ async function dispatchChatRoute(req, res, ctx) {
21492
21449
  history,
21493
21450
  userMessage: message,
21494
21451
  temperature,
21452
+ // Give the assistant the operator's name so it addresses them and
21453
+ // resolves "me"/"my" without asking for a name it already has.
21454
+ operatorName: readIdentity().display_name,
21495
21455
  // Capture each executed tool call (capped) for cross-turn replay memory.
21496
21456
  onToolRecord: (rec) => {
21497
21457
  turns[turns.length - 1]?.toolCalls.push(rec);
@@ -22073,6 +22033,10 @@ async function attachBlob(srcPath, latticeRoot) {
22073
22033
  }
22074
22034
 
22075
22035
  // src/gui/ingest-routes.ts
22036
+ function fileSlug(name, id) {
22037
+ const base = slugify(name.replace(/\.[^./\\]+$/, "")) || "file";
22038
+ return `${base}-${id.slice(0, 8)}`;
22039
+ }
22076
22040
  var MIME_BY_EXT = {
22077
22041
  ".pdf": "application/pdf",
22078
22042
  ".png": "image/png",
@@ -22440,8 +22404,10 @@ async function dispatchIngestRoute(req, res, ctx) {
22440
22404
  } finally {
22441
22405
  await rm(tmp, { force: true }).catch(() => void 0);
22442
22406
  }
22407
+ const fileId = crypto.randomUUID();
22443
22408
  const { id: id2 } = await createRow(mctx, "files", {
22444
- id: crypto.randomUUID(),
22409
+ id: fileId,
22410
+ slug: fileSlug(name2, fileId),
22445
22411
  original_name: name2,
22446
22412
  mime: mime2,
22447
22413
  size_bytes: buf.length,
@@ -22492,8 +22458,10 @@ async function dispatchIngestRoute(req, res, ctx) {
22492
22458
  console.warn("[ingest] url crawl failed:", e.message);
22493
22459
  }
22494
22460
  }
22461
+ const textFileId = crypto.randomUUID();
22495
22462
  const { id: id2 } = await createRow(mctx, "files", {
22496
- id: crypto.randomUUID(),
22463
+ id: textFileId,
22464
+ slug: fileSlug(title, textFileId),
22497
22465
  original_name: title,
22498
22466
  mime: mime2,
22499
22467
  size_bytes: Buffer.byteLength(content, "utf8"),
@@ -22527,8 +22495,10 @@ async function dispatchIngestRoute(req, res, ctx) {
22527
22495
  }
22528
22496
  const name = basename10(abs);
22529
22497
  const mime = mimeFor(name);
22498
+ const localFileId = crypto.randomUUID();
22530
22499
  const { id } = await createRow(mctx, "files", {
22531
- id: crypto.randomUUID(),
22500
+ id: localFileId,
22501
+ slug: fileSlug(name, localFileId),
22532
22502
  path: abs,
22533
22503
  original_name: name,
22534
22504
  mime,
@@ -23065,13 +23035,6 @@ async function openConfig(configPath, outputDir, autoRender = false) {
23065
23035
  if (!isVisibleInTeam(name, teamContext)) validTables.delete(name);
23066
23036
  }
23067
23037
  }
23068
- let directTeamConnection = false;
23069
- try {
23070
- const conns = await teamsClient.listConnections();
23071
- directTeamConnection = conns.some((c) => isPostgresUrl(c.cloud_url));
23072
- } catch (e) {
23073
- console.warn("[openConfig] could not check for direct team connections:", e.message);
23074
- }
23075
23038
  let realtime = null;
23076
23039
  if (db.getDialect() === "postgres") {
23077
23040
  try {
@@ -23112,7 +23075,6 @@ async function openConfig(configPath, outputDir, autoRender = false) {
23112
23075
  teamsClient,
23113
23076
  validTables,
23114
23077
  teamContext,
23115
- directTeamConnection,
23116
23078
  junctionTables,
23117
23079
  entityContextByTable,
23118
23080
  manifest,
@@ -25208,7 +25170,6 @@ data: ${JSON.stringify(data)}
25208
25170
  teamId: active.teamContext.teamId,
25209
25171
  myUserId: active.teamContext.myUserId
25210
25172
  } : null,
25211
- directCloud: active.directTeamConnection,
25212
25173
  swap: async () => {
25213
25174
  const next = await openConfig(active.configPath, active.outputDir, autoRender);
25214
25175
  await disposeActive(active);
package/dist/index.cjs CHANGED
@@ -8096,19 +8096,12 @@ async function destroyTeamDirect(db) {
8096
8096
  }
8097
8097
  await db.delete("__lattice_team_identity", "singleton");
8098
8098
  }
8099
- var directDeprecationWarned = false;
8100
8099
  async function openCloud(cloudUrl) {
8101
8100
  if (!isPostgresUrl(cloudUrl)) {
8102
8101
  throw new Error(
8103
8102
  `direct-ops: cloudUrl must be a postgres:// URL (got ${cloudUrl.slice(0, 12)}\u2026)`
8104
8103
  );
8105
8104
  }
8106
- if (!directDeprecationWarned) {
8107
- directDeprecationWarned = true;
8108
- console.warn(
8109
- "[teams] Direct postgres:// team-cloud connection is deprecated and does NOT enforce 2.2 row-level security. Migrate to a hosted Lattice Teams server."
8110
- );
8111
- }
8112
8105
  const db = new Lattice(cloudUrl);
8113
8106
  await db.init();
8114
8107
  for (const [table, def] of Object.entries(CLOUD_INTERNAL_TABLE_DEFS)) {
package/dist/index.js CHANGED
@@ -7962,19 +7962,12 @@ async function destroyTeamDirect(db) {
7962
7962
  }
7963
7963
  await db.delete("__lattice_team_identity", "singleton");
7964
7964
  }
7965
- var directDeprecationWarned = false;
7966
7965
  async function openCloud(cloudUrl) {
7967
7966
  if (!isPostgresUrl(cloudUrl)) {
7968
7967
  throw new Error(
7969
7968
  `direct-ops: cloudUrl must be a postgres:// URL (got ${cloudUrl.slice(0, 12)}\u2026)`
7970
7969
  );
7971
7970
  }
7972
- if (!directDeprecationWarned) {
7973
- directDeprecationWarned = true;
7974
- console.warn(
7975
- "[teams] Direct postgres:// team-cloud connection is deprecated and does NOT enforce 2.2 row-level security. Migrate to a hosted Lattice Teams server."
7976
- );
7977
- }
7978
7971
  const db = new Lattice(cloudUrl);
7979
7972
  await db.init();
7980
7973
  for (const [table, def] of Object.entries(CLOUD_INTERNAL_TABLE_DEFS)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latticesql",
3
- "version": "2.2.1",
3
+ "version": "2.2.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",