claude-launchpad 0.8.2 → 0.9.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.
- package/README.md +2 -2
- package/dist/chunk-CSLWJEGD.js +0 -0
- package/dist/chunk-FL3JGYDM.js +0 -0
- package/dist/{chunk-NNVJCKEP.js → chunk-JPVLFY2R.js} +36 -1
- package/dist/chunk-JPVLFY2R.js.map +1 -0
- package/dist/chunk-MQJA7TGY.js +60 -0
- package/dist/chunk-MQJA7TGY.js.map +1 -0
- package/dist/chunk-NAW47BYA.js +0 -0
- package/dist/chunk-TALTTAMW.js +0 -0
- package/dist/chunk-UN2XVQ5K.js +0 -0
- package/dist/{chunk-EUAVDA7W.js → chunk-X7ZY2Y2Z.js} +2 -2
- package/dist/cli.js +6 -6
- package/dist/cli.js.map +1 -1
- package/dist/commands/memory/server.js +252 -3
- package/dist/commands/memory/server.js.map +1 -1
- package/dist/{context-QU2QFVS3.js → context-HX5BOXYM.js} +158 -70
- package/dist/context-HX5BOXYM.js.map +1 -0
- package/dist/{extract-ADZYHMUP.js → extract-7D2EEXYD.js} +3 -3
- package/dist/{install-3IW2PDOS.js → install-ULZUZI7T.js} +2 -2
- package/dist/require-deps-6D6IBICL.js +0 -0
- package/dist/{stats-XLVVS3JA.js → stats-Y5ZFAZVF.js} +3 -3
- package/dist/{tui-BXRHLYAS.js → tui-DTIXPD2V.js} +2 -2
- package/package.json +21 -14
- package/dist/chunk-NNVJCKEP.js.map +0 -1
- package/dist/chunk-OYSKBXBB.js +0 -311
- package/dist/chunk-OYSKBXBB.js.map +0 -1
- package/dist/context-QU2QFVS3.js.map +0 -1
- /package/dist/{chunk-EUAVDA7W.js.map → chunk-X7ZY2Y2Z.js.map} +0 -0
- /package/dist/{extract-ADZYHMUP.js.map → extract-7D2EEXYD.js.map} +0 -0
- /package/dist/{install-3IW2PDOS.js.map → install-ULZUZI7T.js.map} +0 -0
- /package/dist/{stats-XLVVS3JA.js.map → stats-Y5ZFAZVF.js.map} +0 -0
- /package/dist/{tui-BXRHLYAS.js.map → tui-DTIXPD2V.js.map} +0 -0
package/README.md
CHANGED
|
@@ -148,10 +148,10 @@ claude-launchpad memory
|
|
|
148
148
|
Requires native deps first: `npm install better-sqlite3 sqlite-vec` (the CLI will prompt you if missing). Interactive setup - asks before changing anything. Installs a SQLite database, hooks for automatic context injection, and 7 MCP tools.
|
|
149
149
|
|
|
150
150
|
**What it does:**
|
|
151
|
-
- **
|
|
151
|
+
- **Smart session injection** - each session starts with the most relevant memories, ranked by 6 signals (context, value, importance, recency, type, noise) and packed into a 2000-token budget across three tiers (full content / summary / title-only)
|
|
152
152
|
- **Stop hook** extracts facts from the conversation transcript when you're done
|
|
153
153
|
- **Decay model** - memories fade naturally based on type (episodic: 60 days, semantic: 1 year, procedural: 2 years)
|
|
154
|
-
- **
|
|
154
|
+
- **Self-tuning retrieval** - memories Claude actively searches for rise in rank; memories injected but never used gradually stop appearing
|
|
155
155
|
- **Project-scoped** - memories are partitioned per project, no cross-contamination
|
|
156
156
|
- **TUI dashboard** (`--dashboard`) for visualization with vim navigation, filtering, and search
|
|
157
157
|
|
package/dist/chunk-CSLWJEGD.js
CHANGED
|
File without changes
|
package/dist/chunk-FL3JGYDM.js
CHANGED
|
File without changes
|
|
@@ -59,6 +59,31 @@ var SCORING_WEIGHTS = {
|
|
|
59
59
|
access: 0.1,
|
|
60
60
|
context: 0.15
|
|
61
61
|
};
|
|
62
|
+
var INJECTION_WEIGHTS = {
|
|
63
|
+
context: 0.3,
|
|
64
|
+
value: 0.25,
|
|
65
|
+
importance: 0.2,
|
|
66
|
+
recency: 0.15,
|
|
67
|
+
typeBonus: 0.05,
|
|
68
|
+
noise: 0.05
|
|
69
|
+
};
|
|
70
|
+
var TYPE_INJECTION_BONUS = {
|
|
71
|
+
procedural: 1,
|
|
72
|
+
pattern: 0.8,
|
|
73
|
+
semantic: 0.6,
|
|
74
|
+
episodic: 0.3,
|
|
75
|
+
working: 0
|
|
76
|
+
};
|
|
77
|
+
var RECENCY_HALF_LIFE = {
|
|
78
|
+
working: 1,
|
|
79
|
+
episodic: 7,
|
|
80
|
+
pattern: 14,
|
|
81
|
+
semantic: 30,
|
|
82
|
+
procedural: 90
|
|
83
|
+
};
|
|
84
|
+
var INJECTION_MIN_SCORE = 0.25;
|
|
85
|
+
var INJECTION_COLD_START_THRESHOLD = 5;
|
|
86
|
+
var INJECTION_HEADER_TOKENS = 50;
|
|
62
87
|
function resolveDataDir(dataDir) {
|
|
63
88
|
if (dataDir.startsWith("~")) {
|
|
64
89
|
return join(homedir(), dataDir.slice(1));
|
|
@@ -93,6 +118,9 @@ function loadConfig(overrides) {
|
|
|
93
118
|
const merged = { ...DEFAULT_CONFIG, ...fileConfig, ...envOverrides, ...overrides };
|
|
94
119
|
return ConfigSchema.parse(merged);
|
|
95
120
|
}
|
|
121
|
+
function estimateTokens(text) {
|
|
122
|
+
return Math.ceil(text.length / 4);
|
|
123
|
+
}
|
|
96
124
|
|
|
97
125
|
// src/commands/memory/storage/database.ts
|
|
98
126
|
import { mkdirSync } from "fs";
|
|
@@ -252,10 +280,17 @@ function migrate(db) {
|
|
|
252
280
|
export {
|
|
253
281
|
DEFAULT_DECAY_PARAMS,
|
|
254
282
|
SCORING_WEIGHTS,
|
|
283
|
+
INJECTION_WEIGHTS,
|
|
284
|
+
TYPE_INJECTION_BONUS,
|
|
285
|
+
RECENCY_HALF_LIFE,
|
|
286
|
+
INJECTION_MIN_SCORE,
|
|
287
|
+
INJECTION_COLD_START_THRESHOLD,
|
|
288
|
+
INJECTION_HEADER_TOKENS,
|
|
255
289
|
resolveDataDir,
|
|
256
290
|
loadConfig,
|
|
291
|
+
estimateTokens,
|
|
257
292
|
createDatabase,
|
|
258
293
|
closeDatabase,
|
|
259
294
|
migrate
|
|
260
295
|
};
|
|
261
|
-
//# sourceMappingURL=chunk-
|
|
296
|
+
//# sourceMappingURL=chunk-JPVLFY2R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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/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(2000),\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: 2000,\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: 60, // fast decay\n semantic: 365, // slow decay\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: 0.7,\n isolatedMultiplier: 1.3,\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_HEADER_TOKENS = 50;\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 type Database from 'better-sqlite3';\nimport * as migration001 from './migrations/001-initial.js';\nimport * as migration002 from './migrations/002-add-project.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];\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"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/memory/utils/git-context.ts
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
var cached = null;
|
|
6
|
+
function getGitContext() {
|
|
7
|
+
if (cached) return cached;
|
|
8
|
+
let branch = null;
|
|
9
|
+
let recentFiles = [];
|
|
10
|
+
try {
|
|
11
|
+
branch = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf-8", timeout: 3e3 }).trim() || null;
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const raw = execSync("git diff --name-only HEAD~5", { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
16
|
+
recentFiles = raw ? raw.split("\n").filter(Boolean) : [];
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
cached = { branch, recentFiles };
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
function computeContextScore(storedContext, currentContext, query) {
|
|
23
|
+
if (!storedContext) return 0;
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = JSON.parse(storedContext);
|
|
27
|
+
} catch {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
const branchScore = parsed.branch && currentContext.branch && parsed.branch === currentContext.branch ? 1 : 0;
|
|
31
|
+
let fileScore = 0;
|
|
32
|
+
if (parsed.files?.length && currentContext.recentFiles.length) {
|
|
33
|
+
const stored = new Set(parsed.files);
|
|
34
|
+
const current = new Set(currentContext.recentFiles);
|
|
35
|
+
let intersection = 0;
|
|
36
|
+
for (const f of stored) {
|
|
37
|
+
if (current.has(f)) intersection++;
|
|
38
|
+
}
|
|
39
|
+
const union = stored.size + current.size - intersection;
|
|
40
|
+
fileScore = union > 0 ? intersection / union : 0;
|
|
41
|
+
}
|
|
42
|
+
let intentScore = 0;
|
|
43
|
+
if (parsed.intent && query) {
|
|
44
|
+
const intentWords = new Set(parsed.intent.toLowerCase().split(/\s+/).filter(Boolean));
|
|
45
|
+
const queryWords = new Set(query.toLowerCase().split(/\s+/).filter(Boolean));
|
|
46
|
+
let overlap = 0;
|
|
47
|
+
for (const w of intentWords) {
|
|
48
|
+
if (queryWords.has(w)) overlap++;
|
|
49
|
+
}
|
|
50
|
+
const union = intentWords.size + queryWords.size - overlap;
|
|
51
|
+
intentScore = union > 0 ? overlap / union : 0;
|
|
52
|
+
}
|
|
53
|
+
return branchScore * 0.4 + fileScore * 0.4 + intentScore * 0.2;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
getGitContext,
|
|
58
|
+
computeContextScore
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=chunk-MQJA7TGY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/memory/utils/git-context.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\n\nexport interface GitContext {\n readonly branch: string | null;\n readonly recentFiles: readonly string[];\n}\n\nlet cached: GitContext | null = null;\n\nexport function getGitContext(): GitContext {\n if (cached) return cached;\n\n let branch: string | null = null;\n let recentFiles: string[] = [];\n\n try {\n branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8', timeout: 3000 }).trim() || null;\n } catch { /* not in a git repo or git not available */ }\n\n try {\n const raw = execSync('git diff --name-only HEAD~5', { encoding: 'utf-8', timeout: 3000 }).trim();\n recentFiles = raw ? raw.split('\\n').filter(Boolean) : [];\n } catch { /* shallow clone or no commits */ }\n\n cached = { branch, recentFiles };\n return cached;\n}\n\nexport function clearGitContextCache(): void {\n cached = null;\n}\n\nexport function computeContextScore(\n storedContext: string | null,\n currentContext: GitContext,\n query: string,\n): number {\n if (!storedContext) return 0;\n\n let parsed: { files?: string[]; branch?: string; intent?: string };\n try {\n parsed = JSON.parse(storedContext) as { files?: string[]; branch?: string; intent?: string };\n } catch {\n return 0;\n }\n\n // Branch match (weight 0.4)\n const branchScore = (parsed.branch && currentContext.branch && parsed.branch === currentContext.branch) ? 1.0 : 0;\n\n // File overlap — Jaccard similarity (weight 0.4)\n let fileScore = 0;\n if (parsed.files?.length && currentContext.recentFiles.length) {\n const stored = new Set(parsed.files);\n const current = new Set(currentContext.recentFiles);\n let intersection = 0;\n for (const f of stored) {\n if (current.has(f)) intersection++;\n }\n const union = stored.size + current.size - intersection;\n fileScore = union > 0 ? intersection / union : 0;\n }\n\n // Intent keyword overlap with query (weight 0.2)\n let intentScore = 0;\n if (parsed.intent && query) {\n const intentWords = new Set(parsed.intent.toLowerCase().split(/\\s+/).filter(Boolean));\n const queryWords = new Set(query.toLowerCase().split(/\\s+/).filter(Boolean));\n let overlap = 0;\n for (const w of intentWords) {\n if (queryWords.has(w)) overlap++;\n }\n const union = intentWords.size + queryWords.size - overlap;\n intentScore = union > 0 ? overlap / union : 0;\n }\n\n return branchScore * 0.4 + fileScore * 0.4 + intentScore * 0.2;\n}\n"],"mappings":";;;AAAA,SAAS,gBAAgB;AAOzB,IAAI,SAA4B;AAEzB,SAAS,gBAA4B;AAC1C,MAAI,OAAQ,QAAO;AAEnB,MAAI,SAAwB;AAC5B,MAAI,cAAwB,CAAC;AAE7B,MAAI;AACF,aAAS,SAAS,mCAAmC,EAAE,UAAU,SAAS,SAAS,IAAK,CAAC,EAAE,KAAK,KAAK;AAAA,EACvG,QAAQ;AAAA,EAA+C;AAEvD,MAAI;AACF,UAAM,MAAM,SAAS,+BAA+B,EAAE,UAAU,SAAS,SAAS,IAAK,CAAC,EAAE,KAAK;AAC/F,kBAAc,MAAM,IAAI,MAAM,IAAI,EAAE,OAAO,OAAO,IAAI,CAAC;AAAA,EACzD,QAAQ;AAAA,EAAoC;AAE5C,WAAS,EAAE,QAAQ,YAAY;AAC/B,SAAO;AACT;AAMO,SAAS,oBACd,eACA,gBACA,OACQ;AACR,MAAI,CAAC,cAAe,QAAO;AAE3B,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,aAAa;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AAGA,QAAM,cAAe,OAAO,UAAU,eAAe,UAAU,OAAO,WAAW,eAAe,SAAU,IAAM;AAGhH,MAAI,YAAY;AAChB,MAAI,OAAO,OAAO,UAAU,eAAe,YAAY,QAAQ;AAC7D,UAAM,SAAS,IAAI,IAAI,OAAO,KAAK;AACnC,UAAM,UAAU,IAAI,IAAI,eAAe,WAAW;AAClD,QAAI,eAAe;AACnB,eAAW,KAAK,QAAQ;AACtB,UAAI,QAAQ,IAAI,CAAC,EAAG;AAAA,IACtB;AACA,UAAM,QAAQ,OAAO,OAAO,QAAQ,OAAO;AAC3C,gBAAY,QAAQ,IAAI,eAAe,QAAQ;AAAA,EACjD;AAGA,MAAI,cAAc;AAClB,MAAI,OAAO,UAAU,OAAO;AAC1B,UAAM,cAAc,IAAI,IAAI,OAAO,OAAO,YAAY,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO,CAAC;AACpF,UAAM,aAAa,IAAI,IAAI,MAAM,YAAY,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO,CAAC;AAC3E,QAAI,UAAU;AACd,eAAW,KAAK,aAAa;AAC3B,UAAI,WAAW,IAAI,CAAC,EAAG;AAAA,IACzB;AACA,UAAM,QAAQ,YAAY,OAAO,WAAW,OAAO;AACnD,kBAAc,QAAQ,IAAI,UAAU,QAAQ;AAAA,EAC9C;AAEA,SAAO,cAAc,MAAM,YAAY,MAAM,cAAc;AAC7D;","names":[]}
|
package/dist/chunk-NAW47BYA.js
CHANGED
|
File without changes
|
package/dist/chunk-TALTTAMW.js
CHANGED
|
File without changes
|
package/dist/chunk-UN2XVQ5K.js
CHANGED
|
File without changes
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
loadConfig,
|
|
11
11
|
migrate,
|
|
12
12
|
resolveDataDir
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-JPVLFY2R.js";
|
|
14
14
|
|
|
15
15
|
// src/commands/memory/subcommands/init-storage.ts
|
|
16
16
|
function initStorage(dbPath) {
|
|
@@ -32,4 +32,4 @@ function initStorage(dbPath) {
|
|
|
32
32
|
export {
|
|
33
33
|
initStorage
|
|
34
34
|
};
|
|
35
|
-
//# sourceMappingURL=chunk-
|
|
35
|
+
//# sourceMappingURL=chunk-X7ZY2Y2Z.js.map
|
package/dist/cli.js
CHANGED
|
@@ -2588,7 +2588,7 @@ function createMemoryCommand() {
|
|
|
2588
2588
|
}
|
|
2589
2589
|
const { requireMemoryDeps } = await import("./require-deps-6D6IBICL.js");
|
|
2590
2590
|
await requireMemoryDeps();
|
|
2591
|
-
const { startTui } = await import("./tui-
|
|
2591
|
+
const { startTui } = await import("./tui-DTIXPD2V.js");
|
|
2592
2592
|
await startTui();
|
|
2593
2593
|
return;
|
|
2594
2594
|
}
|
|
@@ -2610,25 +2610,25 @@ function createMemoryCommand() {
|
|
|
2610
2610
|
log.info("Skipped.");
|
|
2611
2611
|
return;
|
|
2612
2612
|
}
|
|
2613
|
-
const { runInstall } = await import("./install-
|
|
2613
|
+
const { runInstall } = await import("./install-ULZUZI7T.js");
|
|
2614
2614
|
await runInstall({});
|
|
2615
2615
|
} else {
|
|
2616
2616
|
const { requireMemoryDeps } = await import("./require-deps-6D6IBICL.js");
|
|
2617
2617
|
await requireMemoryDeps();
|
|
2618
|
-
const { runStats } = await import("./stats-
|
|
2618
|
+
const { runStats } = await import("./stats-Y5ZFAZVF.js");
|
|
2619
2619
|
await runStats({});
|
|
2620
2620
|
}
|
|
2621
2621
|
});
|
|
2622
2622
|
memory.addCommand(
|
|
2623
2623
|
new Command4("context").description("Load session context (hook handler)").option("--json", "JSON output").action(async (opts) => {
|
|
2624
|
-
const { runContext } = await import("./context-
|
|
2624
|
+
const { runContext } = await import("./context-HX5BOXYM.js");
|
|
2625
2625
|
await runContext(opts);
|
|
2626
2626
|
}).helpCommand(false),
|
|
2627
2627
|
{ hidden: true }
|
|
2628
2628
|
);
|
|
2629
2629
|
memory.addCommand(
|
|
2630
2630
|
new Command4("extract").description("Extract facts from transcript (hook handler)").action(async () => {
|
|
2631
|
-
const { runExtract } = await import("./extract-
|
|
2631
|
+
const { runExtract } = await import("./extract-7D2EEXYD.js");
|
|
2632
2632
|
await runExtract();
|
|
2633
2633
|
}).helpCommand(false),
|
|
2634
2634
|
{ hidden: true }
|
|
@@ -2644,7 +2644,7 @@ function createMemoryCommand() {
|
|
|
2644
2644
|
}
|
|
2645
2645
|
|
|
2646
2646
|
// src/cli.ts
|
|
2647
|
-
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.
|
|
2647
|
+
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.9.0", "-v, --version").action(async () => {
|
|
2648
2648
|
const hasConfig = await fileExists(join11(process.cwd(), "CLAUDE.md")) || await fileExists(join11(process.cwd(), ".claude", "settings.json"));
|
|
2649
2649
|
if (hasConfig) {
|
|
2650
2650
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|