claude-launchpad 1.12.0 → 1.14.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-D6RAMWH6.js} +3 -3
  3. package/dist/{chunk-DTCCQWOU.js.map → chunk-D6RAMWH6.js.map} +1 -1
  4. package/dist/chunk-HSGSTSVN.js +212 -0
  5. package/dist/chunk-HSGSTSVN.js.map +1 -0
  6. package/dist/{chunk-DXDOVWOA.js → chunk-IDH3M4EI.js} +20 -232
  7. package/dist/chunk-IDH3M4EI.js.map +1 -0
  8. package/dist/{chunk-YZ53W47Z.js → chunk-IIWOSSL4.js} +2 -1
  9. package/dist/chunk-IIWOSSL4.js.map +1 -0
  10. package/dist/{chunk-ZLI4LI33.js → chunk-M6GVFN67.js} +2 -2
  11. package/dist/{chunk-F6SLV2FR.js → chunk-N2SCF7DB.js} +5 -6
  12. package/dist/chunk-N2SCF7DB.js.map +1 -0
  13. package/dist/chunk-OPORVSAF.js +225 -0
  14. package/dist/chunk-OPORVSAF.js.map +1 -0
  15. package/dist/{chunk-KPO4YURF.js → chunk-QEPE3WVF.js} +457 -85
  16. package/dist/chunk-QEPE3WVF.js.map +1 -0
  17. package/dist/chunk-UN43OVRW.js +184 -0
  18. package/dist/chunk-UN43OVRW.js.map +1 -0
  19. package/dist/{chunk-PH5OWJ42.js → chunk-VF7U63AI.js} +9 -5
  20. package/dist/{chunk-PH5OWJ42.js.map → chunk-VF7U63AI.js.map} +1 -1
  21. package/dist/cli.js +307 -87
  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-YIPO4LBS.js} +58 -55
  26. package/dist/context-YIPO4LBS.js.map +1 -0
  27. package/dist/doctor-DCHFJ3XV.js +108 -0
  28. package/dist/doctor-DCHFJ3XV.js.map +1 -0
  29. package/dist/{install-Q23F37GK.js → install-D32PV7SF.js} +12 -10
  30. package/dist/install-D32PV7SF.js.map +1 -0
  31. package/dist/{pull-FYKNNLYC.js → pull-YUQTDRUP.js} +17 -19
  32. package/dist/pull-YUQTDRUP.js.map +1 -0
  33. package/dist/{push-QSBK7BQU.js → push-U4IVTFOU.js} +13 -12
  34. package/dist/push-U4IVTFOU.js.map +1 -0
  35. package/dist/{require-deps-ZISUZLYD.js → require-deps-WDMHDGBN.js} +3 -3
  36. package/dist/{stats-SV53G6PQ.js → stats-77BYLKYP.js} +9 -7
  37. package/dist/{stats-SV53G6PQ.js.map → stats-77BYLKYP.js.map} +1 -1
  38. package/dist/{sync-2LDM44U4.js → sync-DTCWK2CY.js} +5 -5
  39. package/dist/{sync-clean-HQ523N7V.js → sync-clean-ACZCB3NZ.js} +4 -5
  40. package/dist/sync-clean-ACZCB3NZ.js.map +1 -0
  41. package/dist/{sync-status-V6WTI32X.js → sync-status-2V2RCYZO.js} +13 -12
  42. package/dist/sync-status-2V2RCYZO.js.map +1 -0
  43. package/dist/{tui-2UJ2OIHB.js → tui-HVJNLRY2.js} +11 -7
  44. package/dist/{tui-2UJ2OIHB.js.map → tui-HVJNLRY2.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-M6GVFN67.js.map} +0 -0
  60. /package/dist/{require-deps-ZISUZLYD.js.map → require-deps-WDMHDGBN.js.map} +0 -0
  61. /package/dist/{sync-2LDM44U4.js.map → sync-DTCWK2CY.js.map} +0 -0
@@ -1,366 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- cwdRequire
4
- } from "./chunk-DTCCQWOU.js";
5
- import {
6
- __export
7
- } from "./chunk-KPO4YURF.js";
8
-
9
- // src/commands/memory/config.ts
10
- import { z } from "zod";
11
- import { readFileSync } from "fs";
12
- import { join } from "path";
13
- import { homedir } from "os";
14
- var ConfigSchema = z.object({
15
- dataDir: z.string().default("~/.agentic-memory"),
16
- injectionBudget: z.number().int().min(100).max(2e4).default(3e3),
17
- consolidationInterval: z.number().int().min(1).default(10),
18
- enableReranker: z.boolean().default(true),
19
- logLevel: z.enum(["debug", "info", "warn", "error"]).default("warn")
20
- });
21
- var DEFAULT_CONFIG = {
22
- dataDir: "~/.agentic-memory",
23
- injectionBudget: 3e3,
24
- consolidationInterval: 10,
25
- enableReranker: true,
26
- logLevel: "warn"
27
- };
28
- var DEFAULT_DECAY_PARAMS = {
29
- tauByType: {
30
- working: 0,
31
- // cleared each session, tau irrelevant
32
- episodic: 30,
33
- // fast decay (was 60, cognitive science: unrehearsed episodes fade in ~30d)
34
- semantic: 540,
35
- // slow decay (was 365, extracted facts are stable for years)
36
- procedural: 730,
37
- // near-permanent
38
- pattern: 180
39
- // medium decay
40
- },
41
- accessModifiers: [
42
- { maxCount: 3, multiplier: 1 },
43
- { maxCount: 10, multiplier: 2 },
44
- { maxCount: Infinity, multiplier: 4 }
45
- ],
46
- relationModifier: {
47
- connectedThreshold: 3,
48
- connectedMultiplier: 1.8,
49
- // higher tau = slower decay for connected memories
50
- isolatedMultiplier: 0.8,
51
- // lower tau = slightly faster decay for isolated memories
52
- highlyConnectedThreshold: 6,
53
- highlyConnectedMultiplier: 2.5
54
- // near-immune: ~2.5x longer effective half-life
55
- },
56
- importanceFloor: 0.05,
57
- pruneThreshold: 0.1,
58
- pruneMinAgeDays: 90
59
- };
60
- var SCORING_WEIGHTS = {
61
- text: 0.35,
62
- importance: 0.2,
63
- recency: 0.2,
64
- access: 0.1,
65
- context: 0.15
66
- };
67
- var INJECTION_WEIGHTS = {
68
- context: 0.3,
69
- value: 0.25,
70
- importance: 0.2,
71
- recency: 0.15,
72
- typeBonus: 0.05,
73
- noise: 0.05
74
- };
75
- var TYPE_INJECTION_BONUS = {
76
- procedural: 1,
77
- pattern: 0.8,
78
- semantic: 0.6,
79
- episodic: 0.3,
80
- working: 0
81
- };
82
- var RECENCY_HALF_LIFE = {
83
- working: 1,
84
- episodic: 7,
85
- pattern: 14,
86
- semantic: 30,
87
- procedural: 90
88
- };
89
- var INJECTION_MIN_SCORE = 0.25;
90
- var INJECTION_COLD_START_THRESHOLD = 5;
91
- var INJECTION_COLD_START_RAMP_END = 20;
92
- var INJECTION_HEADER_TOKENS = 50;
93
- var INJECTION_MAX_SAME_TYPE_FULL = 2;
94
- var INJECTION_PINNED_BUDGET_PCT = 0.1;
95
- var INJECTION_PINNED_IMPORTANCE = 0.8;
96
- var INJECTION_MMR_LAMBDA = 0.7;
97
- var INJECTION_MMR_MAX_RERANK = 50;
98
- var INJECTION_MMR_SIM_WEIGHTS = {
99
- content: 0.6,
100
- tags: 0.4
101
- };
102
- function resolveDataDir(dataDir) {
103
- if (dataDir.startsWith("~")) {
104
- return join(homedir(), dataDir.slice(1));
105
- }
106
- return dataDir;
107
- }
108
- function loadConfig(overrides) {
109
- const envOverrides = {};
110
- const envBudget = process.env["AGENTIC_MEMORY_INJECTION_BUDGET"];
111
- if (envBudget !== void 0) {
112
- envOverrides["injectionBudget"] = parseInt(envBudget, 10);
113
- }
114
- const envLogLevel = process.env["AGENTIC_MEMORY_LOG_LEVEL"];
115
- if (envLogLevel !== void 0) {
116
- envOverrides["logLevel"] = envLogLevel;
117
- }
118
- const envDataDir = process.env["AGENTIC_MEMORY_DATA_DIR"];
119
- if (envDataDir !== void 0) {
120
- envOverrides["dataDir"] = envDataDir;
121
- }
122
- let fileConfig = {};
123
- const baseDir = resolveDataDir(overrides?.dataDir ?? envOverrides["dataDir"] ?? DEFAULT_CONFIG.dataDir);
124
- try {
125
- const raw = readFileSync(join(baseDir, "config.json"), "utf-8");
126
- fileConfig = JSON.parse(raw);
127
- } catch (err) {
128
- const isNotFound = err instanceof Error && "code" in err && err.code === "ENOENT";
129
- if (!isNotFound) {
130
- console.error("[agentic-memory] Failed to load config.json:", err instanceof Error ? err.message : err);
131
- }
132
- }
133
- const merged = { ...DEFAULT_CONFIG, ...fileConfig, ...envOverrides, ...overrides };
134
- return ConfigSchema.parse(merged);
135
- }
136
- function estimateTokens(text) {
137
- return Math.ceil(text.length / 4);
138
- }
139
-
140
- // src/commands/memory/storage/database.ts
141
- import { mkdirSync } from "fs";
142
- import { dirname, join as join2 } from "path";
143
- function createDatabase(options = {}) {
144
- const dbPath = options.dbPath ?? resolveDbPath(options.dataDir);
145
- if (dbPath !== ":memory:") {
146
- mkdirSync(dirname(dbPath), { recursive: true });
147
- }
148
- const Database = cwdRequire("better-sqlite3");
149
- const sqliteVec = cwdRequire("sqlite-vec");
150
- const db = new Database(dbPath);
151
- sqliteVec.load(db);
152
- db.pragma("journal_mode = WAL");
153
- db.pragma("busy_timeout = 5000");
154
- db.pragma("foreign_keys = ON");
155
- db.pragma("cache_size = -64000");
156
- db.pragma("mmap_size = 268435456");
157
- db.pragma("synchronous = NORMAL");
158
- db.pragma("temp_store = MEMORY");
159
- db.pragma("journal_size_limit = 33554432");
160
- return db;
161
- }
162
- function closeDatabase(db) {
163
- try {
164
- db.pragma("wal_checkpoint(TRUNCATE)");
165
- } catch {
166
- }
167
- db.close();
168
- }
169
- function resolveDbPath(dataDir) {
170
- const dir = resolveDataDir(dataDir ?? "~/.agentic-memory");
171
- return join2(dir, "memory.db");
172
- }
173
-
174
- // src/commands/memory/storage/migrations/001-initial.ts
175
- var initial_exports = {};
176
- __export(initial_exports, {
177
- up: () => up,
178
- version: () => version
179
- });
180
- var version = 1;
181
- function up(db) {
182
- db.exec(`
183
- CREATE TABLE IF NOT EXISTS meta (
184
- key TEXT PRIMARY KEY,
185
- value TEXT
186
- );
187
-
188
- CREATE TABLE IF NOT EXISTS memories (
189
- id TEXT PRIMARY KEY,
190
- type TEXT NOT NULL CHECK(type IN ('episodic','semantic','procedural','working','pattern')),
191
- title TEXT,
192
- content TEXT NOT NULL,
193
- context TEXT,
194
- source TEXT CHECK(source IN ('manual','session_end','consolidation','hook','import')),
195
- tags TEXT NOT NULL DEFAULT '[]',
196
- importance REAL NOT NULL DEFAULT 0.5 CHECK(importance >= 0.0 AND importance <= 1.0),
197
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
198
- updated_at TEXT NOT NULL DEFAULT (datetime('now')),
199
- access_count INTEGER NOT NULL DEFAULT 0 CHECK(access_count >= 0),
200
- last_accessed TEXT,
201
- injection_count INTEGER NOT NULL DEFAULT 0 CHECK(injection_count >= 0),
202
- embedding BLOB
203
- );
204
-
205
- CREATE TABLE IF NOT EXISTS relations (
206
- source_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
207
- target_id TEXT NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
208
- relation_type TEXT NOT NULL CHECK(relation_type IN (
209
- 'relates_to','depends_on','contradicts','extends','implements','derived_from'
210
- )),
211
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
212
- PRIMARY KEY (source_id, target_id, relation_type)
213
- );
214
-
215
- -- FTS5 external content (no data duplication)
216
- CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
217
- title, content, tags,
218
- content=memories,
219
- content_rowid=rowid,
220
- tokenize='porter unicode61'
221
- );
222
-
223
- -- FTS5 sync triggers
224
- CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
225
- INSERT INTO memories_fts(rowid, title, content, tags)
226
- VALUES (new.rowid, new.title, new.content, new.tags);
227
- END;
228
-
229
- CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
230
- INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)
231
- VALUES ('delete', old.rowid, old.title, old.content, old.tags);
232
- END;
233
-
234
- CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
235
- INSERT INTO memories_fts(memories_fts, rowid, title, content, tags)
236
- VALUES ('delete', old.rowid, old.title, old.content, old.tags);
237
- INSERT INTO memories_fts(rowid, title, content, tags)
238
- VALUES (new.rowid, new.title, new.content, new.tags);
239
- END;
240
-
241
- -- Vector search (synced manually in application code)
242
- CREATE VIRTUAL TABLE IF NOT EXISTS memories_vec USING vec0(
243
- memory_id TEXT PRIMARY KEY,
244
- embedding float[384] distance_metric=cosine
245
- );
246
-
247
- -- Indexes
248
- CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
249
- CREATE INDEX IF NOT EXISTS idx_memories_importance ON memories(importance);
250
- CREATE INDEX IF NOT EXISTS idx_memories_created_at ON memories(created_at);
251
- CREATE INDEX IF NOT EXISTS idx_relations_target ON relations(target_id);
252
- `);
253
- }
254
-
255
- // src/commands/memory/storage/migrations/002-add-project.ts
256
- var add_project_exports = {};
257
- __export(add_project_exports, {
258
- up: () => up2,
259
- version: () => version2
260
- });
261
- var version2 = 2;
262
- function up2(db) {
263
- db.exec(`
264
- ALTER TABLE memories ADD COLUMN project TEXT;
265
- CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project);
266
- `);
267
- }
268
-
269
- // src/commands/memory/storage/migrations/003-add-content-hash.ts
270
- var add_content_hash_exports = {};
271
- __export(add_content_hash_exports, {
272
- up: () => up3,
273
- version: () => version3
274
- });
275
- import { createHash } from "crypto";
276
- var version3 = 3;
277
- function up3(db) {
278
- db.exec("ALTER TABLE memories ADD COLUMN content_hash TEXT");
279
- const rows = db.prepare("SELECT id, content FROM memories ORDER BY updated_at DESC").all();
280
- const update = db.prepare("UPDATE memories SET content_hash = ? WHERE id = ?");
281
- const remove = db.prepare("DELETE FROM memories WHERE id = ?");
282
- const seen = /* @__PURE__ */ new Set();
283
- for (const row of rows) {
284
- const hash = createHash("sha256").update(row.content).digest("hex");
285
- if (seen.has(hash)) {
286
- remove.run(row.id);
287
- } else {
288
- seen.add(hash);
289
- update.run(hash, row.id);
290
- }
291
- }
292
- db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash)");
293
- }
294
-
295
- // src/commands/memory/storage/migrations/004-add-tombstones.ts
296
- var add_tombstones_exports = {};
297
- __export(add_tombstones_exports, {
298
- up: () => up4,
299
- version: () => version4
300
- });
301
- var version4 = 4;
302
- function up4(db) {
303
- db.exec(`
304
- CREATE TABLE IF NOT EXISTS memory_tombstones (
305
- id TEXT PRIMARY KEY,
306
- project TEXT,
307
- deleted_at TEXT NOT NULL
308
- );
309
-
310
- CREATE INDEX IF NOT EXISTS idx_tombstones_project ON memory_tombstones(project);
311
- CREATE INDEX IF NOT EXISTS idx_tombstones_deleted_at ON memory_tombstones(deleted_at);
312
- `);
313
- }
314
-
315
- // src/commands/memory/storage/migrator.ts
316
- var migrations = [
317
- initial_exports,
318
- add_project_exports,
319
- add_content_hash_exports,
320
- add_tombstones_exports
321
- ];
322
- function getSchemaVersion(db) {
323
- try {
324
- const row = db.prepare("SELECT value FROM meta WHERE key = 'schema_version'").get();
325
- return row ? parseInt(row.value, 10) : 0;
326
- } catch {
327
- return 0;
328
- }
329
- }
330
- function migrate(db) {
331
- const current = getSchemaVersion(db);
332
- const pending = migrations.filter((m) => m.version > current);
333
- if (pending.length === 0) return;
334
- const runMigrations = db.transaction(() => {
335
- for (const m of pending) {
336
- m.up(db);
337
- db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES ('schema_version', ?)").run(String(m.version));
338
- }
339
- });
340
- runMigrations();
341
- }
342
-
343
- export {
344
- DEFAULT_DECAY_PARAMS,
345
- SCORING_WEIGHTS,
346
- INJECTION_WEIGHTS,
347
- TYPE_INJECTION_BONUS,
348
- RECENCY_HALF_LIFE,
349
- INJECTION_MIN_SCORE,
350
- INJECTION_COLD_START_THRESHOLD,
351
- INJECTION_COLD_START_RAMP_END,
352
- INJECTION_HEADER_TOKENS,
353
- INJECTION_MAX_SAME_TYPE_FULL,
354
- INJECTION_PINNED_BUDGET_PCT,
355
- INJECTION_PINNED_IMPORTANCE,
356
- INJECTION_MMR_LAMBDA,
357
- INJECTION_MMR_MAX_RERANK,
358
- INJECTION_MMR_SIM_WEIGHTS,
359
- resolveDataDir,
360
- loadConfig,
361
- estimateTokens,
362
- createDatabase,
363
- closeDatabase,
364
- migrate
365
- };
366
- //# sourceMappingURL=chunk-ZIG75MOB.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/config.ts","../src/commands/memory/storage/database.ts","../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/migrator.ts"],"sourcesContent":["import { z } from 'zod';\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { DecayParams } from './types.js';\n\n// ── Config Schema ─────────────────────────────────────────────\n\nconst ConfigSchema = z.object({\n dataDir: z.string().default('~/.agentic-memory'),\n injectionBudget: z.number().int().min(100).max(20000).default(3000),\n consolidationInterval: z.number().int().min(1).default(10),\n enableReranker: z.boolean().default(true),\n logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('warn'),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\n// ── Defaults ──────────────────────────────────────────────────\n\nexport const DEFAULT_CONFIG: Config = {\n dataDir: '~/.agentic-memory',\n injectionBudget: 3000,\n consolidationInterval: 10,\n enableReranker: true,\n logLevel: 'warn',\n};\n\nexport const DEFAULT_DECAY_PARAMS: DecayParams = {\n tauByType: {\n working: 0, // cleared each session, tau irrelevant\n episodic: 30, // fast decay (was 60, cognitive science: unrehearsed episodes fade in ~30d)\n semantic: 540, // slow decay (was 365, extracted facts are stable for years)\n procedural: 730, // near-permanent\n pattern: 180, // medium decay\n },\n accessModifiers: [\n { maxCount: 3, multiplier: 1.0 },\n { maxCount: 10, multiplier: 2.0 },\n { maxCount: Infinity, multiplier: 4.0 },\n ],\n relationModifier: {\n connectedThreshold: 3,\n connectedMultiplier: 1.8, // higher tau = slower decay for connected memories\n isolatedMultiplier: 0.8, // lower tau = slightly faster decay for isolated memories\n highlyConnectedThreshold: 6,\n highlyConnectedMultiplier: 2.5, // near-immune: ~2.5x longer effective half-life\n },\n importanceFloor: 0.05,\n pruneThreshold: 0.1,\n pruneMinAgeDays: 90,\n};\n\nexport const SCORING_WEIGHTS = {\n text: 0.35,\n importance: 0.20,\n recency: 0.20,\n access: 0.10,\n context: 0.15,\n} as const;\n\n// ── Injection Algorithm Constants ──────────────────────────────\n\nexport const INJECTION_WEIGHTS = {\n context: 0.30,\n value: 0.25,\n importance: 0.20,\n recency: 0.15,\n typeBonus: 0.05,\n noise: 0.05,\n} as const;\n\nexport const TYPE_INJECTION_BONUS: Record<string, number> = {\n procedural: 1.0,\n pattern: 0.8,\n semantic: 0.6,\n episodic: 0.3,\n working: 0.0,\n};\n\nexport const RECENCY_HALF_LIFE: Record<string, number> = {\n working: 1,\n episodic: 7,\n pattern: 14,\n semantic: 30,\n procedural: 90,\n};\n\nexport const INJECTION_MIN_SCORE = 0.25;\nexport const INJECTION_COLD_START_THRESHOLD = 5;\nexport const INJECTION_COLD_START_RAMP_END = 20;\nexport const INJECTION_HEADER_TOKENS = 50;\nexport const INJECTION_MAX_SAME_TYPE_FULL = 2;\nexport const INJECTION_PINNED_BUDGET_PCT = 0.10;\nexport const INJECTION_PINNED_IMPORTANCE = 0.8;\n\n// MMR diversity re-ranking for non-pinned candidates.\n// lambda=1 ≡ pure relevance, lambda=0 ≡ max diversity.\nexport const INJECTION_MMR_LAMBDA = 0.7;\nexport const INJECTION_MMR_MAX_RERANK = 50;\nexport const INJECTION_MMR_SIM_WEIGHTS = {\n content: 0.6,\n tags: 0.4,\n} as const;\n\n// ── Config Loader ─────────────────────────────────────────────\n\nexport function resolveDataDir(dataDir: string): string {\n if (dataDir.startsWith('~')) {\n return join(homedir(), dataDir.slice(1));\n }\n return dataDir;\n}\n\nexport function loadConfig(overrides?: Partial<Config>): Config {\n const envOverrides: Record<string, unknown> = {};\n\n const envBudget = process.env['AGENTIC_MEMORY_INJECTION_BUDGET'];\n if (envBudget !== undefined) {\n envOverrides['injectionBudget'] = parseInt(envBudget, 10);\n }\n\n const envLogLevel = process.env['AGENTIC_MEMORY_LOG_LEVEL'];\n if (envLogLevel !== undefined) {\n envOverrides['logLevel'] = envLogLevel;\n }\n\n const envDataDir = process.env['AGENTIC_MEMORY_DATA_DIR'];\n if (envDataDir !== undefined) {\n envOverrides['dataDir'] = envDataDir;\n }\n\n // Try loading config.json from data dir\n let fileConfig: Record<string, unknown> = {};\n const baseDir = resolveDataDir(overrides?.dataDir ?? envOverrides['dataDir'] as string ?? DEFAULT_CONFIG.dataDir);\n try {\n const raw = readFileSync(join(baseDir, 'config.json'), 'utf-8');\n fileConfig = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n const isNotFound = err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'ENOENT';\n if (!isNotFound) {\n // Malformed JSON or permissions error - warn, don't silently ignore\n console.error('[agentic-memory] Failed to load config.json:', err instanceof Error ? err.message : err);\n }\n }\n\n const merged = { ...DEFAULT_CONFIG, ...fileConfig, ...envOverrides, ...overrides };\n return ConfigSchema.parse(merged);\n}\n\n// ── Token Estimation ──────────────────────────────────────────\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n","import type DatabaseConstructor from 'better-sqlite3';\nimport { resolveDataDir } from '../config.js';\nimport { mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { cwdRequire } from '../utils/require-deps.js';\n\nexport interface DatabaseOptions {\n readonly dbPath?: string; // full path override (e.g. ':memory:' for tests)\n readonly dataDir?: string; // resolved data dir (default ~/.agentic-memory)\n}\n\nexport function createDatabase(options: DatabaseOptions = {}): DatabaseConstructor.Database {\n const dbPath = options.dbPath ?? resolveDbPath(options.dataDir);\n\n if (dbPath !== ':memory:') {\n mkdirSync(dirname(dbPath), { recursive: true });\n }\n\n const Database = cwdRequire('better-sqlite3') as typeof DatabaseConstructor;\n const sqliteVec = cwdRequire('sqlite-vec') as { load: (db: DatabaseConstructor.Database) => void };\n\n const db = new Database(dbPath);\n\n // Load sqlite-vec extension\n sqliteVec.load(db);\n\n // Configure PRAGMAs (order matters: foreign_keys before any ops, journal_mode is persistent)\n db.pragma('journal_mode = WAL');\n db.pragma('busy_timeout = 5000');\n db.pragma('foreign_keys = ON');\n db.pragma('cache_size = -64000');\n db.pragma('mmap_size = 268435456');\n db.pragma('synchronous = NORMAL');\n db.pragma('temp_store = MEMORY');\n db.pragma('journal_size_limit = 33554432');\n\n return db;\n}\n\nexport function closeDatabase(db: DatabaseConstructor.Database): void {\n try {\n db.pragma('wal_checkpoint(TRUNCATE)');\n } catch {\n // Checkpoint may fail on :memory: - that's fine\n }\n db.close();\n}\n\nfunction resolveDbPath(dataDir?: string): string {\n const dir = resolveDataDir(dataDir ?? '~/.agentic-memory');\n return join(dir, 'memory.db');\n}\n","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 embedding BLOB\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 -- Vector search (synced manually in application code)\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_vec USING vec0(\n memory_id TEXT PRIMARY KEY,\n embedding float[384] distance_metric=cosine\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","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';\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];\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":["join","join","up","version","up","version","up","version"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/subcommands/context.ts","../src/commands/memory/services/decay-service.ts","../src/commands/memory/services/consolidation-service.ts","../src/commands/memory/utils/mmr.ts","../src/commands/memory/services/injection-service.ts"],"sourcesContent":["import { readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { DecayService } from '../services/decay-service.js';\nimport { ConsolidationService } from '../services/consolidation-service.js';\nimport { InjectionService } from '../services/injection-service.js';\nimport { detectProject } from '../utils/project.js';\nimport { getGitContext } from '../utils/git-context.js';\nimport { initStorage } from './init-storage.js';\n\ninterface ContextOpts {\n readonly json?: boolean;\n readonly dbPath?: string;\n}\n\nconst CONSOLIDATION_FILE = '.last-consolidation';\n\nfunction shouldConsolidate(dataDir: string, intervalDays: number): boolean {\n const checkpointPath = join(dataDir, CONSOLIDATION_FILE);\n try {\n const raw = readFileSync(checkpointPath, 'utf-8').trim();\n const lastRun = parseInt(raw, 10);\n if (isNaN(lastRun)) return true;\n const daysSince = (Date.now() - lastRun) / 86_400_000;\n return daysSince >= intervalDays;\n } catch {\n return true;\n }\n}\n\nfunction markConsolidated(dataDir: string): void {\n writeFileSync(join(dataDir, CONSOLIDATION_FILE), String(Date.now()), 'utf-8');\n}\n\nfunction write(msg: string): void {\n process.stdout.write(msg + '\\n');\n}\n\nexport async function runContext(opts: ContextOpts): Promise<void> {\n const ctx = initStorage(opts.dbPath);\n\n try {\n // Run maintenance (decay + consolidation) before loading context\n try {\n const decayService = new DecayService({\n memoryRepo: ctx.memoryRepo,\n relationRepo: ctx.relationRepo,\n });\n decayService.run();\n\n if (shouldConsolidate(ctx.dataDir, ctx.config.consolidationInterval)) {\n const consolidationService = new ConsolidationService({\n memoryRepo: ctx.memoryRepo,\n relationRepo: ctx.relationRepo,\n });\n await consolidationService.consolidate();\n markConsolidated(ctx.dataDir);\n }\n } catch (err) {\n process.stderr.write(`[agentic-memory] maintenance error: ${err instanceof Error ? err.message : err}\\n`);\n }\n\n const project = detectProject(process.cwd());\n const gitContext = getGitContext();\n\n const injectionService = new InjectionService({\n memoryRepo: ctx.memoryRepo,\n relationRepo: ctx.relationRepo,\n gitContext: gitContext ?? undefined,\n });\n\n const result = injectionService.selectForInjection(\n ctx.config.injectionBudget,\n project ?? undefined,\n );\n\n write(injectionService.formatInjection(result));\n } finally {\n ctx.close();\n }\n}\n","import type { Memory, DecayParams } from '../types.js';\nimport type { MemoryRepo } from '../storage/memory-repo.js';\nimport type { RelationRepo } from '../storage/relation-repo.js';\nimport { DEFAULT_DECAY_PARAMS } from '../config.js';\n\n// ── Types ────────────────────────────────────────────────────\n\nexport interface DecayServiceDeps {\n readonly memoryRepo: MemoryRepo;\n readonly relationRepo: RelationRepo;\n readonly params?: DecayParams;\n}\n\nexport interface DecayReport {\n readonly decayed: number;\n readonly pruned: number;\n readonly workingCleared: number;\n}\n\n// ── Decay Service ────────────────────────────────────────────\n\nexport class DecayService {\n readonly #memoryRepo: MemoryRepo;\n readonly #relationRepo: RelationRepo;\n readonly #params: DecayParams;\n\n constructor(deps: DecayServiceDeps) {\n this.#memoryRepo = deps.memoryRepo;\n this.#relationRepo = deps.relationRepo;\n this.#params = deps.params ?? DEFAULT_DECAY_PARAMS;\n }\n\n /**\n * Run full decay cycle: clear working memories, apply decay, prune dead memories.\n */\n run(): DecayReport {\n const workingCleared = this.clearWorkingMemories();\n const decayed = this.decayAll();\n const pruned = this.prune();\n return { decayed, pruned, workingCleared };\n }\n\n clearWorkingMemories(): number {\n return this.#memoryRepo.deleteByType('working');\n }\n\n /**\n * Apply decay formula to all non-working memories.\n */\n decayAll(): number {\n const memories = this.#memoryRepo.getAll();\n let updated = 0;\n\n for (const memory of memories) {\n if (memory.type === 'working') continue;\n\n const newImportance = this.computeDecayedImportance(memory);\n if (Math.abs(newImportance - memory.importance) > 0.001) {\n this.#memoryRepo.updateImportanceOnly(memory.id, newImportance);\n updated++;\n }\n }\n\n return updated;\n }\n\n /**\n * Hard-delete memories below prune threshold.\n */\n prune(): number {\n const memories = this.#memoryRepo.getAll();\n const now = Date.now();\n let pruned = 0;\n\n for (const memory of memories) {\n if (memory.type === 'working') continue;\n\n const ageDays = (now - new Date(memory.createdAt).getTime()) / (1000 * 60 * 60 * 24);\n if (\n ageDays > this.#params.pruneMinAgeDays &&\n memory.importance < this.#params.pruneThreshold &&\n memory.accessCount === 0\n ) {\n this.#memoryRepo.hardDelete(memory.id);\n pruned++;\n }\n }\n\n return pruned;\n }\n\n /**\n * Compute decayed importance as a pure function of age from creation.\n * Uses createdAt (immutable) to avoid compounding decay across sessions.\n */\n computeDecayedImportance(memory: Memory): number {\n const tau = this.#params.tauByType[memory.type];\n if (tau === 0) return memory.importance;\n\n const ageDays = (Date.now() - new Date(memory.createdAt).getTime()) / (1000 * 60 * 60 * 24);\n if (ageDays < 0) return memory.importance;\n\n // Synaptic consolidation window (days 0-7)\n if (ageDays <= 7) {\n if (memory.type === 'episodic') {\n // Ebbinghaus curve: steep initial drop with residual floor\n const ebbinghaus = Math.exp(-ageDays * 0.7) + 0.2;\n return Math.max(this.#params.importanceFloor, memory.importance * Math.min(1, ebbinghaus));\n }\n return memory.importance;\n }\n\n // Access modifier: logarithmic curve (spacing effect)\n const accessModifier = this.getAccessModifier(memory.accessCount);\n\n // Relation modifier: connected memories decay slower, highly connected near-immune\n const relationCount = this.#relationRepo.countByMemory(memory.id);\n const rm = this.#params.relationModifier;\n const relationModifier = relationCount >= rm.highlyConnectedThreshold\n ? rm.highlyConnectedMultiplier\n : relationCount >= rm.connectedThreshold\n ? rm.connectedMultiplier\n : rm.isolatedMultiplier;\n\n let effectiveTau = tau * accessModifier * relationModifier;\n\n // Injection penalty: surfaced but never used = noise\n if (memory.injectionCount > 5 && memory.accessCount === 0) {\n effectiveTau /= 1.5;\n }\n\n const decayFactor = Math.exp(-(ageDays - 7) / effectiveTau);\n const newImportance = memory.importance * decayFactor;\n\n return Math.max(this.#params.importanceFloor, newImportance);\n }\n\n private getAccessModifier(accessCount: number): number {\n // Logarithmic curve: 1 + log2(1 + count). Smoother than step function.\n // At 0: 1.0, at 3: 2.0, at 10: 3.5, at 30: 5.0\n return 1 + Math.log2(1 + accessCount);\n }\n}\n","import type { MemoryRepo } from '../storage/memory-repo.js';\nimport type { RelationRepo } from '../storage/relation-repo.js';\n\n// ── Types ────────────────────────────────────────────────────\n\nexport interface ConsolidationDeps {\n readonly memoryRepo: MemoryRepo;\n readonly relationRepo: RelationRepo;\n}\n\nexport interface ConsolidationReport {\n readonly deduplicated: number;\n readonly episodicsCompressed: number;\n readonly pruned: number;\n}\n\n// ── Consolidation Service ────────────────────────────────────\n\nexport class ConsolidationService {\n readonly #deps: ConsolidationDeps;\n\n constructor(deps: ConsolidationDeps) {\n this.#deps = deps;\n }\n\n /**\n * Run consolidation pipeline.\n * Phase 1: Deduplicate exact/near-exact content matches\n * Phase 2: Compress old consolidated episodics\n * Phase 3: Prune dead memories\n */\n async consolidate(): Promise<ConsolidationReport> {\n const deduplicated = this.deduplicateMemories();\n const episodicsCompressed = this.compressEpisodics();\n const pruned = this.prune();\n return { deduplicated, episodicsCompressed, pruned };\n }\n\n /**\n * Phase 1: Deduplication via content similarity.\n */\n deduplicateMemories(): number {\n const memories = this.#deps.memoryRepo.getAll();\n const seen = new Set<string>();\n let merged = 0;\n\n for (const memory of memories) {\n if (seen.has(memory.id)) continue;\n\n const normalizedContent = normalizeText(memory.content);\n\n for (const other of memories) {\n if (other.id === memory.id) continue;\n if (seen.has(other.id)) continue;\n\n const otherNormalized = normalizeText(other.content);\n if (normalizedContent !== otherNormalized) continue;\n\n const [keeper, discard] = memory.importance >= other.importance\n ? [memory, other] : [other, memory];\n\n const mergedTags = [...new Set([...keeper.tags, ...discard.tags])];\n this.#deps.memoryRepo.updateContent(keeper.id, {\n tags: mergedTags,\n importance: Math.max(keeper.importance, discard.importance),\n });\n\n this.#deps.memoryRepo.hardDelete(discard.id);\n seen.add(discard.id);\n merged++;\n\n if (discard.id === memory.id) break;\n }\n\n seen.add(memory.id);\n }\n\n return merged;\n }\n\n /**\n * Phase 2: Compress old episodic memories that have been consolidated.\n */\n compressEpisodics(): number {\n const episodics = this.#deps.memoryRepo.getByType('episodic');\n const now = Date.now();\n let compressed = 0;\n\n for (const memory of episodics) {\n const ageDays = (now - new Date(memory.createdAt).getTime()) / (1000 * 60 * 60 * 24);\n if (ageDays <= 60) continue;\n if (memory.accessCount > 0) continue;\n if (memory.importance >= 0.2) continue;\n\n const relations = this.#deps.relationRepo.getBySource(memory.id);\n const isConsolidated = relations.some(r => r.relationType === 'derived_from');\n if (!isConsolidated) continue;\n\n this.#deps.memoryRepo.hardDelete(memory.id);\n compressed++;\n }\n\n return compressed;\n }\n\n /**\n * Phase 3: Prune dead memories.\n */\n prune(): number {\n const memories = this.#deps.memoryRepo.getAll();\n const now = Date.now();\n let pruned = 0;\n\n for (const memory of memories) {\n if (memory.type === 'working') continue;\n const ageDays = (now - new Date(memory.createdAt).getTime()) / (1000 * 60 * 60 * 24);\n if (ageDays > 90 && memory.importance < 0.1 && memory.accessCount === 0) {\n this.#deps.memoryRepo.hardDelete(memory.id);\n pruned++;\n }\n }\n\n return pruned;\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────\n\nfunction normalizeText(text: string): string {\n return text.toLowerCase().replace(/\\s+/g, ' ').trim();\n}\n","import type { Memory } from \"../types.js\";\nimport { extractKeywords, jaccardOverlap } from \"./similarity.js\";\n\n// ── MMR (Maximal Marginal Relevance) ───────────────────────────\n// Carbonell & Goldstein (1998). Re-ranks a relevance-sorted list\n// by penalizing candidates too similar to already-selected items.\n// Same relevance budget, more topic coverage per slot.\n//\n// MMR(c) = λ · Rel(c) − (1 − λ) · max_{s ∈ S} Sim(c, s)\n//\n// λ=1 preserves pure relevance order. λ=0 maximizes diversity.\n\nexport interface MMRScored {\n readonly memory: Memory;\n readonly score: number;\n}\n\nexport interface MMROptions {\n readonly lambda: number;\n readonly maxRerank: number;\n readonly contentWeight: number;\n readonly tagsWeight: number;\n}\n\ninterface Features {\n readonly content: ReadonlySet<string>;\n readonly tags: ReadonlySet<string>;\n}\n\nfunction featuresOf(memory: Memory): Features {\n return {\n content: extractKeywords(memory.content),\n tags: new Set(memory.tags),\n };\n}\n\nfunction blendedSimilarity(\n a: Features,\n b: Features,\n contentWeight: number,\n tagsWeight: number,\n): number {\n return (\n jaccardOverlap(a.content, b.content) * contentWeight\n + jaccardOverlap(a.tags, b.tags) * tagsWeight\n );\n}\n\nexport function applyMMR<T extends MMRScored>(\n scored: readonly T[],\n options: MMROptions,\n): readonly T[] {\n if (scored.length <= 1) return scored;\n\n const { lambda, maxRerank, contentWeight, tagsWeight } = options;\n const rerankCount = Math.min(scored.length, maxRerank);\n const pool = scored.slice(0, rerankCount);\n const tail = scored.slice(rerankCount);\n\n const features = new Map<string, Features>();\n for (const s of pool) {\n features.set(s.memory.id, featuresOf(s.memory));\n }\n\n const remaining = new Set(pool.map((s) => s.memory.id));\n const selected: T[] = [];\n\n while (remaining.size > 0) {\n let best: T | null = null;\n let bestMMR = -Infinity;\n\n for (const candidate of pool) {\n if (!remaining.has(candidate.memory.id)) continue;\n\n const candFeat = features.get(candidate.memory.id);\n if (!candFeat) continue;\n\n let maxSim = 0;\n for (const picked of selected) {\n const pickedFeat = features.get(picked.memory.id);\n if (!pickedFeat) continue;\n const sim = blendedSimilarity(candFeat, pickedFeat, contentWeight, tagsWeight);\n if (sim > maxSim) maxSim = sim;\n }\n\n const mmr = lambda * candidate.score - (1 - lambda) * maxSim;\n if (mmr > bestMMR) {\n bestMMR = mmr;\n best = candidate;\n }\n }\n\n if (!best) break;\n selected.push(best);\n remaining.delete(best.memory.id);\n }\n\n return [...selected, ...tail];\n}\n","import type { MemoryRepo } from \"../storage/memory-repo.js\";\nimport type { RelationRepo } from \"../storage/relation-repo.js\";\nimport type { Memory } from \"../types.js\";\nimport {\n estimateTokens,\n DEFAULT_DECAY_PARAMS,\n INJECTION_WEIGHTS as W,\n TYPE_INJECTION_BONUS,\n RECENCY_HALF_LIFE,\n INJECTION_MIN_SCORE,\n INJECTION_COLD_START_THRESHOLD,\n INJECTION_COLD_START_RAMP_END,\n INJECTION_HEADER_TOKENS,\n INJECTION_MAX_SAME_TYPE_FULL,\n INJECTION_PINNED_BUDGET_PCT,\n INJECTION_PINNED_IMPORTANCE,\n INJECTION_MMR_LAMBDA,\n INJECTION_MMR_MAX_RERANK,\n INJECTION_MMR_SIM_WEIGHTS,\n} from \"../config.js\";\nimport { computeContextScore, type GitContext } from \"../utils/git-context.js\";\nimport { applyMMR } from \"../utils/mmr.js\";\n\n// ── Types ──────────────────────────────────────────────────────\n\nexport type InjectionTier = \"full\" | \"summary\" | \"index\";\n\nexport interface ScoredMemory {\n readonly memory: Memory;\n readonly score: number;\n readonly tier: InjectionTier;\n readonly tokenCost: number;\n}\n\nexport interface InjectionResult {\n readonly memories: readonly ScoredMemory[];\n readonly tokensUsed: number;\n readonly tokenBudget: number;\n readonly totalCount: number;\n}\n\ninterface InjectionDeps {\n readonly memoryRepo: MemoryRepo;\n readonly relationRepo: RelationRepo;\n readonly gitContext?: GitContext;\n}\n\n// ── Service ────────────────────────────────────────────────────\n\nexport class InjectionService {\n readonly #deps: InjectionDeps;\n\n constructor(deps: InjectionDeps) {\n this.#deps = deps;\n }\n\n selectForInjection(tokenBudget: number, project?: string): InjectionResult {\n const allMemories = this.#deps.memoryRepo.getAll(project);\n const totalCount = allMemories.length;\n\n // Gate: skip working memories and below-floor importance\n const candidates = allMemories.filter(\n (m) => m.type !== \"working\" && m.importance >= DEFAULT_DECAY_PARAMS.importanceFloor,\n );\n\n if (candidates.length === 0) {\n return { memories: [], tokensUsed: 0, tokenBudget, totalCount };\n }\n\n // Cold start: smooth ramp from 0.10 to INJECTION_MIN_SCORE\n const minScore = candidates.length <= INJECTION_COLD_START_THRESHOLD\n ? 0.10\n : candidates.length <= INJECTION_COLD_START_RAMP_END\n ? 0.10 + (INJECTION_MIN_SCORE - 0.10) * (candidates.length - INJECTION_COLD_START_THRESHOLD) / (INJECTION_COLD_START_RAMP_END - INJECTION_COLD_START_THRESHOLD)\n : INJECTION_MIN_SCORE;\n\n // Score all candidates\n const scored = candidates\n .map((m) => ({ memory: m, score: this.#scoreMemory(m) }))\n .filter((s) => s.score >= minScore)\n .sort((a, b) => b.score - a.score);\n\n // MMR diversity re-ranking on non-pinned pool; pinned keep relevance order\n // so oracle-preferred high-importance memories are not demoted by duplicates.\n const pinned = scored.filter((s) => s.memory.importance >= INJECTION_PINNED_IMPORTANCE);\n const nonPinned = scored.filter((s) => s.memory.importance < INJECTION_PINNED_IMPORTANCE);\n const diversified = applyMMR(nonPinned, {\n lambda: INJECTION_MMR_LAMBDA,\n maxRerank: INJECTION_MMR_MAX_RERANK,\n contentWeight: INJECTION_MMR_SIM_WEIGHTS.content,\n tagsWeight: INJECTION_MMR_SIM_WEIGHTS.tags,\n });\n const ordered = [...pinned, ...diversified];\n\n // Greedy token-budget packing with tier assignment\n return this.#packBudget(ordered, tokenBudget, totalCount);\n }\n\n formatInjection(result: InjectionResult): string {\n const { memories, tokensUsed, tokenBudget, totalCount } = result;\n\n if (memories.length === 0) {\n return \"No memories stored for this project. Use memory_store to save knowledge across sessions.\";\n }\n\n const lines: string[] = [];\n lines.push(`# Agentic Memory (${memories.length} of ${totalCount} memories, ${tokensUsed}/${tokenBudget} tokens)`);\n lines.push(\"Use memory_search to retrieve full content for any memory listed here.\\n\");\n\n const full = memories.filter((m) => m.tier === \"full\");\n const summary = memories.filter((m) => m.tier === \"summary\");\n const index = memories.filter((m) => m.tier === \"index\");\n\n if (full.length > 0) {\n lines.push(\"## Key Memories\");\n for (const { memory: m } of full) {\n lines.push(`### ${m.title ?? \"(untitled)\"} [${m.type}]`);\n lines.push(m.content.slice(0, 500));\n if (m.tags.length > 0) lines.push(`Tags: ${m.tags.join(\", \")}`);\n lines.push(\"\");\n }\n }\n\n if (summary.length > 0) {\n lines.push(\"## Related Memories\");\n for (const { memory: m } of summary) {\n const snippet = m.content.slice(0, 350);\n const ellipsis = m.content.length > 350 ? \"...\" : \"\";\n lines.push(`- **${m.title ?? \"(untitled)\"}** [${m.type}]: ${snippet}${ellipsis}`);\n }\n lines.push(\"\");\n }\n\n if (index.length > 0) {\n lines.push(\"## Also Available (use memory_search)\");\n for (const { memory: m } of index) {\n lines.push(`- ${m.id.slice(0, 8)} ${m.title ?? \"(untitled)\"} [${m.type}]`);\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n // ── Scoring ────────────────────────────────────────────────\n\n #scoreMemory(memory: Memory): number {\n const hasGit = !!this.#deps.gitContext;\n const ctx = hasGit ? this.#contextRelevance(memory) : 0;\n const val = this.#valueSignal(memory);\n const imp = memory.importance;\n const rec = this.#recencyScore(memory);\n const typ = TYPE_INJECTION_BONUS[memory.type] ?? 0.5;\n const noise = this.#noisePenalty(memory);\n const branch = this.#branchHeuristic(memory);\n\n // Redistribute context weight when git is unavailable\n if (!hasGit) {\n return (\n val * (W.value + W.context * 0.4) +\n imp * (W.importance + W.context * 0.3) +\n rec * (W.recency + W.context * 0.3) +\n typ * W.typeBonus +\n noise * W.noise\n );\n }\n\n return (\n ctx * W.context +\n val * W.value +\n imp * W.importance +\n rec * W.recency +\n typ * W.typeBonus +\n noise * W.noise +\n branch * 0.05\n );\n }\n\n #contextRelevance(memory: Memory): number {\n if (!this.#deps.gitContext) return 0;\n return computeContextScore(memory.context, this.#deps.gitContext, \"\");\n }\n\n #branchHeuristic(memory: Memory): number {\n if (!this.#deps.gitContext?.branch) return 0;\n const branch = this.#deps.gitContext.branch.toLowerCase();\n if (branch.startsWith('fix/') || branch.startsWith('bugfix/')) {\n return memory.type === 'pattern' ? 1.0 : memory.type === 'episodic' ? 0.5 : 0;\n }\n if (branch.startsWith('feat/') || branch.startsWith('feature/')) {\n return memory.type === 'procedural' ? 1.0 : memory.type === 'semantic' ? 0.5 : 0;\n }\n return 0;\n }\n\n #valueSignal(memory: Memory): number {\n const { accessCount, injectionCount } = memory;\n\n // Never injected or accessed: neutral — give it a chance\n if (accessCount === 0 && injectionCount === 0) return 0.5;\n\n // Injected but never accessed: noise\n if (injectionCount > 0 && accessCount === 0) {\n return Math.max(0.0, 0.5 - Math.min(1.0, injectionCount / 10) * 0.5);\n }\n\n // Access-to-injection ratio\n const ratio = Math.min(1.0, accessCount / Math.max(1, injectionCount));\n return 0.4 + ratio * 0.6;\n }\n\n #recencyScore(memory: Memory): number {\n const halfLife = RECENCY_HALF_LIFE[memory.type] ?? 30;\n const ageDays = (Date.now() - new Date(memory.updatedAt).getTime()) / 86_400_000;\n return Math.exp(-ageDays * Math.LN2 / halfLife);\n }\n\n #noisePenalty(memory: Memory): number {\n if (memory.injectionCount <= 3) return 1.0; // no penalty for first 3\n if (memory.accessCount > 0) return 1.0; // any access = useful\n return Math.max(0.2, 1.0 - Math.log2(memory.injectionCount - 2) * 0.15);\n }\n\n // ── Token Budget Packing ───────────────────────────────────\n\n #packBudget(\n scored: readonly { readonly memory: Memory; readonly score: number }[],\n tokenBudget: number,\n totalCount: number,\n ): InjectionResult {\n const selected: ScoredMemory[] = [];\n let tokensUsed = INJECTION_HEADER_TOKENS;\n const fullTypeCount = new Map<string, number>();\n\n // Phase 1: pinned memories get guaranteed slots\n const pinnedBudget = INJECTION_HEADER_TOKENS + Math.floor(tokenBudget * INJECTION_PINNED_BUDGET_PCT);\n for (const { memory, score } of scored) {\n if (memory.importance < INJECTION_PINNED_IMPORTANCE || tokensUsed >= pinnedBudget) continue;\n const cost = this.#estimateTierTokens(memory, \"full\");\n if (tokensUsed + cost > pinnedBudget) continue;\n selected.push({ memory, score, tier: \"full\", tokenCost: cost });\n tokensUsed += cost;\n this.#bumpTypeCount(fullTypeCount, memory.type);\n }\n\n // Phase 2: remaining memories packed by score\n for (const { memory, score } of scored) {\n if (tokensUsed >= tokenBudget) break;\n if (selected.some((s) => s.memory.id === memory.id)) continue;\n tokensUsed = this.#tryPack(memory, score, tokenBudget, tokensUsed, selected, fullTypeCount);\n }\n\n for (const entry of selected) {\n this.#deps.memoryRepo.incrementInjection(entry.memory.id);\n }\n return { memories: selected, tokensUsed, tokenBudget, totalCount };\n }\n\n #tryPack(\n memory: Memory, score: number, tokenBudget: number, tokensUsed: number,\n selected: ScoredMemory[], fullTypeCount: Map<string, number>,\n ): number {\n const remaining = tokenBudget - tokensUsed;\n let tier = this.#assignTier(score, selected.length, remaining);\n\n if (tier === 'full' && (fullTypeCount.get(memory.type) ?? 0) >= INJECTION_MAX_SAME_TYPE_FULL) {\n tier = 'summary';\n }\n\n const cost = this.#estimateTierTokens(memory, tier);\n if (tokensUsed + cost <= tokenBudget) {\n selected.push({ memory, score, tier, tokenCost: cost });\n if (tier === 'full') this.#bumpTypeCount(fullTypeCount, memory.type);\n return tokensUsed + cost;\n }\n\n const demoted = tier === \"full\" ? \"summary\" as const : tier === \"summary\" ? \"index\" as const : null;\n if (!demoted) return tokensUsed;\n const demotedCost = this.#estimateTierTokens(memory, demoted);\n if (tokensUsed + demotedCost <= tokenBudget) {\n selected.push({ memory, score, tier: demoted, tokenCost: demotedCost });\n return tokensUsed + demotedCost;\n }\n return tokensUsed;\n }\n\n #bumpTypeCount(counts: Map<string, number>, type: string): void {\n counts.set(type, (counts.get(type) ?? 0) + 1);\n }\n\n #assignTier(score: number, position: number, remainingBudget: number): InjectionTier {\n if (position < 3 && score >= 0.60 && remainingBudget > 200) return \"full\";\n if (position < 8 && score >= 0.35 && remainingBudget > 80) return \"summary\";\n return \"index\";\n }\n\n #estimateTierTokens(memory: Memory, tier: InjectionTier): number {\n const meta = `[${memory.type}] ${memory.title ?? \"\"} (${memory.tags.join(\", \")})`;\n switch (tier) {\n case \"full\":\n return estimateTokens(memory.content.slice(0, 500)) + estimateTokens(meta) + 10;\n case \"summary\":\n return estimateTokens(memory.content.slice(0, 350)) + estimateTokens(meta) + 8;\n case \"index\":\n return estimateTokens(`${memory.id.slice(0, 8)} [${memory.type}] ${memory.title ?? \"(untitled)\"}`) + 4;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/subcommands/install.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { createDatabase, closeDatabase } from '../storage/database.js';\nimport { migrate } from '../storage/migrator.js';\nimport { loadConfig, resolveDataDir } from '../config.js';\nimport { readSettingsJson, writeSettingsJson, readSettingsLocalJson, writeSettingsLocalJson } from '../../../lib/settings.js';\nimport { addOrUpdateHook } from '../../../lib/hook-builder.js';\nimport { getMemoryPlacement } from '../../../lib/memory-placement.js';\nimport { log } from '../../../lib/output.js';\nimport type { MemoryPlacement } from '../../../types/index.js';\n\nfunction isGhAuthenticated(): boolean {\n try {\n execSync('gh auth status', { stdio: 'pipe', timeout: 5000 });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isClaudeCliOnPath(): boolean {\n try {\n execSync('claude --version', { stdio: 'pipe', timeout: 5000 });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isGhOnPath(): boolean {\n try {\n execSync('gh --version', { stdio: 'pipe', timeout: 5000 });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction preflight(): void {\n if (!isClaudeCliOnPath()) {\n log.error('The `claude` CLI was not found on PATH.');\n log.blank();\n log.info('The knowledge base installs as a Claude Code MCP server, so the CLI is required.');\n log.info('Install: https://docs.claude.com/en/docs/claude-code');\n process.exit(1);\n }\n if (!isGhOnPath()) {\n log.warn('The GitHub CLI (`gh`) was not found on PATH — cross-device memory sync will be disabled.');\n log.info('Install later for sync: https://cli.github.com/ then `gh auth login`.');\n log.blank();\n }\n}\n\ninterface InstallOpts {\n readonly dbPath?: string;\n /** Non-interactive: default placement to \"shared\" instead of prompting. */\n readonly yes?: boolean;\n}\n\nexport async function runInstall(opts: InstallOpts): Promise<void> {\n log.blank();\n log.step('Setting up your knowledge base');\n log.blank();\n\n // Preflight: `claude` CLI is hard-required; `gh` is a soft warning for sync.\n preflight();\n\n // Step 0: Ensure native deps are installed globally\n await ensureNativeDeps();\n\n // Prompt for placement before any config writes. Non-interactive contexts\n // (-y, or stdin not a TTY — CI, pipes) default to \"shared\" instead of\n // letting inquirer throw ExitPromptError with a misleading exit 0.\n const nonInteractive = opts.yes === true || !process.stdin.isTTY;\n if (nonInteractive) log.info('Non-interactive: using \"shared\" memory placement (CLAUDE.md + settings.json).');\n const placement = await getMemoryPlacement(process.cwd(), nonInteractive);\n\n const config = loadConfig(opts.dbPath ? { dataDir: opts.dbPath } : undefined);\n const dataDir = resolveDataDir(config.dataDir);\n\n // Step 1: Database\n log.step('[1/5] Creating knowledge base...');\n if (!existsSync(dataDir)) {\n mkdirSync(dataDir, { recursive: true });\n }\n const db = createDatabase({ dataDir });\n migrate(db);\n closeDatabase(db);\n log.success(`Knowledge base created at ${dataDir}/memory.db`);\n\n // Step 2: Configure Claude Code settings\n log.step('[2/5] Connecting to Claude Code...');\n await configureSettings(process.cwd(), placement);\n\n // Step 3: Register MCP server (project scope for shared, local scope for local)\n log.step('[3/5] Enabling memory tools...');\n const mcpScope = placement === \"local\" ? \"local\" : \"project\";\n // Must run BEFORE `claude mcp add` — otherwise the add silently fails with \"not allowed by policy\"\n await ensureAllowedMcpServerIncludesMemory(process.cwd(), placement);\n const registered = registerMcpServer(mcpScope);\n if (registered) {\n log.success('Memory tools available in Claude Code');\n } else {\n log.warn('Could not enable memory tools automatically.');\n log.info(`Run: claude mcp add --scope ${mcpScope} agentic-memory -- npx claude-launchpad memory serve`);\n }\n\n // Step 4: CLAUDE.md + skills\n log.step('[4/5] Adding instructions...');\n const guidanceAdded = injectClaudeMdGuidance(process.cwd(), placement);\n if (guidanceAdded) {\n const label = placement === \"local\" ? \".claude/CLAUDE.md\" : \"CLAUDE.md\";\n log.success(`${label} updated with memory instructions`);\n }\n if (placement === \"shared\") {\n const skillsInstalled = installSkills(process.cwd());\n if (skillsInstalled > 0) {\n log.success(`Installed ${skillsInstalled} skill(s) to .claude/skills/`);\n }\n }\n\n log.blank();\n log.success('Knowledge base is ready. Claude will now remember across sessions.');\n log.info('Restart your Claude Code session to activate.');\n\n // Sync guidance\n if (isGhAuthenticated()) {\n log.info('Cross-device sync available. Run `memory push` to back up, or it auto-syncs each session.');\n } else {\n log.blank();\n log.info('Recommended: install the GitHub CLI for cross-device memory sync:');\n log.step(' https://cli.github.com/');\n log.step(' gh auth login');\n }\n log.blank();\n}\n\nexport function detectExistingSetup(projectDir: string): MemoryPlacement | null {\n // Check local CLAUDE.md\n try {\n const localClaude = readFileSync(join(projectDir, '.claude', 'CLAUDE.md'), 'utf-8');\n if (localClaude.includes('## Memory') || localClaude.includes('agentic-memory')) return \"local\";\n } catch { /* not found */ }\n\n // Check root CLAUDE.md\n try {\n const rootClaude = readFileSync(join(projectDir, 'CLAUDE.md'), 'utf-8');\n if (rootClaude.includes('## Memory (agentic-memory)')) return \"shared\";\n } catch { /* not found */ }\n\n return null;\n}\n\nasync function configureSettings(projectDir: string, placement: MemoryPlacement): Promise<void> {\n const read = placement === \"local\" ? readSettingsLocalJson : readSettingsJson;\n const write = placement === \"local\" ? writeSettingsLocalJson : writeSettingsJson;\n const settings = await read(projectDir);\n if (settings === null) {\n throw new Error(\"settings.json is unreadable; repair or remove it before installing memory.\");\n }\n\n // Disable built-in auto-memory\n log.info('Built-in auto-memory disabled (replaced by knowledge base)');\n\n // Build hooks immutably — always add sync hooks (they fail silently without gh)\n const baseHooks = (settings['hooks'] ?? {}) as Record<string, unknown[]>;\n const withPull = addSessionStartPullHook(baseHooks);\n const withContext = addSessionStartHook(withPull);\n const withPush = addSessionEndPushHook(withContext);\n\n // Build permissions immutably\n const withPermissions = addToolPermissions(settings);\n\n const updated = {\n ...withPermissions,\n autoMemoryEnabled: false,\n hooks: withPush,\n };\n\n await write(projectDir, updated);\n const target = placement === \"local\" ? \"settings.local.json\" : \"settings.json\";\n log.success(`Claude Code configured in ${target}`);\n}\n\nfunction addSessionStartPullHook(hooks: Record<string, unknown[]>): Record<string, unknown[]> {\n const result = addOrUpdateHook(hooks, {\n event: 'SessionStart',\n dedupKeyword: 'memory pull',\n entry: {\n matcher: 'startup',\n hooks: [{ type: 'command', command: 'claude-launchpad memory pull -y 2>/dev/null; exit 0' }],\n },\n prepend: true,\n });\n if (result.added) log.info('Session start: memories will auto-pull from GitHub Gist');\n return result.hooks;\n}\n\nfunction addSessionStartHook(hooks: Record<string, unknown[]>): Record<string, unknown[]> {\n const result = addOrUpdateHook(hooks, {\n event: 'SessionStart',\n dedupKeyword: 'claude-launchpad memory context',\n entry: {\n matcher: 'startup|resume',\n hooks: [{ type: 'command', command: 'npx claude-launchpad memory context --json 2>/dev/null; exit 0' }],\n },\n });\n if (result.added) log.info('Session start: Claude will recall relevant context automatically');\n return result.hooks;\n}\n\nfunction addSessionEndPushHook(hooks: Record<string, unknown[]>): Record<string, unknown[]> {\n const result = addOrUpdateHook(hooks, {\n event: 'SessionEnd',\n dedupKeyword: 'memory push',\n entry: {\n hooks: [{ type: 'command', command: 'nohup claude-launchpad memory push -y </dev/null >/dev/null 2>&1 & exit 0' }],\n },\n });\n if (result.added) log.info('Session end: memories will auto-push to GitHub Gist');\n return result.hooks;\n}\n\nfunction addToolPermissions(settings: Record<string, unknown>): Record<string, unknown> {\n const permissions = (settings['permissions'] ?? {}) as Record<string, unknown>;\n const allowList = (permissions['allow'] ?? []) as readonly string[];\n\n const memoryTools = [\n 'mcp__agentic-memory__memory_store',\n 'mcp__agentic-memory__memory_search',\n 'mcp__agentic-memory__memory_recent',\n 'mcp__agentic-memory__memory_forget',\n 'mcp__agentic-memory__memory_relate',\n 'mcp__agentic-memory__memory_stats',\n 'mcp__agentic-memory__memory_update',\n ];\n\n const missing = memoryTools.filter((t) => !allowList.includes(t));\n if (missing.length === 0) return settings;\n\n log.info(`${missing.length} memory tools auto-approved`);\n return {\n ...settings,\n permissions: { ...permissions, allow: [...allowList, ...missing] },\n };\n}\n\nasync function ensureNativeDeps(): Promise<void> {\n const { cwdRequire } = await import('../utils/require-deps.js');\n try {\n cwdRequire('better-sqlite3');\n return;\n } catch {\n // Not installed — install globally\n }\n\n log.step('Installing required database libraries...');\n try {\n execSync('npm install -g better-sqlite3 sqlite-vec', { stdio: 'pipe', timeout: 120000 });\n log.success('Database libraries installed');\n } catch {\n log.error('Could not install database libraries automatically.');\n log.blank();\n log.info('Install manually:');\n log.step(' npm install -g better-sqlite3 sqlite-vec');\n log.blank();\n log.info('Requires a C++ compiler (Xcode on macOS, build-essential on Linux).');\n process.exit(1);\n }\n}\n\nasync function ensureAllowedMcpServerIncludesMemory(\n projectDir: string,\n placement: MemoryPlacement,\n): Promise<void> {\n const read = placement === \"local\" ? readSettingsLocalJson : readSettingsJson;\n const write = placement === \"local\" ? writeSettingsLocalJson : writeSettingsJson;\n const settings = await read(projectDir);\n if (settings === null) return;\n const existing = settings.allowedMcpServers as unknown;\n // No allowlist configured — nothing to patch; Claude Code trusts any added server by default.\n if (!Array.isArray(existing)) return;\n\n const list = existing as Array<{ serverName?: unknown }>;\n const hasMemory = list.some((e) => e && typeof e === \"object\" && e.serverName === \"agentic-memory\");\n if (hasMemory) return;\n\n const updated = {\n ...settings,\n allowedMcpServers: [{ serverName: \"agentic-memory\" }, ...list],\n };\n await write(projectDir, updated);\n const target = placement === \"local\" ? \"settings.local.json\" : \"settings.json\";\n log.info(`Added agentic-memory to allowedMcpServers in ${target}`);\n}\n\nfunction registerMcpServer(scope: \"project\" | \"local\"): boolean {\n try {\n const existing = execSync('claude mcp list', { stdio: 'pipe', timeout: 10000, encoding: 'utf-8' });\n if (existing.includes('agentic-memory')) {\n log.info('Memory tools already registered');\n return true;\n }\n execSync(\n `claude mcp add --scope ${scope} agentic-memory -- npx claude-launchpad memory serve`,\n { stdio: 'pipe', timeout: 10000 },\n );\n return true;\n } catch {\n return false;\n }\n}\n\nconst MEMORY_GUIDANCE = `\n## Memory (agentic-memory)\nThis project uses **agentic-memory** for persistent memory across sessions.\n- **DO NOT** use the built-in auto-memory system (~/.claude/projects/*/memory/)\n- Memory context is **automatically injected** at session start via SessionStart hook - no need to call memory_recent manually\n- Use \\`memory_search\\` to find specific memories by keyword\n- Use \\`memory_store\\` to save decisions, gotchas, and learnings worth remembering\n- Use \\`memory_stats\\` to check memory health\n- **STORE IMMEDIATELY** when: a dependency strategy changes, an architecture decision is made, a convention is established, a bug pattern is discovered, or a feature is killed/added\n`;\n\nexport function injectClaudeMdGuidance(projectDir: string, placement: MemoryPlacement): boolean {\n const claudeMdPath = placement === \"local\"\n ? join(projectDir, '.claude', 'CLAUDE.md')\n : join(projectDir, 'CLAUDE.md');\n\n let content = '';\n try {\n content = readFileSync(claudeMdPath, 'utf-8');\n } catch {\n if (placement !== \"local\") return false;\n // Create local .claude/CLAUDE.md\n mkdirSync(join(projectDir, '.claude'), { recursive: true });\n content = '# Local Claude Config\\n';\n }\n\n if (/^## Memory( \\(agentic-memory\\))?\\s*$/m.test(content)) {\n return false;\n }\n\n const updated = content.trimEnd() + '\\n' + MEMORY_GUIDANCE;\n writeFileSync(claudeMdPath, updated, 'utf-8');\n return true;\n}\n\nconst MIGRATE_MEMORY_SKILL = `---\nname: lp-migrate-memory\ndescription: Migrate legacy Claude Code auto-memory files (~/.claude/projects/*/memory/*.md) into agentic-memory. Use when setting up agentic-memory on a project that already has built-in memories.\nallowed-tools: Read, Glob, Grep, mcp__agentic-memory__memory_store, mcp__agentic-memory__memory_search\n---\n\n# Migrate Legacy Claude Code Memories\n\nMigrate memory files from Claude Code's built-in auto-memory system into agentic-memory.\n\n## Steps\n\n1. **Find legacy memory files** for this project:\n - Scan \\`~/.claude/projects/*/memory/*.md\\` for directories whose slug matches the current project path\n - The slug format is the absolute path with \\`/\\` replaced by \\`-\\` and leading \\`-\\` (e.g. \\`-Users-john-projects-myapp\\`)\n - Also check \\`~/.claude/projects/*/memory/team/*.md\\` for team memories\n\n2. **For each memory file found**, read it and parse:\n - YAML frontmatter: \\`name\\`, \\`description\\`, \\`type\\` (user/feedback/project/reference)\n - Body content (everything after the frontmatter closing \\`---\\`)\n - Skip \\`MEMORY.md\\` (it's just an index file, not a memory)\n\n3. **Before storing**, check for duplicates:\n - Call \\`memory_search\\` with the memory description or first 100 chars of content\n - If a close match exists (same topic), skip it and report\n\n4. **Map types and store** each memory via \\`memory_store\\`:\n - \\`user\\` -> type: \\`semantic\\`, tags: [\\`user\\`, \\`migrated\\`], importance: 0.7\n - \\`feedback\\` -> type: \\`semantic\\`, tags: [\\`feedback\\`, \\`migrated\\`], importance: 0.8\n - \\`project\\` -> type: \\`semantic\\`, tags: [\\`project\\`, \\`migrated\\`], importance: 0.6\n - \\`reference\\` -> type: \\`semantic\\`, tags: [\\`reference\\`, \\`migrated\\`], importance: 0.5\n - Use the frontmatter \\`name\\` as the title\n - Use the body content as the memory content\n - Set source: \\`import\\`\n - Adjust importance up/down based on the content (decisions and gotchas deserve higher importance)\n\n5. **Report results**: list what was migrated, what was skipped (duplicates), and what failed\n\n## Important\n\n- Do NOT delete the original files - the user can do that manually after verifying\n- Do NOT migrate content that is purely derived from code (architecture, file structure) - it belongs in CLAUDE.md, not memory\n- If unsure about a memory's value, migrate it anyway - the decay system will naturally prune low-value memories over time\n`;\n\nconst SKILLS: Readonly<Record<string, string>> = {\n 'lp-migrate-memory': MIGRATE_MEMORY_SKILL,\n};\n\nfunction installSkills(projectDir: string): number {\n const skillsDir = join(projectDir, '.claude', 'skills');\n let installed = 0;\n\n for (const [name, content] of Object.entries(SKILLS)) {\n const skillDir = join(skillsDir, name);\n const skillPath = join(skillDir, 'SKILL.md');\n\n if (existsSync(skillPath)) continue;\n\n mkdirSync(skillDir, { recursive: true });\n writeFileSync(skillPath, content.trimStart(), 'utf-8');\n installed++;\n }\n\n return installed;\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/subcommands/pull.ts"],"sourcesContent":["import { log } from '../../../lib/output.js';\nimport { initStorage } from './init-storage.js';\nimport {\n assertGhAvailable,\n loadSyncConfig,\n readGistFile,\n listGistFiles,\n filenameToProject,\n projectToFilename,\n} from '../utils/gist-transport.js';\nimport { mergeFromRemote, parsePayload } from '../utils/sync-merge.js';\nimport type { MergeResult } from '../types.js';\nimport { detectProject } from '../utils/project.js';\n\ninterface PullOpts {\n readonly all?: boolean;\n /** First-sync friendly: a missing remote file is expected, not an error. */\n readonly quietMissing?: boolean;\n}\n\nexport async function runPull(opts: PullOpts): Promise<void> {\n assertGhAvailable();\n\n const syncConfig = loadSyncConfig();\n if (!syncConfig) {\n log.error('No sync gist found. Run `memory push` first.');\n return;\n }\n\n const { requireMemoryDeps } = await import('../utils/require-deps.js');\n await requireMemoryDeps();\n const ctx = initStorage();\n\n try {\n if (opts.all) {\n pullAll(ctx, syncConfig.gistId);\n } else {\n pullProject(ctx, syncConfig.gistId, opts);\n }\n } finally {\n ctx.close();\n }\n}\n\nfunction pullProject(ctx: ReturnType<typeof initStorage>, gistId: string, opts: PullOpts = {}): void {\n const project = detectProject(process.cwd());\n if (!project) {\n log.error('Could not detect project. Run from a project directory or use --all.');\n return;\n }\n\n const filename = projectToFilename(project);\n const payload = parsePayload(readGistFile(gistId, filename));\n if (!payload) {\n if (opts.quietMissing) {\n log.info(`No remote memories yet for \"${project}\" — push will create them.`);\n } else {\n log.error(`No memories found for project \"${project}\" in gist.`);\n }\n return;\n }\n\n const localCount = ctx.memoryRepo.count(project);\n if (localCount === 0) {\n log.warn(`No local memories for \"${project}\" — creating fresh database from remote.`);\n }\n\n const result = mergeFromRemote(ctx.memoryRepo, ctx.relationRepo, payload);\n printResult(result, project);\n}\n\nfunction pullAll(ctx: ReturnType<typeof initStorage>, gistId: string): void {\n const files = listGistFiles(gistId);\n const projectFiles = files.filter((f) => filenameToProject(f) !== null);\n\n if (projectFiles.length === 0) {\n log.error('No memory files found in gist.');\n return;\n }\n\n const perProject: { project: string; result: MergeResult }[] = [];\n const skipped: string[] = [];\n let totalInserted = 0;\n let totalUpdated = 0;\n let totalRelations = 0;\n\n for (const filename of projectFiles) {\n const project = filenameToProject(filename);\n if (!project) continue;\n\n // Skip projects not set up on this machine (zero local memories).\n // User must `cd` into the project and run `memory pull` to opt-in to a new project.\n if (ctx.memoryRepo.count(project) === 0) {\n skipped.push(project);\n continue;\n }\n\n const payload = parsePayload(readGistFile(gistId, filename));\n if (!payload) continue;\n const result = mergeFromRemote(ctx.memoryRepo, ctx.relationRepo, payload);\n perProject.push({ project, result });\n totalInserted += result.inserted;\n totalUpdated += result.updated;\n totalRelations += result.relationsAdded;\n }\n\n const changed = perProject.filter((p) => p.result.inserted > 0 || p.result.updated > 0 || p.result.relationsAdded > 0);\n const syncedCount = perProject.length;\n\n log.blank();\n if (syncedCount === 0) {\n log.step('No locally set up projects to sync');\n } else if (changed.length === 0) {\n log.step(`Already in sync (${syncedCount} project${syncedCount === 1 ? '' : 's'})`);\n } else {\n log.step(`Pull complete (${changed.length} of ${syncedCount} projects updated)`);\n for (const { project, result } of changed) {\n const parts: string[] = [];\n if (result.inserted > 0) parts.push(`+${result.inserted} new`);\n if (result.updated > 0) parts.push(`~${result.updated} updated`);\n if (result.relationsAdded > 0) parts.push(`+${result.relationsAdded} relations`);\n log.info(`${project.padEnd(30)} ${parts.join(', ')}`);\n }\n if (totalInserted + totalUpdated + totalRelations > 0) {\n log.blank();\n log.info(`Total: +${totalInserted} new, ~${totalUpdated} updated, +${totalRelations} relations`);\n }\n }\n if (skipped.length > 0) {\n log.blank();\n log.info(`Skipped ${skipped.length} project${skipped.length === 1 ? '' : 's'} not set up on this machine:`);\n for (const project of skipped) log.info(` - ${project}`);\n log.info('Run `memory pull` from a project directory to pull that project for the first time.');\n }\n log.blank();\n}\n\nfunction printResult(result: MergeResult, project: string): void {\n log.blank();\n if (result.inserted === 0 && result.updated === 0 && result.relationsAdded === 0) {\n log.step(`${project}: already in sync`);\n } else {\n log.step(`${project}: pull complete`);\n if (result.inserted > 0) log.info(`Inserted: ${result.inserted}`);\n if (result.updated > 0) log.info(`Updated: ${result.updated}`);\n if (result.relationsAdded > 0) log.info(`Relations: ${result.relationsAdded} added`);\n }\n log.info('Tip: run `memory pull --all` to sync every project in this gist.');\n log.blank();\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/subcommands/push.ts"],"sourcesContent":["import { hostname } from 'node:os';\nimport { confirm } from '@inquirer/prompts';\nimport { log } from '../../../lib/output.js';\nimport { initStorage } from './init-storage.js';\nimport type { StorageContext } from './init-storage.js';\nimport {\n assertGhAvailable,\n loadSyncConfig,\n createGist,\n readGistFile,\n updateGistFiles,\n projectToFilename,\n} from '../utils/gist-transport.js';\nimport { mergeFromRemote, memoryToSyncRow, tombstoneToSyncRow, parsePayload } from '../utils/sync-merge.js';\nimport type { Memory, SyncPayload, SyncRelationRow, SyncTombstone, Tombstone } from '../types.js';\nimport { detectProject } from '../utils/project.js';\n\ninterface PushOpts {\n readonly all?: boolean;\n readonly yes?: boolean;\n}\n\nfunction buildPayload(\n memories: readonly ReturnType<typeof memoryToSyncRow>[],\n relations: readonly SyncRelationRow[],\n tombstones: readonly SyncTombstone[],\n): SyncPayload {\n return {\n version: 2,\n machine_id: hostname(),\n pushed_at: new Date().toISOString(),\n memories,\n relations,\n tombstones,\n };\n}\n\nfunction filterRelations(\n allRelations: readonly { sourceId: string; targetId: string; relationType: string; createdAt: string }[],\n memoryIds: ReadonlySet<string>,\n): readonly SyncRelationRow[] {\n return allRelations\n .filter((r) => memoryIds.has(r.sourceId) && memoryIds.has(r.targetId))\n .map((r) => ({\n source_id: r.sourceId,\n target_id: r.targetId,\n relation_type: r.relationType as SyncRelationRow['relation_type'],\n created_at: r.createdAt,\n }));\n}\n\nexport async function runPush(opts: PushOpts): Promise<void> {\n assertGhAvailable();\n\n const { requireMemoryDeps } = await import('../utils/require-deps.js');\n await requireMemoryDeps();\n const ctx = initStorage();\n\n try {\n const syncConfig = loadSyncConfig();\n const allRelations = ctx.relationRepo.getAll();\n\n if (opts.all) {\n await pushAll(ctx, allRelations, syncConfig, opts);\n } else {\n await pushProject(ctx, allRelations, syncConfig, opts);\n }\n } finally {\n ctx.close();\n }\n}\n\nasync function pushProject(\n ctx: StorageContext,\n allRelations: readonly { sourceId: string; targetId: string; relationType: string; createdAt: string }[],\n syncConfig: { gistId: string } | null,\n opts: PushOpts,\n): Promise<void> {\n const project = detectProject(process.cwd());\n if (!project) {\n log.error('Could not detect project. Run from a project directory or use --all.');\n return;\n }\n\n const filename = projectToFilename(project);\n\n // Pull-before-push for this project\n if (syncConfig) {\n const remote = parsePayload(readGistFile(syncConfig.gistId, filename));\n if (remote) mergeFromRemote(ctx.memoryRepo, ctx.relationRepo, remote);\n }\n\n const memories = ctx.memoryRepo.getAllForSync(project);\n const tombstones = ctx.memoryRepo.getTombstonesByProject(project);\n\n if (memories.length === 0 && tombstones.length === 0) {\n log.warn(`No memories found for \"${project}\". Nothing to push.`);\n return;\n }\n\n const memoryIds = new Set(memories.map((m) => m.id));\n const relations = filterRelations(allRelations, memoryIds);\n const json = JSON.stringify(\n buildPayload(memories.map(memoryToSyncRow), relations, tombstones.map(tombstoneToSyncRow)),\n null,\n 2,\n );\n\n if (!syncConfig) {\n if (!opts.yes && !(await confirmCreate())) return;\n createGist(filename, json);\n } else {\n updateGistFiles(syncConfig.gistId, { [filename]: json });\n }\n\n log.blank();\n log.step('Push complete');\n log.info(`Project: ${project} (${memories.length} memories)`);\n log.info(`Relations: ${relations.length}`);\n log.blank();\n}\n\nasync function pushAll(\n ctx: StorageContext,\n allRelations: readonly { sourceId: string; targetId: string; relationType: string; createdAt: string }[],\n syncConfig: { gistId: string } | null,\n opts: PushOpts,\n): Promise<void> {\n const allMemories = ctx.memoryRepo.getAllForSync();\n const allTombstones = ctx.memoryRepo.getAllTombstones();\n\n if (allMemories.length === 0 && allTombstones.length === 0) {\n log.warn('No memories found. Nothing to push.');\n return;\n }\n\n const byProject = groupByProject(allMemories);\n const tombstonesByProject = groupTombstonesByProject(allTombstones);\n\n // Ensure every project with tombstones-only state still produces a file.\n for (const project of tombstonesByProject.keys()) {\n if (!byProject.has(project)) byProject.set(project, []);\n }\n\n const files: Record<string, string> = {};\n for (const [project, memories] of byProject) {\n const memoryIds = new Set(memories.map((m) => m.id));\n const relations = filterRelations(allRelations, memoryIds);\n const tombstones = tombstonesByProject.get(project) ?? [];\n files[projectToFilename(project)] = JSON.stringify(\n buildPayload(memories.map(memoryToSyncRow), relations, tombstones.map(tombstoneToSyncRow)),\n null,\n 2,\n );\n }\n\n if (!syncConfig) {\n if (!opts.yes && !(await confirmCreate())) return;\n const entries = Object.entries(files);\n const gistId = createGist(entries[0]![0], entries[0]![1]);\n if (entries.length > 1) {\n updateGistFiles(gistId, Object.fromEntries(entries.slice(1)));\n }\n } else {\n updateGistFiles(syncConfig.gistId, files);\n }\n\n log.blank();\n log.step('Push complete');\n log.info(`Projects: ${byProject.size}`);\n log.info(`Memories: ${allMemories.length}`);\n log.blank();\n}\n\nfunction groupByProject(memories: readonly Memory[]): Map<string, Memory[]> {\n const byProject = new Map<string, Memory[]>();\n for (const m of memories) {\n const key = m.project ?? '_global';\n const list = byProject.get(key) ?? [];\n list.push(m);\n byProject.set(key, list);\n }\n return byProject;\n}\n\nfunction groupTombstonesByProject(tombstones: readonly Tombstone[]): Map<string, Tombstone[]> {\n const byProject = new Map<string, Tombstone[]>();\n for (const t of tombstones) {\n const key = t.project ?? '_global';\n const list = byProject.get(key) ?? [];\n list.push(t);\n byProject.set(key, list);\n }\n return byProject;\n}\n\nasync function confirmCreate(): Promise<boolean> {\n const proceed = await confirm({\n message: 'Create a private GitHub Gist for memory sync?',\n default: true,\n });\n if (!proceed) log.info('Skipped.');\n return proceed;\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/subcommands/sync-clean.ts"],"sourcesContent":["import { confirm } from '@inquirer/prompts';\nimport { log } from '../../../lib/output.js';\nimport {\n assertGhAvailable,\n loadSyncConfig,\n listGistFiles,\n filenameToProject,\n projectToFilename,\n deleteGistFile,\n} from '../utils/gist-transport.js';\n\ninterface SyncCleanOpts {\n readonly yes?: boolean;\n}\n\nexport async function runSyncClean(project: string, opts: SyncCleanOpts): Promise<void> {\n assertGhAvailable();\n\n const syncConfig = loadSyncConfig();\n if (!syncConfig) {\n log.error('No sync gist found. Run `memory push` first.');\n return;\n }\n\n const filename = projectToFilename(project);\n const files = listGistFiles(syncConfig.gistId);\n const projectFiles = files.filter((f) => filenameToProject(f) !== null);\n\n if (!projectFiles.includes(filename)) {\n log.error(`Project \"${project}\" not found in gist.`);\n if (projectFiles.length > 0) {\n log.blank();\n log.info('Available projects:');\n for (const f of projectFiles) {\n log.info(` ${filenameToProject(f)}`);\n }\n }\n return;\n }\n\n if (!opts.yes) {\n const proceed = await confirm({\n message: `Remove \"${project}\" from sync gist? This only removes the remote copy.`,\n default: false,\n });\n if (!proceed) {\n log.info('Skipped.');\n return;\n }\n }\n\n deleteGistFile(syncConfig.gistId, filename);\n log.success(`Removed \"${project}\" from sync gist.`);\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,eAAe;AAexB,eAAsB,aAAa,SAAiB,MAAoC;AACtF,oBAAkB;AAElB,QAAM,aAAa,eAAe;AAClC,MAAI,CAAC,YAAY;AACf,QAAI,MAAM,8CAA8C;AACxD;AAAA,EACF;AAEA,QAAM,WAAW,kBAAkB,OAAO;AAC1C,QAAM,QAAQ,cAAc,WAAW,MAAM;AAC7C,QAAM,eAAe,MAAM,OAAO,CAAC,MAAM,kBAAkB,CAAC,MAAM,IAAI;AAEtE,MAAI,CAAC,aAAa,SAAS,QAAQ,GAAG;AACpC,QAAI,MAAM,YAAY,OAAO,sBAAsB;AACnD,QAAI,aAAa,SAAS,GAAG;AAC3B,UAAI,MAAM;AACV,UAAI,KAAK,qBAAqB;AAC9B,iBAAW,KAAK,cAAc;AAC5B,YAAI,KAAK,KAAK,kBAAkB,CAAC,CAAC,EAAE;AAAA,MACtC;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI,CAAC,KAAK,KAAK;AACb,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,SAAS,WAAW,OAAO;AAAA,MAC3B,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,UAAI,KAAK,UAAU;AACnB;AAAA,IACF;AAAA,EACF;AAEA,iBAAe,WAAW,QAAQ,QAAQ;AAC1C,MAAI,QAAQ,YAAY,OAAO,mBAAmB;AACpD;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/memory/subcommands/sync-status.ts"],"sourcesContent":["import { log } from '../../../lib/output.js';\nimport { initStorage } from './init-storage.js';\nimport {\n assertGhAvailable,\n loadSyncConfig,\n listGistFiles,\n filenameToProject,\n readGistFile,\n} from '../utils/gist-transport.js';\nimport { parsePayload } from '../utils/sync-merge.js';\n\nexport async function runSyncStatus(): Promise<void> {\n assertGhAvailable();\n\n const syncConfig = loadSyncConfig();\n if (!syncConfig) {\n log.error('No sync gist found. Run `memory push` first.');\n return;\n }\n\n const { requireMemoryDeps } = await import('../utils/require-deps.js');\n await requireMemoryDeps();\n const ctx = initStorage();\n\n try {\n const localCounts = ctx.memoryRepo.projectCounts();\n const localTombstoneIds = new Set(ctx.memoryRepo.getAllTombstones().map((t) => t.id));\n const remoteFiles = listGistFiles(syncConfig.gistId);\n\n // Cosmetic display only: a local tombstone may still be resurrected by a newer remote\n // updated_at, but mergeFromRemote handles that. Excluding tombstoned ids here keeps\n // the reported delta close to what `pull --all` actually ingests most of the time.\n const remoteCounts = new Map<string, number>();\n for (const file of remoteFiles) {\n const project = filenameToProject(file);\n if (!project) continue;\n const payload = parsePayload(readGistFile(syncConfig.gistId, file));\n if (!payload) {\n remoteCounts.set(project, 0);\n continue;\n }\n const mergeable = payload.memories.filter((m) => !localTombstoneIds.has(m.id)).length;\n remoteCounts.set(project, mergeable);\n }\n\n const allProjects = new Set([...localCounts.keys(), ...remoteCounts.keys()]);\n\n log.blank();\n log.step('Sync status');\n log.info(`Gist: ${syncConfig.gistId}`);\n log.blank();\n\n if (allProjects.size === 0) {\n log.info('No projects found locally or remotely.');\n } else {\n log.info('Project Local Remote');\n log.info('─────────────────────────────── ───── ──────');\n for (const project of [...allProjects].sort()) {\n const local = localCounts.get(project) ?? 0;\n const remote = remoteCounts.get(project) ?? 0;\n const name = project.length > 33 ? project.slice(0, 30) + '...' : project;\n log.info(`${name.padEnd(33)} ${String(local).padStart(5)} ${String(remote).padStart(6)}`);\n }\n }\n log.blank();\n } finally {\n ctx.close();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAWA,eAAsB,gBAA+B;AACnD,oBAAkB;AAElB,QAAM,aAAa,eAAe;AAClC,MAAI,CAAC,YAAY;AACf,QAAI,MAAM,8CAA8C;AACxD;AAAA,EACF;AAEA,QAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,4BAA0B;AACrE,QAAM,kBAAkB;AACxB,QAAM,MAAM,YAAY;AAExB,MAAI;AACF,UAAM,cAAc,IAAI,WAAW,cAAc;AACjD,UAAM,oBAAoB,IAAI,IAAI,IAAI,WAAW,iBAAiB,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACpF,UAAM,cAAc,cAAc,WAAW,MAAM;AAKnD,UAAM,eAAe,oBAAI,IAAoB;AAC7C,eAAW,QAAQ,aAAa;AAC9B,YAAM,UAAU,kBAAkB,IAAI;AACtC,UAAI,CAAC,QAAS;AACd,YAAM,UAAU,aAAa,aAAa,WAAW,QAAQ,IAAI,CAAC;AAClE,UAAI,CAAC,SAAS;AACZ,qBAAa,IAAI,SAAS,CAAC;AAC3B;AAAA,MACF;AACA,YAAM,YAAY,QAAQ,SAAS,OAAO,CAAC,MAAM,CAAC,kBAAkB,IAAI,EAAE,EAAE,CAAC,EAAE;AAC/E,mBAAa,IAAI,SAAS,SAAS;AAAA,IACrC;AAEA,UAAM,cAAc,oBAAI,IAAI,CAAC,GAAG,YAAY,KAAK,GAAG,GAAG,aAAa,KAAK,CAAC,CAAC;AAE3E,QAAI,MAAM;AACV,QAAI,KAAK,aAAa;AACtB,QAAI,KAAK,SAAS,WAAW,MAAM,EAAE;AACrC,QAAI,MAAM;AAEV,QAAI,YAAY,SAAS,GAAG;AAC1B,UAAI,KAAK,wCAAwC;AAAA,IACnD,OAAO;AACL,UAAI,KAAK,gDAAgD;AACzD,UAAI,KAAK,kQAAgD;AACzD,iBAAW,WAAW,CAAC,GAAG,WAAW,EAAE,KAAK,GAAG;AAC7C,cAAM,QAAQ,YAAY,IAAI,OAAO,KAAK;AAC1C,cAAM,SAAS,aAAa,IAAI,OAAO,KAAK;AAC5C,cAAM,OAAO,QAAQ,SAAS,KAAK,QAAQ,MAAM,GAAG,EAAE,IAAI,QAAQ;AAClE,YAAI,KAAK,GAAG,KAAK,OAAO,EAAE,CAAC,IAAI,OAAO,KAAK,EAAE,SAAS,CAAC,CAAC,KAAK,OAAO,MAAM,EAAE,SAAS,CAAC,CAAC,EAAE;AAAA,MAC3F;AAAA,IACF;AACA,QAAI,MAAM;AAAA,EACZ,UAAE;AACA,QAAI,MAAM;AAAA,EACZ;AACF;","names":[]}