@vaur94/agz-memory 0.4.0-beta.1 → 0.4.1

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/admin.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // @bun
3
3
 
4
4
  // src/admin/index.ts
5
- import { createHash as createHash5 } from "crypto";
5
+ import { createHash as createHash6 } from "crypto";
6
6
  import { Database as Database3 } from "bun:sqlite";
7
7
  import {
8
8
  existsSync as existsSync4,
@@ -41,7 +41,8 @@ function normalizeProjectName(value) {
41
41
  }
42
42
 
43
43
  // src/types.ts
44
- var SCHEMA_VERSION = 9;
44
+ var SCHEMA_VERSION = 10;
45
+ var KINDS = ["decision", "fact", "procedure", "context", "research", "preference", "task"];
45
46
  var PREDICATES = ["SUPPORTS", "DERIVED_FROM", "PART_OF", "ABOUT", "PRECEDES", "SUPERSEDES"];
46
47
 
47
48
  // src/db/backup.ts
@@ -103,9 +104,12 @@ function hasTable(db, table) {
103
104
  }
104
105
 
105
106
  // src/db/backup.ts
106
- var BACKUP_FORMAT = "opencode2-memory-backup/1";
107
+ var BACKUP_FORMAT = "agz-memory-backup/1";
107
108
  function createVerifiedBackup(db, databasePath, sourceSchema, targetSchema, productVersion) {
108
109
  const sourceHealth = assertHealthyDatabase(db);
110
+ if (sourceHealth.schemaVersion !== undefined && sourceHealth.schemaVersion !== sourceSchema) {
111
+ throw new Error(`backup source schema v${sourceSchema} does not match database schema v${sourceHealth.schemaVersion}`);
112
+ }
109
113
  const checkpoint = db.query("PRAGMA wal_checkpoint(TRUNCATE)").get();
110
114
  if (checkpoint.busy !== 0)
111
115
  throw new Error("database WAL checkpoint is busy");
@@ -133,6 +137,9 @@ function createVerifiedBackup(db, databasePath, sourceSchema, targetSchema, prod
133
137
  if (JSON.stringify(backupHealth.counts) !== JSON.stringify(sourceHealth.counts)) {
134
138
  throw new Error("backup row counts differ from source database");
135
139
  }
140
+ if (backupHealth.schemaVersion !== undefined && backupHealth.schemaVersion !== sourceSchema) {
141
+ throw new Error("backup schema does not match source schema");
142
+ }
136
143
  const bytes = readFileSync(temporaryDatabasePath);
137
144
  const manifest = {
138
145
  format: BACKUP_FORMAT,
@@ -205,6 +212,9 @@ function verifyBackupManifest(manifestPath) {
205
212
  if (JSON.stringify(health.counts) !== JSON.stringify(manifest.counts)) {
206
213
  throw new Error("backup manifest row counts do not match");
207
214
  }
215
+ if (health.schemaVersion !== undefined && health.schemaVersion !== manifest.sourceSchema) {
216
+ throw new Error("backup manifest source schema does not match database");
217
+ }
208
218
  } finally {
209
219
  db.close();
210
220
  }
@@ -390,7 +400,7 @@ function acquireMigrationLock(databasePath, targetSchema, timeoutMs = 30000) {
390
400
  rmSync2(path, { recursive: true, force: true });
391
401
  throw error;
392
402
  }
393
- if (!existsSync2(path))
403
+ if (!isAlreadyExistsError(error))
394
404
  throw error;
395
405
  if (Date.now() >= deadline) {
396
406
  const current = readMigrationLockOwner(path);
@@ -463,12 +473,84 @@ function processIsAlive(pid) {
463
473
  return false;
464
474
  }
465
475
  }
476
+ function isAlreadyExistsError(error) {
477
+ return Boolean(error && typeof error === "object" && "code" in error && String(error.code) === "EEXIST");
478
+ }
466
479
 
467
480
  // src/db/migrations/v009.ts
468
481
  import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
469
482
 
483
+ // src/capture/contract.ts
484
+ import * as z from "zod/v4";
485
+ var CAPTURE_SCHEMA = "agz-memory.capture/1";
486
+ var SUPPORTED_OPENCODE_VERSION = "0.0.0-beta-18743";
487
+ var CAPTURE_EVENT_MAX_BYTES = 16 * 1024;
488
+ var CAPTURE_CONTENT_MAX_CHARACTERS = 4800;
489
+ var CAPTURE_SUMMARY_MAX_CHARACTERS = 1200;
490
+ var CAPTURE_SUBJECT_MAX_CHARACTERS = 240;
491
+ var candidateSchema = z.object({
492
+ kind: z.enum(KINDS),
493
+ title: z.string().min(1).max(240),
494
+ summary: z.string().min(1).max(CAPTURE_SUMMARY_MAX_CHARACTERS),
495
+ content: z.string().min(1).max(CAPTURE_CONTENT_MAX_CHARACTERS),
496
+ subjectKey: z.string().min(1).max(CAPTURE_SUBJECT_MAX_CHARACTERS).optional(),
497
+ intent: z.enum(["create", "supersede", "ignore", "review"]),
498
+ targetNoteID: z.string().min(1).max(240).optional(),
499
+ confidence: z.number().finite().min(0).max(1),
500
+ evidence: z.enum(["explicit-user", "verified-outcome", "session-summary"])
501
+ }).strict();
502
+ var signalSchema = z.object({
503
+ tool: z.string().min(1).max(160),
504
+ status: z.enum(["completed", "error"]),
505
+ errorType: z.string().min(1).max(160).optional()
506
+ }).strict();
507
+ var captureEventSchema = z.object({
508
+ schema: z.literal(CAPTURE_SCHEMA),
509
+ idempotencyKey: z.string().regex(/^[0-9a-f]{64}$/),
510
+ projectID: z.uuid(),
511
+ bindingKey: z.string().regex(/^[0-9a-f]{64}$/),
512
+ kind: z.enum(["user-candidate", "assistant-candidate", "session-summary", "tool-signal"]),
513
+ source: z.object({
514
+ system: z.literal("opencode-v2"),
515
+ opencodeVersion: z.literal(SUPPORTED_OPENCODE_VERSION),
516
+ pluginVersion: z.string().min(1).max(80),
517
+ sessionID: z.string().min(1).max(240),
518
+ messageID: z.string().min(1).max(240).optional(),
519
+ ordinal: z.number().int().nonnegative().optional(),
520
+ toolCallID: z.string().min(1).max(240).optional(),
521
+ observedAt: z.number().int().nonnegative()
522
+ }).strict(),
523
+ candidate: candidateSchema.optional(),
524
+ signal: signalSchema.optional(),
525
+ redaction: z.object({
526
+ policyVersion: z.string().min(1).max(80),
527
+ replacements: z.number().int().nonnegative(),
528
+ truncated: z.boolean()
529
+ }).strict()
530
+ }).strict().superRefine((event, context) => {
531
+ if (event.kind === "tool-signal" && !event.signal) {
532
+ context.addIssue({ code: "custom", message: "tool-signal requires signal" });
533
+ }
534
+ if (event.kind !== "tool-signal" && !event.candidate) {
535
+ context.addIssue({ code: "custom", message: `${event.kind} requires candidate` });
536
+ }
537
+ if (event.kind === "tool-signal" && event.candidate) {
538
+ context.addIssue({ code: "custom", message: "tool-signal cannot carry candidate" });
539
+ }
540
+ if (event.kind !== "tool-signal" && event.signal) {
541
+ context.addIssue({ code: "custom", message: `${event.kind} cannot carry signal` });
542
+ }
543
+ });
544
+ function parseCaptureEvent(value) {
545
+ const event = captureEventSchema.parse(value);
546
+ if (Buffer.byteLength(JSON.stringify(event), "utf8") > CAPTURE_EVENT_MAX_BYTES) {
547
+ throw new Error(`capture event exceeds ${CAPTURE_EVENT_MAX_BYTES} UTF-8 bytes`);
548
+ }
549
+ return event;
550
+ }
551
+
470
552
  // src/db/schema.ts
471
- var SCHEMA_V9_TABLES = `
553
+ var SCHEMA_TABLES = `
472
554
  CREATE TABLE IF NOT EXISTS projects (
473
555
  id TEXT PRIMARY KEY,
474
556
  name TEXT NOT NULL,
@@ -538,28 +620,7 @@ CREATE TABLE IF NOT EXISTS capture_checkpoints (
538
620
  );
539
621
  CREATE INDEX IF NOT EXISTS capture_checkpoints_due_idx
540
622
  ON capture_checkpoints(state, next_reconcile_at);
541
- CREATE TABLE IF NOT EXISTS capture_events (
542
- idempotency_key TEXT PRIMARY KEY,
543
- contract TEXT NOT NULL CHECK (contract = 'opencode2-memory.capture/1'),
544
- project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
545
- binding_key TEXT NOT NULL REFERENCES project_bindings(binding_key) ON DELETE CASCADE,
546
- event_kind TEXT NOT NULL CHECK (event_kind IN ('user-candidate','assistant-candidate','session-summary','tool-signal')),
547
- source_session_id TEXT NOT NULL,
548
- source_message_id TEXT,
549
- source_ordinal INTEGER CHECK (source_ordinal IS NULL OR source_ordinal >= 0),
550
- source_tool_call_id TEXT,
551
- payload_json TEXT CHECK (payload_json IS NULL OR json_valid(payload_json)),
552
- payload_hash TEXT,
553
- redaction_version TEXT NOT NULL,
554
- state TEXT NOT NULL CHECK (state IN ('pending','shadowed','review','materialized','duplicate','ignored','rejected','quarantined','failed','dead')),
555
- attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
556
- note_id TEXT,
557
- last_error_code TEXT,
558
- generation INTEGER NOT NULL DEFAULT 0 CHECK (generation >= 0),
559
- created_at INTEGER NOT NULL,
560
- updated_at INTEGER NOT NULL,
561
- processed_at INTEGER
562
- );
623
+ ${captureEventsTable()}
563
624
  CREATE INDEX IF NOT EXISTS capture_events_state_idx ON capture_events(state, updated_at);
564
625
  CREATE INDEX IF NOT EXISTS capture_events_session_idx ON capture_events(project_id, source_session_id);
565
626
  CREATE INDEX IF NOT EXISTS capture_events_note_idx ON capture_events(project_id, note_id);
@@ -643,15 +704,39 @@ CREATE TRIGGER IF NOT EXISTS notes_fts_au AFTER UPDATE OF title, summary, conten
643
704
  VALUES (new.rowid, new.title, new.summary, new.content);
644
705
  END;
645
706
  `;
646
- function createSchemaV9(db) {
647
- db.exec(SCHEMA_V9_TABLES);
707
+ function createSchema(db) {
708
+ db.exec(SCHEMA_TABLES);
648
709
  db.exec(FTS_V9);
649
710
  db.query("DELETE FROM schema_state").run();
650
- db.query("INSERT INTO schema_state(version) VALUES (9)").run();
711
+ db.query("INSERT INTO schema_state(version) VALUES (10)").run();
651
712
  }
652
713
  function rebuildFts(db) {
653
714
  db.query("INSERT INTO notes_fts(notes_fts) VALUES ('rebuild')").run();
654
715
  }
716
+ function captureEventsTable(table = "capture_events") {
717
+ return `CREATE TABLE IF NOT EXISTS ${table} (
718
+ idempotency_key TEXT PRIMARY KEY,
719
+ contract TEXT NOT NULL CHECK (contract = '${CAPTURE_SCHEMA}'),
720
+ project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
721
+ binding_key TEXT NOT NULL REFERENCES project_bindings(binding_key) ON DELETE CASCADE,
722
+ event_kind TEXT NOT NULL CHECK (event_kind IN ('user-candidate','assistant-candidate','session-summary','tool-signal')),
723
+ source_session_id TEXT NOT NULL,
724
+ source_message_id TEXT,
725
+ source_ordinal INTEGER CHECK (source_ordinal IS NULL OR source_ordinal >= 0),
726
+ source_tool_call_id TEXT,
727
+ payload_json TEXT CHECK (payload_json IS NULL OR json_valid(payload_json)),
728
+ payload_hash TEXT,
729
+ redaction_version TEXT NOT NULL,
730
+ state TEXT NOT NULL CHECK (state IN ('pending','shadowed','review','materialized','duplicate','ignored','rejected','quarantined','failed','dead')),
731
+ attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),
732
+ note_id TEXT,
733
+ last_error_code TEXT,
734
+ generation INTEGER NOT NULL DEFAULT 0 CHECK (generation >= 0),
735
+ created_at INTEGER NOT NULL,
736
+ updated_at INTEGER NOT NULL,
737
+ processed_at INTEGER
738
+ );`;
739
+ }
655
740
 
656
741
  // src/db/migrations/v009.ts
657
742
  function migrateV8ToV9(db) {
@@ -720,7 +805,7 @@ function migrateV8ToV9(db) {
720
805
  ALTER TABLE notes_v9 RENAME TO notes;
721
806
  ALTER TABLE note_edges_v9 RENAME TO note_edges;
722
807
  `);
723
- db.exec(SCHEMA_V9_TABLES);
808
+ db.exec(SCHEMA_TABLES);
724
809
  for (const note of notes) {
725
810
  const provenanceID = randomUUID3();
726
811
  db.query(`
@@ -744,6 +829,57 @@ function noteContentHash(kind, title, summary, content) {
744
829
  return createHash3("sha256").update(`${kind}\x00${title}\x00${summary}\x00${content}`, "utf8").digest("hex");
745
830
  }
746
831
 
832
+ // src/db/migrations/v010.ts
833
+ import { createHash as createHash4 } from "crypto";
834
+ function migrateV9ToV10(db) {
835
+ const payloads = db.query("SELECT idempotency_key, payload_json FROM capture_events WHERE payload_json IS NOT NULL").all();
836
+ const migratedPayloads = payloads.map((row) => {
837
+ const event = JSON.parse(row.payload_json);
838
+ if (!event || typeof event !== "object" || Array.isArray(event)) {
839
+ throw new Error(`capture event ${row.idempotency_key} payload is not an object`);
840
+ }
841
+ event.schema = CAPTURE_SCHEMA;
842
+ const payload = JSON.stringify(parseCaptureEvent(event));
843
+ return {
844
+ idempotencyKey: row.idempotency_key,
845
+ payload,
846
+ payloadHash: createHash4("sha256").update(payload, "utf8").digest("hex")
847
+ };
848
+ });
849
+ db.exec("DROP TABLE IF EXISTS capture_events_v10");
850
+ db.exec(captureEventsTable("capture_events_v10"));
851
+ db.query(`
852
+ INSERT INTO capture_events_v10
853
+ (idempotency_key, contract, project_id, binding_key, event_kind,
854
+ source_session_id, source_message_id, source_ordinal, source_tool_call_id,
855
+ payload_json, payload_hash, redaction_version, state, attempt_count,
856
+ note_id, last_error_code, generation, created_at, updated_at, processed_at)
857
+ SELECT idempotency_key, ?, project_id, binding_key, event_kind,
858
+ source_session_id, source_message_id, source_ordinal, source_tool_call_id,
859
+ payload_json, payload_hash, redaction_version, state, attempt_count,
860
+ note_id, last_error_code, generation, created_at, updated_at, processed_at
861
+ FROM capture_events
862
+ `).run(CAPTURE_SCHEMA);
863
+ const updatePayload = db.query(`
864
+ UPDATE capture_events_v10
865
+ SET payload_json = ?, payload_hash = ?
866
+ WHERE idempotency_key = ?
867
+ `);
868
+ for (const row of migratedPayloads) {
869
+ updatePayload.run(row.payload, row.payloadHash, row.idempotencyKey);
870
+ }
871
+ db.exec(`
872
+ DROP TABLE capture_events;
873
+ ALTER TABLE capture_events_v10 RENAME TO capture_events;
874
+ `);
875
+ db.exec(SCHEMA_TABLES);
876
+ db.query("DELETE FROM schema_state").run();
877
+ db.query("INSERT INTO schema_state(version) VALUES (10)").run();
878
+ }
879
+
880
+ // src/version.ts
881
+ var PRODUCT_VERSION = "0.4.1";
882
+
747
883
  // src/db.ts
748
884
  var DDL = `
749
885
  CREATE TABLE IF NOT EXISTS projects (
@@ -785,13 +921,11 @@ CREATE INDEX IF NOT EXISTS note_edges_target_idx ON note_edges(project_id, targe
785
921
  CREATE TABLE IF NOT EXISTS schema_state (version INTEGER PRIMARY KEY);
786
922
  `;
787
923
  function openMemoryDatabase(path) {
788
- const db = new Database2(path, { create: true });
789
- chmodSync2(path, 384);
924
+ let db = openDatabase(path);
925
+ let dbOpen = true;
790
926
  let lock;
791
927
  let backup;
792
928
  try {
793
- db.exec("PRAGMA busy_timeout=5000");
794
- db.exec("PRAGMA journal_mode=WAL");
795
929
  const existingVersion = getSchemaVersion(db);
796
930
  if (existingVersion && existingVersion.version > SCHEMA_VERSION) {
797
931
  throw new Error(`database schema v${existingVersion.version} is newer than supported v${SCHEMA_VERSION}`);
@@ -799,19 +933,36 @@ function openMemoryDatabase(path) {
799
933
  const hasExistingData = hasLegacyV2(db) || hasTable2(db, "notes") || Boolean(existingVersion);
800
934
  if (!hasExistingData) {
801
935
  db.exec("PRAGMA foreign_keys=ON");
802
- db.transaction(() => createSchemaV9(db))();
936
+ db.transaction(() => createSchema(db))();
803
937
  assertHealthyDatabase(db);
804
938
  return { db, close: () => db.close() };
805
939
  }
806
940
  if ((existingVersion?.version ?? 0) < SCHEMA_VERSION) {
941
+ db.close();
942
+ dbOpen = false;
807
943
  lock = acquireMigrationLock(path, SCHEMA_VERSION);
808
- backup = createVerifiedBackup(db, path, existingVersion?.version ?? 2, SCHEMA_VERSION, "0.4.0-beta.1");
944
+ db = openDatabase(path);
945
+ dbOpen = true;
946
+ const migrationVersion = getSchemaVersion(db);
947
+ if (migrationVersion && migrationVersion.version > SCHEMA_VERSION) {
948
+ throw new Error(`database schema v${migrationVersion.version} is newer than supported v${SCHEMA_VERSION}`);
949
+ }
950
+ if ((migrationVersion?.version ?? 0) === SCHEMA_VERSION) {
951
+ lock.release();
952
+ lock = undefined;
953
+ db.exec("PRAGMA foreign_keys=ON");
954
+ db.exec(SCHEMA_TABLES);
955
+ db.exec(FTS_V9);
956
+ assertHealthyDatabase(db);
957
+ return { db, close: () => db.close() };
958
+ }
959
+ backup = createVerifiedBackup(db, path, migrationVersion?.version ?? 2, SCHEMA_VERSION, PRODUCT_VERSION);
809
960
  db.exec("PRAGMA foreign_keys=OFF");
810
- if (!existingVersion && hasLegacyV2(db)) {
961
+ if (!migrationVersion && hasLegacyV2(db)) {
811
962
  db.exec(DDL);
812
963
  db.exec("CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(id UNINDEXED, title, summary, content, tokenize='unicode61')");
813
964
  migrateFromV2(db, path);
814
- } else if (!existingVersion) {
965
+ } else if (!migrationVersion) {
815
966
  db.exec(DDL);
816
967
  db.exec("CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(id UNINDEXED, title, summary, content, tokenize='unicode61')");
817
968
  db.transaction(() => {
@@ -819,14 +970,18 @@ function openMemoryDatabase(path) {
819
970
  db.query("DELETE FROM schema_state").run();
820
971
  db.query("INSERT INTO schema_state (version) VALUES (8)").run();
821
972
  })();
822
- } else if (existingVersion.version < 8) {
973
+ } else if (migrationVersion.version < 8) {
823
974
  db.exec(DDL);
824
975
  db.exec("CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(id UNINDEXED, title, summary, content, tokenize='unicode61')");
825
976
  migrateToV8(db);
826
977
  }
827
- const version = getSchemaVersion(db)?.version ?? 8;
828
- if (version < 9)
978
+ let version = getSchemaVersion(db)?.version ?? 8;
979
+ if (version < 9) {
829
980
  db.transaction(() => migrateV8ToV9(db))();
981
+ version = 9;
982
+ }
983
+ if (version < 10)
984
+ db.transaction(() => migrateV9ToV10(db))();
830
985
  db.exec("PRAGMA foreign_keys=ON");
831
986
  if (db.query("PRAGMA foreign_keys").get().foreign_keys !== 1) {
832
987
  throw new Error("failed to enable database foreign keys");
@@ -838,13 +993,14 @@ function openMemoryDatabase(path) {
838
993
  return { db, close: () => db.close() };
839
994
  }
840
995
  db.exec("PRAGMA foreign_keys=ON");
841
- db.exec(SCHEMA_V9_TABLES);
996
+ db.exec(SCHEMA_TABLES);
842
997
  db.exec(FTS_V9);
843
998
  assertHealthyDatabase(db);
844
999
  db.exec("PRAGMA foreign_keys=ON");
845
1000
  return { db, close: () => db.close() };
846
1001
  } catch (error) {
847
- db.close();
1002
+ if (dbOpen)
1003
+ db.close();
848
1004
  if (backup) {
849
1005
  try {
850
1006
  restoreVerifiedBackup(backup.manifestPath, path, "RESTORE_DATABASE_FROM_VERIFIED_BACKUP");
@@ -857,6 +1013,18 @@ function openMemoryDatabase(path) {
857
1013
  lock?.release();
858
1014
  }
859
1015
  }
1016
+ function openDatabase(path) {
1017
+ const db = new Database2(path, { create: true });
1018
+ try {
1019
+ chmodSync2(path, 384);
1020
+ db.exec("PRAGMA busy_timeout=5000");
1021
+ db.exec("PRAGMA journal_mode=WAL");
1022
+ return db;
1023
+ } catch (error) {
1024
+ db.close();
1025
+ throw error;
1026
+ }
1027
+ }
860
1028
  function getSchemaVersion(db) {
861
1029
  if (!hasTable2(db, "schema_state"))
862
1030
  return;
@@ -1159,7 +1327,7 @@ function count(db, sql, ...bindings) {
1159
1327
  }
1160
1328
 
1161
1329
  // src/retrieval/derived.ts
1162
- import { createHash as createHash4 } from "crypto";
1330
+ import { createHash as createHash5 } from "crypto";
1163
1331
 
1164
1332
  // src/capture/redact.ts
1165
1333
  var RULES = [
@@ -1190,15 +1358,15 @@ function redactText(value, options = {}) {
1190
1358
  let replacements = 0;
1191
1359
  let highRisk = 0;
1192
1360
  const classes = {};
1193
- for (const literal of options.denylist ?? []) {
1194
- if (!literal)
1361
+ for (const literal2 of options.denylist ?? []) {
1362
+ if (!literal2)
1195
1363
  continue;
1196
- const count2 = text.split(literal).length - 1;
1364
+ const count2 = text.split(literal2).length - 1;
1197
1365
  if (count2 === 0)
1198
1366
  continue;
1199
1367
  replacements += count2;
1200
1368
  classes.denylist = (classes.denylist ?? 0) + count2;
1201
- text = text.replaceAll(literal, "[REDACTED:denylist]");
1369
+ text = text.replaceAll(literal2, "[REDACTED:denylist]");
1202
1370
  }
1203
1371
  for (const rule of RULES) {
1204
1372
  text = text.replace(rule.pattern, () => {
@@ -1248,7 +1416,7 @@ function deriveDocument(source) {
1248
1416
  const content = redactText(source.content);
1249
1417
  if (title.quarantined || summary.quarantined || content.quarantined)
1250
1418
  return;
1251
- const contentHash = createHash4("sha256").update(`${source.kind}\x00${title.text}\x00${summary.text}\x00${content.text}`, "utf8").digest("hex");
1419
+ const contentHash = createHash5("sha256").update(`${source.kind}\x00${title.text}\x00${summary.text}\x00${content.text}`, "utf8").digest("hex");
1252
1420
  return {
1253
1421
  projectID: source.projectID,
1254
1422
  noteID: source.noteID,
@@ -1282,7 +1450,7 @@ async function runAdmin(argv = process.argv.slice(2)) {
1282
1450
  const db = new Database3(databasePath);
1283
1451
  try {
1284
1452
  const version = schemaVersion(db);
1285
- return createVerifiedBackup(db, databasePath, version, version, "0.4.0-beta.1");
1453
+ return createVerifiedBackup(db, databasePath, version, version, PRODUCT_VERSION);
1286
1454
  } finally {
1287
1455
  db.close();
1288
1456
  lock.release();
@@ -1390,7 +1558,7 @@ async function runAdmin(argv = process.argv.slice(2)) {
1390
1558
  if (command === "backup" && subcommand === "prune") {
1391
1559
  const entries = backupEntries(databasePath);
1392
1560
  const root = resolve2(`${databasePath}.backup`);
1393
- const digest = createHash5("sha256").update(`${resolve2(databasePath)}\x00${root}
1561
+ const digest = createHash6("sha256").update(`${resolve2(databasePath)}\x00${root}
1394
1562
  ${entries.map((entry) => `${basename2(entry.manifest)}\x00${basename2(entry.database)}\x00${entry.sha256}\x00${entry.size}\x00${entry.manifestHash}`).join(`
1395
1563
  `)}`).digest("hex");
1396
1564
  if (option(argv, "--confirm") !== "DELETE_VERIFIED_BACKUPS") {
@@ -1472,7 +1640,7 @@ function verifiedBackupEntry(root, manifest) {
1472
1640
  database: verified.databasePath,
1473
1641
  sha256: verified.manifest.sha256,
1474
1642
  size: verified.manifest.size,
1475
- manifestHash: createHash5("sha256").update(bytes).digest("hex")
1643
+ manifestHash: createHash6("sha256").update(bytes).digest("hex")
1476
1644
  };
1477
1645
  }
1478
1646
  if (import.meta.main) {