latticesql 4.3.6 → 4.3.8

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
@@ -58419,8 +58419,18 @@ init_adapter();
58419
58419
  var DELETED_AT_SENTINEL = "internal:upgrade:deleted-at-empty-to-null:v1";
58420
58420
  var FILES_PATH_SENTINEL = "internal:upgrade:files-path-to-local-ref:v1";
58421
58421
  async function upgradeLegacyData(db) {
58422
- await normalizeEmptyDeletedAt(db);
58423
- await backfillFilesPath(db);
58422
+ await runUpgradeStep("deleted_at normalization", () => normalizeEmptyDeletedAt(db));
58423
+ await runUpgradeStep("files path backfill", () => backfillFilesPath(db));
58424
+ }
58425
+ async function runUpgradeStep(name, fn) {
58426
+ try {
58427
+ await fn();
58428
+ } catch (err) {
58429
+ const msg = err instanceof Error ? err.message : String(err);
58430
+ console.warn(
58431
+ `[lattice] open-time data upgrade step "${name}" skipped (will retry on next open): ${msg}`
58432
+ );
58433
+ }
58424
58434
  }
58425
58435
  async function tablesWithDeletedAt(db) {
58426
58436
  if (db.getDialect() === "postgres") {
@@ -58444,14 +58454,40 @@ async function normalizeEmptyDeletedAt(db) {
58444
58454
  await db.migrate([
58445
58455
  {
58446
58456
  version: `${DELETED_AT_SENTINEL}:all`,
58457
+ // TYPE-AWARE: only a text-like deleted_at column can hold the legacy ''
58458
+ // sentinel. A column that is a real `timestamptz` (some clouds' deleted_at
58459
+ // is) MUST be skipped: the predicate `deleted_at = ''` forces Postgres to
58460
+ // parse `''::timestamptz` at PLAN time — invalid input that throws regardless
58461
+ // of data (a timestamptz column can't even hold ''), which aborted the entire
58462
+ // workspace open. We BLACKLIST the non-text types (timestamp/date/time,
58463
+ // numeric, boolean, json, uuid, bytea, xml) rather than allow-list text — so
58464
+ // text-like columns we don't enumerate (citext, a DOMAIN over text, a custom
58465
+ // text type) are still normalized instead of silently leaving '' rows that
58466
+ // 4.x's `deleted_at IS NULL` predicate would read as DELETED. PER-TABLE FAULT
58467
+ // ISOLATION is the backstop: each table's UPDATE runs in its own
58468
+ // subtransaction, so an exotic type that still errors on `= ''` (enum, inet,
58469
+ // interval, array) — or a blocking trigger/lock — is warned + skipped, never
58470
+ // fatal to the open.
58447
58471
  sql: `DO $LATTICE_DAU$
58448
58472
  DECLARE r record;
58449
58473
  BEGIN
58450
58474
  FOR r IN
58451
58475
  SELECT table_name FROM information_schema.columns
58452
- WHERE table_schema = current_schema() AND column_name = 'deleted_at'
58476
+ WHERE table_schema = current_schema()
58477
+ AND column_name = 'deleted_at'
58478
+ AND data_type NOT IN (
58479
+ 'timestamp with time zone', 'timestamp without time zone',
58480
+ 'date', 'time with time zone', 'time without time zone',
58481
+ 'integer', 'bigint', 'smallint', 'numeric', 'decimal',
58482
+ 'real', 'double precision', 'boolean', 'json', 'jsonb',
58483
+ 'bytea', 'uuid', 'xml'
58484
+ )
58453
58485
  LOOP
58454
- EXECUTE format('UPDATE %I SET deleted_at = NULL WHERE deleted_at = ''''', r.table_name);
58486
+ BEGIN
58487
+ EXECUTE format('UPDATE %I SET deleted_at = NULL WHERE deleted_at = ''''', r.table_name);
58488
+ EXCEPTION WHEN others THEN
58489
+ RAISE WARNING 'lattice: skipped deleted_at normalization for %: %', r.table_name, SQLERRM;
58490
+ END;
58455
58491
  END LOOP;
58456
58492
  END $LATTICE_DAU$;`
58457
58493
  }
@@ -58467,23 +58503,18 @@ END $LATTICE_DAU$;`
58467
58503
  });
58468
58504
  if (migrations.length > 0) await db.migrate(migrations);
58469
58505
  }
58470
- async function filesTableHasPath(db) {
58471
- if (db.getDialect() === "postgres") {
58472
- const rows2 = await allAsyncOrSync(
58473
- db.adapter,
58474
- `SELECT 1 AS x FROM information_schema.columns
58475
- WHERE table_schema = current_schema() AND table_name = 'files' AND column_name = 'path'`
58476
- );
58477
- return rows2.length > 0;
58478
- }
58479
- const rows = await allAsyncOrSync(
58480
- db.adapter,
58481
- `SELECT 1 AS x FROM pragma_table_info('files') WHERE name = 'path'`
58482
- );
58483
- return rows.length > 0;
58506
+ async function filesColumns(db) {
58507
+ const sql = db.getDialect() === "postgres" ? `SELECT column_name AS name FROM information_schema.columns
58508
+ WHERE table_schema = current_schema() AND table_name = 'files'` : `SELECT name FROM pragma_table_info('files')`;
58509
+ const rows = await allAsyncOrSync(db.adapter, sql);
58510
+ return new Set(rows.map((r6) => r6.name));
58484
58511
  }
58485
58512
  async function backfillFilesPath(db) {
58486
- if (!await filesTableHasPath(db)) return;
58513
+ const cols = await filesColumns(db);
58514
+ if (!cols.has("path")) return;
58515
+ for (const col of ["ref_kind", "ref_uri", "ref_provider", "blob_path"]) {
58516
+ if (!cols.has(col)) await addColumnAsyncOrSync(db.adapter, "files", col, "TEXT");
58517
+ }
58487
58518
  await db.migrate([
58488
58519
  {
58489
58520
  version: FILES_PATH_SENTINEL,
@@ -82106,7 +82137,7 @@ function printHelp() {
82106
82137
  );
82107
82138
  }
82108
82139
  function getVersion() {
82109
- if (true) return "4.3.6";
82140
+ if (true) return "4.3.8";
82110
82141
  try {
82111
82142
  const pkgPath = new URL("../package.json", import.meta.url).pathname;
82112
82143
  const pkg = JSON.parse(readFileSync26(pkgPath, "utf-8"));
@@ -58113,8 +58113,18 @@ init_adapter();
58113
58113
  var DELETED_AT_SENTINEL = "internal:upgrade:deleted-at-empty-to-null:v1";
58114
58114
  var FILES_PATH_SENTINEL = "internal:upgrade:files-path-to-local-ref:v1";
58115
58115
  async function upgradeLegacyData(db) {
58116
- await normalizeEmptyDeletedAt(db);
58117
- await backfillFilesPath(db);
58116
+ await runUpgradeStep("deleted_at normalization", () => normalizeEmptyDeletedAt(db));
58117
+ await runUpgradeStep("files path backfill", () => backfillFilesPath(db));
58118
+ }
58119
+ async function runUpgradeStep(name, fn) {
58120
+ try {
58121
+ await fn();
58122
+ } catch (err) {
58123
+ const msg = err instanceof Error ? err.message : String(err);
58124
+ console.warn(
58125
+ `[lattice] open-time data upgrade step "${name}" skipped (will retry on next open): ${msg}`
58126
+ );
58127
+ }
58118
58128
  }
58119
58129
  async function tablesWithDeletedAt(db) {
58120
58130
  if (db.getDialect() === "postgres") {
@@ -58138,14 +58148,40 @@ async function normalizeEmptyDeletedAt(db) {
58138
58148
  await db.migrate([
58139
58149
  {
58140
58150
  version: `${DELETED_AT_SENTINEL}:all`,
58151
+ // TYPE-AWARE: only a text-like deleted_at column can hold the legacy ''
58152
+ // sentinel. A column that is a real `timestamptz` (some clouds' deleted_at
58153
+ // is) MUST be skipped: the predicate `deleted_at = ''` forces Postgres to
58154
+ // parse `''::timestamptz` at PLAN time — invalid input that throws regardless
58155
+ // of data (a timestamptz column can't even hold ''), which aborted the entire
58156
+ // workspace open. We BLACKLIST the non-text types (timestamp/date/time,
58157
+ // numeric, boolean, json, uuid, bytea, xml) rather than allow-list text — so
58158
+ // text-like columns we don't enumerate (citext, a DOMAIN over text, a custom
58159
+ // text type) are still normalized instead of silently leaving '' rows that
58160
+ // 4.x's `deleted_at IS NULL` predicate would read as DELETED. PER-TABLE FAULT
58161
+ // ISOLATION is the backstop: each table's UPDATE runs in its own
58162
+ // subtransaction, so an exotic type that still errors on `= ''` (enum, inet,
58163
+ // interval, array) — or a blocking trigger/lock — is warned + skipped, never
58164
+ // fatal to the open.
58141
58165
  sql: `DO $LATTICE_DAU$
58142
58166
  DECLARE r record;
58143
58167
  BEGIN
58144
58168
  FOR r IN
58145
58169
  SELECT table_name FROM information_schema.columns
58146
- WHERE table_schema = current_schema() AND column_name = 'deleted_at'
58170
+ WHERE table_schema = current_schema()
58171
+ AND column_name = 'deleted_at'
58172
+ AND data_type NOT IN (
58173
+ 'timestamp with time zone', 'timestamp without time zone',
58174
+ 'date', 'time with time zone', 'time without time zone',
58175
+ 'integer', 'bigint', 'smallint', 'numeric', 'decimal',
58176
+ 'real', 'double precision', 'boolean', 'json', 'jsonb',
58177
+ 'bytea', 'uuid', 'xml'
58178
+ )
58147
58179
  LOOP
58148
- EXECUTE format('UPDATE %I SET deleted_at = NULL WHERE deleted_at = ''''', r.table_name);
58180
+ BEGIN
58181
+ EXECUTE format('UPDATE %I SET deleted_at = NULL WHERE deleted_at = ''''', r.table_name);
58182
+ EXCEPTION WHEN others THEN
58183
+ RAISE WARNING 'lattice: skipped deleted_at normalization for %: %', r.table_name, SQLERRM;
58184
+ END;
58149
58185
  END LOOP;
58150
58186
  END $LATTICE_DAU$;`
58151
58187
  }
@@ -58161,23 +58197,18 @@ END $LATTICE_DAU$;`
58161
58197
  });
58162
58198
  if (migrations.length > 0) await db.migrate(migrations);
58163
58199
  }
58164
- async function filesTableHasPath(db) {
58165
- if (db.getDialect() === "postgres") {
58166
- const rows2 = await allAsyncOrSync(
58167
- db.adapter,
58168
- `SELECT 1 AS x FROM information_schema.columns
58169
- WHERE table_schema = current_schema() AND table_name = 'files' AND column_name = 'path'`
58170
- );
58171
- return rows2.length > 0;
58172
- }
58173
- const rows = await allAsyncOrSync(
58174
- db.adapter,
58175
- `SELECT 1 AS x FROM pragma_table_info('files') WHERE name = 'path'`
58176
- );
58177
- return rows.length > 0;
58200
+ async function filesColumns(db) {
58201
+ const sql = db.getDialect() === "postgres" ? `SELECT column_name AS name FROM information_schema.columns
58202
+ WHERE table_schema = current_schema() AND table_name = 'files'` : `SELECT name FROM pragma_table_info('files')`;
58203
+ const rows = await allAsyncOrSync(db.adapter, sql);
58204
+ return new Set(rows.map((r6) => r6.name));
58178
58205
  }
58179
58206
  async function backfillFilesPath(db) {
58180
- if (!await filesTableHasPath(db)) return;
58207
+ const cols = await filesColumns(db);
58208
+ if (!cols.has("path")) return;
58209
+ for (const col of ["ref_kind", "ref_uri", "ref_provider", "blob_path"]) {
58210
+ if (!cols.has(col)) await addColumnAsyncOrSync(db.adapter, "files", col, "TEXT");
58211
+ }
58181
58212
  await db.migrate([
58182
58213
  {
58183
58214
  version: FILES_PATH_SENTINEL,
@@ -81684,7 +81715,7 @@ ${e6.stack ?? ""}`
81684
81715
  }
81685
81716
 
81686
81717
  // src/desktop-entry.ts
81687
- var VERSION2 = true ? "4.3.6" : "unknown";
81718
+ var VERSION2 = true ? "4.3.8" : "unknown";
81688
81719
  export {
81689
81720
  VERSION2 as VERSION,
81690
81721
  ensureRootForGui,
package/dist/index.cjs CHANGED
@@ -62650,8 +62650,18 @@ init_adapter();
62650
62650
  var DELETED_AT_SENTINEL = "internal:upgrade:deleted-at-empty-to-null:v1";
62651
62651
  var FILES_PATH_SENTINEL = "internal:upgrade:files-path-to-local-ref:v1";
62652
62652
  async function upgradeLegacyData(db) {
62653
- await normalizeEmptyDeletedAt(db);
62654
- await backfillFilesPath(db);
62653
+ await runUpgradeStep("deleted_at normalization", () => normalizeEmptyDeletedAt(db));
62654
+ await runUpgradeStep("files path backfill", () => backfillFilesPath(db));
62655
+ }
62656
+ async function runUpgradeStep(name, fn) {
62657
+ try {
62658
+ await fn();
62659
+ } catch (err) {
62660
+ const msg = err instanceof Error ? err.message : String(err);
62661
+ console.warn(
62662
+ `[lattice] open-time data upgrade step "${name}" skipped (will retry on next open): ${msg}`
62663
+ );
62664
+ }
62655
62665
  }
62656
62666
  async function tablesWithDeletedAt(db) {
62657
62667
  if (db.getDialect() === "postgres") {
@@ -62675,14 +62685,40 @@ async function normalizeEmptyDeletedAt(db) {
62675
62685
  await db.migrate([
62676
62686
  {
62677
62687
  version: `${DELETED_AT_SENTINEL}:all`,
62688
+ // TYPE-AWARE: only a text-like deleted_at column can hold the legacy ''
62689
+ // sentinel. A column that is a real `timestamptz` (some clouds' deleted_at
62690
+ // is) MUST be skipped: the predicate `deleted_at = ''` forces Postgres to
62691
+ // parse `''::timestamptz` at PLAN time — invalid input that throws regardless
62692
+ // of data (a timestamptz column can't even hold ''), which aborted the entire
62693
+ // workspace open. We BLACKLIST the non-text types (timestamp/date/time,
62694
+ // numeric, boolean, json, uuid, bytea, xml) rather than allow-list text — so
62695
+ // text-like columns we don't enumerate (citext, a DOMAIN over text, a custom
62696
+ // text type) are still normalized instead of silently leaving '' rows that
62697
+ // 4.x's `deleted_at IS NULL` predicate would read as DELETED. PER-TABLE FAULT
62698
+ // ISOLATION is the backstop: each table's UPDATE runs in its own
62699
+ // subtransaction, so an exotic type that still errors on `= ''` (enum, inet,
62700
+ // interval, array) — or a blocking trigger/lock — is warned + skipped, never
62701
+ // fatal to the open.
62678
62702
  sql: `DO $LATTICE_DAU$
62679
62703
  DECLARE r record;
62680
62704
  BEGIN
62681
62705
  FOR r IN
62682
62706
  SELECT table_name FROM information_schema.columns
62683
- WHERE table_schema = current_schema() AND column_name = 'deleted_at'
62707
+ WHERE table_schema = current_schema()
62708
+ AND column_name = 'deleted_at'
62709
+ AND data_type NOT IN (
62710
+ 'timestamp with time zone', 'timestamp without time zone',
62711
+ 'date', 'time with time zone', 'time without time zone',
62712
+ 'integer', 'bigint', 'smallint', 'numeric', 'decimal',
62713
+ 'real', 'double precision', 'boolean', 'json', 'jsonb',
62714
+ 'bytea', 'uuid', 'xml'
62715
+ )
62684
62716
  LOOP
62685
- EXECUTE format('UPDATE %I SET deleted_at = NULL WHERE deleted_at = ''''', r.table_name);
62717
+ BEGIN
62718
+ EXECUTE format('UPDATE %I SET deleted_at = NULL WHERE deleted_at = ''''', r.table_name);
62719
+ EXCEPTION WHEN others THEN
62720
+ RAISE WARNING 'lattice: skipped deleted_at normalization for %: %', r.table_name, SQLERRM;
62721
+ END;
62686
62722
  END LOOP;
62687
62723
  END $LATTICE_DAU$;`
62688
62724
  }
@@ -62698,23 +62734,18 @@ END $LATTICE_DAU$;`
62698
62734
  });
62699
62735
  if (migrations.length > 0) await db.migrate(migrations);
62700
62736
  }
62701
- async function filesTableHasPath(db) {
62702
- if (db.getDialect() === "postgres") {
62703
- const rows2 = await allAsyncOrSync(
62704
- db.adapter,
62705
- `SELECT 1 AS x FROM information_schema.columns
62706
- WHERE table_schema = current_schema() AND table_name = 'files' AND column_name = 'path'`
62707
- );
62708
- return rows2.length > 0;
62709
- }
62710
- const rows = await allAsyncOrSync(
62711
- db.adapter,
62712
- `SELECT 1 AS x FROM pragma_table_info('files') WHERE name = 'path'`
62713
- );
62714
- return rows.length > 0;
62737
+ async function filesColumns(db) {
62738
+ const sql = db.getDialect() === "postgres" ? `SELECT column_name AS name FROM information_schema.columns
62739
+ WHERE table_schema = current_schema() AND table_name = 'files'` : `SELECT name FROM pragma_table_info('files')`;
62740
+ const rows = await allAsyncOrSync(db.adapter, sql);
62741
+ return new Set(rows.map((r6) => r6.name));
62715
62742
  }
62716
62743
  async function backfillFilesPath(db) {
62717
- if (!await filesTableHasPath(db)) return;
62744
+ const cols = await filesColumns(db);
62745
+ if (!cols.has("path")) return;
62746
+ for (const col of ["ref_kind", "ref_uri", "ref_provider", "blob_path"]) {
62747
+ if (!cols.has(col)) await addColumnAsyncOrSync(db.adapter, "files", col, "TEXT");
62748
+ }
62718
62749
  await db.migrate([
62719
62750
  {
62720
62751
  version: FILES_PATH_SENTINEL,
package/dist/index.js CHANGED
@@ -62350,8 +62350,18 @@ init_adapter();
62350
62350
  var DELETED_AT_SENTINEL = "internal:upgrade:deleted-at-empty-to-null:v1";
62351
62351
  var FILES_PATH_SENTINEL = "internal:upgrade:files-path-to-local-ref:v1";
62352
62352
  async function upgradeLegacyData(db) {
62353
- await normalizeEmptyDeletedAt(db);
62354
- await backfillFilesPath(db);
62353
+ await runUpgradeStep("deleted_at normalization", () => normalizeEmptyDeletedAt(db));
62354
+ await runUpgradeStep("files path backfill", () => backfillFilesPath(db));
62355
+ }
62356
+ async function runUpgradeStep(name, fn) {
62357
+ try {
62358
+ await fn();
62359
+ } catch (err) {
62360
+ const msg = err instanceof Error ? err.message : String(err);
62361
+ console.warn(
62362
+ `[lattice] open-time data upgrade step "${name}" skipped (will retry on next open): ${msg}`
62363
+ );
62364
+ }
62355
62365
  }
62356
62366
  async function tablesWithDeletedAt(db) {
62357
62367
  if (db.getDialect() === "postgres") {
@@ -62375,14 +62385,40 @@ async function normalizeEmptyDeletedAt(db) {
62375
62385
  await db.migrate([
62376
62386
  {
62377
62387
  version: `${DELETED_AT_SENTINEL}:all`,
62388
+ // TYPE-AWARE: only a text-like deleted_at column can hold the legacy ''
62389
+ // sentinel. A column that is a real `timestamptz` (some clouds' deleted_at
62390
+ // is) MUST be skipped: the predicate `deleted_at = ''` forces Postgres to
62391
+ // parse `''::timestamptz` at PLAN time — invalid input that throws regardless
62392
+ // of data (a timestamptz column can't even hold ''), which aborted the entire
62393
+ // workspace open. We BLACKLIST the non-text types (timestamp/date/time,
62394
+ // numeric, boolean, json, uuid, bytea, xml) rather than allow-list text — so
62395
+ // text-like columns we don't enumerate (citext, a DOMAIN over text, a custom
62396
+ // text type) are still normalized instead of silently leaving '' rows that
62397
+ // 4.x's `deleted_at IS NULL` predicate would read as DELETED. PER-TABLE FAULT
62398
+ // ISOLATION is the backstop: each table's UPDATE runs in its own
62399
+ // subtransaction, so an exotic type that still errors on `= ''` (enum, inet,
62400
+ // interval, array) — or a blocking trigger/lock — is warned + skipped, never
62401
+ // fatal to the open.
62378
62402
  sql: `DO $LATTICE_DAU$
62379
62403
  DECLARE r record;
62380
62404
  BEGIN
62381
62405
  FOR r IN
62382
62406
  SELECT table_name FROM information_schema.columns
62383
- WHERE table_schema = current_schema() AND column_name = 'deleted_at'
62407
+ WHERE table_schema = current_schema()
62408
+ AND column_name = 'deleted_at'
62409
+ AND data_type NOT IN (
62410
+ 'timestamp with time zone', 'timestamp without time zone',
62411
+ 'date', 'time with time zone', 'time without time zone',
62412
+ 'integer', 'bigint', 'smallint', 'numeric', 'decimal',
62413
+ 'real', 'double precision', 'boolean', 'json', 'jsonb',
62414
+ 'bytea', 'uuid', 'xml'
62415
+ )
62384
62416
  LOOP
62385
- EXECUTE format('UPDATE %I SET deleted_at = NULL WHERE deleted_at = ''''', r.table_name);
62417
+ BEGIN
62418
+ EXECUTE format('UPDATE %I SET deleted_at = NULL WHERE deleted_at = ''''', r.table_name);
62419
+ EXCEPTION WHEN others THEN
62420
+ RAISE WARNING 'lattice: skipped deleted_at normalization for %: %', r.table_name, SQLERRM;
62421
+ END;
62386
62422
  END LOOP;
62387
62423
  END $LATTICE_DAU$;`
62388
62424
  }
@@ -62398,23 +62434,18 @@ END $LATTICE_DAU$;`
62398
62434
  });
62399
62435
  if (migrations.length > 0) await db.migrate(migrations);
62400
62436
  }
62401
- async function filesTableHasPath(db) {
62402
- if (db.getDialect() === "postgres") {
62403
- const rows2 = await allAsyncOrSync(
62404
- db.adapter,
62405
- `SELECT 1 AS x FROM information_schema.columns
62406
- WHERE table_schema = current_schema() AND table_name = 'files' AND column_name = 'path'`
62407
- );
62408
- return rows2.length > 0;
62409
- }
62410
- const rows = await allAsyncOrSync(
62411
- db.adapter,
62412
- `SELECT 1 AS x FROM pragma_table_info('files') WHERE name = 'path'`
62413
- );
62414
- return rows.length > 0;
62437
+ async function filesColumns(db) {
62438
+ const sql = db.getDialect() === "postgres" ? `SELECT column_name AS name FROM information_schema.columns
62439
+ WHERE table_schema = current_schema() AND table_name = 'files'` : `SELECT name FROM pragma_table_info('files')`;
62440
+ const rows = await allAsyncOrSync(db.adapter, sql);
62441
+ return new Set(rows.map((r6) => r6.name));
62415
62442
  }
62416
62443
  async function backfillFilesPath(db) {
62417
- if (!await filesTableHasPath(db)) return;
62444
+ const cols = await filesColumns(db);
62445
+ if (!cols.has("path")) return;
62446
+ for (const col of ["ref_kind", "ref_uri", "ref_provider", "blob_path"]) {
62447
+ if (!cols.has(col)) await addColumnAsyncOrSync(db.adapter, "files", col, "TEXT");
62448
+ }
62418
62449
  await db.migrate([
62419
62450
  {
62420
62451
  version: FILES_PATH_SENTINEL,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latticesql",
3
- "version": "4.3.6",
3
+ "version": "4.3.8",
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",