claude-launchpad 0.9.2-dev.3 → 0.10.1-dev.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 +123 -113
- package/dist/chunk-7YDBTED2.js +154 -0
- package/dist/chunk-7YDBTED2.js.map +1 -0
- package/dist/chunk-J5NT4JGE.js +77 -0
- package/dist/chunk-J5NT4JGE.js.map +1 -0
- package/dist/{chunk-TALTTAMW.js → chunk-JXFTVFPC.js} +43 -3
- package/dist/chunk-JXFTVFPC.js.map +1 -0
- package/dist/{chunk-4AF3NGNF.js → chunk-YEGOHLE7.js} +3 -3
- package/dist/{chunk-JTKRLIEV.js → chunk-ZMSHFAZQ.js} +2 -1
- package/dist/cli.js +47 -90
- package/dist/cli.js.map +1 -1
- package/dist/commands/memory/server.js +39 -75
- package/dist/commands/memory/server.js.map +1 -1
- package/dist/{context-AGNCZJPC.js → context-SGPGEJV4.js} +4 -4
- package/dist/{extract-RPRYPT3Z.js → extract-T32FMLN5.js} +4 -4
- package/dist/{install-PSSMUGLO.js → install-OKLYDFBJ.js} +2 -2
- package/dist/pull-4VKUDKTB.js +66 -0
- package/dist/pull-4VKUDKTB.js.map +1 -0
- package/dist/push-WI3ZIPZU.js +89 -0
- package/dist/push-WI3ZIPZU.js.map +1 -0
- package/dist/{stats-DAUYJ4BE.js → stats-77WLARNA.js} +4 -4
- package/dist/{tui-A4TJFNE3.js → tui-YV7AFJFR.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-TALTTAMW.js.map +0 -1
- /package/dist/{chunk-4AF3NGNF.js.map → chunk-YEGOHLE7.js.map} +0 -0
- /package/dist/{chunk-JTKRLIEV.js.map → chunk-ZMSHFAZQ.js.map} +0 -0
- /package/dist/{context-AGNCZJPC.js.map → context-SGPGEJV4.js.map} +0 -0
- /package/dist/{extract-RPRYPT3Z.js.map → extract-T32FMLN5.js.map} +0 -0
- /package/dist/{install-PSSMUGLO.js.map → install-OKLYDFBJ.js.map} +0 -0
- /package/dist/{stats-DAUYJ4BE.js.map → stats-77WLARNA.js.map} +0 -0
- /package/dist/{tui-A4TJFNE3.js.map → tui-YV7AFJFR.js.map} +0 -0
|
@@ -70,7 +70,17 @@ var MemoryRepo = class {
|
|
|
70
70
|
topInjected: db.prepare(`
|
|
71
71
|
SELECT id, title, injection_count FROM memories
|
|
72
72
|
WHERE injection_count > 0 ORDER BY injection_count DESC LIMIT ?
|
|
73
|
-
`)
|
|
73
|
+
`),
|
|
74
|
+
upsertSync: db.prepare(`
|
|
75
|
+
INSERT OR REPLACE INTO memories
|
|
76
|
+
(id, type, title, content, context, source, project, tags, importance,
|
|
77
|
+
access_count, injection_count, created_at, updated_at, last_accessed, embedding)
|
|
78
|
+
VALUES (@id, @type, @title, @content, @context, @source, @project, @tags, @importance,
|
|
79
|
+
@accessCount, @injectionCount, @createdAt, @updatedAt, @lastAccessed, NULL)
|
|
80
|
+
`),
|
|
81
|
+
getAllStrictProject: db.prepare(
|
|
82
|
+
"SELECT * FROM memories WHERE project = ? ORDER BY created_at DESC"
|
|
83
|
+
)
|
|
74
84
|
};
|
|
75
85
|
}
|
|
76
86
|
create(input, _embedding = null) {
|
|
@@ -207,6 +217,31 @@ var MemoryRepo = class {
|
|
|
207
217
|
const rows = this.#stmts.topInjected.all(limit);
|
|
208
218
|
return rows.map((r) => ({ id: r.id, title: r.title, injectionCount: r.injection_count }));
|
|
209
219
|
}
|
|
220
|
+
upsertFromSync(row) {
|
|
221
|
+
this.#stmts.upsertSync.run({
|
|
222
|
+
id: row.id,
|
|
223
|
+
type: row.type,
|
|
224
|
+
title: row.title,
|
|
225
|
+
content: row.content,
|
|
226
|
+
context: row.context,
|
|
227
|
+
source: row.source,
|
|
228
|
+
project: row.project,
|
|
229
|
+
tags: JSON.stringify(row.tags),
|
|
230
|
+
importance: row.importance,
|
|
231
|
+
accessCount: row.access_count,
|
|
232
|
+
injectionCount: row.injection_count,
|
|
233
|
+
createdAt: row.created_at,
|
|
234
|
+
updatedAt: row.updated_at,
|
|
235
|
+
lastAccessed: row.last_accessed
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
getAllForSync(project) {
|
|
239
|
+
if (project) {
|
|
240
|
+
const rows = this.#stmts.getAllStrictProject.all(project);
|
|
241
|
+
return rows.map(rowToMemory);
|
|
242
|
+
}
|
|
243
|
+
return this.getAll();
|
|
244
|
+
}
|
|
210
245
|
};
|
|
211
246
|
|
|
212
247
|
// src/commands/memory/storage/relation-repo.ts
|
|
@@ -237,7 +272,8 @@ var RelationRepo = class {
|
|
|
237
272
|
countByMemory: db.prepare(`
|
|
238
273
|
SELECT COUNT(*) as count FROM relations WHERE source_id = ? OR target_id = ?
|
|
239
274
|
`),
|
|
240
|
-
count: db.prepare("SELECT COUNT(*) as count FROM relations")
|
|
275
|
+
count: db.prepare("SELECT COUNT(*) as count FROM relations"),
|
|
276
|
+
getAll: db.prepare("SELECT * FROM relations")
|
|
241
277
|
};
|
|
242
278
|
}
|
|
243
279
|
create(sourceId, targetId, relationType) {
|
|
@@ -268,6 +304,10 @@ var RelationRepo = class {
|
|
|
268
304
|
const row = this.#stmts.count.get();
|
|
269
305
|
return row.count;
|
|
270
306
|
}
|
|
307
|
+
getAll() {
|
|
308
|
+
const rows = this.#stmts.getAll.all();
|
|
309
|
+
return rows.map(rowToRelation);
|
|
310
|
+
}
|
|
271
311
|
};
|
|
272
312
|
|
|
273
313
|
// src/commands/memory/storage/search-repo.ts
|
|
@@ -387,4 +427,4 @@ export {
|
|
|
387
427
|
RelationRepo,
|
|
388
428
|
SearchRepo
|
|
389
429
|
};
|
|
390
|
-
//# sourceMappingURL=chunk-
|
|
430
|
+
//# sourceMappingURL=chunk-JXFTVFPC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/memory/storage/memory-repo.ts","../src/commands/memory/storage/relation-repo.ts","../src/commands/memory/storage/search-repo.ts"],"sourcesContent":["import type Database from 'better-sqlite3';\nimport type { Memory, MemoryType, MemorySource, StoreInput, SyncMemoryRow } from '../types.js';\nimport { randomUUID } from 'node:crypto';\n\nfunction safeParseTags(raw: string): string[] {\n try {\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed.filter(t => typeof t === 'string') : [];\n } catch {\n return [];\n }\n}\n\n// ── Row shape from SQLite ─────────────────────────────────────\n\ninterface MemoryRow {\n id: string;\n type: string;\n title: string | null;\n content: string;\n context: string | null;\n source: string | null;\n project: string | null;\n tags: string;\n importance: number;\n created_at: string;\n updated_at: string;\n access_count: number;\n last_accessed: string | null;\n injection_count: number;\n embedding: Buffer | null;\n}\n\nfunction rowToMemory(row: MemoryRow): Memory {\n return {\n id: row.id,\n type: row.type as MemoryType,\n title: row.title,\n content: row.content,\n context: row.context,\n source: row.source as MemorySource | null,\n project: row.project,\n tags: safeParseTags(row.tags),\n importance: row.importance,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n accessCount: row.access_count,\n lastAccessed: row.last_accessed,\n injectionCount: row.injection_count,\n };\n}\n\n// ── Repository ────────────────────────────────────────────────\n\nexport class MemoryRepo {\n readonly #stmts;\n readonly db: Database.Database;\n\n constructor(db: Database.Database) {\n this.db = db;\n this.#stmts = {\n insert: db.prepare(`\n INSERT INTO memories (id, type, title, content, context, source, project, tags, importance, created_at, updated_at, embedding)\n VALUES (@id, @type, @title, @content, @context, @source, @project, @tags, @importance, @createdAt, @updatedAt, @embedding)\n `),\n getById: db.prepare('SELECT * FROM memories WHERE id = ?'),\n getAll: db.prepare('SELECT * FROM memories ORDER BY created_at DESC'),\n getAllByProject: db.prepare('SELECT * FROM memories WHERE project = ? OR project IS NULL ORDER BY created_at DESC'),\n getByType: db.prepare('SELECT * FROM memories WHERE type = ? ORDER BY created_at DESC'),\n getByTypeAndProject: db.prepare('SELECT * FROM memories WHERE type = ? AND (project = ? OR project IS NULL) ORDER BY created_at DESC'),\n getRecent: db.prepare('SELECT * FROM memories ORDER BY created_at DESC LIMIT ?'),\n getRecentByProject: db.prepare('SELECT * FROM memories WHERE project = ? OR project IS NULL ORDER BY created_at DESC LIMIT ?'),\n getRecentByTypeAndProject: db.prepare('SELECT * FROM memories WHERE type = ? AND (project = ? OR project IS NULL) ORDER BY created_at DESC LIMIT ?'),\n update: db.prepare(`\n UPDATE memories\n SET title = @title, content = @content, context = @context, tags = @tags,\n importance = @importance, updated_at = @updatedAt, embedding = @embedding\n WHERE id = @id\n `),\n updateImportance: db.prepare('UPDATE memories SET importance = ?, updated_at = ? WHERE id = ?'),\n updateImportanceOnly: db.prepare('UPDATE memories SET importance = ? WHERE id = ?'),\n incrementAccess: db.prepare(`\n UPDATE memories SET access_count = access_count + 1, last_accessed = ? WHERE id = ?\n `),\n incrementInjection: db.prepare(`\n UPDATE memories SET injection_count = injection_count + 1 WHERE id = ?\n `),\n softDelete: db.prepare('UPDATE memories SET importance = 0, updated_at = ? WHERE id = ?'),\n hardDelete: db.prepare('DELETE FROM memories WHERE id = ?'),\n deleteByType: db.prepare('DELETE FROM memories WHERE type = ?'),\n count: db.prepare('SELECT COUNT(*) as count FROM memories'),\n countByProject: db.prepare('SELECT COUNT(*) as count FROM memories WHERE project = ?'),\n countByType: db.prepare('SELECT type, COUNT(*) as count FROM memories GROUP BY type'),\n dateRange: db.prepare('SELECT MIN(created_at) as oldest, MAX(created_at) as newest FROM memories'),\n topInjected: db.prepare(`\n SELECT id, title, injection_count FROM memories\n WHERE injection_count > 0 ORDER BY injection_count DESC LIMIT ?\n `),\n upsertSync: db.prepare(`\n INSERT OR REPLACE INTO memories\n (id, type, title, content, context, source, project, tags, importance,\n access_count, injection_count, created_at, updated_at, last_accessed, embedding)\n VALUES (@id, @type, @title, @content, @context, @source, @project, @tags, @importance,\n @accessCount, @injectionCount, @createdAt, @updatedAt, @lastAccessed, NULL)\n `),\n getAllStrictProject: db.prepare(\n 'SELECT * FROM memories WHERE project = ? ORDER BY created_at DESC'\n ),\n };\n }\n\n create(input: StoreInput, _embedding: Buffer | null = null): Memory {\n const now = new Date().toISOString();\n const id = randomUUID();\n\n const params = {\n id,\n type: input.type,\n title: input.title ?? null,\n content: input.content,\n context: input.context ?? null,\n source: input.source,\n project: input.project ?? null,\n tags: JSON.stringify(input.tags),\n importance: input.importance,\n createdAt: now,\n updatedAt: now,\n embedding: null,\n };\n\n this.#stmts.insert.run(params);\n\n const row: MemoryRow = {\n id,\n type: input.type,\n title: input.title ?? null,\n content: input.content,\n context: input.context ?? null,\n source: input.source,\n project: input.project ?? null,\n tags: JSON.stringify(input.tags),\n importance: input.importance,\n created_at: now,\n updated_at: now,\n access_count: 0,\n last_accessed: null,\n injection_count: 0,\n embedding: null,\n };\n\n return rowToMemory(row);\n }\n\n getById(id: string): Memory | undefined {\n const row = this.#stmts.getById.get(id) as MemoryRow | undefined;\n return row ? rowToMemory(row) : undefined;\n }\n\n getAll(project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getAllByProject.all(project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getAll.all() as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n getRecent(limit: number, project?: string, type?: MemoryType): readonly Memory[] {\n if (type && project) {\n const rows = this.#stmts.getRecentByTypeAndProject.all(type, project, limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n if (project) {\n const rows = this.#stmts.getRecentByProject.all(project, limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getRecent.all(limit) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n getByType(type: MemoryType, project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getByTypeAndProject.all(type, project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n const rows = this.#stmts.getByType.all(type) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n\n updateContent(id: string, updates: {\n readonly title?: string | null;\n readonly content?: string;\n readonly context?: string | null;\n readonly tags?: readonly string[];\n readonly importance?: number;\n }): boolean {\n const existing = this.getById(id);\n if (!existing) return false;\n\n const now = new Date().toISOString();\n\n const params = {\n id,\n title: updates.title !== undefined ? updates.title : existing.title,\n content: updates.content ?? existing.content,\n context: updates.context !== undefined ? updates.context : existing.context,\n tags: JSON.stringify(updates.tags ?? existing.tags),\n importance: updates.importance ?? existing.importance,\n updatedAt: now,\n embedding: null,\n };\n\n this.#stmts.update.run(params);\n return true;\n }\n\n updateImportance(id: string, importance: number): boolean {\n const now = new Date().toISOString();\n const result = this.#stmts.updateImportance.run(importance, now, id);\n return result.changes > 0;\n }\n\n /** Update importance without touching updated_at - used by decay to avoid resetting the clock. */\n updateImportanceOnly(id: string, importance: number): boolean {\n const result = this.#stmts.updateImportanceOnly.run(importance, id);\n return result.changes > 0;\n }\n\n incrementAccess(id: string): void {\n this.#stmts.incrementAccess.run(new Date().toISOString(), id);\n }\n\n incrementInjection(id: string): void {\n this.#stmts.incrementInjection.run(id);\n }\n\n softDelete(id: string): boolean {\n const result = this.#stmts.softDelete.run(new Date().toISOString(), id);\n return result.changes > 0;\n }\n\n hardDelete(id: string): boolean {\n const result = this.#stmts.hardDelete.run(id);\n return result.changes > 0;\n }\n\n deleteByType(type: MemoryType): number {\n const result = this.#stmts.deleteByType.run(type);\n return result.changes;\n }\n\n count(project?: string): number {\n if (project) {\n const row = this.#stmts.countByProject.get(project) as { count: number };\n return row.count;\n }\n const row = this.#stmts.count.get() as { count: number };\n return row.count;\n }\n\n countByType(): Record<string, number> {\n const rows = this.#stmts.countByType.all() as { type: string; count: number }[];\n return Object.fromEntries(rows.map(r => [r.type, r.count]));\n }\n\n dateRange(): { oldest: string | null; newest: string | null } {\n const row = this.#stmts.dateRange.get() as { oldest: string | null; newest: string | null };\n return { oldest: row.oldest, newest: row.newest };\n }\n\n topInjected(limit: number = 5): readonly { id: string; title: string | null; injectionCount: number }[] {\n const rows = this.#stmts.topInjected.all(limit) as { id: string; title: string | null; injection_count: number }[];\n return rows.map(r => ({ id: r.id, title: r.title, injectionCount: r.injection_count }));\n }\n\n upsertFromSync(row: SyncMemoryRow): void {\n this.#stmts.upsertSync.run({\n id: row.id,\n type: row.type,\n title: row.title,\n content: row.content,\n context: row.context,\n source: row.source,\n project: row.project,\n tags: JSON.stringify(row.tags),\n importance: row.importance,\n accessCount: row.access_count,\n injectionCount: row.injection_count,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n lastAccessed: row.last_accessed,\n });\n }\n\n getAllForSync(project?: string): readonly Memory[] {\n if (project) {\n const rows = this.#stmts.getAllStrictProject.all(project) as MemoryRow[];\n return rows.map(rowToMemory);\n }\n return this.getAll();\n }\n}\n","import type Database from 'better-sqlite3';\nimport type { Relation, RelationType } from '../types.js';\n\ninterface RelationRow {\n source_id: string;\n target_id: string;\n relation_type: string;\n created_at: string;\n}\n\nfunction rowToRelation(row: RelationRow): Relation {\n return {\n sourceId: row.source_id,\n targetId: row.target_id,\n relationType: row.relation_type as RelationType,\n createdAt: row.created_at,\n };\n}\n\nexport class RelationRepo {\n readonly #stmts;\n\n constructor(db: Database.Database) {\n this.#stmts = {\n insert: db.prepare(`\n INSERT OR IGNORE INTO relations (source_id, target_id, relation_type)\n VALUES (?, ?, ?)\n `),\n getBySource: db.prepare('SELECT * FROM relations WHERE source_id = ?'),\n getByTarget: db.prepare('SELECT * FROM relations WHERE target_id = ?'),\n getByMemory: db.prepare(`\n SELECT * FROM relations WHERE source_id = ? OR target_id = ?\n `),\n delete: db.prepare(`\n DELETE FROM relations WHERE source_id = ? AND target_id = ? AND relation_type = ?\n `),\n countByMemory: db.prepare(`\n SELECT COUNT(*) as count FROM relations WHERE source_id = ? OR target_id = ?\n `),\n count: db.prepare('SELECT COUNT(*) as count FROM relations'),\n getAll: db.prepare('SELECT * FROM relations'),\n };\n }\n\n create(sourceId: string, targetId: string, relationType: RelationType): boolean {\n const result = this.#stmts.insert.run(sourceId, targetId, relationType);\n return result.changes > 0;\n }\n\n getBySource(sourceId: string): readonly Relation[] {\n const rows = this.#stmts.getBySource.all(sourceId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n getByTarget(targetId: string): readonly Relation[] {\n const rows = this.#stmts.getByTarget.all(targetId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n getByMemory(memoryId: string): readonly Relation[] {\n const rows = this.#stmts.getByMemory.all(memoryId, memoryId) as RelationRow[];\n return rows.map(rowToRelation);\n }\n\n delete(sourceId: string, targetId: string, relationType: RelationType): boolean {\n const result = this.#stmts.delete.run(sourceId, targetId, relationType);\n return result.changes > 0;\n }\n\n countByMemory(memoryId: string): number {\n const row = this.#stmts.countByMemory.get(memoryId, memoryId) as { count: number };\n return row.count;\n }\n\n count(): number {\n const row = this.#stmts.count.get() as { count: number };\n return row.count;\n }\n\n getAll(): readonly Relation[] {\n const rows = this.#stmts.getAll.all() as RelationRow[];\n return rows.map(rowToRelation);\n }\n}\n","import type Database from 'better-sqlite3';\nimport type { FtsMatch, MemoryType } from '../types.js';\n\n// ── FTS5 Search ───────────────────────────────────────────────\n\nexport interface FtsSearchOptions {\n readonly query: string;\n readonly limit: number;\n readonly type?: MemoryType;\n readonly minImportance?: number;\n readonly project?: string;\n}\n\n\nexport class SearchRepo {\n readonly #stmts;\n\n constructor(db: Database.Database) {\n // FTS5 search with BM25 ranking (weights: title=5.0, content=1.0, tags=2.0)\n this.#stmts = {\n ftsSearch: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchByProject: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND (m.project = @project OR m.project IS NULL)\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchFiltered: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND m.type = @type\n AND m.importance >= @minImportance\n ORDER BY rank\n LIMIT @limit\n `),\n ftsSearchFilteredByProject: db.prepare(`\n SELECT\n m.rowid,\n m.id as memory_id,\n bm25(memories_fts, 5.0, 1.0, 2.0) as rank\n FROM memories_fts f\n JOIN memories m ON m.rowid = f.rowid\n WHERE memories_fts MATCH @query\n AND m.type = @type\n AND m.importance >= @minImportance\n AND (m.project = @project OR m.project IS NULL)\n ORDER BY rank\n LIMIT @limit\n `),\n };\n }\n\n /**\n * Full-text search using BM25 ranking.\n * Returns matches sorted by relevance (most relevant first).\n */\n searchFts(options: FtsSearchOptions): readonly FtsMatch[] {\n const ftsQuery = toFtsQuery(options.query);\n if (!ftsQuery) return [];\n\n try {\n const hasType = !!options.type;\n const hasProject = !!options.project;\n\n let rows: FtsRow[];\n if (hasType && hasProject) {\n rows = this.#stmts.ftsSearchFilteredByProject.all({\n query: ftsQuery, limit: options.limit,\n type: options.type, minImportance: options.minImportance ?? 0,\n project: options.project,\n }) as FtsRow[];\n } else if (hasType) {\n rows = this.#stmts.ftsSearchFiltered.all({\n query: ftsQuery, limit: options.limit,\n type: options.type, minImportance: options.minImportance ?? 0,\n }) as FtsRow[];\n } else if (hasProject) {\n rows = this.#stmts.ftsSearchByProject.all({\n query: ftsQuery, limit: options.limit,\n project: options.project,\n }) as FtsRow[];\n } else {\n rows = this.#stmts.ftsSearch.all({\n query: ftsQuery, limit: options.limit,\n }) as FtsRow[];\n }\n\n return rows.map(r => ({\n rowid: r.rowid,\n memoryId: r.memory_id,\n rank: r.rank,\n }));\n } catch (err) {\n // FTS5 MATCH throws on invalid query syntax - degrade gracefully\n console.error('[agentic-memory] FTS5 search error:', err instanceof Error ? err.message : err);\n return [];\n }\n }\n\n}\n\n// ── Internal helpers ──────────────────────────────────────────\n\ninterface FtsRow {\n rowid: number;\n memory_id: string;\n rank: number;\n}\n\n/**\n * Convert a natural language query to FTS5 query syntax.\n * Wraps each word in quotes to avoid syntax errors from special characters.\n */\nfunction toFtsQuery(input: string): string | null {\n const words = input\n .replace(/[^\\w\\s]/g, ' ') // strip punctuation\n .split(/\\s+/)\n .filter(w => w.length > 0);\n\n if (words.length === 0) return null;\n\n // Use OR between words for broader recall\n return words.map(w => `\"${w}\"`).join(' OR ');\n}\n"],"mappings":"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","names":["rows","row"]}
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
MemoryRepo,
|
|
4
4
|
RelationRepo,
|
|
5
5
|
SearchRepo
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JXFTVFPC.js";
|
|
7
7
|
import {
|
|
8
8
|
closeDatabase,
|
|
9
9
|
createDatabase,
|
|
10
10
|
loadConfig,
|
|
11
11
|
migrate,
|
|
12
12
|
resolveDataDir
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-ZMSHFAZQ.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-YEGOHLE7.js.map
|
|
@@ -278,6 +278,7 @@ function migrate(db) {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
export {
|
|
281
|
+
DEFAULT_CONFIG,
|
|
281
282
|
DEFAULT_DECAY_PARAMS,
|
|
282
283
|
SCORING_WEIGHTS,
|
|
283
284
|
INJECTION_WEIGHTS,
|
|
@@ -293,4 +294,4 @@ export {
|
|
|
293
294
|
closeDatabase,
|
|
294
295
|
migrate
|
|
295
296
|
};
|
|
296
|
-
//# sourceMappingURL=chunk-
|
|
297
|
+
//# sourceMappingURL=chunk-ZMSHFAZQ.js.map
|
package/dist/cli.js
CHANGED
|
@@ -591,7 +591,7 @@ Also review .claude/settings.json hooks:
|
|
|
591
591
|
|
|
592
592
|
// src/commands/init/generators/backlog.ts
|
|
593
593
|
function generateBacklogMd(options) {
|
|
594
|
-
return `# ${options.name}
|
|
594
|
+
return `# ${options.name} - Backlog
|
|
595
595
|
|
|
596
596
|
> Features discussed but deferred. Pick up when relevant.
|
|
597
597
|
> Priority: P0 = next sprint, P1 = soon, P2 = when relevant.
|
|
@@ -1566,26 +1566,29 @@ async function tryFix(issue, root, detected) {
|
|
|
1566
1566
|
);
|
|
1567
1567
|
return entry ? entry.fix(root, detected) : false;
|
|
1568
1568
|
}
|
|
1569
|
-
async function
|
|
1569
|
+
async function addHook(root, event, dedupKeyword, entry, successMsg) {
|
|
1570
1570
|
const settings = await readSettingsJson(root);
|
|
1571
1571
|
const hooks = settings.hooks ?? {};
|
|
1572
|
-
const
|
|
1573
|
-
const alreadyHas =
|
|
1572
|
+
const hookList = hooks[event] ?? [];
|
|
1573
|
+
const alreadyHas = hookList.some((g) => {
|
|
1574
1574
|
const nested = g.hooks;
|
|
1575
|
-
return nested?.some((h) => String(h.command ?? "").includes(
|
|
1575
|
+
return nested?.some((h) => String(h.command ?? "").includes(dedupKeyword));
|
|
1576
1576
|
});
|
|
1577
1577
|
if (alreadyHas) return false;
|
|
1578
|
-
|
|
1578
|
+
hookList.push(entry);
|
|
1579
|
+
settings.hooks = { ...hooks, [event]: hookList };
|
|
1580
|
+
await writeSettingsJson(root, settings);
|
|
1581
|
+
log.success(successMsg);
|
|
1582
|
+
return true;
|
|
1583
|
+
}
|
|
1584
|
+
async function addEnvProtectionHook(root) {
|
|
1585
|
+
return addHook(root, "PreToolUse", ".env", {
|
|
1579
1586
|
matcher: "Read|Write|Edit",
|
|
1580
1587
|
hooks: [{
|
|
1581
1588
|
type: "command",
|
|
1582
1589
|
command: `echo "$TOOL_INPUT_FILE_PATH" | grep -qE '\\.(env|env\\..*)$' && ! echo "$TOOL_INPUT_FILE_PATH" | grep -q '.env.example' && echo 'BLOCKED: .env files contain secrets' && exit 1; exit 0`
|
|
1583
1590
|
}]
|
|
1584
|
-
});
|
|
1585
|
-
settings.hooks = { ...hooks, PreToolUse: preToolUse };
|
|
1586
|
-
await writeSettingsJson(root, settings);
|
|
1587
|
-
log.success("Added .env file protection hook (PreToolUse)");
|
|
1588
|
-
return true;
|
|
1591
|
+
}, "Added .env file protection hook (PreToolUse)");
|
|
1589
1592
|
}
|
|
1590
1593
|
async function addAutoFormatHook(root, detected) {
|
|
1591
1594
|
if (!detected.language) return false;
|
|
@@ -1600,82 +1603,41 @@ async function addAutoFormatHook(root, detected) {
|
|
|
1600
1603
|
};
|
|
1601
1604
|
const config = formatters[detected.language];
|
|
1602
1605
|
if (!config) return false;
|
|
1603
|
-
const settings = await readSettingsJson(root);
|
|
1604
|
-
const hooks = settings.hooks ?? {};
|
|
1605
|
-
const postToolUse = hooks.PostToolUse ?? [];
|
|
1606
|
-
const alreadyHas = postToolUse.some((g) => {
|
|
1607
|
-
const nested = g.hooks;
|
|
1608
|
-
return nested?.some((h) => String(h.command ?? "").includes("format"));
|
|
1609
|
-
});
|
|
1610
|
-
if (alreadyHas) return false;
|
|
1611
1606
|
const extChecks = config.extensions.map((ext) => `[ "$ext" = "${ext}" ]`).join(" || ");
|
|
1612
|
-
|
|
1607
|
+
return addHook(root, "PostToolUse", "format", {
|
|
1613
1608
|
matcher: "Write|Edit",
|
|
1614
1609
|
hooks: [{
|
|
1615
1610
|
type: "command",
|
|
1616
1611
|
command: `ext=\${TOOL_INPUT_FILE_PATH##*.}; (${extChecks}) && ${config.command} "$TOOL_INPUT_FILE_PATH" 2>/dev/null; exit 0`
|
|
1617
1612
|
}]
|
|
1618
|
-
});
|
|
1619
|
-
settings.hooks = { ...hooks, PostToolUse: postToolUse };
|
|
1620
|
-
await writeSettingsJson(root, settings);
|
|
1621
|
-
log.success(`Added auto-format hook (PostToolUse \u2192 ${config.command})`);
|
|
1622
|
-
return true;
|
|
1613
|
+
}, `Added auto-format hook (PostToolUse \u2192 ${config.command})`);
|
|
1623
1614
|
}
|
|
1624
1615
|
async function addForcePushProtection(root) {
|
|
1625
|
-
|
|
1626
|
-
const hooks = settings.hooks ?? {};
|
|
1627
|
-
const preToolUse = hooks.PreToolUse ?? [];
|
|
1628
|
-
const alreadyHas = preToolUse.some((g) => {
|
|
1629
|
-
const nested = g.hooks;
|
|
1630
|
-
return nested?.some((h) => String(h.command ?? "").includes("force"));
|
|
1631
|
-
});
|
|
1632
|
-
if (alreadyHas) return false;
|
|
1633
|
-
preToolUse.push({
|
|
1616
|
+
return addHook(root, "PreToolUse", "force", {
|
|
1634
1617
|
matcher: "Bash",
|
|
1635
1618
|
hooks: [{
|
|
1636
1619
|
type: "command",
|
|
1637
1620
|
command: `echo "$TOOL_INPUT_COMMAND" | grep -qE 'push.*--force|push.*-f' && echo 'WARNING: Force push detected \u2014 this can destroy remote history' && exit 1; exit 0`
|
|
1638
1621
|
}]
|
|
1639
|
-
});
|
|
1640
|
-
settings.hooks = { ...hooks, PreToolUse: preToolUse };
|
|
1641
|
-
await writeSettingsJson(root, settings);
|
|
1642
|
-
log.success("Added force-push protection hook (PreToolUse \u2192 Bash)");
|
|
1643
|
-
return true;
|
|
1622
|
+
}, "Added force-push protection hook (PreToolUse \u2192 Bash)");
|
|
1644
1623
|
}
|
|
1645
1624
|
async function addPostCompactHook(root) {
|
|
1646
|
-
|
|
1647
|
-
const hooks = settings.hooks ?? {};
|
|
1648
|
-
const postCompact = hooks.PostCompact ?? [];
|
|
1649
|
-
const alreadyHas = postCompact.length > 0;
|
|
1650
|
-
if (alreadyHas) return false;
|
|
1651
|
-
postCompact.push({
|
|
1625
|
+
return addHook(root, "PostCompact", "TASKS.md", {
|
|
1652
1626
|
matcher: "",
|
|
1653
1627
|
hooks: [{
|
|
1654
1628
|
type: "command",
|
|
1655
1629
|
command: "cat TASKS.md 2>/dev/null; exit 0"
|
|
1656
1630
|
}]
|
|
1657
|
-
});
|
|
1658
|
-
settings.hooks = { ...hooks, PostCompact: postCompact };
|
|
1659
|
-
await writeSettingsJson(root, settings);
|
|
1660
|
-
log.success("Added PostCompact hook (re-injects TASKS.md after compaction)");
|
|
1661
|
-
return true;
|
|
1631
|
+
}, "Added PostCompact hook (re-injects TASKS.md after compaction)");
|
|
1662
1632
|
}
|
|
1663
1633
|
async function addSessionStartHook(root) {
|
|
1664
|
-
|
|
1665
|
-
const hooks = settings.hooks ?? {};
|
|
1666
|
-
const sessionStart = hooks.SessionStart ?? [];
|
|
1667
|
-
if (sessionStart.length > 0) return false;
|
|
1668
|
-
sessionStart.push({
|
|
1634
|
+
return addHook(root, "SessionStart", "TASKS.md", {
|
|
1669
1635
|
matcher: "startup|resume",
|
|
1670
1636
|
hooks: [{
|
|
1671
1637
|
type: "command",
|
|
1672
1638
|
command: "cat TASKS.md 2>/dev/null; exit 0"
|
|
1673
1639
|
}]
|
|
1674
|
-
});
|
|
1675
|
-
settings.hooks = { ...hooks, SessionStart: sessionStart };
|
|
1676
|
-
await writeSettingsJson(root, settings);
|
|
1677
|
-
log.success("Added SessionStart hook (injects TASKS.md at startup)");
|
|
1678
|
-
return true;
|
|
1640
|
+
}, "Added SessionStart hook (injects TASKS.md at startup)");
|
|
1679
1641
|
}
|
|
1680
1642
|
async function migrateAttribution(root) {
|
|
1681
1643
|
const settings = await readSettingsJson(root);
|
|
@@ -1758,7 +1720,7 @@ async function createBacklogMd(root) {
|
|
|
1758
1720
|
} catch {
|
|
1759
1721
|
}
|
|
1760
1722
|
const name = root.split("/").pop() ?? "Project";
|
|
1761
|
-
await writeFile2(backlogPath, `# ${name}
|
|
1723
|
+
await writeFile2(backlogPath, `# ${name} - Backlog
|
|
1762
1724
|
|
|
1763
1725
|
> Features discussed but deferred. Pick up when relevant.
|
|
1764
1726
|
> Priority: P0 = next sprint, P1 = soon, P2 = when relevant.
|
|
@@ -2183,7 +2145,7 @@ async function listYamlFiles(dir) {
|
|
|
2183
2145
|
}
|
|
2184
2146
|
|
|
2185
2147
|
// src/commands/eval/runner.ts
|
|
2186
|
-
import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile6, readdir as readdir4, rm, cp
|
|
2148
|
+
import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile6, readdir as readdir4, rm, cp } from "fs/promises";
|
|
2187
2149
|
import { join as join8, dirname as dirname3 } from "path";
|
|
2188
2150
|
import { tmpdir } from "os";
|
|
2189
2151
|
import { randomUUID } from "crypto";
|
|
@@ -2248,27 +2210,19 @@ async function copyProjectConfig(sandboxDir, projectRoot) {
|
|
|
2248
2210
|
const claudeDir = join8(projectRoot, ".claude");
|
|
2249
2211
|
const sandboxClaudeDir = join8(sandboxDir, ".claude");
|
|
2250
2212
|
const settingsPath = join8(claudeDir, "settings.json");
|
|
2251
|
-
if (await
|
|
2213
|
+
if (await fileExists(settingsPath)) {
|
|
2252
2214
|
await mkdir3(sandboxClaudeDir, { recursive: true });
|
|
2253
2215
|
await cp(settingsPath, join8(sandboxClaudeDir, "settings.json"));
|
|
2254
2216
|
}
|
|
2255
2217
|
const rulesDir = join8(claudeDir, "rules");
|
|
2256
|
-
if (await
|
|
2218
|
+
if (await fileExists(rulesDir)) {
|
|
2257
2219
|
await cp(rulesDir, join8(sandboxClaudeDir, "rules"), { recursive: true });
|
|
2258
2220
|
}
|
|
2259
2221
|
const ignorePath = join8(projectRoot, ".claudeignore");
|
|
2260
|
-
if (await
|
|
2222
|
+
if (await fileExists(ignorePath)) {
|
|
2261
2223
|
await cp(ignorePath, join8(sandboxDir, ".claudeignore"));
|
|
2262
2224
|
}
|
|
2263
2225
|
}
|
|
2264
|
-
async function fileExistsSafe(path) {
|
|
2265
|
-
try {
|
|
2266
|
-
await access6(path);
|
|
2267
|
-
return true;
|
|
2268
|
-
} catch {
|
|
2269
|
-
return false;
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
2226
|
async function runClaudeInSandbox(cwd, prompt, timeout, model) {
|
|
2273
2227
|
try {
|
|
2274
2228
|
const sdk = await import("@anthropic-ai/claude-agent-sdk");
|
|
@@ -2347,9 +2301,8 @@ async function evaluateSingleCheck(check, sandboxDir) {
|
|
|
2347
2301
|
case "grep":
|
|
2348
2302
|
return checkGrep(check, sandboxDir);
|
|
2349
2303
|
case "file-exists":
|
|
2350
|
-
return checkFileExists(check, sandboxDir);
|
|
2351
2304
|
case "file-absent":
|
|
2352
|
-
return
|
|
2305
|
+
return checkFilePresence(check, sandboxDir);
|
|
2353
2306
|
case "max-lines":
|
|
2354
2307
|
return checkMaxLines(check, sandboxDir);
|
|
2355
2308
|
case "custom":
|
|
@@ -2373,7 +2326,7 @@ async function checkGrep(check, sandboxDir) {
|
|
|
2373
2326
|
return check.expect === "absent";
|
|
2374
2327
|
}
|
|
2375
2328
|
}
|
|
2376
|
-
async function
|
|
2329
|
+
async function checkFilePresence(check, sandboxDir) {
|
|
2377
2330
|
try {
|
|
2378
2331
|
await readFile6(join8(sandboxDir, check.target));
|
|
2379
2332
|
return check.expect === "present";
|
|
@@ -2381,14 +2334,6 @@ async function checkFileExists(check, sandboxDir) {
|
|
|
2381
2334
|
return check.expect === "absent";
|
|
2382
2335
|
}
|
|
2383
2336
|
}
|
|
2384
|
-
async function checkFileAbsent(check, sandboxDir) {
|
|
2385
|
-
try {
|
|
2386
|
-
await readFile6(join8(sandboxDir, check.target));
|
|
2387
|
-
return check.expect === "absent";
|
|
2388
|
-
} catch {
|
|
2389
|
-
return check.expect === "present";
|
|
2390
|
-
}
|
|
2391
|
-
}
|
|
2392
2337
|
async function checkMaxLines(check, sandboxDir) {
|
|
2393
2338
|
const maxLines = parseInt(check.pattern ?? "800", 10);
|
|
2394
2339
|
try {
|
|
@@ -2642,7 +2587,7 @@ function createMemoryCommand() {
|
|
|
2642
2587
|
}
|
|
2643
2588
|
const { requireMemoryDeps } = await import("./require-deps-NKRCPVAO.js");
|
|
2644
2589
|
await requireMemoryDeps();
|
|
2645
|
-
const { startTui } = await import("./tui-
|
|
2590
|
+
const { startTui } = await import("./tui-YV7AFJFR.js");
|
|
2646
2591
|
await startTui();
|
|
2647
2592
|
return;
|
|
2648
2593
|
}
|
|
@@ -2664,25 +2609,25 @@ function createMemoryCommand() {
|
|
|
2664
2609
|
log.info("Skipped.");
|
|
2665
2610
|
return;
|
|
2666
2611
|
}
|
|
2667
|
-
const { runInstall } = await import("./install-
|
|
2612
|
+
const { runInstall } = await import("./install-OKLYDFBJ.js");
|
|
2668
2613
|
await runInstall({});
|
|
2669
2614
|
} else {
|
|
2670
2615
|
const { requireMemoryDeps } = await import("./require-deps-NKRCPVAO.js");
|
|
2671
2616
|
await requireMemoryDeps();
|
|
2672
|
-
const { runStats } = await import("./stats-
|
|
2617
|
+
const { runStats } = await import("./stats-77WLARNA.js");
|
|
2673
2618
|
await runStats({});
|
|
2674
2619
|
}
|
|
2675
2620
|
});
|
|
2676
2621
|
memory.addCommand(
|
|
2677
2622
|
new Command4("context").description("Load session context (hook handler)").option("--json", "JSON output").action(async (opts) => {
|
|
2678
|
-
const { runContext } = await import("./context-
|
|
2623
|
+
const { runContext } = await import("./context-SGPGEJV4.js");
|
|
2679
2624
|
await runContext(opts);
|
|
2680
2625
|
}).helpCommand(false),
|
|
2681
2626
|
{ hidden: true }
|
|
2682
2627
|
);
|
|
2683
2628
|
memory.addCommand(
|
|
2684
2629
|
new Command4("extract").description("Extract facts from transcript (hook handler)").action(async () => {
|
|
2685
|
-
const { runExtract } = await import("./extract-
|
|
2630
|
+
const { runExtract } = await import("./extract-T32FMLN5.js");
|
|
2686
2631
|
await runExtract();
|
|
2687
2632
|
}).helpCommand(false),
|
|
2688
2633
|
{ hidden: true }
|
|
@@ -2694,11 +2639,23 @@ function createMemoryCommand() {
|
|
|
2694
2639
|
}).helpCommand(false),
|
|
2695
2640
|
{ hidden: true }
|
|
2696
2641
|
);
|
|
2642
|
+
memory.addCommand(
|
|
2643
|
+
new Command4("push").description("Push memories to GitHub Gist").option("--project <name>", "Scope to a specific project").option("-y, --yes", "Skip confirmation prompt").action(async (opts) => {
|
|
2644
|
+
const { runPush } = await import("./push-WI3ZIPZU.js");
|
|
2645
|
+
await runPush(opts);
|
|
2646
|
+
})
|
|
2647
|
+
);
|
|
2648
|
+
memory.addCommand(
|
|
2649
|
+
new Command4("pull").description("Pull memories from GitHub Gist").option("--project <name>", "Scope to a specific project").action(async (opts) => {
|
|
2650
|
+
const { runPull } = await import("./pull-4VKUDKTB.js");
|
|
2651
|
+
await runPull(opts);
|
|
2652
|
+
})
|
|
2653
|
+
);
|
|
2697
2654
|
return memory;
|
|
2698
2655
|
}
|
|
2699
2656
|
|
|
2700
2657
|
// src/cli.ts
|
|
2701
|
-
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.
|
|
2658
|
+
var program = new Command5().name("claude-launchpad").description("CLI toolkit that makes Claude Code setups measurably good").version("0.10.1-dev.0", "-v, --version").action(async () => {
|
|
2702
2659
|
const hasConfig = await fileExists(join11(process.cwd(), "CLAUDE.md")) || await fileExists(join11(process.cwd(), ".claude", "settings.json"));
|
|
2703
2660
|
if (hasConfig) {
|
|
2704
2661
|
await program.commands.find((c) => c.name() === "doctor")?.parseAsync([], { from: "user" });
|