@codelia/storage 0.1.2 → 0.1.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/index.cjs +351 -22
- package/dist/index.d.cts +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.js +351 -22
- package/package.json +6 -2
package/dist/index.cjs
CHANGED
|
@@ -255,8 +255,12 @@ var StoragePathServiceImpl = class {
|
|
|
255
255
|
var import_node_fs3 = require("fs");
|
|
256
256
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
257
257
|
var import_core = require("@codelia/core");
|
|
258
|
-
var
|
|
259
|
-
var
|
|
258
|
+
var LEGACY_STATE_DIRNAME = "state";
|
|
259
|
+
var MESSAGES_DIRNAME = "messages";
|
|
260
|
+
var STATE_DB_FILENAME = "state.db";
|
|
261
|
+
var resolveLegacyStateDir = (paths) => import_node_path3.default.join(paths.sessionsDir, LEGACY_STATE_DIRNAME);
|
|
262
|
+
var resolveMessagesDir = (paths) => import_node_path3.default.join(paths.sessionsDir, MESSAGES_DIRNAME);
|
|
263
|
+
var resolveStateDbPath = (paths) => import_node_path3.default.join(paths.sessionsDir, STATE_DB_FILENAME);
|
|
260
264
|
var extractLastUserMessage = (messages) => {
|
|
261
265
|
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
|
262
266
|
const message = messages[idx];
|
|
@@ -276,69 +280,394 @@ var toSummary = (state) => ({
|
|
|
276
280
|
message_count: Array.isArray(state.messages) ? state.messages.length : void 0,
|
|
277
281
|
last_user_message: Array.isArray(state.messages) ? extractLastUserMessage(state.messages) : void 0
|
|
278
282
|
});
|
|
283
|
+
var fromSummaryRow = (row) => ({
|
|
284
|
+
session_id: row.session_id,
|
|
285
|
+
updated_at: row.updated_at,
|
|
286
|
+
run_id: row.run_id ?? void 0,
|
|
287
|
+
message_count: row.message_count ?? void 0,
|
|
288
|
+
last_user_message: row.last_user_message ?? void 0
|
|
289
|
+
});
|
|
290
|
+
var serializeMessages = (messages) => {
|
|
291
|
+
if (messages.length === 0) return "";
|
|
292
|
+
return `${messages.map((message) => JSON.stringify(message)).join("\n")}
|
|
293
|
+
`;
|
|
294
|
+
};
|
|
295
|
+
var deserializeMessages = (payload) => {
|
|
296
|
+
if (!payload.trim()) return [];
|
|
297
|
+
const messages = [];
|
|
298
|
+
const lines = payload.split(/\r?\n/);
|
|
299
|
+
for (const rawLine of lines) {
|
|
300
|
+
const line = rawLine.trim();
|
|
301
|
+
if (!line) continue;
|
|
302
|
+
const parsed = JSON.parse(line);
|
|
303
|
+
if (!parsed || typeof parsed !== "object") {
|
|
304
|
+
throw new Error("Invalid session message entry");
|
|
305
|
+
}
|
|
306
|
+
messages.push(parsed);
|
|
307
|
+
}
|
|
308
|
+
return messages;
|
|
309
|
+
};
|
|
310
|
+
var atomicWriteFile = async (filePath, payload) => {
|
|
311
|
+
const dirname = import_node_path3.default.dirname(filePath);
|
|
312
|
+
const basename = import_node_path3.default.basename(filePath);
|
|
313
|
+
const tempFile = import_node_path3.default.join(
|
|
314
|
+
dirname,
|
|
315
|
+
`${basename}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`
|
|
316
|
+
);
|
|
317
|
+
let wroteTemp = false;
|
|
318
|
+
try {
|
|
319
|
+
await import_node_fs3.promises.writeFile(tempFile, payload, "utf8");
|
|
320
|
+
wroteTemp = true;
|
|
321
|
+
await import_node_fs3.promises.rename(tempFile, filePath);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
if (wroteTemp) {
|
|
324
|
+
await import_node_fs3.promises.rm(tempFile, { force: true }).catch(() => {
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
throw error;
|
|
328
|
+
}
|
|
329
|
+
};
|
|
279
330
|
var SessionStateStoreImpl = class {
|
|
280
|
-
|
|
281
|
-
|
|
331
|
+
legacyStateDir;
|
|
332
|
+
messagesDir;
|
|
333
|
+
stateDbPath;
|
|
334
|
+
ensureDirs;
|
|
335
|
+
db;
|
|
336
|
+
schemaInit;
|
|
282
337
|
onError;
|
|
283
338
|
constructor(options = {}) {
|
|
284
339
|
const paths = options.paths ?? resolveStoragePaths();
|
|
285
|
-
this.
|
|
286
|
-
this.
|
|
340
|
+
this.legacyStateDir = resolveLegacyStateDir(paths);
|
|
341
|
+
this.messagesDir = resolveMessagesDir(paths);
|
|
342
|
+
this.stateDbPath = resolveStateDbPath(paths);
|
|
343
|
+
this.ensureDirs = Promise.all([
|
|
344
|
+
import_node_fs3.promises.mkdir(paths.sessionsDir, { recursive: true }),
|
|
345
|
+
import_node_fs3.promises.mkdir(this.legacyStateDir, { recursive: true }),
|
|
346
|
+
import_node_fs3.promises.mkdir(this.messagesDir, { recursive: true })
|
|
347
|
+
]).then(() => {
|
|
287
348
|
});
|
|
288
349
|
this.onError = options.onError;
|
|
350
|
+
this.db = this.openDatabase();
|
|
351
|
+
this.schemaInit = null;
|
|
289
352
|
}
|
|
290
|
-
|
|
291
|
-
return import_node_path3.default.join(this.
|
|
353
|
+
resolveLegacyPath(sessionId) {
|
|
354
|
+
return import_node_path3.default.join(this.legacyStateDir, `${sessionId}.json`);
|
|
292
355
|
}
|
|
293
|
-
|
|
356
|
+
resolveMessagePath(sessionId) {
|
|
357
|
+
return import_node_path3.default.join(this.messagesDir, `${sessionId}.jsonl`);
|
|
358
|
+
}
|
|
359
|
+
async openDatabase() {
|
|
360
|
+
await this.ensureDirs;
|
|
361
|
+
if (process.versions.bun) {
|
|
362
|
+
const bunSqliteSpecifier = "bun:sqlite";
|
|
363
|
+
const { Database } = await import(bunSqliteSpecifier);
|
|
364
|
+
const db2 = new Database(this.stateDbPath, { create: true });
|
|
365
|
+
return {
|
|
366
|
+
exec: (sql) => {
|
|
367
|
+
db2.exec(sql);
|
|
368
|
+
},
|
|
369
|
+
run: (sql, params = []) => {
|
|
370
|
+
db2.query(sql).run(...params);
|
|
371
|
+
},
|
|
372
|
+
get: (sql, params = []) => {
|
|
373
|
+
const row = db2.query(sql).get(...params);
|
|
374
|
+
return row ?? void 0;
|
|
375
|
+
},
|
|
376
|
+
all: (sql, params = []) => db2.query(sql).all(...params)
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
const betterSqliteSpecifier = "better-sqlite3";
|
|
380
|
+
const betterSqliteModule = await import(betterSqliteSpecifier);
|
|
381
|
+
const BetterSqlite3 = betterSqliteModule.default ?? betterSqliteModule;
|
|
382
|
+
const db = new BetterSqlite3(this.stateDbPath);
|
|
383
|
+
return {
|
|
384
|
+
exec: (sql) => {
|
|
385
|
+
db.exec(sql);
|
|
386
|
+
},
|
|
387
|
+
run: (sql, params = []) => {
|
|
388
|
+
db.prepare(sql).run(...params);
|
|
389
|
+
},
|
|
390
|
+
get: (sql, params = []) => {
|
|
391
|
+
const row = db.prepare(sql).get(...params);
|
|
392
|
+
return row ?? void 0;
|
|
393
|
+
},
|
|
394
|
+
all: (sql, params = []) => db.prepare(sql).all(...params)
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
initDatabaseSchema(db) {
|
|
398
|
+
db.exec("PRAGMA journal_mode = WAL;");
|
|
399
|
+
db.exec(`
|
|
400
|
+
CREATE TABLE IF NOT EXISTS session_state (
|
|
401
|
+
session_id TEXT PRIMARY KEY,
|
|
402
|
+
updated_at TEXT NOT NULL,
|
|
403
|
+
run_id TEXT,
|
|
404
|
+
invoke_seq INTEGER,
|
|
405
|
+
schema_version INTEGER NOT NULL,
|
|
406
|
+
meta_json TEXT,
|
|
407
|
+
message_count INTEGER,
|
|
408
|
+
last_user_message TEXT
|
|
409
|
+
);
|
|
410
|
+
`);
|
|
411
|
+
db.exec(`
|
|
412
|
+
CREATE INDEX IF NOT EXISTS idx_session_state_updated_at
|
|
413
|
+
ON session_state(updated_at DESC);
|
|
414
|
+
`);
|
|
415
|
+
}
|
|
416
|
+
async tryGetDb(action, detail) {
|
|
294
417
|
try {
|
|
295
|
-
const
|
|
418
|
+
const db = await this.db;
|
|
419
|
+
if (!this.schemaInit) {
|
|
420
|
+
this.schemaInit = Promise.resolve().then(() => {
|
|
421
|
+
this.initDatabaseSchema(db);
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
await this.schemaInit;
|
|
425
|
+
return db;
|
|
426
|
+
} catch (error) {
|
|
427
|
+
this.onError?.(error, { action: `${action}.db_unavailable`, detail });
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
async loadLegacy(sessionId) {
|
|
432
|
+
try {
|
|
433
|
+
const file = await import_node_fs3.promises.readFile(this.resolveLegacyPath(sessionId), "utf8");
|
|
296
434
|
const parsed = JSON.parse(file);
|
|
297
435
|
if (!parsed || typeof parsed !== "object") return null;
|
|
298
|
-
return
|
|
436
|
+
if (!parsed.session_id || !parsed.updated_at) return null;
|
|
437
|
+
const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
438
|
+
return {
|
|
439
|
+
schema_version: typeof parsed.schema_version === "number" ? parsed.schema_version : 1,
|
|
440
|
+
session_id: parsed.session_id,
|
|
441
|
+
updated_at: parsed.updated_at,
|
|
442
|
+
run_id: parsed.run_id,
|
|
443
|
+
invoke_seq: parsed.invoke_seq,
|
|
444
|
+
messages,
|
|
445
|
+
meta: parsed.meta && typeof parsed.meta === "object" ? parsed.meta : void 0
|
|
446
|
+
};
|
|
299
447
|
} catch (error) {
|
|
300
448
|
if (error.code === "ENOENT") {
|
|
301
449
|
return null;
|
|
302
450
|
}
|
|
303
|
-
this.onError?.(error, { action: "load", detail: sessionId });
|
|
451
|
+
this.onError?.(error, { action: "legacy.load", detail: sessionId });
|
|
304
452
|
throw error;
|
|
305
453
|
}
|
|
306
454
|
}
|
|
307
|
-
async
|
|
308
|
-
|
|
455
|
+
async loadFromIndex(sessionId, db) {
|
|
456
|
+
let row;
|
|
457
|
+
try {
|
|
458
|
+
row = db.get(
|
|
459
|
+
`SELECT session_id, updated_at, run_id, invoke_seq, schema_version, meta_json
|
|
460
|
+
FROM session_state
|
|
461
|
+
WHERE session_id = ?`,
|
|
462
|
+
[sessionId]
|
|
463
|
+
);
|
|
464
|
+
} catch (error) {
|
|
465
|
+
this.onError?.(error, { action: "index.load", detail: sessionId });
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
if (!row) return null;
|
|
469
|
+
let messages;
|
|
470
|
+
try {
|
|
471
|
+
const payload = await import_node_fs3.promises.readFile(this.resolveMessagePath(sessionId), "utf8");
|
|
472
|
+
messages = deserializeMessages(payload);
|
|
473
|
+
} catch (error) {
|
|
474
|
+
if (error.code === "ENOENT") {
|
|
475
|
+
messages = [];
|
|
476
|
+
} else {
|
|
477
|
+
this.onError?.(error, { action: "messages.load", detail: sessionId });
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
let meta;
|
|
482
|
+
if (row.meta_json) {
|
|
483
|
+
try {
|
|
484
|
+
const parsed = JSON.parse(row.meta_json);
|
|
485
|
+
if (parsed && typeof parsed === "object") {
|
|
486
|
+
meta = parsed;
|
|
487
|
+
}
|
|
488
|
+
} catch (error) {
|
|
489
|
+
this.onError?.(error, { action: "index.meta.parse", detail: sessionId });
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return {
|
|
493
|
+
schema_version: 1,
|
|
494
|
+
session_id: row.session_id,
|
|
495
|
+
updated_at: row.updated_at,
|
|
496
|
+
run_id: row.run_id ?? void 0,
|
|
497
|
+
invoke_seq: row.invoke_seq ?? void 0,
|
|
498
|
+
messages,
|
|
499
|
+
meta
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
async saveToIndex(state, db) {
|
|
503
|
+
const messagePayload = serializeMessages(
|
|
504
|
+
Array.isArray(state.messages) ? state.messages : []
|
|
505
|
+
);
|
|
506
|
+
await atomicWriteFile(this.resolveMessagePath(state.session_id), messagePayload);
|
|
507
|
+
const summary = toSummary(state);
|
|
508
|
+
db.run(
|
|
509
|
+
`INSERT INTO session_state (
|
|
510
|
+
session_id,
|
|
511
|
+
updated_at,
|
|
512
|
+
run_id,
|
|
513
|
+
invoke_seq,
|
|
514
|
+
schema_version,
|
|
515
|
+
meta_json,
|
|
516
|
+
message_count,
|
|
517
|
+
last_user_message
|
|
518
|
+
)
|
|
519
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
520
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
521
|
+
updated_at = excluded.updated_at,
|
|
522
|
+
run_id = excluded.run_id,
|
|
523
|
+
invoke_seq = excluded.invoke_seq,
|
|
524
|
+
schema_version = excluded.schema_version,
|
|
525
|
+
meta_json = excluded.meta_json,
|
|
526
|
+
message_count = excluded.message_count,
|
|
527
|
+
last_user_message = excluded.last_user_message`,
|
|
528
|
+
[
|
|
529
|
+
state.session_id,
|
|
530
|
+
state.updated_at,
|
|
531
|
+
state.run_id ?? null,
|
|
532
|
+
state.invoke_seq ?? null,
|
|
533
|
+
state.schema_version ?? 1,
|
|
534
|
+
state.meta ? JSON.stringify(state.meta) : null,
|
|
535
|
+
summary.message_count ?? null,
|
|
536
|
+
summary.last_user_message ?? null
|
|
537
|
+
]
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
async saveLegacy(state) {
|
|
309
541
|
const payload = `${JSON.stringify(state)}
|
|
310
542
|
`;
|
|
311
|
-
await
|
|
543
|
+
await atomicWriteFile(this.resolveLegacyPath(state.session_id), payload);
|
|
312
544
|
}
|
|
313
|
-
async
|
|
314
|
-
|
|
545
|
+
async hasLegacySnapshot(sessionId) {
|
|
546
|
+
try {
|
|
547
|
+
const stat = await import_node_fs3.promises.stat(this.resolveLegacyPath(sessionId));
|
|
548
|
+
return stat.isFile();
|
|
549
|
+
} catch (error) {
|
|
550
|
+
if (error.code === "ENOENT") {
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
throw error;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
async saveLegacyIfPresent(state) {
|
|
557
|
+
if (!await this.hasLegacySnapshot(state.session_id)) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
await this.saveLegacy(state);
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
async load(sessionId) {
|
|
564
|
+
const db = await this.tryGetDb("load", sessionId);
|
|
565
|
+
if (db) {
|
|
566
|
+
try {
|
|
567
|
+
const indexed = await this.loadFromIndex(sessionId, db);
|
|
568
|
+
if (indexed) return indexed;
|
|
569
|
+
} catch (error) {
|
|
570
|
+
this.onError?.(error, { action: "load.index", detail: sessionId });
|
|
571
|
+
throw error;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
const legacy = await this.loadLegacy(sessionId);
|
|
575
|
+
if (!legacy) return null;
|
|
576
|
+
if (db) {
|
|
577
|
+
try {
|
|
578
|
+
await this.saveToIndex(legacy, db);
|
|
579
|
+
} catch (error) {
|
|
580
|
+
this.onError?.(error, { action: "load.migrate_legacy", detail: sessionId });
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return legacy;
|
|
584
|
+
}
|
|
585
|
+
async save(state) {
|
|
586
|
+
await this.ensureDirs;
|
|
587
|
+
const db = await this.tryGetDb("save", state.session_id);
|
|
588
|
+
if (!db) {
|
|
589
|
+
const savedLegacy = await this.saveLegacyIfPresent(state);
|
|
590
|
+
if (savedLegacy) return;
|
|
591
|
+
throw new Error(
|
|
592
|
+
"Session index database unavailable and no legacy snapshot found"
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
try {
|
|
596
|
+
await this.saveToIndex(state, db);
|
|
597
|
+
} catch (error) {
|
|
598
|
+
this.onError?.(error, { action: "save.index", detail: state.session_id });
|
|
599
|
+
try {
|
|
600
|
+
const savedLegacy = await this.saveLegacyIfPresent(state);
|
|
601
|
+
if (savedLegacy) return;
|
|
602
|
+
} catch (legacyError) {
|
|
603
|
+
this.onError?.(legacyError, {
|
|
604
|
+
action: "save.legacy_fallback",
|
|
605
|
+
detail: state.session_id
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
async listLegacySummaries() {
|
|
315
612
|
let entries;
|
|
316
613
|
try {
|
|
317
|
-
entries = await import_node_fs3.promises.readdir(this.
|
|
614
|
+
entries = await import_node_fs3.promises.readdir(this.legacyStateDir, {
|
|
318
615
|
withFileTypes: true,
|
|
319
616
|
encoding: "utf8"
|
|
320
617
|
});
|
|
321
618
|
} catch (error) {
|
|
322
|
-
this.onError?.(error, { action: "list" });
|
|
619
|
+
this.onError?.(error, { action: "legacy.list" });
|
|
323
620
|
throw error;
|
|
324
621
|
}
|
|
325
622
|
const summaries = [];
|
|
326
623
|
for (const entry of entries) {
|
|
327
624
|
if (!entry.isFile()) continue;
|
|
328
625
|
if (!entry.name.endsWith(".json")) continue;
|
|
329
|
-
const filePath = import_node_path3.default.join(this.
|
|
626
|
+
const filePath = import_node_path3.default.join(this.legacyStateDir, entry.name);
|
|
330
627
|
try {
|
|
331
628
|
const contents = await import_node_fs3.promises.readFile(filePath, "utf8");
|
|
332
629
|
const parsed = JSON.parse(contents);
|
|
333
630
|
if (!parsed || typeof parsed !== "object") continue;
|
|
334
631
|
if (!parsed.session_id || !parsed.updated_at) continue;
|
|
335
|
-
summaries.push(
|
|
632
|
+
summaries.push(
|
|
633
|
+
toSummary({
|
|
634
|
+
...parsed,
|
|
635
|
+
schema_version: typeof parsed.schema_version === "number" ? parsed.schema_version : 1,
|
|
636
|
+
messages: Array.isArray(parsed.messages) ? parsed.messages : []
|
|
637
|
+
})
|
|
638
|
+
);
|
|
336
639
|
} catch (error) {
|
|
337
|
-
this.onError?.(error, { action: "parse", detail: filePath });
|
|
640
|
+
this.onError?.(error, { action: "legacy.parse", detail: filePath });
|
|
338
641
|
}
|
|
339
642
|
}
|
|
340
643
|
return summaries;
|
|
341
644
|
}
|
|
645
|
+
async list() {
|
|
646
|
+
await this.ensureDirs;
|
|
647
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
648
|
+
const db = await this.tryGetDb("list");
|
|
649
|
+
if (db) {
|
|
650
|
+
try {
|
|
651
|
+
const rows = db.all(
|
|
652
|
+
`SELECT session_id, updated_at, run_id, message_count, last_user_message
|
|
653
|
+
FROM session_state
|
|
654
|
+
ORDER BY updated_at DESC`
|
|
655
|
+
);
|
|
656
|
+
for (const row of rows) {
|
|
657
|
+
summaries.set(row.session_id, fromSummaryRow(row));
|
|
658
|
+
}
|
|
659
|
+
} catch (error) {
|
|
660
|
+
this.onError?.(error, { action: "list.index" });
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const legacy = await this.listLegacySummaries();
|
|
664
|
+
for (const item of legacy) {
|
|
665
|
+
if (!summaries.has(item.session_id)) {
|
|
666
|
+
summaries.set(item.session_id, item);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return [...summaries.values()];
|
|
670
|
+
}
|
|
342
671
|
};
|
|
343
672
|
|
|
344
673
|
// src/tool-output-cache.ts
|
package/dist/index.d.cts
CHANGED
|
@@ -40,13 +40,28 @@ type SessionStateStoreOptions = {
|
|
|
40
40
|
}) => void;
|
|
41
41
|
};
|
|
42
42
|
declare class SessionStateStoreImpl implements SessionStateStore {
|
|
43
|
-
private readonly
|
|
44
|
-
private readonly
|
|
43
|
+
private readonly legacyStateDir;
|
|
44
|
+
private readonly messagesDir;
|
|
45
|
+
private readonly stateDbPath;
|
|
46
|
+
private readonly ensureDirs;
|
|
47
|
+
private readonly db;
|
|
48
|
+
private schemaInit;
|
|
45
49
|
private readonly onError?;
|
|
46
50
|
constructor(options?: SessionStateStoreOptions);
|
|
47
|
-
private
|
|
51
|
+
private resolveLegacyPath;
|
|
52
|
+
private resolveMessagePath;
|
|
53
|
+
private openDatabase;
|
|
54
|
+
private initDatabaseSchema;
|
|
55
|
+
private tryGetDb;
|
|
56
|
+
private loadLegacy;
|
|
57
|
+
private loadFromIndex;
|
|
58
|
+
private saveToIndex;
|
|
59
|
+
private saveLegacy;
|
|
60
|
+
private hasLegacySnapshot;
|
|
61
|
+
private saveLegacyIfPresent;
|
|
48
62
|
load(sessionId: string): Promise<SessionState | null>;
|
|
49
63
|
save(state: SessionState): Promise<void>;
|
|
64
|
+
private listLegacySummaries;
|
|
50
65
|
list(): Promise<SessionStateSummary[]>;
|
|
51
66
|
}
|
|
52
67
|
|
package/dist/index.d.ts
CHANGED
|
@@ -40,13 +40,28 @@ type SessionStateStoreOptions = {
|
|
|
40
40
|
}) => void;
|
|
41
41
|
};
|
|
42
42
|
declare class SessionStateStoreImpl implements SessionStateStore {
|
|
43
|
-
private readonly
|
|
44
|
-
private readonly
|
|
43
|
+
private readonly legacyStateDir;
|
|
44
|
+
private readonly messagesDir;
|
|
45
|
+
private readonly stateDbPath;
|
|
46
|
+
private readonly ensureDirs;
|
|
47
|
+
private readonly db;
|
|
48
|
+
private schemaInit;
|
|
45
49
|
private readonly onError?;
|
|
46
50
|
constructor(options?: SessionStateStoreOptions);
|
|
47
|
-
private
|
|
51
|
+
private resolveLegacyPath;
|
|
52
|
+
private resolveMessagePath;
|
|
53
|
+
private openDatabase;
|
|
54
|
+
private initDatabaseSchema;
|
|
55
|
+
private tryGetDb;
|
|
56
|
+
private loadLegacy;
|
|
57
|
+
private loadFromIndex;
|
|
58
|
+
private saveToIndex;
|
|
59
|
+
private saveLegacy;
|
|
60
|
+
private hasLegacySnapshot;
|
|
61
|
+
private saveLegacyIfPresent;
|
|
48
62
|
load(sessionId: string): Promise<SessionState | null>;
|
|
49
63
|
save(state: SessionState): Promise<void>;
|
|
64
|
+
private listLegacySummaries;
|
|
50
65
|
list(): Promise<SessionStateSummary[]>;
|
|
51
66
|
}
|
|
52
67
|
|
package/dist/index.js
CHANGED
|
@@ -212,8 +212,12 @@ var StoragePathServiceImpl = class {
|
|
|
212
212
|
import { promises as fs3 } from "fs";
|
|
213
213
|
import path3 from "path";
|
|
214
214
|
import { stringifyContent } from "@codelia/core";
|
|
215
|
-
var
|
|
216
|
-
var
|
|
215
|
+
var LEGACY_STATE_DIRNAME = "state";
|
|
216
|
+
var MESSAGES_DIRNAME = "messages";
|
|
217
|
+
var STATE_DB_FILENAME = "state.db";
|
|
218
|
+
var resolveLegacyStateDir = (paths) => path3.join(paths.sessionsDir, LEGACY_STATE_DIRNAME);
|
|
219
|
+
var resolveMessagesDir = (paths) => path3.join(paths.sessionsDir, MESSAGES_DIRNAME);
|
|
220
|
+
var resolveStateDbPath = (paths) => path3.join(paths.sessionsDir, STATE_DB_FILENAME);
|
|
217
221
|
var extractLastUserMessage = (messages) => {
|
|
218
222
|
for (let idx = messages.length - 1; idx >= 0; idx -= 1) {
|
|
219
223
|
const message = messages[idx];
|
|
@@ -233,69 +237,394 @@ var toSummary = (state) => ({
|
|
|
233
237
|
message_count: Array.isArray(state.messages) ? state.messages.length : void 0,
|
|
234
238
|
last_user_message: Array.isArray(state.messages) ? extractLastUserMessage(state.messages) : void 0
|
|
235
239
|
});
|
|
240
|
+
var fromSummaryRow = (row) => ({
|
|
241
|
+
session_id: row.session_id,
|
|
242
|
+
updated_at: row.updated_at,
|
|
243
|
+
run_id: row.run_id ?? void 0,
|
|
244
|
+
message_count: row.message_count ?? void 0,
|
|
245
|
+
last_user_message: row.last_user_message ?? void 0
|
|
246
|
+
});
|
|
247
|
+
var serializeMessages = (messages) => {
|
|
248
|
+
if (messages.length === 0) return "";
|
|
249
|
+
return `${messages.map((message) => JSON.stringify(message)).join("\n")}
|
|
250
|
+
`;
|
|
251
|
+
};
|
|
252
|
+
var deserializeMessages = (payload) => {
|
|
253
|
+
if (!payload.trim()) return [];
|
|
254
|
+
const messages = [];
|
|
255
|
+
const lines = payload.split(/\r?\n/);
|
|
256
|
+
for (const rawLine of lines) {
|
|
257
|
+
const line = rawLine.trim();
|
|
258
|
+
if (!line) continue;
|
|
259
|
+
const parsed = JSON.parse(line);
|
|
260
|
+
if (!parsed || typeof parsed !== "object") {
|
|
261
|
+
throw new Error("Invalid session message entry");
|
|
262
|
+
}
|
|
263
|
+
messages.push(parsed);
|
|
264
|
+
}
|
|
265
|
+
return messages;
|
|
266
|
+
};
|
|
267
|
+
var atomicWriteFile = async (filePath, payload) => {
|
|
268
|
+
const dirname = path3.dirname(filePath);
|
|
269
|
+
const basename = path3.basename(filePath);
|
|
270
|
+
const tempFile = path3.join(
|
|
271
|
+
dirname,
|
|
272
|
+
`${basename}.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`
|
|
273
|
+
);
|
|
274
|
+
let wroteTemp = false;
|
|
275
|
+
try {
|
|
276
|
+
await fs3.writeFile(tempFile, payload, "utf8");
|
|
277
|
+
wroteTemp = true;
|
|
278
|
+
await fs3.rename(tempFile, filePath);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
if (wroteTemp) {
|
|
281
|
+
await fs3.rm(tempFile, { force: true }).catch(() => {
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
236
287
|
var SessionStateStoreImpl = class {
|
|
237
|
-
|
|
238
|
-
|
|
288
|
+
legacyStateDir;
|
|
289
|
+
messagesDir;
|
|
290
|
+
stateDbPath;
|
|
291
|
+
ensureDirs;
|
|
292
|
+
db;
|
|
293
|
+
schemaInit;
|
|
239
294
|
onError;
|
|
240
295
|
constructor(options = {}) {
|
|
241
296
|
const paths = options.paths ?? resolveStoragePaths();
|
|
242
|
-
this.
|
|
243
|
-
this.
|
|
297
|
+
this.legacyStateDir = resolveLegacyStateDir(paths);
|
|
298
|
+
this.messagesDir = resolveMessagesDir(paths);
|
|
299
|
+
this.stateDbPath = resolveStateDbPath(paths);
|
|
300
|
+
this.ensureDirs = Promise.all([
|
|
301
|
+
fs3.mkdir(paths.sessionsDir, { recursive: true }),
|
|
302
|
+
fs3.mkdir(this.legacyStateDir, { recursive: true }),
|
|
303
|
+
fs3.mkdir(this.messagesDir, { recursive: true })
|
|
304
|
+
]).then(() => {
|
|
244
305
|
});
|
|
245
306
|
this.onError = options.onError;
|
|
307
|
+
this.db = this.openDatabase();
|
|
308
|
+
this.schemaInit = null;
|
|
246
309
|
}
|
|
247
|
-
|
|
248
|
-
return path3.join(this.
|
|
310
|
+
resolveLegacyPath(sessionId) {
|
|
311
|
+
return path3.join(this.legacyStateDir, `${sessionId}.json`);
|
|
249
312
|
}
|
|
250
|
-
|
|
313
|
+
resolveMessagePath(sessionId) {
|
|
314
|
+
return path3.join(this.messagesDir, `${sessionId}.jsonl`);
|
|
315
|
+
}
|
|
316
|
+
async openDatabase() {
|
|
317
|
+
await this.ensureDirs;
|
|
318
|
+
if (process.versions.bun) {
|
|
319
|
+
const bunSqliteSpecifier = "bun:sqlite";
|
|
320
|
+
const { Database } = await import(bunSqliteSpecifier);
|
|
321
|
+
const db2 = new Database(this.stateDbPath, { create: true });
|
|
322
|
+
return {
|
|
323
|
+
exec: (sql) => {
|
|
324
|
+
db2.exec(sql);
|
|
325
|
+
},
|
|
326
|
+
run: (sql, params = []) => {
|
|
327
|
+
db2.query(sql).run(...params);
|
|
328
|
+
},
|
|
329
|
+
get: (sql, params = []) => {
|
|
330
|
+
const row = db2.query(sql).get(...params);
|
|
331
|
+
return row ?? void 0;
|
|
332
|
+
},
|
|
333
|
+
all: (sql, params = []) => db2.query(sql).all(...params)
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
const betterSqliteSpecifier = "better-sqlite3";
|
|
337
|
+
const betterSqliteModule = await import(betterSqliteSpecifier);
|
|
338
|
+
const BetterSqlite3 = betterSqliteModule.default ?? betterSqliteModule;
|
|
339
|
+
const db = new BetterSqlite3(this.stateDbPath);
|
|
340
|
+
return {
|
|
341
|
+
exec: (sql) => {
|
|
342
|
+
db.exec(sql);
|
|
343
|
+
},
|
|
344
|
+
run: (sql, params = []) => {
|
|
345
|
+
db.prepare(sql).run(...params);
|
|
346
|
+
},
|
|
347
|
+
get: (sql, params = []) => {
|
|
348
|
+
const row = db.prepare(sql).get(...params);
|
|
349
|
+
return row ?? void 0;
|
|
350
|
+
},
|
|
351
|
+
all: (sql, params = []) => db.prepare(sql).all(...params)
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
initDatabaseSchema(db) {
|
|
355
|
+
db.exec("PRAGMA journal_mode = WAL;");
|
|
356
|
+
db.exec(`
|
|
357
|
+
CREATE TABLE IF NOT EXISTS session_state (
|
|
358
|
+
session_id TEXT PRIMARY KEY,
|
|
359
|
+
updated_at TEXT NOT NULL,
|
|
360
|
+
run_id TEXT,
|
|
361
|
+
invoke_seq INTEGER,
|
|
362
|
+
schema_version INTEGER NOT NULL,
|
|
363
|
+
meta_json TEXT,
|
|
364
|
+
message_count INTEGER,
|
|
365
|
+
last_user_message TEXT
|
|
366
|
+
);
|
|
367
|
+
`);
|
|
368
|
+
db.exec(`
|
|
369
|
+
CREATE INDEX IF NOT EXISTS idx_session_state_updated_at
|
|
370
|
+
ON session_state(updated_at DESC);
|
|
371
|
+
`);
|
|
372
|
+
}
|
|
373
|
+
async tryGetDb(action, detail) {
|
|
251
374
|
try {
|
|
252
|
-
const
|
|
375
|
+
const db = await this.db;
|
|
376
|
+
if (!this.schemaInit) {
|
|
377
|
+
this.schemaInit = Promise.resolve().then(() => {
|
|
378
|
+
this.initDatabaseSchema(db);
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
await this.schemaInit;
|
|
382
|
+
return db;
|
|
383
|
+
} catch (error) {
|
|
384
|
+
this.onError?.(error, { action: `${action}.db_unavailable`, detail });
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async loadLegacy(sessionId) {
|
|
389
|
+
try {
|
|
390
|
+
const file = await fs3.readFile(this.resolveLegacyPath(sessionId), "utf8");
|
|
253
391
|
const parsed = JSON.parse(file);
|
|
254
392
|
if (!parsed || typeof parsed !== "object") return null;
|
|
255
|
-
return
|
|
393
|
+
if (!parsed.session_id || !parsed.updated_at) return null;
|
|
394
|
+
const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
395
|
+
return {
|
|
396
|
+
schema_version: typeof parsed.schema_version === "number" ? parsed.schema_version : 1,
|
|
397
|
+
session_id: parsed.session_id,
|
|
398
|
+
updated_at: parsed.updated_at,
|
|
399
|
+
run_id: parsed.run_id,
|
|
400
|
+
invoke_seq: parsed.invoke_seq,
|
|
401
|
+
messages,
|
|
402
|
+
meta: parsed.meta && typeof parsed.meta === "object" ? parsed.meta : void 0
|
|
403
|
+
};
|
|
256
404
|
} catch (error) {
|
|
257
405
|
if (error.code === "ENOENT") {
|
|
258
406
|
return null;
|
|
259
407
|
}
|
|
260
|
-
this.onError?.(error, { action: "load", detail: sessionId });
|
|
408
|
+
this.onError?.(error, { action: "legacy.load", detail: sessionId });
|
|
261
409
|
throw error;
|
|
262
410
|
}
|
|
263
411
|
}
|
|
264
|
-
async
|
|
265
|
-
|
|
412
|
+
async loadFromIndex(sessionId, db) {
|
|
413
|
+
let row;
|
|
414
|
+
try {
|
|
415
|
+
row = db.get(
|
|
416
|
+
`SELECT session_id, updated_at, run_id, invoke_seq, schema_version, meta_json
|
|
417
|
+
FROM session_state
|
|
418
|
+
WHERE session_id = ?`,
|
|
419
|
+
[sessionId]
|
|
420
|
+
);
|
|
421
|
+
} catch (error) {
|
|
422
|
+
this.onError?.(error, { action: "index.load", detail: sessionId });
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
425
|
+
if (!row) return null;
|
|
426
|
+
let messages;
|
|
427
|
+
try {
|
|
428
|
+
const payload = await fs3.readFile(this.resolveMessagePath(sessionId), "utf8");
|
|
429
|
+
messages = deserializeMessages(payload);
|
|
430
|
+
} catch (error) {
|
|
431
|
+
if (error.code === "ENOENT") {
|
|
432
|
+
messages = [];
|
|
433
|
+
} else {
|
|
434
|
+
this.onError?.(error, { action: "messages.load", detail: sessionId });
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
let meta;
|
|
439
|
+
if (row.meta_json) {
|
|
440
|
+
try {
|
|
441
|
+
const parsed = JSON.parse(row.meta_json);
|
|
442
|
+
if (parsed && typeof parsed === "object") {
|
|
443
|
+
meta = parsed;
|
|
444
|
+
}
|
|
445
|
+
} catch (error) {
|
|
446
|
+
this.onError?.(error, { action: "index.meta.parse", detail: sessionId });
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return {
|
|
450
|
+
schema_version: 1,
|
|
451
|
+
session_id: row.session_id,
|
|
452
|
+
updated_at: row.updated_at,
|
|
453
|
+
run_id: row.run_id ?? void 0,
|
|
454
|
+
invoke_seq: row.invoke_seq ?? void 0,
|
|
455
|
+
messages,
|
|
456
|
+
meta
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
async saveToIndex(state, db) {
|
|
460
|
+
const messagePayload = serializeMessages(
|
|
461
|
+
Array.isArray(state.messages) ? state.messages : []
|
|
462
|
+
);
|
|
463
|
+
await atomicWriteFile(this.resolveMessagePath(state.session_id), messagePayload);
|
|
464
|
+
const summary = toSummary(state);
|
|
465
|
+
db.run(
|
|
466
|
+
`INSERT INTO session_state (
|
|
467
|
+
session_id,
|
|
468
|
+
updated_at,
|
|
469
|
+
run_id,
|
|
470
|
+
invoke_seq,
|
|
471
|
+
schema_version,
|
|
472
|
+
meta_json,
|
|
473
|
+
message_count,
|
|
474
|
+
last_user_message
|
|
475
|
+
)
|
|
476
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
477
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
478
|
+
updated_at = excluded.updated_at,
|
|
479
|
+
run_id = excluded.run_id,
|
|
480
|
+
invoke_seq = excluded.invoke_seq,
|
|
481
|
+
schema_version = excluded.schema_version,
|
|
482
|
+
meta_json = excluded.meta_json,
|
|
483
|
+
message_count = excluded.message_count,
|
|
484
|
+
last_user_message = excluded.last_user_message`,
|
|
485
|
+
[
|
|
486
|
+
state.session_id,
|
|
487
|
+
state.updated_at,
|
|
488
|
+
state.run_id ?? null,
|
|
489
|
+
state.invoke_seq ?? null,
|
|
490
|
+
state.schema_version ?? 1,
|
|
491
|
+
state.meta ? JSON.stringify(state.meta) : null,
|
|
492
|
+
summary.message_count ?? null,
|
|
493
|
+
summary.last_user_message ?? null
|
|
494
|
+
]
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
async saveLegacy(state) {
|
|
266
498
|
const payload = `${JSON.stringify(state)}
|
|
267
499
|
`;
|
|
268
|
-
await
|
|
500
|
+
await atomicWriteFile(this.resolveLegacyPath(state.session_id), payload);
|
|
269
501
|
}
|
|
270
|
-
async
|
|
271
|
-
|
|
502
|
+
async hasLegacySnapshot(sessionId) {
|
|
503
|
+
try {
|
|
504
|
+
const stat = await fs3.stat(this.resolveLegacyPath(sessionId));
|
|
505
|
+
return stat.isFile();
|
|
506
|
+
} catch (error) {
|
|
507
|
+
if (error.code === "ENOENT") {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
throw error;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
async saveLegacyIfPresent(state) {
|
|
514
|
+
if (!await this.hasLegacySnapshot(state.session_id)) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
await this.saveLegacy(state);
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
async load(sessionId) {
|
|
521
|
+
const db = await this.tryGetDb("load", sessionId);
|
|
522
|
+
if (db) {
|
|
523
|
+
try {
|
|
524
|
+
const indexed = await this.loadFromIndex(sessionId, db);
|
|
525
|
+
if (indexed) return indexed;
|
|
526
|
+
} catch (error) {
|
|
527
|
+
this.onError?.(error, { action: "load.index", detail: sessionId });
|
|
528
|
+
throw error;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
const legacy = await this.loadLegacy(sessionId);
|
|
532
|
+
if (!legacy) return null;
|
|
533
|
+
if (db) {
|
|
534
|
+
try {
|
|
535
|
+
await this.saveToIndex(legacy, db);
|
|
536
|
+
} catch (error) {
|
|
537
|
+
this.onError?.(error, { action: "load.migrate_legacy", detail: sessionId });
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return legacy;
|
|
541
|
+
}
|
|
542
|
+
async save(state) {
|
|
543
|
+
await this.ensureDirs;
|
|
544
|
+
const db = await this.tryGetDb("save", state.session_id);
|
|
545
|
+
if (!db) {
|
|
546
|
+
const savedLegacy = await this.saveLegacyIfPresent(state);
|
|
547
|
+
if (savedLegacy) return;
|
|
548
|
+
throw new Error(
|
|
549
|
+
"Session index database unavailable and no legacy snapshot found"
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
await this.saveToIndex(state, db);
|
|
554
|
+
} catch (error) {
|
|
555
|
+
this.onError?.(error, { action: "save.index", detail: state.session_id });
|
|
556
|
+
try {
|
|
557
|
+
const savedLegacy = await this.saveLegacyIfPresent(state);
|
|
558
|
+
if (savedLegacy) return;
|
|
559
|
+
} catch (legacyError) {
|
|
560
|
+
this.onError?.(legacyError, {
|
|
561
|
+
action: "save.legacy_fallback",
|
|
562
|
+
detail: state.session_id
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
throw error;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
async listLegacySummaries() {
|
|
272
569
|
let entries;
|
|
273
570
|
try {
|
|
274
|
-
entries = await fs3.readdir(this.
|
|
571
|
+
entries = await fs3.readdir(this.legacyStateDir, {
|
|
275
572
|
withFileTypes: true,
|
|
276
573
|
encoding: "utf8"
|
|
277
574
|
});
|
|
278
575
|
} catch (error) {
|
|
279
|
-
this.onError?.(error, { action: "list" });
|
|
576
|
+
this.onError?.(error, { action: "legacy.list" });
|
|
280
577
|
throw error;
|
|
281
578
|
}
|
|
282
579
|
const summaries = [];
|
|
283
580
|
for (const entry of entries) {
|
|
284
581
|
if (!entry.isFile()) continue;
|
|
285
582
|
if (!entry.name.endsWith(".json")) continue;
|
|
286
|
-
const filePath = path3.join(this.
|
|
583
|
+
const filePath = path3.join(this.legacyStateDir, entry.name);
|
|
287
584
|
try {
|
|
288
585
|
const contents = await fs3.readFile(filePath, "utf8");
|
|
289
586
|
const parsed = JSON.parse(contents);
|
|
290
587
|
if (!parsed || typeof parsed !== "object") continue;
|
|
291
588
|
if (!parsed.session_id || !parsed.updated_at) continue;
|
|
292
|
-
summaries.push(
|
|
589
|
+
summaries.push(
|
|
590
|
+
toSummary({
|
|
591
|
+
...parsed,
|
|
592
|
+
schema_version: typeof parsed.schema_version === "number" ? parsed.schema_version : 1,
|
|
593
|
+
messages: Array.isArray(parsed.messages) ? parsed.messages : []
|
|
594
|
+
})
|
|
595
|
+
);
|
|
293
596
|
} catch (error) {
|
|
294
|
-
this.onError?.(error, { action: "parse", detail: filePath });
|
|
597
|
+
this.onError?.(error, { action: "legacy.parse", detail: filePath });
|
|
295
598
|
}
|
|
296
599
|
}
|
|
297
600
|
return summaries;
|
|
298
601
|
}
|
|
602
|
+
async list() {
|
|
603
|
+
await this.ensureDirs;
|
|
604
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
605
|
+
const db = await this.tryGetDb("list");
|
|
606
|
+
if (db) {
|
|
607
|
+
try {
|
|
608
|
+
const rows = db.all(
|
|
609
|
+
`SELECT session_id, updated_at, run_id, message_count, last_user_message
|
|
610
|
+
FROM session_state
|
|
611
|
+
ORDER BY updated_at DESC`
|
|
612
|
+
);
|
|
613
|
+
for (const row of rows) {
|
|
614
|
+
summaries.set(row.session_id, fromSummaryRow(row));
|
|
615
|
+
}
|
|
616
|
+
} catch (error) {
|
|
617
|
+
this.onError?.(error, { action: "list.index" });
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
const legacy = await this.listLegacySummaries();
|
|
621
|
+
for (const item of legacy) {
|
|
622
|
+
if (!summaries.has(item.session_id)) {
|
|
623
|
+
summaries.set(item.session_id, item);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return [...summaries.values()];
|
|
627
|
+
}
|
|
299
628
|
};
|
|
300
629
|
|
|
301
630
|
// src/tool-output-cache.ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codelia/storage",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=20 <25"
|
|
7
|
+
},
|
|
5
8
|
"files": [
|
|
6
9
|
"dist"
|
|
7
10
|
],
|
|
@@ -20,7 +23,8 @@
|
|
|
20
23
|
"typecheck": "tsc --noEmit"
|
|
21
24
|
},
|
|
22
25
|
"dependencies": {
|
|
23
|
-
"@codelia/core": "0.1.
|
|
26
|
+
"@codelia/core": "0.1.3",
|
|
27
|
+
"better-sqlite3": "^12.6.2"
|
|
24
28
|
},
|
|
25
29
|
"publishConfig": {
|
|
26
30
|
"access": "public"
|