learning-agent 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/storage/jsonl.ts","../src/storage/sqlite.ts","../src/capture/quality.ts","../src/capture/triggers.ts","../src/capture/integration.ts","../src/cli-utils.ts","../src/embeddings/model.ts","../src/index.ts","../src/storage/compact.ts","../src/cli.ts"],"names":["createHash","join","dirname","mtime","readFile","mkdir","lines","appendFile","statSync"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Lesson type definitions using Zod schemas\n */\n\nimport { createHash } from 'node:crypto';\nimport { z } from 'zod';\n\n// Source of lesson capture\nexport const SourceSchema = z.enum([\n 'user_correction',\n 'self_correction',\n 'test_failure',\n 'manual',\n]);\n\n// Context about when lesson was learned\nexport const ContextSchema = z.object({\n tool: z.string(),\n intent: z.string(),\n});\n\n// Code pattern (bad -> good)\nexport const PatternSchema = z.object({\n bad: z.string(),\n good: z.string(),\n});\n\n// Severity levels for lessons\nexport const SeveritySchema = z.enum(['high', 'medium', 'low']);\n\n// Lesson type - semantic marker for lesson quality tier\nexport const LessonTypeSchema = z.enum(['quick', 'full']);\n\n/**\n * Unified Lesson schema.\n *\n * The `type` field is a semantic marker:\n * - 'quick': Minimal lesson for fast capture\n * - 'full': Important lesson (typically has evidence/severity)\n *\n * All fields except core identity are optional for flexibility.\n * Semantic meaning is preserved through convention, not schema enforcement.\n */\nexport const LessonSchema = z.object({\n // Core identity (required)\n id: z.string(),\n type: LessonTypeSchema,\n trigger: z.string(),\n insight: z.string(),\n\n // Metadata (required)\n tags: z.array(z.string()),\n source: SourceSchema,\n context: ContextSchema,\n created: z.string(), // ISO8601\n confirmed: z.boolean(),\n\n // Relationships (required, can be empty arrays)\n supersedes: z.array(z.string()),\n related: z.array(z.string()),\n\n // Extended fields (optional - typically present for 'full' type)\n evidence: z.string().optional(),\n severity: SeveritySchema.optional(),\n pattern: PatternSchema.optional(),\n\n // Lifecycle fields (optional)\n deleted: z.boolean().optional(),\n retrievalCount: z.number().optional(),\n});\n\n// Tombstone for deletions (append-only delete marker)\nexport const TombstoneSchema = z.object({\n id: z.string(),\n deleted: z.literal(true),\n deletedAt: z.string(), // ISO8601\n});\n\n// Type exports\nexport type Lesson = z.infer<typeof LessonSchema>;\nexport type LessonType = z.infer<typeof LessonTypeSchema>;\nexport type Tombstone = z.infer<typeof TombstoneSchema>;\nexport type Source = z.infer<typeof SourceSchema>;\nexport type Severity = z.infer<typeof SeveritySchema>;\nexport type Context = z.infer<typeof ContextSchema>;\nexport type Pattern = z.infer<typeof PatternSchema>;\n\n/**\n * Generate deterministic lesson ID from insight text.\n * Format: L + 8 hex characters from SHA-256 hash\n */\nexport function generateId(insight: string): string {\n const hash = createHash('sha256').update(insight).digest('hex');\n return `L${hash.slice(0, 8)}`;\n}\n","/**\n * JSONL storage layer for lessons\n *\n * Append-only storage with last-write-wins deduplication.\n * Source of truth - git trackable.\n */\n\nimport { appendFile, mkdir, readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { LessonSchema, type Lesson } from '../types.js';\n\n/** Relative path to lessons file from repo root */\nexport const LESSONS_PATH = '.claude/lessons/index.jsonl';\n\n/** Options for reading lessons */\nexport interface ReadLessonsOptions {\n /** If true, throw on first parse error. Default: false (skip errors) */\n strict?: boolean;\n /** Callback for each parse error in non-strict mode */\n onParseError?: (error: ParseError) => void;\n}\n\n/** Parse error details */\nexport interface ParseError {\n /** 1-based line number */\n line: number;\n /** Error message */\n message: string;\n /** Original error */\n cause: unknown;\n}\n\n/** Result of reading lessons */\nexport interface ReadLessonsResult {\n /** Successfully parsed lessons */\n lessons: Lesson[];\n /** Number of lines skipped due to errors */\n skippedCount: number;\n}\n\n/**\n * Append a lesson to the JSONL file.\n * Creates directory structure if missing.\n */\nexport async function appendLesson(repoRoot: string, lesson: Lesson): Promise<void> {\n const filePath = join(repoRoot, LESSONS_PATH);\n await mkdir(dirname(filePath), { recursive: true });\n\n const line = JSON.stringify(lesson) + '\\n';\n await appendFile(filePath, line, 'utf-8');\n}\n\n/**\n * Parse and validate a single JSON line.\n * @returns Parsed lesson or null if invalid\n */\nfunction parseJsonLine(\n line: string,\n lineNumber: number,\n strict: boolean,\n onParseError?: (error: ParseError) => void\n): Lesson | null {\n // Try to parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch (err) {\n const parseError: ParseError = {\n line: lineNumber,\n message: `Invalid JSON: ${(err as Error).message}`,\n cause: err,\n };\n if (strict) {\n throw new Error(`Parse error on line ${lineNumber}: ${parseError.message}`);\n }\n onParseError?.(parseError);\n return null;\n }\n\n // Validate against schema\n const result = LessonSchema.safeParse(parsed);\n if (!result.success) {\n const parseError: ParseError = {\n line: lineNumber,\n message: `Schema validation failed: ${result.error.message}`,\n cause: result.error,\n };\n if (strict) {\n throw new Error(`Parse error on line ${lineNumber}: ${parseError.message}`);\n }\n onParseError?.(parseError);\n return null;\n }\n\n return result.data;\n}\n\n/**\n * Read all non-deleted lessons from the JSONL file.\n * Applies last-write-wins deduplication by ID.\n * Returns result object with lessons and skippedCount.\n *\n * @param repoRoot - Repository root directory\n * @param options - Optional settings for error handling\n * @returns Result with lessons array and count of skipped lines\n */\nexport async function readLessons(\n repoRoot: string,\n options: ReadLessonsOptions = {}\n): Promise<ReadLessonsResult> {\n const { strict = false, onParseError } = options;\n const filePath = join(repoRoot, LESSONS_PATH);\n\n let content: string;\n try {\n content = await readFile(filePath, 'utf-8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { lessons: [], skippedCount: 0 };\n }\n throw err;\n }\n\n const lessons = new Map<string, Lesson>();\n let skippedCount = 0;\n\n const lines = content.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (!trimmed) continue;\n\n const lesson = parseJsonLine(trimmed, i + 1, strict, onParseError);\n if (!lesson) {\n skippedCount++;\n continue;\n }\n\n if (lesson.deleted) {\n lessons.delete(lesson.id);\n } else {\n lessons.set(lesson.id, lesson);\n }\n }\n\n return { lessons: Array.from(lessons.values()), skippedCount };\n}\n","/**\n * SQLite storage layer with FTS5 for full-text search\n *\n * Rebuildable index - not the source of truth.\n * Stored in .claude/.cache (gitignored).\n */\n\nimport { createHash } from 'node:crypto';\nimport { mkdirSync, statSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport Database from 'better-sqlite3';\nimport type { Database as DatabaseType } from 'better-sqlite3';\n\nimport type { Lesson } from '../types.js';\n\nimport { LESSONS_PATH, readLessons } from './jsonl.js';\n\n/** Relative path to database file from repo root */\nexport const DB_PATH = '.claude/.cache/lessons.sqlite';\n\n/** SQL schema for lessons database */\nconst SCHEMA_SQL = `\n -- Main lessons table\n CREATE TABLE IF NOT EXISTS lessons (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n trigger TEXT NOT NULL,\n insight TEXT NOT NULL,\n evidence TEXT,\n severity TEXT,\n tags TEXT NOT NULL DEFAULT '',\n source TEXT NOT NULL,\n context TEXT NOT NULL DEFAULT '{}',\n supersedes TEXT NOT NULL DEFAULT '[]',\n related TEXT NOT NULL DEFAULT '[]',\n created TEXT NOT NULL,\n confirmed INTEGER NOT NULL DEFAULT 0,\n deleted INTEGER NOT NULL DEFAULT 0,\n retrieval_count INTEGER NOT NULL DEFAULT 0,\n last_retrieved TEXT,\n embedding BLOB,\n content_hash TEXT\n );\n\n -- FTS5 virtual table for full-text search\n CREATE VIRTUAL TABLE IF NOT EXISTS lessons_fts USING fts5(\n id,\n trigger,\n insight,\n tags,\n content='lessons',\n content_rowid='rowid'\n );\n\n -- Trigger to sync FTS on INSERT\n CREATE TRIGGER IF NOT EXISTS lessons_ai AFTER INSERT ON lessons BEGIN\n INSERT INTO lessons_fts(rowid, id, trigger, insight, tags)\n VALUES (new.rowid, new.id, new.trigger, new.insight, new.tags);\n END;\n\n -- Trigger to sync FTS on DELETE\n CREATE TRIGGER IF NOT EXISTS lessons_ad AFTER DELETE ON lessons BEGIN\n INSERT INTO lessons_fts(lessons_fts, rowid, id, trigger, insight, tags)\n VALUES ('delete', old.rowid, old.id, old.trigger, old.insight, old.tags);\n END;\n\n -- Trigger to sync FTS on UPDATE\n CREATE TRIGGER IF NOT EXISTS lessons_au AFTER UPDATE ON lessons BEGIN\n INSERT INTO lessons_fts(lessons_fts, rowid, id, trigger, insight, tags)\n VALUES ('delete', old.rowid, old.id, old.trigger, old.insight, old.tags);\n INSERT INTO lessons_fts(rowid, id, trigger, insight, tags)\n VALUES (new.rowid, new.id, new.trigger, new.insight, new.tags);\n END;\n\n -- Index for common queries\n CREATE INDEX IF NOT EXISTS idx_lessons_created ON lessons(created);\n CREATE INDEX IF NOT EXISTS idx_lessons_confirmed ON lessons(confirmed);\n CREATE INDEX IF NOT EXISTS idx_lessons_severity ON lessons(severity);\n\n -- Metadata table for sync tracking\n CREATE TABLE IF NOT EXISTS metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n`;\n\n/**\n * Create database schema for lessons storage.\n */\nfunction createSchema(database: DatabaseType): void {\n database.exec(SCHEMA_SQL);\n}\n\nlet db: DatabaseType | null = null;\n\n/**\n * Compute deterministic content hash for embedding cache validation.\n * Format: SHA-256 hex of \"trigger insight\"\n */\nexport function contentHash(trigger: string, insight: string): string {\n return createHash('sha256').update(`${trigger} ${insight}`).digest('hex');\n}\n\n/**\n * Open or create the SQLite database.\n *\n * Creates directory structure and schema if needed.\n * Returns a singleton instance - subsequent calls return the same connection.\n *\n * **Resource lifecycle:**\n * - First call creates the database file (if needed) and opens a connection\n * - Connection uses WAL mode for better concurrent access\n * - Connection remains open until `closeDb()` is called\n *\n * **Note:** Most code should not call this directly. Higher-level functions\n * like `searchKeyword` and `rebuildIndex` call it internally.\n *\n * @param repoRoot - Path to repository root (database stored at `.claude/.cache/lessons.sqlite`)\n * @returns The singleton database connection\n *\n * @see {@link closeDb} for releasing resources\n */\nexport function openDb(repoRoot: string): DatabaseType {\n if (db) return db;\n\n const dbPath = join(repoRoot, DB_PATH);\n\n // Create directory synchronously (better-sqlite3 is sync)\n const dir = dirname(dbPath);\n mkdirSync(dir, { recursive: true });\n\n db = new Database(dbPath);\n\n // Enable WAL mode for better concurrent access\n db.pragma('journal_mode = WAL');\n\n createSchema(db);\n\n return db;\n}\n\n/**\n * Close the database connection and release resources.\n *\n * **Resource lifecycle:**\n * - The database is opened lazily on first call to `openDb()` or any function that uses it\n * (e.g., `searchKeyword`, `rebuildIndex`, `syncIfNeeded`, `getCachedEmbedding`)\n * - Once opened, the connection remains active until `closeDb()` is called\n * - After closing, subsequent database operations will reopen the connection\n *\n * **When to call:**\n * - At the end of CLI commands to ensure clean process exit\n * - When transitioning between repositories in long-running processes\n * - Before process exit in graceful shutdown handlers\n *\n * **Best practices for long-running processes:**\n * - In single-operation scripts: call before exit\n * - In daemon/server processes: call in shutdown handler\n * - Not necessary to call between operations in the same repository\n *\n * @example\n * ```typescript\n * // CLI command pattern\n * try {\n * await searchKeyword(repoRoot, 'typescript', 10);\n * // ... process results\n * } finally {\n * closeDb();\n * }\n *\n * // Graceful shutdown pattern\n * process.on('SIGTERM', () => {\n * closeDb();\n * process.exit(0);\n * });\n * ```\n */\nexport function closeDb(): void {\n if (db) {\n db.close();\n db = null;\n }\n}\n\n/**\n * Get cached embedding for a lesson if content hash matches.\n * Returns null if no cache exists or hash mismatches.\n */\nexport function getCachedEmbedding(\n repoRoot: string,\n lessonId: string,\n expectedHash?: string\n): number[] | null {\n const database = openDb(repoRoot);\n const row = database\n .prepare('SELECT embedding, content_hash FROM lessons WHERE id = ?')\n .get(lessonId) as { embedding: Buffer | null; content_hash: string | null } | undefined;\n\n if (!row || !row.embedding || !row.content_hash) {\n return null;\n }\n\n // If expected hash provided, validate it matches\n if (expectedHash && row.content_hash !== expectedHash) {\n return null;\n }\n\n // Convert Buffer to Float32Array then to number[]\n const float32 = new Float32Array(\n row.embedding.buffer,\n row.embedding.byteOffset,\n row.embedding.byteLength / 4\n );\n return Array.from(float32);\n}\n\n/**\n * Cache an embedding for a lesson with content hash.\n */\nexport function setCachedEmbedding(\n repoRoot: string,\n lessonId: string,\n embedding: Float32Array | number[],\n hash: string\n): void {\n const database = openDb(repoRoot);\n\n // Convert to Buffer for storage\n const float32 = embedding instanceof Float32Array ? embedding : new Float32Array(embedding);\n const buffer = Buffer.from(float32.buffer, float32.byteOffset, float32.byteLength);\n\n database\n .prepare('UPDATE lessons SET embedding = ?, content_hash = ? WHERE id = ?')\n .run(buffer, hash, lessonId);\n}\n\n/** DB row type for lessons table */\ninterface LessonRow {\n id: string;\n type: string;\n trigger: string;\n insight: string;\n evidence: string | null;\n severity: string | null;\n tags: string;\n source: string;\n context: string;\n supersedes: string;\n related: string;\n created: string;\n confirmed: number;\n deleted: number;\n retrieval_count: number;\n last_retrieved: string | null;\n embedding: Buffer | null;\n}\n\n/**\n * Convert a database row to a typed Lesson object.\n * Maps NULL to undefined for optional fields (lossless roundtrip).\n */\nfunction rowToLesson(row: LessonRow): Lesson {\n const lesson: Lesson = {\n id: row.id,\n type: row.type as 'quick' | 'full',\n trigger: row.trigger,\n insight: row.insight,\n tags: row.tags ? row.tags.split(',').filter(Boolean) : [],\n source: row.source as Lesson['source'],\n context: JSON.parse(row.context) as Lesson['context'],\n supersedes: JSON.parse(row.supersedes) as string[],\n related: JSON.parse(row.related) as string[],\n created: row.created,\n confirmed: row.confirmed === 1,\n };\n\n // Optional fields: map NULL -> undefined (lossless roundtrip)\n if (row.evidence !== null) {\n lesson.evidence = row.evidence;\n }\n if (row.severity !== null) {\n lesson.severity = row.severity as 'high' | 'medium' | 'low';\n }\n if (row.deleted === 1) {\n lesson.deleted = true;\n }\n if (row.retrieval_count > 0) {\n lesson.retrievalCount = row.retrieval_count;\n }\n\n return lesson;\n}\n\n/** Cached embedding with its content hash */\ninterface CachedEmbeddingData {\n embedding: Buffer;\n contentHash: string;\n}\n\n/**\n * Collect cached embeddings from existing lessons for preservation.\n */\nfunction collectCachedEmbeddings(database: DatabaseType): Map<string, CachedEmbeddingData> {\n const cache = new Map<string, CachedEmbeddingData>();\n const rows = database\n .prepare('SELECT id, embedding, content_hash FROM lessons WHERE embedding IS NOT NULL')\n .all() as Array<{ id: string; embedding: Buffer; content_hash: string | null }>;\n\n for (const row of rows) {\n if (row.embedding && row.content_hash) {\n cache.set(row.id, { embedding: row.embedding, contentHash: row.content_hash });\n }\n }\n return cache;\n}\n\n/** SQL for inserting a lesson row */\nconst INSERT_LESSON_SQL = `\n INSERT INTO lessons (id, type, trigger, insight, evidence, severity, tags, source, context, supersedes, related, created, confirmed, deleted, retrieval_count, last_retrieved, embedding, content_hash)\n VALUES (@id, @type, @trigger, @insight, @evidence, @severity, @tags, @source, @context, @supersedes, @related, @created, @confirmed, @deleted, @retrieval_count, @last_retrieved, @embedding, @content_hash)\n`;\n\n/**\n * Get the mtime of the JSONL file, or null if it doesn't exist.\n */\nfunction getJsonlMtime(repoRoot: string): number | null {\n const jsonlPath = join(repoRoot, LESSONS_PATH);\n try {\n const stat = statSync(jsonlPath);\n return stat.mtimeMs;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the last synced mtime from metadata table.\n */\nfunction getLastSyncMtime(database: DatabaseType): number | null {\n const row = database\n .prepare('SELECT value FROM metadata WHERE key = ?')\n .get('last_sync_mtime') as { value: string } | undefined;\n return row ? parseFloat(row.value) : null;\n}\n\n/**\n * Store the last synced mtime in metadata table.\n */\nfunction setLastSyncMtime(database: DatabaseType, mtime: number): void {\n database\n .prepare('INSERT OR REPLACE INTO metadata (key, value) VALUES (?, ?)')\n .run('last_sync_mtime', mtime.toString());\n}\n\n/**\n * Rebuild the SQLite index from the JSONL source of truth.\n * Preserves embeddings where content hash is unchanged.\n * Updates the last sync mtime after successful rebuild.\n */\nexport async function rebuildIndex(repoRoot: string): Promise<void> {\n const database = openDb(repoRoot);\n const { lessons } = await readLessons(repoRoot);\n\n const cachedEmbeddings = collectCachedEmbeddings(database);\n database.exec('DELETE FROM lessons');\n\n if (lessons.length === 0) {\n // Still update mtime even for empty file\n const mtime = getJsonlMtime(repoRoot);\n if (mtime !== null) {\n setLastSyncMtime(database, mtime);\n }\n return;\n }\n\n const insert = database.prepare(INSERT_LESSON_SQL);\n const insertMany = database.transaction((items: Lesson[]) => {\n for (const lesson of items) {\n const newHash = contentHash(lesson.trigger, lesson.insight);\n const cached = cachedEmbeddings.get(lesson.id);\n const hasValidCache = cached && cached.contentHash === newHash;\n\n insert.run({\n id: lesson.id,\n type: lesson.type,\n trigger: lesson.trigger,\n insight: lesson.insight,\n evidence: lesson.evidence ?? null,\n severity: lesson.severity ?? null,\n tags: lesson.tags.join(','),\n source: lesson.source,\n context: JSON.stringify(lesson.context),\n supersedes: JSON.stringify(lesson.supersedes),\n related: JSON.stringify(lesson.related),\n created: lesson.created,\n confirmed: lesson.confirmed ? 1 : 0,\n deleted: lesson.deleted ? 1 : 0,\n retrieval_count: lesson.retrievalCount ?? 0,\n last_retrieved: null, // Reset on rebuild since we're rebuilding from source\n embedding: hasValidCache ? cached.embedding : null,\n content_hash: hasValidCache ? cached.contentHash : null,\n });\n }\n });\n\n insertMany(lessons);\n\n // Update last sync mtime\n const mtime = getJsonlMtime(repoRoot);\n if (mtime !== null) {\n setLastSyncMtime(database, mtime);\n }\n}\n\n/** Options for syncIfNeeded */\nexport interface SyncOptions {\n /** Force rebuild even if JSONL unchanged */\n force?: boolean;\n}\n\n/**\n * Sync the index if JSONL has changed since last sync.\n * Returns true if a rebuild was performed, false if skipped.\n */\nexport async function syncIfNeeded(\n repoRoot: string,\n options: SyncOptions = {}\n): Promise<boolean> {\n const { force = false } = options;\n\n // Check JSONL mtime\n const jsonlMtime = getJsonlMtime(repoRoot);\n if (jsonlMtime === null && !force) {\n // No JSONL file exists\n return false;\n }\n\n const database = openDb(repoRoot);\n const lastSyncMtime = getLastSyncMtime(database);\n\n // Rebuild if forced, no previous sync, or JSONL is newer\n const needsRebuild = force || lastSyncMtime === null || (jsonlMtime !== null && jsonlMtime > lastSyncMtime);\n\n if (needsRebuild) {\n await rebuildIndex(repoRoot);\n return true;\n }\n\n return false;\n}\n\n/**\n * Search lessons using FTS5 keyword search.\n * Returns matching lessons up to the specified limit.\n * Increments retrieval count for all returned lessons.\n */\nexport async function searchKeyword(\n repoRoot: string,\n query: string,\n limit: number\n): Promise<Lesson[]> {\n const database = openDb(repoRoot);\n\n // Check if there are any lessons\n const countResult = database.prepare('SELECT COUNT(*) as cnt FROM lessons').get() as {\n cnt: number;\n };\n if (countResult.cnt === 0) return [];\n\n // Use FTS5 MATCH for search\n const rows = database\n .prepare(\n `\n SELECT l.*\n FROM lessons l\n JOIN lessons_fts fts ON l.rowid = fts.rowid\n WHERE lessons_fts MATCH ?\n LIMIT ?\n `\n )\n .all(query, limit) as LessonRow[];\n\n // Increment retrieval count for matched lessons\n if (rows.length > 0) {\n incrementRetrievalCount(repoRoot, rows.map((r) => r.id));\n }\n\n return rows.map(rowToLesson);\n}\n\n/** Retrieval statistics for a lesson */\nexport interface RetrievalStat {\n id: string;\n count: number;\n lastRetrieved: string | null;\n}\n\n/**\n * Increment retrieval count for a list of lesson IDs.\n * Updates both count and last_retrieved timestamp.\n * Non-existent IDs are silently ignored.\n */\nexport function incrementRetrievalCount(repoRoot: string, lessonIds: string[]): void {\n if (lessonIds.length === 0) return;\n\n const database = openDb(repoRoot);\n const now = new Date().toISOString();\n\n const update = database.prepare(`\n UPDATE lessons\n SET retrieval_count = retrieval_count + 1,\n last_retrieved = ?\n WHERE id = ?\n `);\n\n const updateMany = database.transaction((ids: string[]) => {\n for (const id of ids) {\n update.run(now, id);\n }\n });\n\n updateMany(lessonIds);\n}\n\n/**\n * Get retrieval statistics for all lessons.\n * Returns id, retrieval count, and last retrieved timestamp for each lesson.\n */\nexport function getRetrievalStats(repoRoot: string): RetrievalStat[] {\n const database = openDb(repoRoot);\n\n const rows = database\n .prepare('SELECT id, retrieval_count, last_retrieved FROM lessons')\n .all() as Array<{ id: string; retrieval_count: number; last_retrieved: string | null }>;\n\n return rows.map((row) => ({\n id: row.id,\n count: row.retrieval_count,\n lastRetrieved: row.last_retrieved,\n }));\n}\n","/**\n * Quality filters for lesson capture\n *\n * Filters to ensure lessons are:\n * - Novel (not duplicate)\n * - Specific (not vague)\n * - Actionable (contains action words)\n */\n\nimport { searchKeyword, syncIfNeeded } from '../storage/sqlite.js';\n\n/** Default similarity threshold for duplicate detection */\nconst DEFAULT_SIMILARITY_THRESHOLD = 0.8;\n\n/** Result of novelty check */\nexport interface NoveltyResult {\n novel: boolean;\n reason?: string;\n existingId?: string;\n}\n\n/** Options for novelty check */\nexport interface NoveltyOptions {\n threshold?: number;\n}\n\n/**\n * Check if an insight is novel (not a duplicate of existing lessons).\n * Uses keyword search to find potentially similar lessons.\n */\nexport async function isNovel(\n repoRoot: string,\n insight: string,\n options: NoveltyOptions = {}\n): Promise<NoveltyResult> {\n const threshold = options.threshold ?? DEFAULT_SIMILARITY_THRESHOLD;\n\n // Sync index if JSONL has changed\n await syncIfNeeded(repoRoot);\n\n // Extract key words for search (take first 3 significant words)\n const words = insight\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, '')\n .split(/\\s+/)\n .filter((w) => w.length > 3)\n .slice(0, 3);\n\n if (words.length === 0) {\n return { novel: true };\n }\n\n // Search for each word and collect results\n const searchQuery = words.join(' OR ');\n const results = await searchKeyword(repoRoot, searchQuery, 10);\n\n if (results.length === 0) {\n return { novel: true };\n }\n\n // Check similarity using simple word overlap (since we may not have embeddings)\n const insightWords = new Set(insight.toLowerCase().split(/\\s+/));\n\n for (const lesson of results) {\n const lessonWords = new Set(lesson.insight.toLowerCase().split(/\\s+/));\n\n // Calculate Jaccard similarity\n const intersection = [...insightWords].filter((w) => lessonWords.has(w)).length;\n const union = new Set([...insightWords, ...lessonWords]).size;\n const similarity = union > 0 ? intersection / union : 0;\n\n if (similarity >= threshold) {\n return {\n novel: false,\n reason: `Found similar existing lesson: \"${lesson.insight.slice(0, 50)}...\"`,\n existingId: lesson.id,\n };\n }\n\n // Also check exact match\n if (lesson.insight.toLowerCase() === insight.toLowerCase()) {\n return {\n novel: false,\n reason: `Exact duplicate found`,\n existingId: lesson.id,\n };\n }\n }\n\n return { novel: true };\n}\n\n/** Minimum word count for a specific insight */\nconst MIN_WORD_COUNT = 4;\n\n/** Vague patterns that indicate non-specific advice */\nconst VAGUE_PATTERNS = [\n /\\bwrite better\\b/i,\n /\\bbe careful\\b/i,\n /\\bremember to\\b/i,\n /\\bmake sure\\b/i,\n /\\btry to\\b/i,\n /\\bdouble check\\b/i,\n];\n\n/** Generic \"always/never\" phrases (short, lacking specificity) */\nconst GENERIC_IMPERATIVE_PATTERN = /^(always|never)\\s+\\w+(\\s+\\w+){0,2}$/i;\n\n/** Result of specificity check */\nexport interface SpecificityResult {\n specific: boolean;\n reason?: string;\n}\n\n/**\n * Check if an insight is specific enough to be useful.\n * Rejects vague, generic advice that doesn't provide actionable guidance.\n */\nexport function isSpecific(insight: string): SpecificityResult {\n // Check minimum length first\n const words = insight.trim().split(/\\s+/).filter((w) => w.length > 0);\n if (words.length < MIN_WORD_COUNT) {\n return { specific: false, reason: 'Insight is too short to be actionable' };\n }\n\n // Check for vague patterns\n for (const pattern of VAGUE_PATTERNS) {\n if (pattern.test(insight)) {\n return { specific: false, reason: 'Insight matches a vague pattern' };\n }\n }\n\n // Check for generic \"Always X\" or \"Never X\" phrases\n if (GENERIC_IMPERATIVE_PATTERN.test(insight)) {\n return { specific: false, reason: 'Insight matches a vague pattern' };\n }\n\n return { specific: true };\n}\n\n/** Action word patterns that indicate actionable guidance */\nconst ACTION_PATTERNS = [\n /\\buse\\s+.+\\s+instead\\s+of\\b/i, // \"use X instead of Y\"\n /\\bprefer\\s+.+\\s+(over|to)\\b/i, // \"prefer X over Y\" or \"prefer X to Y\"\n /\\balways\\s+.+\\s+when\\b/i, // \"always X when Y\"\n /\\bnever\\s+.+\\s+without\\b/i, // \"never X without Y\"\n /\\bavoid\\s+(using\\s+)?\\w+/i, // \"avoid X\" or \"avoid using X\"\n /\\bcheck\\s+.+\\s+before\\b/i, // \"check X before Y\"\n /^(run|use|add|remove|install|update|configure|set|enable|disable)\\s+/i, // Imperative commands at start\n];\n\n/** Result of actionability check */\nexport interface ActionabilityResult {\n actionable: boolean;\n reason?: string;\n}\n\n/**\n * Check if an insight contains actionable guidance.\n * Returns false for pure observations or questions.\n */\nexport function isActionable(insight: string): ActionabilityResult {\n // Check for action patterns\n for (const pattern of ACTION_PATTERNS) {\n if (pattern.test(insight)) {\n return { actionable: true };\n }\n }\n\n return { actionable: false, reason: 'Insight lacks clear action guidance' };\n}\n\n/** Result of combined quality check */\nexport interface ProposeResult {\n shouldPropose: boolean;\n reason?: string;\n}\n\n/**\n * Combined quality check for lesson proposals.\n * Returns true only if insight is novel, specific, AND actionable.\n */\nexport async function shouldPropose(\n repoRoot: string,\n insight: string\n): Promise<ProposeResult> {\n // Check specificity first (fast, no DB)\n const specificResult = isSpecific(insight);\n if (!specificResult.specific) {\n return { shouldPropose: false, reason: specificResult.reason };\n }\n\n // Check actionability (fast, no DB)\n const actionableResult = isActionable(insight);\n if (!actionableResult.actionable) {\n return { shouldPropose: false, reason: actionableResult.reason };\n }\n\n // Check novelty (requires DB lookup)\n const noveltyResult = await isNovel(repoRoot, insight);\n if (!noveltyResult.novel) {\n return { shouldPropose: false, reason: noveltyResult.reason };\n }\n\n return { shouldPropose: true };\n}\n","/**\n * Trigger detection for automatic lesson capture\n *\n * Detects patterns that indicate potential learning opportunities:\n * - User corrections\n * - Self-corrections\n * - Test failures\n */\n\nimport type { Context } from '../types.js';\n\n/** Signal data for correction detection */\nexport interface CorrectionSignal {\n messages: string[];\n context: Context;\n}\n\n/** Detected correction result */\nexport interface DetectedCorrection {\n trigger: string;\n correctionMessage: string;\n context: Context;\n}\n\n/** User correction patterns */\nconst USER_CORRECTION_PATTERNS = [\n /\\bno\\b[,.]?\\s/i, // \"no, ...\" or \"no ...\"\n /\\bwrong\\b/i, // \"wrong\"\n /\\bactually\\b/i, // \"actually...\"\n /\\bnot that\\b/i, // \"not that\"\n /\\bi meant\\b/i, // \"I meant\"\n];\n\n/**\n * Detect user correction signals in conversation.\n *\n * Looks for patterns that indicate the user is correcting Claude's\n * understanding or actions.\n *\n * @param signals - Messages and context to analyze\n * @returns Detected correction or null if none found\n */\nexport function detectUserCorrection(signals: CorrectionSignal): DetectedCorrection | null {\n const { messages, context } = signals;\n\n if (messages.length < 2) {\n return null;\n }\n\n // Check later messages for correction patterns\n for (let i = 1; i < messages.length; i++) {\n const message = messages[i];\n if (!message) continue;\n\n for (const pattern of USER_CORRECTION_PATTERNS) {\n if (pattern.test(message)) {\n return {\n trigger: `User correction during ${context.intent}`,\n correctionMessage: message,\n context,\n };\n }\n }\n }\n\n return null;\n}\n\n/** Edit history entry */\nexport interface EditEntry {\n file: string;\n success: boolean;\n timestamp: number;\n}\n\n/** Edit history for self-correction detection */\nexport interface EditHistory {\n edits: EditEntry[];\n}\n\n/** Detected self-correction */\nexport interface DetectedSelfCorrection {\n file: string;\n trigger: string;\n}\n\n/**\n * Detect self-correction patterns in edit history.\n *\n * Looks for edit→fail→re-edit patterns on the same file,\n * which indicate Claude had to correct its own work.\n *\n * @param history - Edit history to analyze\n * @returns Detected self-correction or null if none found\n */\nexport function detectSelfCorrection(history: EditHistory): DetectedSelfCorrection | null {\n const { edits } = history;\n\n if (edits.length < 3) {\n return null;\n }\n\n // Look for edit→fail→re-edit pattern on same file\n for (let i = 0; i <= edits.length - 3; i++) {\n const first = edits[i];\n const second = edits[i + 1];\n const third = edits[i + 2];\n\n if (!first || !second || !third) continue;\n\n // Pattern: success → fail → success on same file\n if (\n first.file === second.file &&\n second.file === third.file &&\n first.success &&\n !second.success &&\n third.success\n ) {\n return {\n file: first.file,\n trigger: `Self-correction on ${first.file}`,\n };\n }\n }\n\n return null;\n}\n\n/** Test result for failure detection */\nexport interface TestResult {\n passed: boolean;\n output: string;\n testFile: string;\n}\n\n/** Detected test failure */\nexport interface DetectedTestFailure {\n testFile: string;\n errorOutput: string;\n trigger: string;\n}\n\n/**\n * Detect test failure patterns.\n *\n * When tests fail, this creates a potential learning opportunity\n * if the failure is later fixed.\n *\n * @param testResult - Test result to analyze\n * @returns Detected test failure or null if tests passed\n */\nexport function detectTestFailure(testResult: TestResult): DetectedTestFailure | null {\n if (testResult.passed) {\n return null;\n }\n\n // Extract first meaningful error line for trigger\n const lines = testResult.output.split('\\n').filter((line) => line.trim().length > 0);\n const errorLine = lines.find((line) => /error|fail|assert/i.test(line)) ?? lines[0] ?? '';\n\n return {\n testFile: testResult.testFile,\n errorOutput: testResult.output,\n trigger: `Test failure in ${testResult.testFile}: ${errorLine.slice(0, 100)}`,\n };\n}\n","/**\n * Trigger detection integration\n *\n * Orchestrates detection -> quality filter -> lesson proposal flow.\n * Provides a high-level API for CLI and hooks.\n */\n\nimport * as fs from 'node:fs/promises';\n\nimport type { Source } from '../types.js';\nimport { shouldPropose } from './quality.js';\nimport {\n detectUserCorrection,\n detectSelfCorrection,\n detectTestFailure,\n} from './triggers.js';\nimport type {\n CorrectionSignal,\n EditHistory,\n TestResult,\n} from './triggers.js';\n\n/** Detection input types */\nexport type DetectionType = 'user' | 'self' | 'test';\n\n/** Input for user correction detection */\nexport interface UserDetectionInput {\n type: 'user';\n data: CorrectionSignal;\n}\n\n/** Input for self correction detection */\nexport interface SelfDetectionInput {\n type: 'self';\n data: EditHistory;\n}\n\n/** Input for test failure detection */\nexport interface TestDetectionInput {\n type: 'test';\n data: TestResult;\n}\n\n/** Union type for all detection inputs */\nexport type DetectionInput = UserDetectionInput | SelfDetectionInput | TestDetectionInput;\n\n/** Result of successful detection */\nexport interface DetectionResult {\n trigger: string;\n source: Source;\n proposedInsight: string;\n}\n\n/**\n * Detect triggers and propose lessons.\n *\n * Runs the appropriate detector based on input type, then filters\n * through quality checks. Returns a proposal if detection passes\n * all quality filters.\n *\n * @param repoRoot - Repository root path\n * @param input - Detection input with type and data\n * @returns Detection result with proposed insight, or null\n */\nexport async function detectAndPropose(\n repoRoot: string,\n input: DetectionInput\n): Promise<DetectionResult | null> {\n const detected = runDetector(input);\n if (!detected) {\n return null;\n }\n\n const { trigger, source, proposedInsight } = detected;\n\n // Run quality filters on proposed insight\n const quality = await shouldPropose(repoRoot, proposedInsight);\n if (!quality.shouldPropose) {\n return null;\n }\n\n return { trigger, source, proposedInsight };\n}\n\n/** Internal detection result before quality filtering */\ninterface RawDetection {\n trigger: string;\n source: Source;\n proposedInsight: string;\n}\n\n/**\n * Run the appropriate detector based on input type.\n */\nfunction runDetector(input: DetectionInput): RawDetection | null {\n switch (input.type) {\n case 'user':\n return detectUserCorrectionFlow(input.data);\n case 'self':\n return detectSelfCorrectionFlow(input.data);\n case 'test':\n return detectTestFailureFlow(input.data);\n }\n}\n\n/**\n * Detect user correction and extract insight.\n */\nfunction detectUserCorrectionFlow(data: CorrectionSignal): RawDetection | null {\n const result = detectUserCorrection(data);\n if (!result) {\n return null;\n }\n\n return {\n trigger: result.trigger,\n source: 'user_correction',\n proposedInsight: result.correctionMessage,\n };\n}\n\n/**\n * Detect self correction and extract insight.\n */\nfunction detectSelfCorrectionFlow(data: EditHistory): RawDetection | null {\n const result = detectSelfCorrection(data);\n if (!result) {\n return null;\n }\n\n return {\n trigger: result.trigger,\n source: 'self_correction',\n // Self-corrections need context to form useful insights\n proposedInsight: `Check ${result.file} for common errors before editing`,\n };\n}\n\n/**\n * Detect test failure and extract insight.\n */\nfunction detectTestFailureFlow(data: TestResult): RawDetection | null {\n const result = detectTestFailure(data);\n if (!result) {\n return null;\n }\n\n return {\n trigger: result.trigger,\n source: 'test_failure',\n proposedInsight: result.errorOutput,\n };\n}\n\n/** Valid detection types for validation */\nconst VALID_TYPES = new Set<string>(['user', 'self', 'test']);\n\n/**\n * Parse detection input from a JSON file.\n *\n * @param filePath - Path to JSON input file\n * @returns Parsed detection input\n * @throws Error if file is invalid or type is unknown\n */\nexport async function parseInputFile(filePath: string): Promise<DetectionInput> {\n const content = await fs.readFile(filePath, 'utf-8');\n const data = JSON.parse(content) as { type: string; data: unknown };\n\n if (!VALID_TYPES.has(data.type)) {\n throw new Error(`Invalid detection type: ${data.type}. Must be one of: user, self, test`);\n }\n\n return data as DetectionInput;\n}\n","/**\n * CLI utility functions.\n *\n * Pure functions extracted from cli.ts for testability.\n */\n\n/**\n * Format bytes to human-readable string.\n *\n * @param bytes - Number of bytes\n * @returns Formatted string (e.g., \"1.5 KB\", \"2.0 MB\")\n */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n if (bytes < 1024) return `${bytes} B`;\n const kb = bytes / 1024;\n if (kb < 1024) return `${kb.toFixed(1)} KB`;\n const mb = kb / 1024;\n return `${mb.toFixed(1)} MB`;\n}\n\n/**\n * Parse limit option and validate it's a positive integer.\n *\n * @param value - String value from command option\n * @param name - Option name for error message\n * @returns Parsed integer\n * @throws Error if value is not a valid positive integer\n */\nexport function parseLimit(value: string, name: string): number {\n const parsed = parseInt(value, 10);\n if (Number.isNaN(parsed) || parsed <= 0) {\n throw new Error(`Invalid ${name}: must be a positive integer`);\n }\n return parsed;\n}\n\n/**\n * Get repository root from environment variable or current directory.\n *\n * @returns Repository root path for lesson storage\n */\nexport function getRepoRoot(): string {\n return process.env['LEARNING_AGENT_ROOT'] ?? process.cwd();\n}\n","/**\n * Embedding model resolution using node-llama-cpp's built-in resolver.\n *\n * Uses resolveModelFile for automatic download and caching.\n * Model is stored in ~/.node-llama-cpp/models/ by default.\n */\n\nimport { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { resolveModelFile } from 'node-llama-cpp';\n\n/**\n * HuggingFace URI for EmbeddingGemma-300M (Q4_0 quantization).\n *\n * - Size: ~278MB\n * - Dimensions: 768 (default), supports MRL truncation to 512/256/128\n * - Context: 2048 tokens\n */\nexport const MODEL_URI = 'hf:ggml-org/embeddinggemma-300M-qat-q4_0-GGUF/embeddinggemma-300M-qat-Q4_0.gguf';\n\n/**\n * Expected model filename after download.\n * node-llama-cpp uses format: hf_{org}_{filename}\n */\nexport const MODEL_FILENAME = 'hf_ggml-org_embeddinggemma-300M-qat-Q4_0.gguf';\n\n/** Default model directory used by node-llama-cpp */\nconst DEFAULT_MODEL_DIR = join(homedir(), '.node-llama-cpp', 'models');\n\n/**\n * Check if the embedding model is available locally.\n *\n * @returns true if model file exists\n */\nexport function isModelAvailable(): boolean {\n return existsSync(join(DEFAULT_MODEL_DIR, MODEL_FILENAME));\n}\n\n/**\n * Resolve the embedding model path, downloading if necessary.\n *\n * Uses node-llama-cpp's resolveModelFile for automatic download with progress.\n *\n * @param options - Optional configuration\n * @param options.cli - Show download progress in console (default: true)\n * @returns Path to the resolved model file\n *\n * @example\n * ```typescript\n * const modelPath = await resolveModel();\n * const llama = await getLlama();\n * const model = await llama.loadModel({ modelPath });\n * ```\n */\nexport async function resolveModel(options: { cli?: boolean } = {}): Promise<string> {\n const { cli = true } = options;\n return resolveModelFile(MODEL_URI, { cli });\n}\n","/**\n * Learning Agent - Repository-scoped learning system for Claude Code\n *\n * This package helps Claude Code learn from mistakes and avoid repeating them.\n * It captures lessons during coding sessions and retrieves relevant lessons\n * when planning new work.\n *\n * ## Quick Start\n *\n * ```typescript\n * import { appendLesson, retrieveForPlan, loadSessionLessons } from 'learning-agent';\n *\n * // At session start, load high-severity lessons\n * const criticalLessons = await loadSessionLessons(repoRoot);\n *\n * // When planning, retrieve relevant lessons\n * const { lessons, message } = await retrieveForPlan(repoRoot, planText);\n *\n * // When capturing a lesson\n * await appendLesson(repoRoot, lesson);\n * ```\n *\n * ## Hook Integration\n *\n * Add to your `.claude/settings.json`:\n *\n * ```json\n * {\n * \"hooks\": {\n * \"session_start\": \"npx learning-agent load-session\",\n * \"pre_tool\": \"npx learning-agent check-plan\"\n * }\n * }\n * ```\n *\n * ## Resource Management\n *\n * This library manages two heavyweight resources that require cleanup:\n *\n * ### SQLite Database\n * - **Acquired:** Lazily on first database operation (search, rebuild, etc.)\n * - **Memory:** Minimal (~few KB for connection, index cached by OS)\n * - **Cleanup:** Call `closeDb()` before process exit\n *\n * ### Embedding Model\n * - **Acquired:** Lazily on first embedding call (embedText, embedTexts, searchVector)\n * - **Memory:** ~150MB RAM for the EmbeddingGemma model\n * - **Cleanup:** Call `unloadEmbedding()` before process exit\n *\n * ### Recommended Cleanup Pattern\n *\n * ```typescript\n * import { closeDb, unloadEmbedding } from 'learning-agent';\n *\n * // For CLI commands - use try/finally\n * async function main() {\n * try {\n * // ... your code that uses learning-agent\n * } finally {\n * unloadEmbedding();\n * closeDb();\n * }\n * }\n *\n * // For long-running processes - use shutdown handlers\n * process.on('SIGTERM', () => {\n * unloadEmbedding();\n * closeDb();\n * process.exit(0);\n * });\n * process.on('SIGINT', () => {\n * unloadEmbedding();\n * closeDb();\n * process.exit(0);\n * });\n * ```\n *\n * **Note:** Failing to clean up will not corrupt data, but may cause:\n * - Memory leaks in long-running processes\n * - Unclean process exits (warnings in some environments)\n *\n * @see {@link closeDb} for database cleanup\n * @see {@link unloadEmbedding} for embedding model cleanup\n * @module learning-agent\n */\n\nexport const VERSION = '0.1.0';\n\n// Storage API\nexport { appendLesson, readLessons, LESSONS_PATH } from './storage/jsonl.js';\nexport type { ReadLessonsOptions, ReadLessonsResult, ParseError } from './storage/jsonl.js';\nexport { rebuildIndex, searchKeyword, closeDb, DB_PATH } from './storage/sqlite.js';\n\n// Embeddings API\nexport { embedText, embedTexts, getEmbedding, isModelAvailable, unloadEmbedding } from './embeddings/nomic.js';\nexport { MODEL_FILENAME, MODEL_URI, resolveModel } from './embeddings/model.js';\n\n// Search API\nexport { searchVector, cosineSimilarity } from './search/vector.js';\nexport type { ScoredLesson, SearchVectorOptions } from './search/vector.js';\nexport { rankLessons, calculateScore, severityBoost, recencyBoost, confirmationBoost } from './search/ranking.js';\nexport type { RankedLesson } from './search/ranking.js';\n\n// Capture API - Quality filters\nexport { shouldPropose, isNovel, isSpecific, isActionable } from './capture/quality.js';\nexport type { NoveltyResult, NoveltyOptions, SpecificityResult, ActionabilityResult, ProposeResult } from './capture/quality.js';\n\n// Capture API - Triggers\nexport { detectUserCorrection, detectSelfCorrection, detectTestFailure } from './capture/triggers.js';\nexport type {\n CorrectionSignal,\n DetectedCorrection,\n EditHistory,\n EditEntry,\n DetectedSelfCorrection,\n TestResult,\n DetectedTestFailure,\n} from './capture/triggers.js';\n\n// Retrieval API\nexport { loadSessionLessons } from './retrieval/session.js';\nexport { retrieveForPlan, formatLessonsCheck } from './retrieval/plan.js';\nexport type { PlanRetrievalResult } from './retrieval/plan.js';\n\n// Types and schemas\nexport {\n generateId,\n LessonSchema,\n LessonTypeSchema,\n TombstoneSchema,\n} from './types.js';\nexport type {\n Lesson,\n LessonType,\n Tombstone,\n Source,\n Severity,\n Context,\n} from './types.js';\n","/**\n * Compaction and auto-archive for lessons\n *\n * Handles:\n * - Archiving old lessons (>90 days with 0 retrievals)\n * - Removing tombstones through JSONL rewrite\n * - Tracking compaction thresholds\n */\n\nimport { appendFile, mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\nimport type { Lesson } from '../types.js';\n\nimport { LESSONS_PATH, readLessons } from './jsonl.js';\n\n/** Relative path to archive directory from repo root */\nexport const ARCHIVE_DIR = '.claude/lessons/archive';\n\n/** Number of tombstones that triggers automatic compaction */\nexport const TOMBSTONE_THRESHOLD = 100;\n\n/** Age threshold for archiving (in days) */\nexport const ARCHIVE_AGE_DAYS = 90;\n\n/** Milliseconds per day for time calculations */\nconst MS_PER_DAY = 1000 * 60 * 60 * 24;\n\n/** Month offset for JavaScript's 0-indexed months */\nconst MONTH_INDEX_OFFSET = 1;\n\n/** Padding length for month in archive filename (e.g., \"01\" not \"1\") */\nconst MONTH_PAD_LENGTH = 2;\n\n/**\n * Result of a compaction operation\n */\nexport interface CompactResult {\n /** Number of lessons moved to archive */\n archived: number;\n /** Number of tombstones removed */\n tombstonesRemoved: number;\n /** Number of lessons remaining in index.jsonl */\n lessonsRemaining: number;\n}\n\n/**\n * Generate archive file path for a given date.\n * Format: .claude/lessons/archive/YYYY-MM.jsonl\n */\nexport function getArchivePath(repoRoot: string, date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + MONTH_INDEX_OFFSET).padStart(MONTH_PAD_LENGTH, '0');\n return join(repoRoot, ARCHIVE_DIR, `${year}-${month}.jsonl`);\n}\n\n/**\n * Parse raw JSONL lines from the lessons file.\n * Returns all lines (including invalid ones) as parsed objects or null.\n */\nasync function parseRawJsonlLines(\n repoRoot: string\n): Promise<Array<{ line: string; parsed: Record<string, unknown> | null }>> {\n const filePath = join(repoRoot, LESSONS_PATH);\n let content: string;\n try {\n content = await readFile(filePath, 'utf-8');\n } catch {\n return [];\n }\n\n const results: Array<{ line: string; parsed: Record<string, unknown> | null }> = [];\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n try {\n const parsed = JSON.parse(trimmed) as Record<string, unknown>;\n results.push({ line: trimmed, parsed });\n } catch {\n results.push({ line: trimmed, parsed: null });\n }\n }\n return results;\n}\n\n/**\n * Count the number of tombstones (deleted: true records) in the JSONL file.\n */\nexport async function countTombstones(repoRoot: string): Promise<number> {\n const lines = await parseRawJsonlLines(repoRoot);\n let count = 0;\n for (const { parsed } of lines) {\n if (parsed && parsed['deleted'] === true) {\n count++;\n }\n }\n return count;\n}\n\n/**\n * Check if compaction is needed based on tombstone count.\n */\nexport async function needsCompaction(repoRoot: string): Promise<boolean> {\n const count = await countTombstones(repoRoot);\n return count >= TOMBSTONE_THRESHOLD;\n}\n\n/**\n * Rewrite the JSONL file without tombstones.\n * Applies last-write-wins deduplication.\n */\nexport async function rewriteWithoutTombstones(repoRoot: string): Promise<number> {\n const filePath = join(repoRoot, LESSONS_PATH);\n const tempPath = filePath + '.tmp';\n\n // Read deduplicated lessons (already handles last-write-wins)\n const { lessons } = await readLessons(repoRoot);\n\n // Count tombstones before rewrite\n const tombstoneCount = await countTombstones(repoRoot);\n\n // Ensure directory exists\n await mkdir(dirname(filePath), { recursive: true });\n\n // Write clean lessons to temp file\n const lines = lessons.map((lesson) => JSON.stringify(lesson) + '\\n');\n await writeFile(tempPath, lines.join(''), 'utf-8');\n\n // Atomic rename\n await rename(tempPath, filePath);\n\n return tombstoneCount;\n}\n\n/**\n * Determine if a lesson should be archived based on age and retrieval count.\n * Lessons are archived if older than ARCHIVE_AGE_DAYS and never retrieved.\n *\n * @param lesson - The lesson to evaluate\n * @param now - Current date for age calculation\n * @returns true if lesson should be archived\n */\nfunction shouldArchive(lesson: Lesson, now: Date): boolean {\n const created = new Date(lesson.created);\n const ageMs = now.getTime() - created.getTime();\n const ageDays = ageMs / MS_PER_DAY;\n\n // Archive if: older than threshold AND never retrieved\n return ageDays > ARCHIVE_AGE_DAYS && (lesson.retrievalCount === undefined || lesson.retrievalCount === 0);\n}\n\n/**\n * Archive old lessons that haven't been retrieved.\n * Moves lessons >90 days old with 0 retrievals to archive files.\n * Returns the number of lessons archived.\n */\nexport async function archiveOldLessons(repoRoot: string): Promise<number> {\n const { lessons } = await readLessons(repoRoot);\n const now = new Date();\n\n const toArchive: Lesson[] = [];\n const toKeep: Lesson[] = [];\n\n for (const lesson of lessons) {\n if (shouldArchive(lesson, now)) {\n toArchive.push(lesson);\n } else {\n toKeep.push(lesson);\n }\n }\n\n if (toArchive.length === 0) {\n return 0;\n }\n\n // Group lessons by archive file (YYYY-MM)\n const archiveGroups = new Map<string, Lesson[]>();\n for (const lesson of toArchive) {\n const created = new Date(lesson.created);\n const archivePath = getArchivePath(repoRoot, created);\n const group = archiveGroups.get(archivePath) ?? [];\n group.push(lesson);\n archiveGroups.set(archivePath, group);\n }\n\n // Create archive directory\n const archiveDir = join(repoRoot, ARCHIVE_DIR);\n await mkdir(archiveDir, { recursive: true });\n\n // Append to archive files\n for (const [archivePath, archiveLessons] of archiveGroups) {\n const lines = archiveLessons.map((l) => JSON.stringify(l) + '\\n').join('');\n await appendFile(archivePath, lines, 'utf-8');\n }\n\n // Rewrite main file without archived lessons\n const filePath = join(repoRoot, LESSONS_PATH);\n const tempPath = filePath + '.tmp';\n await mkdir(dirname(filePath), { recursive: true });\n\n const lines = toKeep.map((lesson) => JSON.stringify(lesson) + '\\n');\n await writeFile(tempPath, lines.join(''), 'utf-8');\n await rename(tempPath, filePath);\n\n return toArchive.length;\n}\n\n/**\n * Run full compaction: archive old lessons and remove tombstones.\n */\nexport async function compact(repoRoot: string): Promise<CompactResult> {\n // Count tombstones BEFORE any operations (archiving also rewrites the file)\n const tombstonesBefore = await countTombstones(repoRoot);\n\n // First, archive old lessons\n const archived = await archiveOldLessons(repoRoot);\n\n // Then, remove tombstones (may be fewer now if archiving removed some)\n const tombstonesAfterArchive = await countTombstones(repoRoot);\n await rewriteWithoutTombstones(repoRoot);\n\n // Total tombstones removed = before - after rewrite (which is 0 after rewrite)\n // But we want to report what was actually in the file before compaction\n const tombstonesRemoved = archived > 0 ? tombstonesBefore : tombstonesAfterArchive;\n\n // Get final count\n const { lessons } = await readLessons(repoRoot);\n\n return {\n archived,\n tombstonesRemoved,\n lessonsRemaining: lessons.length,\n };\n}\n","#!/usr/bin/env node\n/**\n * Learning Agent CLI\n *\n * Commands:\n * learn <insight> - Capture a new lesson\n * search <query> - Search lessons by keyword\n * list - List all lessons\n * detect --input - Detect learning triggers from input\n * compact - Archive old lessons and remove tombstones\n */\n\nimport chalk from 'chalk';\nimport { Command } from 'commander';\n\nimport { statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { detectAndPropose, parseInputFile } from './capture/integration.js';\nimport { formatBytes, getRepoRoot, parseLimit } from './cli-utils.js';\nimport { VERSION } from './index.js';\nimport { compact, countTombstones, needsCompaction, TOMBSTONE_THRESHOLD } from './storage/compact.js';\nimport { appendLesson, LESSONS_PATH, readLessons } from './storage/jsonl.js';\nimport { DB_PATH, getRetrievalStats, rebuildIndex, searchKeyword, syncIfNeeded } from './storage/sqlite.js';\nimport { generateId, LessonSchema } from './types.js';\nimport type { Lesson } from './types.js';\n\n// ============================================================================\n// Output Formatting Helpers\n// ============================================================================\n\n/** Output helper functions for consistent formatting */\nconst out = {\n success: (msg: string): void => console.log(chalk.green('[ok]'), msg),\n error: (msg: string): void => console.error(chalk.red('[error]'), msg),\n info: (msg: string): void => console.log(chalk.blue('[info]'), msg),\n warn: (msg: string): void => console.log(chalk.yellow('[warn]'), msg),\n};\n\n/** Global options interface */\ninterface GlobalOpts {\n verbose: boolean;\n quiet: boolean;\n}\n\n/**\n * Get global options from command.\n */\nfunction getGlobalOpts(cmd: Command): GlobalOpts {\n const opts = cmd.optsWithGlobals() as { verbose?: boolean; quiet?: boolean };\n return {\n verbose: opts.verbose ?? false,\n quiet: opts.quiet ?? false,\n };\n}\n\n/** Default limit for search results */\nconst DEFAULT_SEARCH_LIMIT = '10';\n\n/** Default limit for list results */\nconst DEFAULT_LIST_LIMIT = '20';\n\nconst program = new Command();\n\n// Add global options\nprogram\n .option('-v, --verbose', 'Show detailed output')\n .option('-q, --quiet', 'Suppress non-essential output');\n\nprogram\n .name('learning-agent')\n .description('Repository-scoped learning system for Claude Code')\n .version(VERSION);\n\nprogram\n .command('learn <insight>')\n .description('Capture a new lesson')\n .option('-t, --trigger <text>', 'What triggered this lesson')\n .option('--tags <tags>', 'Comma-separated tags', '')\n .option('-y, --yes', 'Skip confirmation')\n .action(async function (this: Command, insight: string, options: { trigger?: string; tags: string; yes?: boolean }) {\n const repoRoot = getRepoRoot();\n const { quiet } = getGlobalOpts(this);\n\n const lesson: Lesson = {\n id: generateId(insight),\n type: 'quick',\n trigger: options.trigger ?? 'Manual capture',\n insight,\n tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : [],\n source: 'manual',\n context: {\n tool: 'cli',\n intent: 'manual learning',\n },\n created: new Date().toISOString(),\n confirmed: options.yes ?? false,\n supersedes: [],\n related: [],\n };\n\n await appendLesson(repoRoot, lesson);\n out.success(`Learned: ${insight}`);\n if (!quiet) {\n console.log(`ID: ${chalk.dim(lesson.id)}`);\n }\n });\n\nprogram\n .command('search <query>')\n .description('Search lessons by keyword')\n .option('-n, --limit <number>', 'Maximum results', DEFAULT_SEARCH_LIMIT)\n .action(async function (this: Command, query: string, options: { limit: string }) {\n const repoRoot = getRepoRoot();\n const limit = parseLimit(options.limit, 'limit');\n const { verbose, quiet } = getGlobalOpts(this);\n\n // Sync index if JSONL has changed\n await syncIfNeeded(repoRoot);\n\n const results = await searchKeyword(repoRoot, query, limit);\n\n if (results.length === 0) {\n console.log('No lessons match your search. Try a different query or use \"list\" to see all lessons.');\n return;\n }\n\n if (!quiet) {\n out.info(`Found ${results.length} lesson(s):\\n`);\n }\n for (const lesson of results) {\n console.log(`[${chalk.cyan(lesson.id)}] ${lesson.insight}`);\n console.log(` Trigger: ${lesson.trigger}`);\n if (verbose && lesson.context) {\n console.log(` Context: ${lesson.context.tool} - ${lesson.context.intent}`);\n console.log(` Created: ${lesson.created}`);\n }\n if (lesson.tags.length > 0) {\n console.log(` Tags: ${lesson.tags.join(', ')}`);\n }\n console.log();\n }\n });\n\nprogram\n .command('list')\n .description('List all lessons')\n .option('-n, --limit <number>', 'Maximum results', DEFAULT_LIST_LIMIT)\n .action(async function (this: Command, options: { limit: string }) {\n const repoRoot = getRepoRoot();\n const limit = parseLimit(options.limit, 'limit');\n const { verbose, quiet } = getGlobalOpts(this);\n\n const { lessons, skippedCount } = await readLessons(repoRoot);\n\n if (lessons.length === 0) {\n console.log('No lessons found. Get started with: learn \"Your first lesson\"');\n if (skippedCount > 0) {\n out.warn(`${skippedCount} corrupted lesson(s) skipped.`);\n }\n return;\n }\n\n const toShow = lessons.slice(0, limit);\n\n // Show summary unless quiet mode\n if (!quiet) {\n out.info(`Showing ${toShow.length} of ${lessons.length} lesson(s):\\n`);\n }\n\n for (const lesson of toShow) {\n console.log(`[${chalk.cyan(lesson.id)}] ${lesson.insight}`);\n if (verbose) {\n console.log(` Type: ${lesson.type} | Source: ${lesson.source}`);\n console.log(` Created: ${lesson.created}`);\n if (lesson.context) {\n console.log(` Context: ${lesson.context.tool} - ${lesson.context.intent}`);\n }\n } else {\n console.log(` Type: ${lesson.type} | Source: ${lesson.source}`);\n }\n if (lesson.tags.length > 0) {\n console.log(` Tags: ${lesson.tags.join(', ')}`);\n }\n console.log();\n }\n\n if (skippedCount > 0) {\n out.warn(`${skippedCount} corrupted lesson(s) skipped.`);\n }\n });\n\nprogram\n .command('rebuild')\n .description('Rebuild SQLite index from JSONL')\n .option('-f, --force', 'Force rebuild even if unchanged')\n .action(async (options: { force?: boolean }) => {\n const repoRoot = getRepoRoot();\n if (options.force) {\n console.log('Forcing index rebuild...');\n await rebuildIndex(repoRoot);\n console.log('Index rebuilt.');\n } else {\n const rebuilt = await syncIfNeeded(repoRoot);\n if (rebuilt) {\n console.log('Index rebuilt (JSONL changed).');\n } else {\n console.log('Index is up to date.');\n }\n }\n });\n\nprogram\n .command('detect')\n .description('Detect learning triggers from input')\n .requiredOption('--input <file>', 'Path to JSON input file')\n .option('--save', 'Automatically save proposed lesson')\n .option('--json', 'Output result as JSON')\n .action(\n async (options: { input: string; save?: boolean; json?: boolean }) => {\n const repoRoot = getRepoRoot();\n\n const input = await parseInputFile(options.input);\n const result = await detectAndPropose(repoRoot, input);\n\n if (!result) {\n if (options.json) {\n console.log(JSON.stringify({ detected: false }));\n } else {\n console.log('No learning trigger detected.');\n }\n return;\n }\n\n if (options.json) {\n console.log(JSON.stringify({ detected: true, ...result }));\n return;\n }\n\n console.log('Learning trigger detected!');\n console.log(` Trigger: ${result.trigger}`);\n console.log(` Source: ${result.source}`);\n console.log(` Proposed: ${result.proposedInsight}`);\n\n if (options.save) {\n const lesson: Lesson = {\n id: generateId(result.proposedInsight),\n type: 'quick',\n trigger: result.trigger,\n insight: result.proposedInsight,\n tags: [],\n source: result.source,\n context: { tool: 'detect', intent: 'auto-capture' },\n created: new Date().toISOString(),\n confirmed: false,\n supersedes: [],\n related: [],\n };\n\n await appendLesson(repoRoot, lesson);\n console.log(`\\nSaved as lesson: ${lesson.id}`);\n }\n }\n );\n\nprogram\n .command('compact')\n .description('Compact lessons: archive old lessons and remove tombstones')\n .option('-f, --force', 'Run compaction even if below threshold')\n .option('--dry-run', 'Show what would be done without making changes')\n .action(async (options: { force?: boolean; dryRun?: boolean }) => {\n const repoRoot = getRepoRoot();\n\n const tombstones = await countTombstones(repoRoot);\n const needs = await needsCompaction(repoRoot);\n\n if (options.dryRun) {\n console.log('Dry run - no changes will be made.\\n');\n console.log(`Tombstones found: ${tombstones}`);\n console.log(`Compaction needed: ${needs ? 'yes' : 'no'}`);\n return;\n }\n\n if (!needs && !options.force) {\n console.log(`Compaction not needed (${tombstones} tombstones, threshold is ${TOMBSTONE_THRESHOLD}).`);\n console.log('Use --force to compact anyway.');\n return;\n }\n\n console.log('Running compaction...');\n const result = await compact(repoRoot);\n\n console.log('\\nCompaction complete:');\n console.log(` Archived: ${result.archived} lesson(s)`);\n console.log(` Tombstones removed: ${result.tombstonesRemoved}`);\n console.log(` Lessons remaining: ${result.lessonsRemaining}`);\n\n // Rebuild SQLite index after compaction\n await rebuildIndex(repoRoot);\n console.log(' Index rebuilt.');\n });\n\nprogram\n .command('export')\n .description('Export lessons as JSON to stdout')\n .option('--since <date>', 'Only include lessons created after this date (ISO8601)')\n .option('--tags <tags>', 'Filter by tags (comma-separated, OR logic)')\n .action(async (options: { since?: string; tags?: string }) => {\n const repoRoot = getRepoRoot();\n\n const { lessons } = await readLessons(repoRoot);\n\n let filtered = lessons;\n\n // Filter by date if --since provided\n if (options.since) {\n const sinceDate = new Date(options.since);\n if (Number.isNaN(sinceDate.getTime())) {\n console.error(`Invalid date format: ${options.since}. Use ISO8601 format (e.g., 2024-01-15).`);\n process.exit(1);\n }\n filtered = filtered.filter((lesson) => new Date(lesson.created) >= sinceDate);\n }\n\n // Filter by tags if --tags provided (OR logic)\n if (options.tags) {\n const filterTags = options.tags.split(',').map((t) => t.trim());\n filtered = filtered.filter((lesson) => lesson.tags.some((tag) => filterTags.includes(tag)));\n }\n\n // Output JSON to stdout (portable format for sharing)\n console.log(JSON.stringify(filtered, null, 2));\n });\n\nprogram\n .command('import <file>')\n .description('Import lessons from a JSONL file')\n .action(async (file: string) => {\n const repoRoot = getRepoRoot();\n\n // Read input file\n let content: string;\n try {\n const { readFile } = await import('node:fs/promises');\n content = await readFile(file, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n console.error(`Error: File not found: ${file}`);\n } else {\n console.error(`Error reading file: ${(err as Error).message}`);\n }\n process.exit(1);\n }\n\n // Get existing lesson IDs\n const { lessons: existingLessons } = await readLessons(repoRoot);\n const existingIds = new Set(existingLessons.map((l) => l.id));\n\n // Parse and validate each line\n const lines = content.split('\\n');\n let imported = 0;\n let skipped = 0;\n let invalid = 0;\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n // Parse JSON\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n invalid++;\n continue;\n }\n\n // Validate schema\n const result = LessonSchema.safeParse(parsed);\n if (!result.success) {\n invalid++;\n continue;\n }\n\n const lesson: Lesson = result.data;\n\n // Skip if ID already exists\n if (existingIds.has(lesson.id)) {\n skipped++;\n continue;\n }\n\n // Append lesson\n await appendLesson(repoRoot, lesson);\n existingIds.add(lesson.id);\n imported++;\n }\n\n // Format summary\n const lessonWord = imported === 1 ? 'lesson' : 'lessons';\n const parts: string[] = [];\n if (skipped > 0) parts.push(`${skipped} skipped`);\n if (invalid > 0) parts.push(`${invalid} invalid`);\n\n if (parts.length > 0) {\n console.log(`Imported ${imported} ${lessonWord} (${parts.join(', ')})`);\n } else {\n console.log(`Imported ${imported} ${lessonWord}`);\n }\n });\n\nprogram\n .command('stats')\n .description('Show database health and statistics')\n .action(async () => {\n const repoRoot = getRepoRoot();\n\n // Sync index to ensure accurate stats\n await syncIfNeeded(repoRoot);\n\n // Read lessons from JSONL to get accurate counts\n const { lessons } = await readLessons(repoRoot);\n const deletedCount = await countTombstones(repoRoot);\n const totalLessons = lessons.length;\n\n // Get retrieval stats from SQLite\n const retrievalStats = getRetrievalStats(repoRoot);\n const totalRetrievals = retrievalStats.reduce((sum, s) => sum + s.count, 0);\n const avgRetrievals = totalLessons > 0 ? (totalRetrievals / totalLessons).toFixed(1) : '0.0';\n\n // Get storage sizes\n const jsonlPath = join(repoRoot, LESSONS_PATH);\n const dbPath = join(repoRoot, DB_PATH);\n\n let dataSize = 0;\n let indexSize = 0;\n\n try {\n dataSize = statSync(jsonlPath).size;\n } catch {\n // File doesn't exist\n }\n\n try {\n indexSize = statSync(dbPath).size;\n } catch {\n // File doesn't exist\n }\n\n const totalSize = dataSize + indexSize;\n\n // Format output\n const deletedInfo = deletedCount > 0 ? ` (${deletedCount} deleted)` : '';\n console.log(`Lessons: ${totalLessons} total${deletedInfo}`);\n console.log(`Retrievals: ${totalRetrievals} total, ${avgRetrievals} avg per lesson`);\n console.log(`Storage: ${formatBytes(totalSize)} (index: ${formatBytes(indexSize)}, data: ${formatBytes(dataSize)})`);\n });\n\nprogram.parse();\n"]}