claude-launchpad 1.12.0 → 1.15.0

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.
Files changed (61) hide show
  1. package/README.md +11 -3
  2. package/dist/{chunk-DTCCQWOU.js → chunk-7KB5YGQZ.js} +3 -3
  3. package/dist/{chunk-DTCCQWOU.js.map → chunk-7KB5YGQZ.js.map} +1 -1
  4. package/dist/chunk-DLDVXHI3.js +184 -0
  5. package/dist/chunk-DLDVXHI3.js.map +1 -0
  6. package/dist/chunk-HSGSTSVN.js +212 -0
  7. package/dist/chunk-HSGSTSVN.js.map +1 -0
  8. package/dist/{chunk-DXDOVWOA.js → chunk-IDH3M4EI.js} +20 -232
  9. package/dist/chunk-IDH3M4EI.js.map +1 -0
  10. package/dist/{chunk-YZ53W47Z.js → chunk-IIWOSSL4.js} +2 -1
  11. package/dist/chunk-IIWOSSL4.js.map +1 -0
  12. package/dist/{chunk-ZLI4LI33.js → chunk-IPGNXDJF.js} +2 -2
  13. package/dist/{chunk-PH5OWJ42.js → chunk-LCKV24Q3.js} +9 -5
  14. package/dist/{chunk-PH5OWJ42.js.map → chunk-LCKV24Q3.js.map} +1 -1
  15. package/dist/chunk-MX3T2VEX.js +225 -0
  16. package/dist/chunk-MX3T2VEX.js.map +1 -0
  17. package/dist/{chunk-F6SLV2FR.js → chunk-N2SCF7DB.js} +5 -6
  18. package/dist/chunk-N2SCF7DB.js.map +1 -0
  19. package/dist/{chunk-KPO4YURF.js → chunk-U2TFIUGE.js} +513 -89
  20. package/dist/chunk-U2TFIUGE.js.map +1 -0
  21. package/dist/cli.js +424 -130
  22. package/dist/cli.js.map +1 -1
  23. package/dist/commands/memory/server.js +48 -14
  24. package/dist/commands/memory/server.js.map +1 -1
  25. package/dist/{context-JALSYDYO.js → context-3GHG7KW6.js} +58 -55
  26. package/dist/context-3GHG7KW6.js.map +1 -0
  27. package/dist/doctor-EKGJ2YAO.js +108 -0
  28. package/dist/doctor-EKGJ2YAO.js.map +1 -0
  29. package/dist/{install-Q23F37GK.js → install-543ZKMXX.js} +12 -10
  30. package/dist/install-543ZKMXX.js.map +1 -0
  31. package/dist/{pull-FYKNNLYC.js → pull-ULSZEVCR.js} +17 -19
  32. package/dist/pull-ULSZEVCR.js.map +1 -0
  33. package/dist/{push-QSBK7BQU.js → push-JXCWX4NY.js} +13 -12
  34. package/dist/push-JXCWX4NY.js.map +1 -0
  35. package/dist/{require-deps-ZISUZLYD.js → require-deps-AEDO5YRM.js} +3 -3
  36. package/dist/{stats-SV53G6PQ.js → stats-63L7C24W.js} +9 -7
  37. package/dist/{stats-SV53G6PQ.js.map → stats-63L7C24W.js.map} +1 -1
  38. package/dist/{sync-2LDM44U4.js → sync-QTJ6BXQ4.js} +5 -5
  39. package/dist/{sync-clean-HQ523N7V.js → sync-clean-OJEK4XH4.js} +4 -5
  40. package/dist/sync-clean-OJEK4XH4.js.map +1 -0
  41. package/dist/{sync-status-V6WTI32X.js → sync-status-EAX527SC.js} +13 -12
  42. package/dist/sync-status-EAX527SC.js.map +1 -0
  43. package/dist/{tui-2UJ2OIHB.js → tui-3KITZCNS.js} +11 -7
  44. package/dist/{tui-2UJ2OIHB.js.map → tui-3KITZCNS.js.map} +1 -1
  45. package/package.json +27 -7
  46. package/scenarios/workflow/premature-victory.yaml +44 -0
  47. package/dist/chunk-DXDOVWOA.js.map +0 -1
  48. package/dist/chunk-F6SLV2FR.js.map +0 -1
  49. package/dist/chunk-KPO4YURF.js.map +0 -1
  50. package/dist/chunk-YZ53W47Z.js.map +0 -1
  51. package/dist/chunk-ZIG75MOB.js +0 -366
  52. package/dist/chunk-ZIG75MOB.js.map +0 -1
  53. package/dist/context-JALSYDYO.js.map +0 -1
  54. package/dist/install-Q23F37GK.js.map +0 -1
  55. package/dist/pull-FYKNNLYC.js.map +0 -1
  56. package/dist/push-QSBK7BQU.js.map +0 -1
  57. package/dist/sync-clean-HQ523N7V.js.map +0 -1
  58. package/dist/sync-status-V6WTI32X.js.map +0 -1
  59. /package/dist/{chunk-ZLI4LI33.js.map → chunk-IPGNXDJF.js.map} +0 -0
  60. /package/dist/{require-deps-ZISUZLYD.js.map → require-deps-AEDO5YRM.js.map} +0 -0
  61. /package/dist/{sync-2LDM44U4.js.map → sync-QTJ6BXQ4.js.map} +0 -0
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ cwdRequire
4
+ } from "./chunk-7KB5YGQZ.js";
5
+ import {
6
+ __export
7
+ } from "./chunk-U2TFIUGE.js";
8
+
9
+ // src/commands/memory/storage/migrations/001-initial.ts
10
+ var initial_exports = {};
11
+ __export(initial_exports, {
12
+ up: () => up,
13
+ version: () => version
14
+ });
15
+ var version = 1;
16
+ function up(db) {
17
+ db.exec(`
18
+ CREATE TABLE IF NOT EXISTS meta (
19
+ key TEXT PRIMARY KEY,
20
+ value TEXT
21
+ );
22
+
23
+ CREATE TABLE IF NOT EXISTS memories (
24
+ id TEXT PRIMARY KEY,
25
+ type TEXT NOT NULL CHECK(type IN ('episodic','semantic','procedural','working','pattern')),
26
+ title TEXT,
27
+ content TEXT NOT NULL,
28
+ context TEXT,
29
+ source TEXT CHECK(source IN ('manual','session_end','consolidation','hook','import')),
30
+ tags TEXT NOT NULL DEFAULT '[]',
31
+ importance REAL NOT NULL DEFAULT 0.5 CHECK(importance >= 0.0 AND importance <= 1.0),
32
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
33
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
34
+ access_count INTEGER NOT NULL DEFAULT 0 CHECK(access_count >= 0),
35
+ last_accessed TEXT,
36
+ injection_count INTEGER NOT NULL DEFAULT 0 CHECK(injection_count >= 0)
37
+ );
38
+
39
+ CREATE TABLE IF NOT EXISTS relations (
40
+ source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
41
+ target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
42
+ relation_type TEXT NOT NULL CHECK(relation_type IN (
43
+ 'relates_to','depends_on','contradicts','extends','implements','derived_from'
44
+ )),
45
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
46
+ PRIMARY KEY (source_id, target_id, relation_type)
47
+ );
48
+
49
+ -- FTS5 external content (no data duplication)
50
+ CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
51
+ title, content, tags,
52
+ content=memories,
53
+ content_rowid=rowid,
54
+ tokenize='porter unicode61'
55
+ );
56
+
57
+ -- FTS5 sync triggers
58
+ CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
59
+ INSERT INTO memories_fts(rowid, title, content, tags)
60
+ VALUES (new.rowid, new.title, new.content, new.tags);
61
+ END;
62
+
63
+ CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
64
+ INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)
65
+ VALUES ('delete', old.rowid, old.title, old.content, old.tags);
66
+ END;
67
+
68
+ CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
69
+ INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)
70
+ VALUES ('delete', old.rowid, old.title, old.content, old.tags);
71
+ INSERT INTO memories_fts(rowid, title, content, tags)
72
+ VALUES (new.rowid, new.title, new.content, new.tags);
73
+ END;
74
+
75
+
76
+ -- Indexes
77
+ CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
78
+ CREATE INDEX IF NOT EXISTS idx_memories_importance ON memories(importance);
79
+ CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories(created_at);
80
+ CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_id);
81
+ `);
82
+ }
83
+
84
+ // src/commands/memory/storage/migrations/002-add-project.ts
85
+ var add_project_exports = {};
86
+ __export(add_project_exports, {
87
+ up: () => up2,
88
+ version: () => version2
89
+ });
90
+ var version2 = 2;
91
+ function up2(db) {
92
+ db.exec(`
93
+ ALTER TABLE memories ADD COLUMN project TEXT;
94
+ CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project);
95
+ `);
96
+ }
97
+
98
+ // src/commands/memory/storage/migrations/003-add-content-hash.ts
99
+ var add_content_hash_exports = {};
100
+ __export(add_content_hash_exports, {
101
+ up: () => up3,
102
+ version: () => version3
103
+ });
104
+ import { createHash } from "crypto";
105
+ var version3 = 3;
106
+ function up3(db) {
107
+ db.exec("ALTER TABLE memories ADD COLUMN content_hash TEXT");
108
+ const rows = db.prepare("SELECT id, content FROM memories ORDER BY updated_at DESC").all();
109
+ const update = db.prepare("UPDATE memories SET content_hash = ? WHERE id = ?");
110
+ const remove = db.prepare("DELETE FROM memories WHERE id = ?");
111
+ const seen = /* @__PURE__ */ new Set();
112
+ for (const row of rows) {
113
+ const hash = createHash("sha256").update(row.content).digest("hex");
114
+ if (seen.has(hash)) {
115
+ remove.run(row.id);
116
+ } else {
117
+ seen.add(hash);
118
+ update.run(hash, row.id);
119
+ }
120
+ }
121
+ db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash)");
122
+ }
123
+
124
+ // src/commands/memory/storage/migrations/004-add-tombstones.ts
125
+ var add_tombstones_exports = {};
126
+ __export(add_tombstones_exports, {
127
+ up: () => up4,
128
+ version: () => version4
129
+ });
130
+ var version4 = 4;
131
+ function up4(db) {
132
+ db.exec(`
133
+ CREATE TABLE IF NOT EXISTS memory_tombstones (
134
+ id TEXT PRIMARY KEY,
135
+ project TEXT,
136
+ deleted_at TEXT NOT NULL
137
+ );
138
+
139
+ CREATE INDEX IF NOT EXISTS idx_tombstones_project ON memory_tombstones(project);
140
+ CREATE INDEX IF NOT EXISTS idx_tombstones_deleted_at ON memory_tombstones(deleted_at);
141
+ `);
142
+ }
143
+
144
+ // src/commands/memory/storage/migrations/005-add-base-importance.ts
145
+ var add_base_importance_exports = {};
146
+ __export(add_base_importance_exports, {
147
+ up: () => up5,
148
+ version: () => version5
149
+ });
150
+ var version5 = 5;
151
+ function up5(db) {
152
+ db.exec("ALTER TABLE memories ADD COLUMN base_importance REAL");
153
+ db.exec("UPDATE memories SET base_importance = importance");
154
+ }
155
+
156
+ // src/commands/memory/storage/migrations/006-content-hash-per-project.ts
157
+ var content_hash_per_project_exports = {};
158
+ __export(content_hash_per_project_exports, {
159
+ up: () => up6,
160
+ version: () => version6
161
+ });
162
+ var version6 = 6;
163
+ function up6(db) {
164
+ db.exec("DROP INDEX IF EXISTS idx_memories_content_hash");
165
+ db.exec("CREATE UNIQUE INDEX idx_memories_content_hash ON memories(content_hash, COALESCE(project, '_global'))");
166
+ }
167
+
168
+ // src/commands/memory/storage/migrations/007-drop-vector-layer.ts
169
+ var drop_vector_layer_exports = {};
170
+ __export(drop_vector_layer_exports, {
171
+ up: () => up7,
172
+ version: () => version7
173
+ });
174
+ var version7 = 7;
175
+ function up7(db) {
176
+ const hasVecTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'memories_vec'").get();
177
+ if (hasVecTable) {
178
+ try {
179
+ const vec = cwdRequire("sqlite-vec");
180
+ vec.load(db);
181
+ db.exec("DROP TABLE memories_vec");
182
+ } catch {
183
+ }
184
+ }
185
+ const cols = db.prepare("SELECT name FROM pragma_table_info('memories')").all();
186
+ if (cols.some((c) => c.name === "embedding")) {
187
+ db.exec("ALTER TABLE memories DROP COLUMN embedding");
188
+ }
189
+ }
190
+
191
+ // src/commands/memory/storage/migrator.ts
192
+ var migrations = [
193
+ initial_exports,
194
+ add_project_exports,
195
+ add_content_hash_exports,
196
+ add_tombstones_exports,
197
+ add_base_importance_exports,
198
+ content_hash_per_project_exports,
199
+ drop_vector_layer_exports
200
+ ];
201
+ function getSchemaVersion(db) {
202
+ try {
203
+ const row = db.prepare("SELECT value FROM meta WHERE key = 'schema_version'").get();
204
+ return row ? parseInt(row.value, 10) : 0;
205
+ } catch {
206
+ return 0;
207
+ }
208
+ }
209
+ function migrate(db) {
210
+ const current = getSchemaVersion(db);
211
+ const pending = migrations.filter((m) => m.version > current);
212
+ if (pending.length === 0) return;
213
+ const runMigrations = db.transaction(() => {
214
+ for (const m of pending) {
215
+ m.up(db);
216
+ db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)").run(String(m.version));
217
+ }
218
+ });
219
+ runMigrations();
220
+ }
221
+
222
+ export {
223
+ migrate
224
+ };
225
+ //# sourceMappingURL=chunk-MX3T2VEX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/storage/migrations/001-initial.ts","../src/commands/memory/storage/migrations/002-add-project.ts","../src/commands/memory/storage/migrations/003-add-content-hash.ts","../src/commands/memory/storage/migrations/004-add-tombstones.ts","../src/commands/memory/storage/migrations/005-add-base-importance.ts","../src/commands/memory/storage/migrations/006-content-hash-per-project.ts","../src/commands/memory/storage/migrations/007-drop-vector-layer.ts","../src/commands/memory/storage/migrator.ts"],"sourcesContent":["import type Database from 'better-sqlite3';\n\nexport const version = 1;\n\nexport function up(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT\n );\n\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('episodic','semantic','procedural','working','pattern')),\n title TEXT,\n content TEXT NOT NULL,\n context TEXT,\n source TEXT CHECK(source IN ('manual','session_end','consolidation','hook','import')),\n tags TEXT NOT NULL DEFAULT '[]',\n importance REAL NOT NULL DEFAULT 0.5 CHECK(importance >= 0.0 AND importance <= 1.0),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now')),\n access_count INTEGER NOT NULL DEFAULT 0 CHECK(access_count >= 0),\n last_accessed TEXT,\n injection_count INTEGER NOT NULL DEFAULT 0 CHECK(injection_count >= 0)\n );\n\n CREATE TABLE IF NOT EXISTS relations (\n source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,\n relation_type TEXT NOT NULL CHECK(relation_type IN (\n 'relates_to','depends_on','contradicts','extends','implements','derived_from'\n )),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (source_id, target_id, relation_type)\n );\n\n -- FTS5 external content (no data duplication)\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n title, content, tags,\n content=memories,\n content_rowid=rowid,\n tokenize='porter unicode61'\n );\n\n -- FTS5 sync triggers\n CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, title, content, tags)\n VALUES (new.rowid, new.title, new.content, new.tags);\n END;\n\n CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)\n VALUES ('delete', old.rowid, old.title, old.content, old.tags);\n END;\n\n CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)\n VALUES ('delete', old.rowid, old.title, old.content, old.tags);\n INSERT INTO memories_fts(rowid, title, content, tags)\n VALUES (new.rowid, new.title, new.content, new.tags);\n END;\n\n\n -- Indexes\n CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);\n CREATE INDEX IF NOT EXISTS idx_memories_importance ON memories(importance);\n CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories(created_at);\n CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_id);\n `);\n}\n","import type Database from 'better-sqlite3';\n\nexport const version = 2;\n\nexport function up(db: Database.Database): void {\n db.exec(`\n ALTER TABLE memories ADD COLUMN project TEXT;\n CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project);\n `);\n}\n","import { createHash } from 'node:crypto';\nimport type Database from 'better-sqlite3';\n\nexport const version = 3;\n\nexport function up(db: Database.Database): void {\n db.exec('ALTER TABLE memories ADD COLUMN content_hash TEXT');\n\n // Backfill existing rows with SHA-256 hashes\n const rows = db.prepare('SELECT id, content FROM memories ORDER BY updated_at DESC').all() as { id: string; content: string }[];\n const update = db.prepare('UPDATE memories SET content_hash = ? WHERE id = ?');\n const remove = db.prepare('DELETE FROM memories WHERE id = ?');\n\n // Track seen hashes — keep the most recently updated, remove older duplicates\n const seen = new Set<string>();\n for (const row of rows) {\n const hash = createHash('sha256').update(row.content).digest('hex');\n if (seen.has(hash)) {\n remove.run(row.id);\n } else {\n seen.add(hash);\n update.run(hash, row.id);\n }\n }\n\n db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash)');\n}\n","import type Database from 'better-sqlite3';\n\nexport const version = 4;\n\nexport function up(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS memory_tombstones (\n id TEXT PRIMARY KEY,\n project TEXT,\n deleted_at TEXT NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_tombstones_project ON memory_tombstones(project);\n CREATE INDEX IF NOT EXISTS idx_tombstones_deleted_at ON memory_tombstones(deleted_at);\n `);\n}\n","export const version = 5;\n\nimport type Database from 'better-sqlite3';\n\n/**\n * WP-044: decay must be a pure function of age. `importance` becomes the\n * displayed/query value that decay recomputes; `base_importance` is the\n * immutable anchor set at creation (or explicit user re-rating) that the\n * decay formula multiplies. Backfill: current importance is the best\n * available approximation of base for existing rows.\n */\nexport function up(db: Database.Database): void {\n db.exec('ALTER TABLE memories ADD COLUMN base_importance REAL');\n db.exec('UPDATE memories SET base_importance = importance');\n}\n","export const version = 6;\n\nimport type Database from 'better-sqlite3';\n\n/**\n * WP-046: content dedup is a per-project concern. The global UNIQUE index\n * blocked the same insight from existing in two projects and made sync\n * silently drop same-content/different-id rows from other machines.\n * COALESCE keeps NULL-project (global) rows deduping among themselves.\n */\nexport function up(db: Database.Database): void {\n db.exec('DROP INDEX IF EXISTS idx_memories_content_hash');\n db.exec(\"CREATE UNIQUE INDEX idx_memories_content_hash ON memories(content_hash, COALESCE(project, '_global'))\");\n}\n","export const version = 7;\n\nimport type Database from 'better-sqlite3';\nimport { cwdRequire } from '../../utils/require-deps.js';\n\n/**\n * WP-045: the vector layer was never wired — no embedding was ever written\n * and memories_vec was never queried. Dropping it removes the sqlite-vec\n * native dependency entirely.\n *\n * A virtual table cannot be dropped unless its module is registered, and\n * v1.14+ no longer loads sqlite-vec at open. Upgraders have the module\n * installed (the old installer ran `npm install -g better-sqlite3\n * sqlite-vec`), so we load it just for the drop. If the module is gone,\n * the vtab schema entry is left in place — it is inert (never queried,\n * blocks nothing) and direct sqlite_master surgery is forbidden by\n * better-sqlite3's SQLite build, so removal would risk more than it buys.\n */\nexport function up(db: Database.Database): void {\n const hasVecTable = db\n .prepare(\"SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'memories_vec'\")\n .get();\n if (hasVecTable) {\n try {\n const vec = cwdRequire('sqlite-vec') as { load: (db: Database.Database) => void };\n vec.load(db);\n db.exec('DROP TABLE memories_vec');\n } catch {\n // Module unavailable: leave the inert vtab entry. Everything below\n // still applies.\n }\n }\n\n const cols = db.prepare(\"SELECT name FROM pragma_table_info('memories')\").all() as { name: string }[];\n if (cols.some((c) => c.name === 'embedding')) {\n db.exec('ALTER TABLE memories DROP COLUMN embedding');\n }\n}\n","import type Database from 'better-sqlite3';\nimport * as migration001 from './migrations/001-initial.js';\nimport * as migration002 from './migrations/002-add-project.js';\nimport * as migration003 from './migrations/003-add-content-hash.js';\nimport * as migration004 from './migrations/004-add-tombstones.js';\nimport * as migration005 from './migrations/005-add-base-importance.js';\nimport * as migration006 from './migrations/006-content-hash-per-project.js';\nimport * as migration007 from './migrations/007-drop-vector-layer.js';\n\ninterface Migration {\n readonly version: number;\n readonly up: (db: Database.Database) => void;\n}\n\nconst migrations: readonly Migration[] = [\n migration001,\n migration002,\n migration003,\n migration004,\n migration005,\n migration006,\n migration007,\n];\n\nexport function getSchemaVersion(db: Database.Database): number {\n try {\n const row = db.prepare(\"SELECT value FROM meta WHERE key = 'schema_version'\").get() as\n { value: string } | undefined;\n return row ? parseInt(row.value, 10) : 0;\n } catch {\n return 0;\n }\n}\n\nexport function migrate(db: Database.Database): void {\n const current = getSchemaVersion(db);\n const pending = migrations.filter(m => m.version > current);\n\n if (pending.length === 0) return;\n\n const runMigrations = db.transaction(() => {\n for (const m of pending) {\n m.up(db);\n db.prepare(\"INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)\")\n .run(String(m.version));\n }\n });\n\n runMigrations();\n}\n"],"mappings":"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","names":["up","version","up","version","up","version","up","version","up","version","up","version","version","up"]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SyncPayloadSchema
4
- } from "./chunk-YZ53W47Z.js";
4
+ } from "./chunk-IIWOSSL4.js";
5
5
 
6
6
  // src/commands/memory/utils/sync-merge.ts
7
7
  function memoryToSyncRow(m) {
@@ -15,6 +15,7 @@ function memoryToSyncRow(m) {
15
15
  project: m.project,
16
16
  tags: [...m.tags],
17
17
  importance: m.importance,
18
+ base_importance: m.baseImportance,
18
19
  access_count: m.accessCount,
19
20
  injection_count: m.injectionCount,
20
21
  created_at: m.createdAt,
@@ -56,11 +57,9 @@ function mergeFromRemote(memoryRepo, relationRepo, payload) {
56
57
  }
57
58
  const local = memoryRepo.getById(remote.id);
58
59
  if (!local) {
59
- memoryRepo.upsertFromSync(remote);
60
- inserted++;
60
+ if (memoryRepo.upsertFromSync(remote)) inserted++;
61
61
  } else if (remote.updated_at > local.updatedAt) {
62
- memoryRepo.upsertFromSync(remote);
63
- updated++;
62
+ if (memoryRepo.upsertFromSync(remote)) updated++;
64
63
  }
65
64
  }
66
65
  const localIds = new Set(memoryRepo.getAll().map((m) => m.id));
@@ -84,4 +83,4 @@ export {
84
83
  parsePayload,
85
84
  mergeFromRemote
86
85
  };
87
- //# sourceMappingURL=chunk-F6SLV2FR.js.map
86
+ //# sourceMappingURL=chunk-N2SCF7DB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/utils/sync-merge.ts"],"sourcesContent":["import { SyncPayloadSchema } from '../types.js';\nimport type { Memory, SyncPayload, SyncMemoryRow, SyncTombstone, MergeResult, RelationType, Tombstone } from '../types.js';\nimport type { MemoryRepo } from '../storage/memory-repo.js';\nimport type { RelationRepo } from '../storage/relation-repo.js';\n\nfunction memoryToSyncRow(m: Memory): SyncMemoryRow {\n return {\n id: m.id,\n type: m.type,\n title: m.title,\n content: m.content,\n context: m.context,\n source: m.source,\n project: m.project,\n tags: [...m.tags],\n importance: m.importance,\n base_importance: m.baseImportance,\n access_count: m.accessCount,\n injection_count: m.injectionCount,\n created_at: m.createdAt,\n updated_at: m.updatedAt,\n last_accessed: m.lastAccessed,\n };\n}\n\nfunction tombstoneToSyncRow(t: Tombstone): SyncTombstone {\n return { id: t.id, project: t.project, deleted_at: t.deletedAt };\n}\n\nexport { memoryToSyncRow, tombstoneToSyncRow };\n\nexport function parsePayload(raw: string | null): SyncPayload | null {\n if (!raw || raw === 'null') return null;\n try { return SyncPayloadSchema.parse(JSON.parse(raw)); }\n catch { return null; }\n}\n\nexport function mergeFromRemote(\n memoryRepo: MemoryRepo,\n relationRepo: RelationRepo,\n payload: SyncPayload,\n): MergeResult {\n let inserted = 0;\n let updated = 0;\n let deleted = 0;\n let relationsAdded = 0;\n\n // Phase 1: apply remote tombstones — delete locally or persist the tombstone\n // so future remote memory rows with older updated_at don't resurrect them.\n // Tie-break: delete wins when timestamps are equal (matches Phase 2 semantics).\n // upsertTombstone is safe to call unconditionally — ON CONFLICT keeps the newer row.\n for (const t of payload.tombstones) {\n const local = memoryRepo.getById(t.id);\n if (local && local.updatedAt <= t.deleted_at) {\n memoryRepo.hardDelete(t.id);\n deleted++;\n }\n memoryRepo.upsertTombstone(t.id, t.project, t.deleted_at);\n }\n\n // Phase 2: merge remote memories, honoring local tombstones\n for (const remote of payload.memories) {\n const tombstone = memoryRepo.getTombstone(remote.id);\n if (tombstone && tombstone.deletedAt >= remote.updated_at) {\n // Delete wins; skip this memory.\n continue;\n }\n if (tombstone && tombstone.deletedAt < remote.updated_at) {\n // Remote update is newer than the delete — resurrect and drop the stale tombstone.\n memoryRepo.deleteTombstone(remote.id);\n }\n\n const local = memoryRepo.getById(remote.id);\n if (!local) {\n if (memoryRepo.upsertFromSync(remote)) inserted++;\n } else if (remote.updated_at > local.updatedAt) {\n if (memoryRepo.upsertFromSync(remote)) updated++;\n }\n }\n\n // Phase 3: relations — only link memories that survived both phases.\n const localIds = new Set(memoryRepo.getAll().map((m) => m.id));\n const relations = payload.relations.filter(\n (r) => localIds.has(r.source_id) && localIds.has(r.target_id),\n );\n\n for (const rel of relations) {\n const added = relationRepo.create(\n rel.source_id,\n rel.target_id,\n rel.relation_type as RelationType,\n );\n if (added) relationsAdded++;\n }\n\n return { inserted, updated, deleted, relationsAdded };\n}\n"],"mappings":";;;;;;AAKA,SAAS,gBAAgB,GAA0B;AACjD,SAAO;AAAA,IACL,IAAI,EAAE;AAAA,IACN,MAAM,EAAE;AAAA,IACR,OAAO,EAAE;AAAA,IACT,SAAS,EAAE;AAAA,IACX,SAAS,EAAE;AAAA,IACX,QAAQ,EAAE;AAAA,IACV,SAAS,EAAE;AAAA,IACX,MAAM,CAAC,GAAG,EAAE,IAAI;AAAA,IAChB,YAAY,EAAE;AAAA,IACd,iBAAiB,EAAE;AAAA,IACnB,cAAc,EAAE;AAAA,IAChB,iBAAiB,EAAE;AAAA,IACnB,YAAY,EAAE;AAAA,IACd,YAAY,EAAE;AAAA,IACd,eAAe,EAAE;AAAA,EACnB;AACF;AAEA,SAAS,mBAAmB,GAA6B;AACvD,SAAO,EAAE,IAAI,EAAE,IAAI,SAAS,EAAE,SAAS,YAAY,EAAE,UAAU;AACjE;AAIO,SAAS,aAAa,KAAwC;AACnE,MAAI,CAAC,OAAO,QAAQ,OAAQ,QAAO;AACnC,MAAI;AAAE,WAAO,kBAAkB,MAAM,KAAK,MAAM,GAAG,CAAC;AAAA,EAAG,QACjD;AAAE,WAAO;AAAA,EAAM;AACvB;AAEO,SAAS,gBACd,YACA,cACA,SACa;AACb,MAAI,WAAW;AACf,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,iBAAiB;AAMrB,aAAW,KAAK,QAAQ,YAAY;AAClC,UAAM,QAAQ,WAAW,QAAQ,EAAE,EAAE;AACrC,QAAI,SAAS,MAAM,aAAa,EAAE,YAAY;AAC5C,iBAAW,WAAW,EAAE,EAAE;AAC1B;AAAA,IACF;AACA,eAAW,gBAAgB,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU;AAAA,EAC1D;AAGA,aAAW,UAAU,QAAQ,UAAU;AACrC,UAAM,YAAY,WAAW,aAAa,OAAO,EAAE;AACnD,QAAI,aAAa,UAAU,aAAa,OAAO,YAAY;AAEzD;AAAA,IACF;AACA,QAAI,aAAa,UAAU,YAAY,OAAO,YAAY;AAExD,iBAAW,gBAAgB,OAAO,EAAE;AAAA,IACtC;AAEA,UAAM,QAAQ,WAAW,QAAQ,OAAO,EAAE;AAC1C,QAAI,CAAC,OAAO;AACV,UAAI,WAAW,eAAe,MAAM,EAAG;AAAA,IACzC,WAAW,OAAO,aAAa,MAAM,WAAW;AAC9C,UAAI,WAAW,eAAe,MAAM,EAAG;AAAA,IACzC;AAAA,EACF;AAGA,QAAM,WAAW,IAAI,IAAI,WAAW,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC7D,QAAM,YAAY,QAAQ,UAAU;AAAA,IAClC,CAAC,MAAM,SAAS,IAAI,EAAE,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS;AAAA,EAC9D;AAEA,aAAW,OAAO,WAAW;AAC3B,UAAM,QAAQ,aAAa;AAAA,MACzB,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IACN;AACA,QAAI,MAAO;AAAA,EACb;AAEA,SAAO,EAAE,UAAU,SAAS,SAAS,eAAe;AACtD;","names":[]}