latticesql 0.18.2 → 0.18.3

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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { resolve as resolve3, dirname as dirname5 } from "path";
4
+ import { resolve as resolve4, dirname as dirname5 } from "path";
5
5
  import { readFileSync as readFileSync6 } from "fs";
6
6
  import { parse as parse2 } from "yaml";
7
7
 
@@ -634,8 +634,8 @@ var Sanitizer = class {
634
634
  };
635
635
 
636
636
  // src/render/engine.ts
637
- import { join as join5 } from "path";
638
- import { mkdirSync as mkdirSync3 } from "fs";
637
+ import { join as join5, basename, isAbsolute, resolve as resolve3 } from "path";
638
+ import { mkdirSync as mkdirSync3, existsSync as existsSync5, copyFileSync } from "fs";
639
639
 
640
640
  // src/render/entity-query.ts
641
641
  var SAFE_COL_RE = /^[a-zA-Z0-9_]+$/;
@@ -1175,6 +1175,22 @@ var RenderEngine = class {
1175
1175
  const slug = def.slug(entityRow);
1176
1176
  const entityDir = def.directory ? join5(outputDir, def.directory(entityRow)) : join5(outputDir, directoryRoot, slug);
1177
1177
  mkdirSync3(entityDir, { recursive: true });
1178
+ if (def.attachFileColumn) {
1179
+ const filePath = entityRow[def.attachFileColumn];
1180
+ if (filePath && typeof filePath === "string" && filePath.length > 0) {
1181
+ const absPath = isAbsolute(filePath) ? filePath : resolve3(outputDir, filePath);
1182
+ if (existsSync5(absPath)) {
1183
+ const destPath = join5(entityDir, basename(absPath));
1184
+ if (!existsSync5(destPath)) {
1185
+ try {
1186
+ copyFileSync(absPath, destPath);
1187
+ filesWritten.push(destPath);
1188
+ } catch {
1189
+ }
1190
+ }
1191
+ }
1192
+ }
1193
+ }
1178
1194
  const renderedFiles = /* @__PURE__ */ new Map();
1179
1195
  const entityFileHashes = {};
1180
1196
  const protection = protectedTables.size > 0 ? { protectedTables, currentTable: table } : void 0;
@@ -1224,7 +1240,7 @@ var RenderEngine = class {
1224
1240
 
1225
1241
  // src/reverse-sync/engine.ts
1226
1242
  import { join as join6 } from "path";
1227
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
1243
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
1228
1244
  var ReverseSyncEngine = class {
1229
1245
  _schema;
1230
1246
  _adapter;
@@ -1276,7 +1292,7 @@ var ReverseSyncEngine = class {
1276
1292
  if (!fileInfo.hash) continue;
1277
1293
  const filePath = join6(entityDir, filename);
1278
1294
  result.filesScanned++;
1279
- if (!existsSync5(filePath)) continue;
1295
+ if (!existsSync6(filePath)) continue;
1280
1296
  let currentContent;
1281
1297
  try {
1282
1298
  currentContent = readFileSync4(filePath, "utf8");
@@ -1376,8 +1392,8 @@ var SyncLoop = class {
1376
1392
  };
1377
1393
 
1378
1394
  // src/writeback/pipeline.ts
1379
- import { readFileSync as readFileSync5, statSync as statSync2, existsSync as existsSync6, readdirSync as readdirSync2 } from "fs";
1380
- import { join as join7, dirname as dirname4, basename } from "path";
1395
+ import { readFileSync as readFileSync5, statSync as statSync2, existsSync as existsSync7, readdirSync as readdirSync2 } from "fs";
1396
+ import { join as join7, dirname as dirname4, basename as basename2 } from "path";
1381
1397
 
1382
1398
  // src/writeback/state-store.ts
1383
1399
  var InMemoryStateStore = class {
@@ -1427,7 +1443,7 @@ var WritebackPipeline = class {
1427
1443
  let processed = 0;
1428
1444
  const store = def.stateStore ?? this._stateStore;
1429
1445
  for (const filePath of paths) {
1430
- if (!existsSync6(filePath)) continue;
1446
+ if (!existsSync7(filePath)) continue;
1431
1447
  const stat = statSync2(filePath);
1432
1448
  const currentSize = stat.size;
1433
1449
  const storedOffset = store.getOffset(filePath);
@@ -1461,8 +1477,8 @@ var WritebackPipeline = class {
1461
1477
  return [pattern];
1462
1478
  }
1463
1479
  const dir = dirname4(pattern);
1464
- const filePattern = basename(pattern);
1465
- if (!existsSync6(dir)) return [];
1480
+ const filePattern = basename2(pattern);
1481
+ if (!existsSync7(dir)) return [];
1466
1482
  const regexStr = filePattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
1467
1483
  const regex = new RegExp(`^${regexStr}$`);
1468
1484
  return readdirSync2(dir).filter((f) => regex.test(f)).map((f) => join7(dir, f));
@@ -2738,7 +2754,7 @@ function printVersion() {
2738
2754
  }
2739
2755
  }
2740
2756
  function runGenerate(args) {
2741
- const configPath = resolve3(args.config);
2757
+ const configPath = resolve4(args.config);
2742
2758
  let raw;
2743
2759
  try {
2744
2760
  raw = readFileSync6(configPath, "utf-8");
@@ -2758,7 +2774,7 @@ function runGenerate(args) {
2758
2774
  process.exit(1);
2759
2775
  }
2760
2776
  const configDir = dirname5(configPath);
2761
- const outDir = resolve3(args.out);
2777
+ const outDir = resolve4(args.out);
2762
2778
  try {
2763
2779
  const result = generateAll({ config, configDir, outDir, scaffold: args.scaffold });
2764
2780
  console.log(`Generated ${String(result.filesWritten.length)} file(s):`);
@@ -2771,15 +2787,15 @@ function runGenerate(args) {
2771
2787
  }
2772
2788
  }
2773
2789
  async function runRender(args) {
2774
- const outputDir = resolve3(args.output);
2790
+ const outputDir = resolve4(args.output);
2775
2791
  let parsed;
2776
2792
  try {
2777
- parsed = parseConfigFile(resolve3(args.config));
2793
+ parsed = parseConfigFile(resolve4(args.config));
2778
2794
  } catch (e) {
2779
2795
  console.error(`Error: ${e.message}`);
2780
2796
  process.exit(1);
2781
2797
  }
2782
- const db = new Lattice({ config: resolve3(args.config) });
2798
+ const db = new Lattice({ config: resolve4(args.config) });
2783
2799
  try {
2784
2800
  await db.init();
2785
2801
  const start = Date.now();
@@ -2798,8 +2814,8 @@ async function runRender(args) {
2798
2814
  void parsed;
2799
2815
  }
2800
2816
  async function runReconcile(args, isDryRun) {
2801
- const outputDir = resolve3(args.output);
2802
- const db = new Lattice({ config: resolve3(args.config) });
2817
+ const outputDir = resolve4(args.output);
2818
+ const db = new Lattice({ config: resolve4(args.config) });
2803
2819
  try {
2804
2820
  await db.init();
2805
2821
  const start = Date.now();
@@ -2858,8 +2874,8 @@ function formatTimestamp() {
2858
2874
  return `${hh}:${mm}:${ss}`;
2859
2875
  }
2860
2876
  async function runWatch(args) {
2861
- const outputDir = resolve3(args.output);
2862
- const db = new Lattice({ config: resolve3(args.config) });
2877
+ const outputDir = resolve4(args.output);
2878
+ const db = new Lattice({ config: resolve4(args.config) });
2863
2879
  try {
2864
2880
  await db.init();
2865
2881
  } catch (e) {
package/dist/index.cjs CHANGED
@@ -935,6 +935,22 @@ var RenderEngine = class {
935
935
  const slug = def.slug(entityRow);
936
936
  const entityDir = def.directory ? (0, import_node_path4.join)(outputDir, def.directory(entityRow)) : (0, import_node_path4.join)(outputDir, directoryRoot, slug);
937
937
  (0, import_node_fs4.mkdirSync)(entityDir, { recursive: true });
938
+ if (def.attachFileColumn) {
939
+ const filePath = entityRow[def.attachFileColumn];
940
+ if (filePath && typeof filePath === "string" && filePath.length > 0) {
941
+ const absPath = (0, import_node_path4.isAbsolute)(filePath) ? filePath : (0, import_node_path4.resolve)(outputDir, filePath);
942
+ if ((0, import_node_fs4.existsSync)(absPath)) {
943
+ const destPath = (0, import_node_path4.join)(entityDir, (0, import_node_path4.basename)(absPath));
944
+ if (!(0, import_node_fs4.existsSync)(destPath)) {
945
+ try {
946
+ (0, import_node_fs4.copyFileSync)(absPath, destPath);
947
+ filesWritten.push(destPath);
948
+ } catch {
949
+ }
950
+ }
951
+ }
952
+ }
953
+ }
938
954
  const renderedFiles = /* @__PURE__ */ new Map();
939
955
  const entityFileHashes = {};
940
956
  const protection = protectedTables.size > 0 ? { protectedTables, currentTable: table } : void 0;
package/dist/index.d.cts CHANGED
@@ -534,6 +534,24 @@ interface EntityContextDefinition {
534
534
  encrypted?: boolean | {
535
535
  columns: string[];
536
536
  };
537
+ /**
538
+ * Column name containing a file path. When set, the render pipeline
539
+ * copies the referenced file into each entity's rendered directory.
540
+ *
541
+ * If the path is relative, it's resolved from `outputDir`.
542
+ * If the file doesn't exist, it's silently skipped.
543
+ * The column value is updated to the new relative path after copy.
544
+ *
545
+ * @example
546
+ * ```ts
547
+ * db.defineEntityContext('files', {
548
+ * slug: (r) => r.name,
549
+ * attachFileColumn: 'file_path', // copies file at row.file_path into entity dir
550
+ * files: { 'FILE.md': { ... } },
551
+ * });
552
+ * ```
553
+ */
554
+ attachFileColumn?: string;
537
555
  }
538
556
 
539
557
  interface CleanupOptions {
package/dist/index.d.ts CHANGED
@@ -534,6 +534,24 @@ interface EntityContextDefinition {
534
534
  encrypted?: boolean | {
535
535
  columns: string[];
536
536
  };
537
+ /**
538
+ * Column name containing a file path. When set, the render pipeline
539
+ * copies the referenced file into each entity's rendered directory.
540
+ *
541
+ * If the path is relative, it's resolved from `outputDir`.
542
+ * If the file doesn't exist, it's silently skipped.
543
+ * The column value is updated to the new relative path after copy.
544
+ *
545
+ * @example
546
+ * ```ts
547
+ * db.defineEntityContext('files', {
548
+ * slug: (r) => r.name,
549
+ * attachFileColumn: 'file_path', // copies file at row.file_path into entity dir
550
+ * files: { 'FILE.md': { ... } },
551
+ * });
552
+ * ```
553
+ */
554
+ attachFileColumn?: string;
537
555
  }
538
556
 
539
557
  interface CleanupOptions {
package/dist/index.js CHANGED
@@ -320,8 +320,8 @@ var Sanitizer = class {
320
320
  };
321
321
 
322
322
  // src/render/engine.ts
323
- import { join as join4 } from "path";
324
- import { mkdirSync as mkdirSync2 } from "fs";
323
+ import { join as join4, basename, isAbsolute, resolve } from "path";
324
+ import { mkdirSync as mkdirSync2, existsSync as existsSync4, copyFileSync } from "fs";
325
325
 
326
326
  // src/render/entity-query.ts
327
327
  var SAFE_COL_RE = /^[a-zA-Z0-9_]+$/;
@@ -868,6 +868,22 @@ var RenderEngine = class {
868
868
  const slug = def.slug(entityRow);
869
869
  const entityDir = def.directory ? join4(outputDir, def.directory(entityRow)) : join4(outputDir, directoryRoot, slug);
870
870
  mkdirSync2(entityDir, { recursive: true });
871
+ if (def.attachFileColumn) {
872
+ const filePath = entityRow[def.attachFileColumn];
873
+ if (filePath && typeof filePath === "string" && filePath.length > 0) {
874
+ const absPath = isAbsolute(filePath) ? filePath : resolve(outputDir, filePath);
875
+ if (existsSync4(absPath)) {
876
+ const destPath = join4(entityDir, basename(absPath));
877
+ if (!existsSync4(destPath)) {
878
+ try {
879
+ copyFileSync(absPath, destPath);
880
+ filesWritten.push(destPath);
881
+ } catch {
882
+ }
883
+ }
884
+ }
885
+ }
886
+ }
871
887
  const renderedFiles = /* @__PURE__ */ new Map();
872
888
  const entityFileHashes = {};
873
889
  const protection = protectedTables.size > 0 ? { protectedTables, currentTable: table } : void 0;
@@ -917,7 +933,7 @@ var RenderEngine = class {
917
933
 
918
934
  // src/reverse-sync/engine.ts
919
935
  import { join as join5 } from "path";
920
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
936
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
921
937
  var ReverseSyncEngine = class {
922
938
  _schema;
923
939
  _adapter;
@@ -969,7 +985,7 @@ var ReverseSyncEngine = class {
969
985
  if (!fileInfo.hash) continue;
970
986
  const filePath = join5(entityDir, filename);
971
987
  result.filesScanned++;
972
- if (!existsSync4(filePath)) continue;
988
+ if (!existsSync5(filePath)) continue;
973
989
  let currentContent;
974
990
  try {
975
991
  currentContent = readFileSync3(filePath, "utf8");
@@ -1069,8 +1085,8 @@ var SyncLoop = class {
1069
1085
  };
1070
1086
 
1071
1087
  // src/writeback/pipeline.ts
1072
- import { readFileSync as readFileSync4, statSync as statSync2, existsSync as existsSync5, readdirSync as readdirSync2 } from "fs";
1073
- import { join as join6, dirname as dirname2, basename } from "path";
1088
+ import { readFileSync as readFileSync4, statSync as statSync2, existsSync as existsSync6, readdirSync as readdirSync2 } from "fs";
1089
+ import { join as join6, dirname as dirname2, basename as basename2 } from "path";
1074
1090
 
1075
1091
  // src/writeback/state-store.ts
1076
1092
  var InMemoryStateStore = class {
@@ -1176,7 +1192,7 @@ var WritebackPipeline = class {
1176
1192
  let processed = 0;
1177
1193
  const store = def.stateStore ?? this._stateStore;
1178
1194
  for (const filePath of paths) {
1179
- if (!existsSync5(filePath)) continue;
1195
+ if (!existsSync6(filePath)) continue;
1180
1196
  const stat = statSync2(filePath);
1181
1197
  const currentSize = stat.size;
1182
1198
  const storedOffset = store.getOffset(filePath);
@@ -1210,8 +1226,8 @@ var WritebackPipeline = class {
1210
1226
  return [pattern];
1211
1227
  }
1212
1228
  const dir = dirname2(pattern);
1213
- const filePattern = basename(pattern);
1214
- if (!existsSync5(dir)) return [];
1229
+ const filePattern = basename2(pattern);
1230
+ if (!existsSync6(dir)) return [];
1215
1231
  const regexStr = filePattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
1216
1232
  const regex = new RegExp(`^${regexStr}$`);
1217
1233
  return readdirSync2(dir).filter((f) => regex.test(f)).map((f) => join6(dir, f));
@@ -1335,10 +1351,10 @@ ${body}`;
1335
1351
 
1336
1352
  // src/config/parser.ts
1337
1353
  import { readFileSync as readFileSync5 } from "fs";
1338
- import { resolve, dirname as dirname3 } from "path";
1354
+ import { resolve as resolve2, dirname as dirname3 } from "path";
1339
1355
  import { parse } from "yaml";
1340
1356
  function parseConfigFile(configPath) {
1341
- const absPath = resolve(configPath);
1357
+ const absPath = resolve2(configPath);
1342
1358
  const configDir = dirname3(absPath);
1343
1359
  let raw;
1344
1360
  try {
@@ -1377,7 +1393,7 @@ function buildParsedConfig(raw, sourceName, configDir) {
1377
1393
  throw new Error(`Lattice: config.entities must be an object`);
1378
1394
  }
1379
1395
  const config = raw;
1380
- const dbPath = resolve(configDir, config.db);
1396
+ const dbPath = resolve2(configDir, config.db);
1381
1397
  const tables = [];
1382
1398
  for (const [entityName, entityDef] of Object.entries(config.entities)) {
1383
1399
  const definition = entityToTableDef(entityName, entityDef);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "latticesql",
3
- "version": "0.18.2",
3
+ "version": "0.18.3",
4
4
  "description": "Persistent structured memory for AI agent systems — SQLite ↔ LLM context bridge",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",