@gencode/agents 0.0.4 → 0.0.6
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/dist/commands/new.js +6 -6
- package/dist/commands/new.js.map +1 -1
- package/dist/config/types.d.ts +2 -2
- package/dist/config/types.d.ts.map +1 -1
- package/dist/plugins/hooks.d.ts +20 -1
- package/dist/plugins/hooks.d.ts.map +1 -1
- package/dist/plugins/hooks.js.map +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/runner/agent-runtime.d.ts +62 -0
- package/dist/runner/agent-runtime.d.ts.map +1 -0
- package/dist/runner/agent-runtime.js +179 -0
- package/dist/runner/agent-runtime.js.map +1 -0
- package/dist/runner/announce-loop.d.ts +41 -0
- package/dist/runner/announce-loop.d.ts.map +1 -0
- package/dist/runner/announce-loop.js +94 -0
- package/dist/runner/announce-loop.js.map +1 -0
- package/dist/runner/event-dispatcher.d.ts +31 -0
- package/dist/runner/event-dispatcher.d.ts.map +1 -0
- package/dist/runner/event-dispatcher.js +87 -0
- package/dist/runner/event-dispatcher.js.map +1 -0
- package/dist/runner/finalizer.d.ts +30 -0
- package/dist/runner/finalizer.d.ts.map +1 -0
- package/dist/runner/finalizer.js +75 -0
- package/dist/runner/finalizer.js.map +1 -0
- package/dist/runner/invocation-resolver.d.ts +67 -0
- package/dist/runner/invocation-resolver.d.ts.map +1 -0
- package/dist/runner/invocation-resolver.js +224 -0
- package/dist/runner/invocation-resolver.js.map +1 -0
- package/dist/runner/plugin-context.d.ts +18 -0
- package/dist/runner/plugin-context.d.ts.map +1 -0
- package/dist/runner/plugin-context.js +26 -0
- package/dist/runner/plugin-context.js.map +1 -0
- package/dist/runner/run-context.d.ts +38 -0
- package/dist/runner/run-context.d.ts.map +1 -0
- package/dist/runner/run-context.js +159 -0
- package/dist/runner/run-context.js.map +1 -0
- package/dist/runner/runner-session.d.ts +34 -0
- package/dist/runner/runner-session.d.ts.map +1 -0
- package/dist/runner/runner-session.js +61 -0
- package/dist/runner/runner-session.js.map +1 -0
- package/dist/runner/runner.d.ts +1 -2
- package/dist/runner/runner.d.ts.map +1 -1
- package/dist/runner/runner.js +115 -889
- package/dist/runner/runner.js.map +1 -1
- package/dist/runner/runtime.d.ts +7 -0
- package/dist/runner/runtime.d.ts.map +1 -0
- package/dist/runner/runtime.js +21 -0
- package/dist/runner/runtime.js.map +1 -0
- package/dist/runner/session-lifecycle.d.ts +31 -0
- package/dist/runner/session-lifecycle.d.ts.map +1 -0
- package/dist/runner/session-lifecycle.js +46 -0
- package/dist/runner/session-lifecycle.js.map +1 -0
- package/dist/runner/title.d.ts +3 -0
- package/dist/runner/title.d.ts.map +1 -0
- package/dist/runner/title.js +6 -0
- package/dist/runner/title.js.map +1 -0
- package/dist/runner/turn-executor.d.ts +51 -0
- package/dist/runner/turn-executor.d.ts.map +1 -0
- package/dist/runner/turn-executor.js +255 -0
- package/dist/runner/turn-executor.js.map +1 -0
- package/dist/tools/cron.d.ts +15 -22
- package/dist/tools/cron.d.ts.map +1 -1
- package/dist/tools/cron.js +20 -40
- package/dist/tools/cron.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/config-DJX-VM7S.js +0 -198
- package/dist/config-DJX-VM7S.js.map +0 -1
- package/dist/index-JD6Ye-N5.d.ts +0 -149
- package/dist/index-JD6Ye-N5.d.ts.map +0 -1
- package/dist/manager-qXa-NP0p.js +0 -1651
- package/dist/manager-qXa-NP0p.js.map +0 -1
- package/dist/message.d.ts +0 -11
- package/dist/message.d.ts.map +0 -1
- package/dist/message.js +0 -46
- package/dist/message.js.map +0 -1
- package/dist/security/command-dangerous-rules.d.ts +0 -4
- package/dist/security/command-dangerous-rules.d.ts.map +0 -1
- package/dist/security/command-dangerous-rules.js +0 -26
- package/dist/security/command-dangerous-rules.js.map +0 -1
- package/dist/security/command-parser.d.ts +0 -3
- package/dist/security/command-parser.d.ts.map +0 -1
- package/dist/security/command-parser.js +0 -191
- package/dist/security/command-parser.js.map +0 -1
- package/dist/security/command-path-guard.d.ts +0 -10
- package/dist/security/command-path-guard.d.ts.map +0 -1
- package/dist/security/command-path-guard.js +0 -126
- package/dist/security/command-path-guard.js.map +0 -1
- package/dist/security/command-policy-config.d.ts +0 -5
- package/dist/security/command-policy-config.d.ts.map +0 -1
- package/dist/security/command-policy-config.js +0 -212
- package/dist/security/command-policy-config.js.map +0 -1
- package/dist/security/command-policy-engine.d.ts +0 -8
- package/dist/security/command-policy-engine.d.ts.map +0 -1
- package/dist/security/command-policy-engine.js +0 -122
- package/dist/security/command-policy-engine.js.map +0 -1
- package/dist/security/command-policy-types.d.ts +0 -67
- package/dist/security/command-policy-types.d.ts.map +0 -1
- package/dist/security/command-policy-types.js +0 -2
- package/dist/security/command-policy-types.js.map +0 -1
- package/dist/security/command-safe-bins.d.ts +0 -4
- package/dist/security/command-safe-bins.d.ts.map +0 -1
- package/dist/security/command-safe-bins.js +0 -84
- package/dist/security/command-safe-bins.js.map +0 -1
- package/dist/security/command-trusted-executables.d.ts +0 -6
- package/dist/security/command-trusted-executables.d.ts.map +0 -1
- package/dist/security/command-trusted-executables.js +0 -57
- package/dist/security/command-trusted-executables.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manager-qXa-NP0p.js","names":["tokenize"],"sources":["../src/session/session.ts","../src/memory/embeddings.ts","../src/memory/fs-utils.ts","../src/memory/internal.ts","../src/memory/mmr.ts","../src/memory/temporal-decay.ts","../src/memory/hybrid.ts","../src/memory/memory-schema.ts","../src/memory/manager-search.ts","../src/memory/sqlite.ts","../src/memory/config.ts","../src/memory/sqlite-vec.ts","../src/memory/session-files.ts","../src/memory/manager.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport type { TranscriptEntry, Channel } from \"../types.js\";\n\nexport type SessionMetadata = {\n id: string;\n title: string;\n channel: Channel;\n createdAt: string;\n updatedAt: string;\n};\n\nexport type SessionSummary = {\n id: string;\n title: string;\n channel: Channel;\n createdAt: string;\n updatedAt: string;\n};\n\n/** Resolves the sessions directory path within a data directory */\nexport function sessionsDir(dataDir: string): string {\n return path.join(dataDir, \".pingclaw\", \"sessions\");\n}\n\n/** Resolves the directory for a specific session */\nexport function sessionDir(dataDir: string, sessionId: string): string {\n return path.join(sessionsDir(dataDir), sessionId);\n}\n\n/** Resolves the transcript file path for a session */\nexport function transcriptPath(dataDir: string, sessionId: string): string {\n return path.join(sessionDir(dataDir, sessionId), \"transcript.jsonl\");\n}\n\n/** Resolves the metadata file path for a session */\nexport function metadataPath(dataDir: string, sessionId: string): string {\n return path.join(sessionDir(dataDir, sessionId), \"session.json\");\n}\n\n/** Creates a new session with a generated ID */\nexport async function createSession(dataDir: string, channel: Channel): Promise<string> {\n const sessionId = randomUUID();\n const dir = sessionDir(dataDir, sessionId);\n await fs.mkdir(dir, { recursive: true });\n // Store channel in a temporary file to be used later\n const channelPath = path.join(dir, \".channel\");\n await fs.writeFile(channelPath, channel, \"utf-8\");\n return sessionId;\n}\n\n/** Ensures a session directory exists (for resuming an existing session) */\nexport async function ensureSession(dataDir: string, sessionId: string): Promise<void> {\n const dir = sessionDir(dataDir, sessionId);\n await fs.mkdir(dir, { recursive: true });\n}\n\n/** Loads all transcript entries from a session */\nexport async function loadTranscript(\n dataDir: string,\n sessionId: string,\n): Promise<TranscriptEntry[]> {\n const filePath = transcriptPath(dataDir, sessionId);\n let content: string;\n try {\n content = await fs.readFile(filePath, \"utf-8\");\n } catch (err) {\n const code = (err as { code?: string }).code;\n if (code === \"ENOENT\") {\n return [];\n }\n throw err;\n }\n\n const entries: TranscriptEntry[] = [];\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n entries.push(JSON.parse(trimmed) as TranscriptEntry);\n } catch {\n // Skip malformed lines\n }\n }\n return entries;\n}\n\n/** Appends a single entry to the transcript file */\nexport async function appendTranscriptEntry(\n dataDir: string,\n sessionId: string,\n entry: TranscriptEntry,\n): Promise<void> {\n await ensureSession(dataDir, sessionId);\n const filePath = transcriptPath(dataDir, sessionId);\n const line = JSON.stringify(entry) + \"\\n\";\n await fs.appendFile(filePath, line, \"utf-8\");\n try {\n const { MemoryIndexManager } = await import(\"../memory/manager.js\");\n MemoryIndexManager.get(dataDir).noteSessionUpdate(filePath);\n } catch {\n // Non-fatal: memory index may be unavailable.\n }\n}\n\n/** Lists all session IDs within a data directory */\nexport async function listSessions(dataDir: string): Promise<string[]> {\n const dir = sessionsDir(dataDir);\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n return entries\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name)\n .sort();\n } catch (err) {\n const code = (err as { code?: string }).code;\n if (code === \"ENOENT\") {\n return [];\n }\n throw err;\n }\n}\n\n/** Saves session metadata to disk */\nexport async function saveSessionMetadata(dataDir: string, metadata: SessionMetadata): Promise<void> {\n await ensureSession(dataDir, metadata.id);\n const filePath = metadataPath(dataDir, metadata.id);\n await fs.writeFile(filePath, JSON.stringify(metadata, null, 2), \"utf-8\");\n}\n\n/** Loads session metadata from disk; returns null if not found */\nexport async function loadSessionMetadata(\n dataDir: string,\n sessionId: string,\n): Promise<SessionMetadata | null> {\n const filePath = metadataPath(dataDir, sessionId);\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n const meta = JSON.parse(content) as SessionMetadata;\n\n // If channel is not in metadata, try to read from .channel file for backward compatibility\n if (!meta.channel) {\n const channelPath = path.join(sessionDir(dataDir, sessionId), \".channel\");\n try {\n const channelContent = await fs.readFile(channelPath, \"utf-8\");\n meta.channel = channelContent.trim() as Channel;\n } catch {\n // Default to WEB if no channel info exists\n meta.channel = \"WEB\";\n }\n }\n\n return meta;\n } catch (err) {\n const code = (err as { code?: string }).code;\n if (code === \"ENOENT\") {\n // Metadata file doesn't exist, return null\n // Note: The .channel file is only used when metadata exists but lacks channel\n return null;\n }\n throw err;\n }\n}\n\n/** Lists all sessions with their metadata summaries, optionally filtered by channel */\nexport async function listSessionSummaries(dataDir: string, channel?: Channel): Promise<SessionSummary[]> {\n const ids = await listSessions(dataDir);\n const summaries = await Promise.all(\n ids.map(async (id) => {\n const meta = await loadSessionMetadata(dataDir, id);\n return {\n id,\n title: meta?.title ?? id,\n channel: meta?.channel ?? \"WEB\",\n createdAt: meta?.createdAt ?? \"\",\n updatedAt: meta?.updatedAt ?? \"\",\n };\n }),\n );\n return channel ? summaries.filter((s) => s.channel === channel) : summaries;\n}\n","import crypto from \"node:crypto\";\n\nexport type EmbeddingProvider = {\n id: string;\n model: string;\n embedQuery: (text: string) => Promise<number[]>;\n embedBatch: (texts: string[]) => Promise<number[][]>;\n};\n\nconst DEFAULT_DIMENSIONS = 384;\n\nfunction tokenize(text: string): string[] {\n const tokens = text.toLowerCase().match(/[\\p{L}\\p{N}_]+/gu) ?? [];\n return tokens.filter(Boolean);\n}\n\nfunction hashToken(token: string): number {\n const hash = crypto.createHash(\"sha256\").update(token).digest();\n return hash.readUInt32BE(0);\n}\n\nfunction buildEmbedding(text: string, dims = DEFAULT_DIMENSIONS): number[] {\n const vec = new Array<number>(dims).fill(0);\n const tokens = tokenize(text);\n if (tokens.length === 0) {\n return vec;\n }\n for (const token of tokens) {\n const h = hashToken(token);\n const idx = h % dims;\n vec[idx] += 1;\n }\n const norm = Math.sqrt(vec.reduce((sum, v) => sum + v * v, 0));\n if (norm > 0) {\n for (let i = 0; i < vec.length; i += 1) {\n vec[i] = vec[i] / norm;\n }\n }\n return vec;\n}\n\nexport function createMockEmbeddingProvider(params?: {\n model?: string;\n dimensions?: number;\n}): EmbeddingProvider {\n const model = params?.model?.trim() || \"mock-embedding-v1\";\n const dimensions = params?.dimensions ?? DEFAULT_DIMENSIONS;\n\n return {\n id: \"external-mock\",\n model,\n embedQuery: async (text) => buildEmbedding(text, dimensions),\n embedBatch: async (texts) => texts.map((text) => buildEmbedding(text, dimensions)),\n };\n}\n","import type { Stats } from \"node:fs\";\nimport fs from \"node:fs/promises\";\n\nexport type RegularFileStatResult = { missing: true } | { missing: false; stat: Stats };\n\nexport function isFileMissingError(\n err: unknown,\n): err is NodeJS.ErrnoException & { code: \"ENOENT\" } {\n return Boolean(\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n (err as Partial<NodeJS.ErrnoException>).code === \"ENOENT\",\n );\n}\n\nexport async function statRegularFile(absPath: string): Promise<RegularFileStatResult> {\n let stat: Stats;\n try {\n stat = await fs.lstat(absPath);\n } catch (err) {\n if (isFileMissingError(err)) {\n return { missing: true };\n }\n throw err;\n }\n if (stat.isSymbolicLink() || !stat.isFile()) {\n throw new Error(\"path required\");\n }\n return { missing: false, stat };\n}\n","import crypto from \"node:crypto\";\nimport fsSync from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { isFileMissingError } from \"./fs-utils.js\";\n\nexport type MemoryFileEntry = {\n path: string;\n absPath: string;\n mtimeMs: number;\n size: number;\n hash: string;\n};\n\nexport type MemoryChunk = {\n startLine: number;\n endLine: number;\n text: string;\n hash: string;\n};\n\nexport function ensureDir(dir: string): string {\n try {\n fsSync.mkdirSync(dir, { recursive: true });\n } catch {}\n return dir;\n}\n\nexport function normalizeRelPath(value: string): string {\n const trimmed = value.trim().replace(/^[./]+/, \"\");\n return trimmed.replace(/\\\\/g, \"/\");\n}\n\nexport function isMemoryPath(relPath: string): boolean {\n const normalized = normalizeRelPath(relPath);\n if (!normalized) {\n return false;\n }\n if (normalized === \"MEMORY.md\" || normalized === \"memory.md\") {\n return true;\n }\n return normalized.startsWith(\"memory/\");\n}\n\nasync function walkDir(dir: string, files: string[]) {\n const entries = await fs.readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isSymbolicLink()) {\n continue;\n }\n if (entry.isDirectory()) {\n await walkDir(full, files);\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n if (!entry.name.endsWith(\".md\")) {\n continue;\n }\n files.push(full);\n }\n}\n\nexport async function listMemoryFiles(memoryRoot: string): Promise<string[]> {\n const result: string[] = [];\n const memoryFile = path.join(memoryRoot, \"MEMORY.md\");\n const altMemoryFile = path.join(memoryRoot, \"memory.md\");\n const memoryDir = path.join(memoryRoot, \"memory\");\n\n const addMarkdownFile = async (absPath: string) => {\n try {\n const stat = await fs.lstat(absPath);\n if (stat.isSymbolicLink() || !stat.isFile()) {\n return;\n }\n if (!absPath.endsWith(\".md\")) {\n return;\n }\n result.push(absPath);\n } catch {}\n };\n\n await addMarkdownFile(memoryFile);\n await addMarkdownFile(altMemoryFile);\n try {\n const dirStat = await fs.lstat(memoryDir);\n if (!dirStat.isSymbolicLink() && dirStat.isDirectory()) {\n await walkDir(memoryDir, result);\n }\n } catch {}\n\n if (result.length <= 1) {\n return result;\n }\n const seen = new Set<string>();\n const deduped: string[] = [];\n for (const entry of result) {\n let key = entry;\n try {\n key = await fs.realpath(entry);\n } catch {}\n if (seen.has(key)) {\n continue;\n }\n seen.add(key);\n deduped.push(entry);\n }\n return deduped;\n}\n\nexport function hashText(value: string): string {\n return crypto.createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nexport async function buildFileEntry(\n absPath: string,\n memoryRoot: string,\n): Promise<MemoryFileEntry | null> {\n let stat;\n try {\n stat = await fs.stat(absPath);\n } catch (err) {\n if (isFileMissingError(err)) {\n return null;\n }\n throw err;\n }\n let content: string;\n try {\n content = await fs.readFile(absPath, \"utf-8\");\n } catch (err) {\n if (isFileMissingError(err)) {\n return null;\n }\n throw err;\n }\n const hash = hashText(content);\n return {\n path: path.relative(memoryRoot, absPath).replace(/\\\\/g, \"/\"),\n absPath,\n mtimeMs: stat.mtimeMs,\n size: stat.size,\n hash,\n };\n}\n\nexport function chunkMarkdown(\n content: string,\n chunking: { tokens: number; overlap: number },\n): MemoryChunk[] {\n const lines = content.split(\"\\n\");\n if (lines.length === 0) {\n return [];\n }\n const maxChars = Math.max(32, chunking.tokens * 4);\n const overlapChars = Math.max(0, chunking.overlap * 4);\n const chunks: MemoryChunk[] = [];\n\n let current: Array<{ line: string; lineNo: number }> = [];\n let currentChars = 0;\n\n const flush = () => {\n if (current.length === 0) {\n return;\n }\n const firstEntry = current[0];\n const lastEntry = current[current.length - 1];\n if (!firstEntry || !lastEntry) {\n return;\n }\n const text = current.map((entry) => entry.line).join(\"\\n\");\n const startLine = firstEntry.lineNo;\n const endLine = lastEntry.lineNo;\n chunks.push({\n startLine,\n endLine,\n text,\n hash: hashText(text),\n });\n };\n\n const carryOverlap = () => {\n if (overlapChars <= 0 || current.length === 0) {\n current = [];\n currentChars = 0;\n return;\n }\n let acc = 0;\n const kept: Array<{ line: string; lineNo: number }> = [];\n for (let i = current.length - 1; i >= 0; i -= 1) {\n const entry = current[i];\n if (!entry) {\n continue;\n }\n acc += entry.line.length + 1;\n kept.unshift(entry);\n if (acc >= overlapChars) {\n break;\n }\n }\n current = kept;\n currentChars = kept.reduce((sum, entry) => sum + entry.line.length + 1, 0);\n };\n\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i] ?? \"\";\n const lineNo = i + 1;\n const segments: string[] = [];\n if (line.length === 0) {\n segments.push(\"\");\n } else {\n for (let start = 0; start < line.length; start += maxChars) {\n segments.push(line.slice(start, start + maxChars));\n }\n }\n for (const segment of segments) {\n const lineSize = segment.length + 1;\n if (currentChars + lineSize > maxChars && current.length > 0) {\n flush();\n carryOverlap();\n }\n current.push({ line: segment, lineNo });\n currentChars += lineSize;\n }\n }\n flush();\n return chunks;\n}\n\nexport function remapChunkLines(chunks: MemoryChunk[], lineMap: number[] | undefined): void {\n if (!lineMap || lineMap.length === 0) {\n return;\n }\n for (const chunk of chunks) {\n chunk.startLine = lineMap[chunk.startLine - 1] ?? chunk.startLine;\n chunk.endLine = lineMap[chunk.endLine - 1] ?? chunk.endLine;\n }\n}\n\nexport function parseEmbedding(raw: string): number[] {\n try {\n const parsed = JSON.parse(raw) as number[];\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nexport function cosineSimilarity(a: number[], b: number[]): number {\n if (a.length === 0 || b.length === 0) {\n return 0;\n }\n const len = Math.min(a.length, b.length);\n let dot = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < len; i += 1) {\n const av = a[i] ?? 0;\n const bv = b[i] ?? 0;\n dot += av * bv;\n normA += av * av;\n normB += bv * bv;\n }\n if (normA === 0 || normB === 0) {\n return 0;\n }\n return dot / (Math.sqrt(normA) * Math.sqrt(normB));\n}\n\nexport async function runWithConcurrency<T>(\n tasks: Array<() => Promise<T>>,\n limit: number,\n): Promise<T[]> {\n const results: T[] = [];\n let index = 0;\n let rejected: unknown = null;\n\n const workers = Array.from({ length: Math.max(1, limit) }, async () => {\n while (true) {\n if (rejected) {\n return;\n }\n const current = index;\n index += 1;\n const task = tasks[current];\n if (!task) {\n return;\n }\n try {\n results[current] = await task();\n } catch (err) {\n rejected = err;\n return;\n }\n }\n });\n\n await Promise.all(workers);\n if (rejected) {\n throw rejected;\n }\n return results;\n}\n","export type MMRItem = {\n id: string;\n score: number;\n content: string;\n};\n\nexport type MMRConfig = {\n enabled: boolean;\n lambda: number;\n};\n\nexport const DEFAULT_MMR_CONFIG: MMRConfig = {\n enabled: false,\n lambda: 0.7,\n};\n\nexport function tokenize(text: string): Set<string> {\n const tokens = text.toLowerCase().match(/[a-z0-9_]+/g) ?? [];\n return new Set(tokens);\n}\n\nexport function jaccardSimilarity(setA: Set<string>, setB: Set<string>): number {\n if (setA.size === 0 && setB.size === 0) {\n return 1;\n }\n if (setA.size === 0 || setB.size === 0) {\n return 0;\n }\n\n let intersectionSize = 0;\n const smaller = setA.size <= setB.size ? setA : setB;\n const larger = setA.size <= setB.size ? setB : setA;\n\n for (const token of smaller) {\n if (larger.has(token)) {\n intersectionSize++;\n }\n }\n\n const unionSize = setA.size + setB.size - intersectionSize;\n return unionSize === 0 ? 0 : intersectionSize / unionSize;\n}\n\nexport function textSimilarity(contentA: string, contentB: string): number {\n return jaccardSimilarity(tokenize(contentA), tokenize(contentB));\n}\n\nfunction maxSimilarityToSelected(\n item: MMRItem,\n selectedItems: MMRItem[],\n tokenCache: Map<string, Set<string>>,\n): number {\n if (selectedItems.length === 0) {\n return 0;\n }\n\n let maxSim = 0;\n const itemTokens = tokenCache.get(item.id) ?? tokenize(item.content);\n\n for (const selected of selectedItems) {\n const selectedTokens = tokenCache.get(selected.id) ?? tokenize(selected.content);\n const sim = jaccardSimilarity(itemTokens, selectedTokens);\n if (sim > maxSim) {\n maxSim = sim;\n }\n }\n\n return maxSim;\n}\n\nexport function computeMMRScore(relevance: number, maxSimilarity: number, lambda: number): number {\n return lambda * relevance - (1 - lambda) * maxSimilarity;\n}\n\nexport function mmrRerank<T extends MMRItem>(items: T[], config: Partial<MMRConfig> = {}): T[] {\n const { enabled = DEFAULT_MMR_CONFIG.enabled, lambda = DEFAULT_MMR_CONFIG.lambda } = config;\n\n if (!enabled || items.length <= 1) {\n return [...items];\n }\n\n const clampedLambda = Math.max(0, Math.min(1, lambda));\n\n if (clampedLambda === 1) {\n return items.slice().sort((a, b) => b.score - a.score);\n }\n\n const tokenCache = new Map<string, Set<string>>();\n for (const item of items) {\n tokenCache.set(item.id, tokenize(item.content));\n }\n\n const maxScore = Math.max(...items.map((i) => i.score));\n const minScore = Math.min(...items.map((i) => i.score));\n const scoreRange = maxScore - minScore;\n\n const normalizeScore = (score: number): number => {\n if (scoreRange === 0) {\n return 1;\n }\n return (score - minScore) / scoreRange;\n };\n\n const selected: T[] = [];\n const remaining = new Set(items);\n\n while (remaining.size > 0) {\n let bestItem: T | null = null;\n let bestMMRScore = -Infinity;\n\n for (const candidate of remaining) {\n const normalizedRelevance = normalizeScore(candidate.score);\n const maxSim = maxSimilarityToSelected(candidate, selected, tokenCache);\n const mmrScore = computeMMRScore(normalizedRelevance, maxSim, clampedLambda);\n\n if (\n mmrScore > bestMMRScore ||\n (mmrScore === bestMMRScore && candidate.score > (bestItem?.score ?? -Infinity))\n ) {\n bestMMRScore = mmrScore;\n bestItem = candidate;\n }\n }\n\n if (bestItem) {\n selected.push(bestItem);\n remaining.delete(bestItem);\n } else {\n break;\n }\n }\n\n return selected;\n}\n\nexport function applyMMRToHybridResults<\n T extends { score: number; snippet: string; path: string; startLine: number },\n>(results: T[], config: Partial<MMRConfig> = {}): T[] {\n if (results.length === 0) {\n return results;\n }\n\n const itemById = new Map<string, T>();\n\n const mmrItems: MMRItem[] = results.map((r, index) => {\n const id = `${r.path}:${r.startLine}:${index}`;\n itemById.set(id, r);\n return {\n id,\n score: r.score,\n content: r.snippet,\n };\n });\n\n const reranked = mmrRerank(mmrItems, config);\n\n return reranked.map((item) => itemById.get(item.id)!);\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport type TemporalDecayConfig = {\n enabled: boolean;\n halfLifeDays: number;\n};\n\nexport const DEFAULT_TEMPORAL_DECAY_CONFIG: TemporalDecayConfig = {\n enabled: false,\n halfLifeDays: 30,\n};\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst DATED_MEMORY_PATH_RE = /(?:^|\\/)(?:memory)\\/(\\d{4})-(\\d{2})-(\\d{2})\\.md$/;\n\nexport function toDecayLambda(halfLifeDays: number): number {\n if (!Number.isFinite(halfLifeDays) || halfLifeDays <= 0) {\n return 0;\n }\n return Math.LN2 / halfLifeDays;\n}\n\nexport function calculateTemporalDecayMultiplier(params: {\n ageInDays: number;\n halfLifeDays: number;\n}): number {\n const lambda = toDecayLambda(params.halfLifeDays);\n const clampedAge = Math.max(0, params.ageInDays);\n if (lambda <= 0 || !Number.isFinite(clampedAge)) {\n return 1;\n }\n return Math.exp(-lambda * clampedAge);\n}\n\nexport function applyTemporalDecayToScore(params: {\n score: number;\n ageInDays: number;\n halfLifeDays: number;\n}): number {\n return params.score * calculateTemporalDecayMultiplier(params);\n}\n\nfunction parseMemoryDateFromPath(filePath: string): Date | null {\n const normalized = filePath.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\");\n const match = DATED_MEMORY_PATH_RE.exec(normalized);\n if (!match) {\n return null;\n }\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n if (!Number.isInteger(year) || !Number.isInteger(month) || !Number.isInteger(day)) {\n return null;\n }\n\n const timestamp = Date.UTC(year, month - 1, day);\n const parsed = new Date(timestamp);\n if (\n parsed.getUTCFullYear() !== year ||\n parsed.getUTCMonth() !== month - 1 ||\n parsed.getUTCDate() !== day\n ) {\n return null;\n }\n\n return parsed;\n}\n\nfunction isEvergreenMemoryPath(filePath: string): boolean {\n const normalized = filePath.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\//, \"\");\n if (normalized === \"MEMORY.md\" || normalized === \"memory.md\") {\n return true;\n }\n if (!normalized.startsWith(\"memory/\")) {\n return false;\n }\n return !DATED_MEMORY_PATH_RE.test(normalized);\n}\n\nasync function extractTimestamp(params: {\n filePath: string;\n source?: string;\n memoryRoot?: string;\n}): Promise<Date | null> {\n const fromPath = parseMemoryDateFromPath(params.filePath);\n if (fromPath) {\n return fromPath;\n }\n\n if (params.source === \"memory\" && isEvergreenMemoryPath(params.filePath)) {\n return null;\n }\n\n if (!params.memoryRoot) {\n return null;\n }\n\n const absolutePath = path.isAbsolute(params.filePath)\n ? params.filePath\n : path.resolve(params.memoryRoot, params.filePath);\n\n try {\n const stat = await fs.stat(absolutePath);\n if (!Number.isFinite(stat.mtimeMs)) {\n return null;\n }\n return new Date(stat.mtimeMs);\n } catch {\n return null;\n }\n}\n\nfunction ageInDaysFromTimestamp(timestamp: Date, nowMs: number): number {\n const ageMs = Math.max(0, nowMs - timestamp.getTime());\n return ageMs / DAY_MS;\n}\n\nexport async function applyTemporalDecayToHybridResults<\n T extends { path: string; score: number; source: string },\n>(params: {\n results: T[];\n temporalDecay?: Partial<TemporalDecayConfig>;\n memoryRoot?: string;\n nowMs?: number;\n}): Promise<T[]> {\n const config = { ...DEFAULT_TEMPORAL_DECAY_CONFIG, ...params.temporalDecay };\n if (!config.enabled) {\n return [...params.results];\n }\n\n const nowMs = params.nowMs ?? Date.now();\n const timestampPromiseCache = new Map<string, Promise<Date | null>>();\n\n return Promise.all(\n params.results.map(async (entry) => {\n const cacheKey = `${entry.source}:${entry.path}`;\n let timestampPromise = timestampPromiseCache.get(cacheKey);\n if (!timestampPromise) {\n timestampPromise = extractTimestamp({\n filePath: entry.path,\n source: entry.source,\n memoryRoot: params.memoryRoot,\n });\n timestampPromiseCache.set(cacheKey, timestampPromise);\n }\n\n const timestamp = await timestampPromise;\n if (!timestamp) {\n return entry;\n }\n\n const decayedScore = applyTemporalDecayToScore({\n score: entry.score,\n ageInDays: ageInDaysFromTimestamp(timestamp, nowMs),\n halfLifeDays: config.halfLifeDays,\n });\n\n return {\n ...entry,\n score: decayedScore,\n };\n }),\n );\n}\n","import { applyMMRToHybridResults, type MMRConfig, DEFAULT_MMR_CONFIG } from \"./mmr.js\";\nimport {\n applyTemporalDecayToHybridResults,\n type TemporalDecayConfig,\n DEFAULT_TEMPORAL_DECAY_CONFIG,\n} from \"./temporal-decay.js\";\n\nexport type HybridSource = string;\n\nexport { type MMRConfig, DEFAULT_MMR_CONFIG };\nexport { type TemporalDecayConfig, DEFAULT_TEMPORAL_DECAY_CONFIG };\n\nexport type HybridVectorResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n vectorScore: number;\n};\n\nexport type HybridKeywordResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n textScore: number;\n};\n\nexport function buildFtsQuery(raw: string): string | null {\n const tokens =\n raw\n .match(/[\\p{L}\\p{N}_]+/gu)\n ?.map((t) => t.trim())\n .filter(Boolean) ?? [];\n if (tokens.length === 0) {\n return null;\n }\n const quoted = tokens.map((t) => `\"${t.replaceAll('\"', \"\")}\"`);\n return quoted.join(\" AND \");\n}\n\nexport function bm25RankToScore(rank: number): number {\n const normalized = Number.isFinite(rank) ? Math.max(0, rank) : 999;\n return 1 / (1 + normalized);\n}\n\nexport async function mergeHybridResults(params: {\n vector: HybridVectorResult[];\n keyword: HybridKeywordResult[];\n vectorWeight: number;\n textWeight: number;\n memoryRoot?: string;\n mmr?: Partial<MMRConfig>;\n temporalDecay?: Partial<TemporalDecayConfig>;\n nowMs?: number;\n}): Promise<\n Array<{\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: HybridSource;\n }>\n> {\n const byId = new Map<\n string,\n {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n source: HybridSource;\n snippet: string;\n vectorScore: number;\n textScore: number;\n }\n >();\n\n for (const r of params.vector) {\n byId.set(r.id, {\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: r.vectorScore,\n textScore: 0,\n });\n }\n\n for (const r of params.keyword) {\n const existing = byId.get(r.id);\n if (existing) {\n existing.textScore = r.textScore;\n if (r.snippet && r.snippet.length > 0) {\n existing.snippet = r.snippet;\n }\n } else {\n byId.set(r.id, {\n id: r.id,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: 0,\n textScore: r.textScore,\n });\n }\n }\n\n const merged = Array.from(byId.values()).map((entry) => {\n const score = params.vectorWeight * entry.vectorScore + params.textWeight * entry.textScore;\n return {\n path: entry.path,\n startLine: entry.startLine,\n endLine: entry.endLine,\n score,\n snippet: entry.snippet,\n source: entry.source,\n };\n });\n\n const temporalDecayConfig = { ...DEFAULT_TEMPORAL_DECAY_CONFIG, ...params.temporalDecay };\n const decayed = await applyTemporalDecayToHybridResults({\n results: merged,\n temporalDecay: temporalDecayConfig,\n memoryRoot: params.memoryRoot,\n nowMs: params.nowMs,\n });\n const sorted = decayed.slice().sort((a, b) => b.score - a.score);\n\n const mmrConfig = { ...DEFAULT_MMR_CONFIG, ...params.mmr };\n if (mmrConfig.enabled) {\n return applyMMRToHybridResults(sorted, mmrConfig);\n }\n\n return sorted;\n}\n","import type { DatabaseSync } from \"node:sqlite\";\n\nexport function ensureMemoryIndexSchema(params: {\n db: DatabaseSync;\n embeddingCacheTable: string;\n ftsTable: string;\n ftsEnabled: boolean;\n}): { ftsAvailable: boolean; ftsError?: string } {\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS files (\n path TEXT PRIMARY KEY,\n source TEXT NOT NULL DEFAULT 'memory',\n hash TEXT NOT NULL,\n mtime INTEGER NOT NULL,\n size INTEGER NOT NULL\n );\n `);\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS chunks (\n id TEXT PRIMARY KEY,\n path TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'memory',\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n hash TEXT NOT NULL,\n model TEXT NOT NULL,\n text TEXT NOT NULL,\n embedding TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n `);\n params.db.exec(`\n CREATE TABLE IF NOT EXISTS ${params.embeddingCacheTable} (\n provider TEXT NOT NULL,\n model TEXT NOT NULL,\n provider_key TEXT NOT NULL,\n hash TEXT NOT NULL,\n embedding TEXT NOT NULL,\n dims INTEGER,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (provider, model, provider_key, hash)\n );\n `);\n params.db.exec(\n `CREATE INDEX IF NOT EXISTS idx_embedding_cache_updated_at ON ${params.embeddingCacheTable}(updated_at);`,\n );\n\n let ftsAvailable = false;\n let ftsError: string | undefined;\n if (params.ftsEnabled) {\n try {\n params.db.exec(\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${params.ftsTable} USING fts5(\\n` +\n ` text,\\n` +\n ` id UNINDEXED,\\n` +\n ` path UNINDEXED,\\n` +\n ` source UNINDEXED,\\n` +\n ` model UNINDEXED,\\n` +\n ` start_line UNINDEXED,\\n` +\n ` end_line UNINDEXED\\n` +\n `);`,\n );\n ftsAvailable = true;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n ftsAvailable = false;\n ftsError = message;\n }\n }\n\n ensureColumn(params.db, \"files\", \"source\", \"TEXT NOT NULL DEFAULT 'memory'\");\n ensureColumn(params.db, \"chunks\", \"source\", \"TEXT NOT NULL DEFAULT 'memory'\");\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_path ON chunks(path);`);\n params.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_source ON chunks(source);`);\n\n return { ftsAvailable, ...(ftsError ? { ftsError } : {}) };\n}\n\nfunction ensureColumn(\n db: DatabaseSync,\n table: \"files\" | \"chunks\",\n column: string,\n definition: string,\n): void {\n const rows = db.prepare(`PRAGMA table_info(${table})`).all() as Array<{ name: string }>;\n if (rows.some((row) => row.name === column)) {\n return;\n }\n db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);\n}\n","import type { DatabaseSync } from \"node:sqlite\";\nimport { cosineSimilarity, parseEmbedding } from \"./internal.js\";\n\nexport type SearchSource = string;\n\nexport type SearchRowResult = {\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: SearchSource;\n};\n\nfunction truncateUtf16Safe(input: string, maxChars: number): string {\n if (input.length <= maxChars) {\n return input;\n }\n return input.slice(0, maxChars);\n}\n\nconst vectorToBlob = (embedding: number[]): Buffer =>\n Buffer.from(new Float32Array(embedding).buffer);\n\nexport async function searchVector(params: {\n db: DatabaseSync;\n vectorTable: string;\n providerModel: string;\n queryVec: number[];\n limit: number;\n snippetMaxChars: number;\n ensureVectorReady: (dimensions: number) => Promise<boolean>;\n sourceFilterVec: { sql: string; params: SearchSource[] };\n sourceFilterChunks: { sql: string; params: SearchSource[] };\n}): Promise<SearchRowResult[]> {\n if (params.queryVec.length === 0 || params.limit <= 0) {\n return [];\n }\n if (await params.ensureVectorReady(params.queryVec.length)) {\n const rows = params.db\n .prepare(\n `SELECT c.id, c.path, c.start_line, c.end_line, c.text,\\n` +\n ` c.source,\\n` +\n ` vec_distance_cosine(v.embedding, ?) AS dist\\n` +\n ` FROM ${params.vectorTable} v\\n` +\n ` JOIN chunks c ON c.id = v.id\\n` +\n ` WHERE c.model = ?${params.sourceFilterVec.sql}\\n` +\n ` ORDER BY dist ASC\\n` +\n ` LIMIT ?`,\n )\n .all(\n vectorToBlob(params.queryVec),\n params.providerModel,\n ...params.sourceFilterVec.params,\n params.limit,\n ) as Array<{\n id: string;\n path: string;\n start_line: number;\n end_line: number;\n text: string;\n source: SearchSource;\n dist: number;\n }>;\n return rows.map((row) => ({\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n score: 1 - row.dist,\n snippet: truncateUtf16Safe(row.text, params.snippetMaxChars),\n source: row.source,\n }));\n }\n\n const candidates = listChunks({\n db: params.db,\n providerModel: params.providerModel,\n sourceFilter: params.sourceFilterChunks,\n });\n const scored = candidates\n .map((chunk) => ({\n chunk,\n score: cosineSimilarity(params.queryVec, chunk.embedding),\n }))\n .filter((entry) => Number.isFinite(entry.score));\n return scored\n .slice().sort((a, b) => b.score - a.score)\n .slice(0, params.limit)\n .map((entry) => ({\n id: entry.chunk.id,\n path: entry.chunk.path,\n startLine: entry.chunk.startLine,\n endLine: entry.chunk.endLine,\n score: entry.score,\n snippet: truncateUtf16Safe(entry.chunk.text, params.snippetMaxChars),\n source: entry.chunk.source,\n }));\n}\n\nexport function listChunks(params: {\n db: DatabaseSync;\n providerModel: string;\n sourceFilter: { sql: string; params: SearchSource[] };\n}): Array<{\n id: string;\n path: string;\n startLine: number;\n endLine: number;\n text: string;\n embedding: number[];\n source: SearchSource;\n}> {\n const rows = params.db\n .prepare(\n `SELECT id, path, start_line, end_line, text, embedding, source\\n` +\n ` FROM chunks\\n` +\n ` WHERE model = ?${params.sourceFilter.sql}`,\n )\n .all(params.providerModel, ...params.sourceFilter.params) as Array<{\n id: string;\n path: string;\n start_line: number;\n end_line: number;\n text: string;\n embedding: string;\n source: SearchSource;\n }>;\n\n return rows.map((row) => ({\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n text: row.text,\n embedding: parseEmbedding(row.embedding),\n source: row.source,\n }));\n}\n\nexport async function searchKeyword(params: {\n db: DatabaseSync;\n ftsTable: string;\n providerModel: string | undefined;\n query: string;\n limit: number;\n snippetMaxChars: number;\n sourceFilter: { sql: string; params: SearchSource[] };\n buildFtsQuery: (raw: string) => string | null;\n bm25RankToScore: (rank: number) => number;\n}): Promise<Array<SearchRowResult & { textScore: number }>> {\n if (params.limit <= 0) {\n return [];\n }\n const ftsQuery = params.buildFtsQuery(params.query);\n if (!ftsQuery) {\n return [];\n }\n\n const modelClause = params.providerModel ? \" AND model = ?\" : \"\";\n const modelParams = params.providerModel ? [params.providerModel] : [];\n\n const rows = params.db\n .prepare(\n `SELECT id, path, source, start_line, end_line, text,\\n` +\n ` bm25(${params.ftsTable}) AS rank\\n` +\n ` FROM ${params.ftsTable}\\n` +\n ` WHERE ${params.ftsTable} MATCH ?${modelClause}${params.sourceFilter.sql}\\n` +\n ` ORDER BY rank ASC\\n` +\n ` LIMIT ?`,\n )\n .all(ftsQuery, ...modelParams, ...params.sourceFilter.params, params.limit) as Array<{\n id: string;\n path: string;\n source: SearchSource;\n start_line: number;\n end_line: number;\n text: string;\n rank: number;\n }>;\n\n return rows.map((row) => {\n const textScore = params.bm25RankToScore(row.rank);\n return {\n id: row.id,\n path: row.path,\n startLine: row.start_line,\n endLine: row.end_line,\n score: textScore,\n textScore,\n snippet: truncateUtf16Safe(row.text, params.snippetMaxChars),\n source: row.source,\n };\n });\n}\n","import { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\n\nexport function requireNodeSqlite(): typeof import(\"node:sqlite\") {\n try {\n return require(\"node:sqlite\") as typeof import(\"node:sqlite\");\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `SQLite support is unavailable in this Node runtime (missing node:sqlite). ${message}`,\n { cause: err },\n );\n }\n}\n","export type MemorySearchConfig = {\n chunkTokens: number;\n chunkOverlap: number;\n maxResults: number;\n minScore: number;\n experimental: {\n sessionMemory: boolean;\n };\n sources: Array<\"memory\" | \"sessions\">;\n store: {\n vector: {\n enabled: boolean;\n extensionPath?: string;\n };\n };\n hybrid: {\n enabled: boolean;\n vectorWeight: number;\n textWeight: number;\n candidateMultiplier: number;\n mmr: {\n enabled: boolean;\n lambda: number;\n };\n temporalDecay: {\n enabled: boolean;\n halfLifeDays: number;\n };\n };\n cache: {\n enabled: boolean;\n maxEntries?: number;\n };\n sync: {\n onSessionStart: boolean;\n onSearch: boolean;\n watch: boolean;\n watchDebounceMs: number;\n sessions: {\n deltaBytes: number;\n deltaMessages: number;\n };\n };\n citations: \"off\" | \"auto\" | \"on\";\n};\n\nexport const DEFAULT_MEMORY_SEARCH_CONFIG: MemorySearchConfig = {\n chunkTokens: 400,\n chunkOverlap: 80,\n maxResults: 6,\n minScore: 0.35,\n experimental: {\n sessionMemory: false,\n },\n sources: [\"memory\"],\n store: {\n vector: {\n enabled: true,\n },\n },\n hybrid: {\n enabled: true,\n vectorWeight: 0.7,\n textWeight: 0.3,\n candidateMultiplier: 4,\n mmr: {\n enabled: false,\n lambda: 0.7,\n },\n temporalDecay: {\n enabled: false,\n halfLifeDays: 30,\n },\n },\n cache: {\n enabled: true,\n maxEntries: 50000,\n },\n sync: {\n onSessionStart: true,\n onSearch: true,\n watch: true,\n watchDebounceMs: 1500,\n sessions: {\n deltaBytes: 100_000,\n deltaMessages: 50,\n },\n },\n citations: \"auto\",\n};\n","import type { DatabaseSync } from \"node:sqlite\";\n\nexport async function loadSqliteVecExtension(params: {\n db: DatabaseSync;\n extensionPath?: string;\n}): Promise<{ ok: boolean; extensionPath?: string; error?: string }> {\n try {\n const sqliteVec = await import(\"sqlite-vec\");\n const resolvedPath = params.extensionPath?.trim() ? params.extensionPath.trim() : undefined;\n const extensionPath = resolvedPath ?? sqliteVec.getLoadablePath();\n\n params.db.enableLoadExtension(true);\n if (resolvedPath) {\n params.db.loadExtension(extensionPath);\n } else {\n sqliteVec.load(params.db);\n }\n\n return { ok: true, extensionPath };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { ok: false, error: message };\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { isFileMissingError } from \"./fs-utils.js\";\nimport { hashText } from \"./internal.js\";\nimport { sessionsDir } from \"../session/session.js\";\n\nexport type SessionFileEntry = {\n path: string;\n absPath: string;\n mtimeMs: number;\n size: number;\n hash: string;\n content: string;\n lineMap?: number[];\n};\n\nexport function sessionPathForFile(dataDir: string, absPath: string): string {\n const root = sessionsDir(dataDir);\n return path.relative(root, absPath).replace(/\\\\/g, \"/\");\n}\n\nexport async function listSessionFilesForAgent(dataDir: string): Promise<string[]> {\n const root = sessionsDir(dataDir);\n try {\n const entries = await fs.readdir(root, { withFileTypes: true });\n const files: string[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory()) {\n continue;\n }\n const transcript = path.join(root, entry.name, \"transcript.jsonl\");\n try {\n const stat = await fs.stat(transcript);\n if (stat.isFile()) {\n files.push(transcript);\n }\n } catch {}\n }\n return files;\n } catch (err) {\n if (isFileMissingError(err)) {\n return [];\n }\n throw err;\n }\n}\n\nfunction stringifyContent(raw: unknown): string {\n if (typeof raw === \"string\") {\n return raw;\n }\n if (Array.isArray(raw)) {\n return raw\n .map((item) => {\n if (typeof item === \"string\") {\n return item;\n }\n if (item && typeof item === \"object\" && \"text\" in item) {\n return String((item as { text?: unknown }).text ?? \"\");\n }\n return \"\";\n })\n .filter(Boolean)\n .join(\" \");\n }\n return raw ? String(raw) : \"\";\n}\n\nexport async function buildSessionEntry(dataDir: string, absPath: string): Promise<SessionFileEntry | null> {\n let stat;\n try {\n stat = await fs.stat(absPath);\n } catch (err) {\n if (isFileMissingError(err)) {\n return null;\n }\n throw err;\n }\n let content: string;\n try {\n content = await fs.readFile(absPath, \"utf-8\");\n } catch (err) {\n if (isFileMissingError(err)) {\n return null;\n }\n throw err;\n }\n\n const lines: string[] = [];\n const lineMap: number[] = [];\n const rawLines = content.split(\"\\n\");\n for (let i = 0; i < rawLines.length; i += 1) {\n const raw = rawLines[i];\n const trimmed = raw?.trim();\n if (!trimmed) {\n continue;\n }\n try {\n const parsed = JSON.parse(trimmed) as { role?: string; content?: unknown };\n const role = parsed.role ?? \"unknown\";\n const text = stringifyContent(parsed.content);\n if (!text) {\n continue;\n }\n const entryLines = text.split(\"\\n\");\n for (const entryLine of entryLines) {\n lines.push(`[${role}] ${entryLine}`);\n lineMap.push(i + 1);\n }\n } catch {\n // skip malformed lines\n }\n }\n\n const flattened = lines.join(\"\\n\");\n const hash = hashText(flattened);\n\n return {\n path: path.join(\"sessions\", sessionPathForFile(dataDir, absPath)).replace(/\\\\/g, \"/\"),\n absPath,\n mtimeMs: stat.mtimeMs,\n size: stat.size,\n hash,\n content: flattened,\n lineMap,\n };\n}\n","import fs from \"node:fs/promises\";\nimport fsSync from \"node:fs\";\nimport path from \"node:path\";\nimport type { DatabaseSync } from \"node:sqlite\";\nimport { createMockEmbeddingProvider, type EmbeddingProvider } from \"./embeddings.js\";\nimport { isFileMissingError, statRegularFile } from \"./fs-utils.js\";\nimport {\n buildFileEntry,\n chunkMarkdown,\n ensureDir,\n hashText,\n isMemoryPath,\n listMemoryFiles,\n parseEmbedding,\n remapChunkLines,\n} from \"./internal.js\";\nimport { bm25RankToScore, buildFtsQuery, mergeHybridResults } from \"./hybrid.js\";\nimport { ensureMemoryIndexSchema } from \"./memory-schema.js\";\nimport { searchKeyword, searchVector } from \"./manager-search.js\";\nimport { requireNodeSqlite } from \"./sqlite.js\";\nimport { DEFAULT_MEMORY_SEARCH_CONFIG, type MemorySearchConfig } from \"./config.js\";\nimport { loadSqliteVecExtension } from \"./sqlite-vec.js\";\nimport { buildSessionEntry, listSessionFilesForAgent } from \"./session-files.js\";\n\nexport type MemorySearchResult = {\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: \"memory\" | \"sessions\";\n citation?: string;\n};\n\nexport type MemoryProviderStatus = {\n backend: \"builtin\";\n provider: string;\n model?: string;\n files?: number;\n chunks?: number;\n dirty?: boolean;\n workspaceDir?: string;\n dbPath?: string;\n sources?: Array<\"memory\" | \"sessions\">;\n sourceCounts?: Array<{ source: \"memory\" | \"sessions\"; files: number; chunks: number }>;\n cache?: { enabled: boolean; entries?: number; maxEntries?: number };\n fts?: { enabled: boolean; available: boolean; error?: string };\n vector?: {\n enabled: boolean;\n available?: boolean;\n extensionPath?: string;\n loadError?: string;\n dims?: number;\n };\n custom?: Record<string, unknown>;\n};\n\nconst SNIPPET_MAX_CHARS = 700;\nconst VECTOR_TABLE = \"chunks_vec\";\nconst FTS_TABLE = \"chunks_fts\";\nconst EMBEDDING_CACHE_TABLE = \"embedding_cache\";\nconst META_KEY = \"memory_index_meta_v1\";\nconst VECTOR_LOAD_TIMEOUT_MS = 30_000;\n\ntype MemoryIndexMeta = {\n model: string;\n provider: string;\n providerKey?: string;\n chunkTokens: number;\n chunkOverlap: number;\n vectorDims?: number;\n};\n\nconst MANAGER_CACHE = new Map<string, MemoryIndexManager>();\n\nfunction resolveConfig(\n base: MemorySearchConfig,\n override?: Partial<MemorySearchConfig>,\n): MemorySearchConfig {\n const config: MemorySearchConfig = {\n ...base,\n ...override,\n hybrid: { ...base.hybrid, ...(override?.hybrid ?? {}) },\n cache: { ...base.cache, ...(override?.cache ?? {}) },\n sync: { ...base.sync, ...(override?.sync ?? {}) },\n experimental: { ...base.experimental, ...(override?.experimental ?? {}) },\n sources: override?.sources ?? base.sources,\n store: {\n ...base.store,\n ...(override?.store ?? {}),\n vector: { ...base.store.vector, ...(override?.store?.vector ?? {}) },\n },\n };\n if (config.experimental.sessionMemory && !config.sources.includes(\"sessions\")) {\n config.sources = [...config.sources, \"sessions\"];\n }\n return config;\n}\n\nexport class MemoryIndexManager {\n private readonly dataDir: string;\n private readonly memoryRoot: string;\n private readonly storePath: string;\n private readonly config: MemorySearchConfig;\n private provider: EmbeddingProvider;\n private providerKey: string;\n private db: DatabaseSync;\n private dirty = true;\n private ftsAvailable = false;\n private ftsError?: string;\n private vector = {\n enabled: true,\n available: null as boolean | null,\n extensionPath: undefined as string | undefined,\n loadError: undefined as string | undefined,\n dims: undefined as number | undefined,\n };\n private vectorReady: Promise<boolean> | null = null;\n private watchers: fsSync.FSWatcher[] = [];\n private watchTimer: NodeJS.Timeout | null = null;\n private sessionWatchTimer: NodeJS.Timeout | null = null;\n private sessionsDirty = false;\n private sessionsDirtyFiles = new Set<string>();\n private sessionPendingFiles = new Set<string>();\n private sessionDeltas = new Map<\n string,\n { lastSize: number; pendingBytes: number; pendingMessages: number }\n >();\n\n static get(dataDir: string, config?: Partial<MemorySearchConfig>): MemoryIndexManager {\n const memoryRoot = path.join(dataDir, \".pingclaw\", \"memory\");\n const existing = MANAGER_CACHE.get(memoryRoot);\n if (existing) {\n if (config) {\n existing.applyConfig(config);\n }\n return existing;\n }\n const manager = new MemoryIndexManager(dataDir, memoryRoot, config);\n MANAGER_CACHE.set(memoryRoot, manager);\n return manager;\n }\n\n private constructor(dataDir: string, memoryRoot: string, config?: Partial<MemorySearchConfig>) {\n this.dataDir = dataDir;\n this.memoryRoot = memoryRoot;\n this.storePath = path.join(memoryRoot, \".index.sqlite\");\n this.config = resolveConfig(DEFAULT_MEMORY_SEARCH_CONFIG, config);\n this.provider = createMockEmbeddingProvider();\n this.providerKey = this.computeProviderKey();\n this.vector.enabled = this.config.store.vector.enabled;\n this.vector.extensionPath = this.config.store.vector.extensionPath;\n this.db = this.openDatabase();\n this.ensureSchema();\n this.ensureWatcher();\n this.ensureSessionListener();\n this.dirty = true;\n }\n\n private applyConfig(config: Partial<MemorySearchConfig>): void {\n (this as any).config = resolveConfig(this.config, config);\n this.vector.enabled = this.config.store.vector.enabled;\n this.vector.extensionPath = this.config.store.vector.extensionPath;\n this.ensureWatcher();\n this.ensureSessionListener();\n }\n\n warmSession(): void {\n if (!this.config.sync.onSessionStart) {\n return;\n }\n void this.sync({ reason: \"session-start\" }).catch(() => {});\n }\n\n noteSessionUpdate(sessionFile: string): void {\n this.scheduleSessionDirty(sessionFile);\n }\n\n status(): MemoryProviderStatus {\n const sourceFilter = this.buildSourceFilter();\n const files = this.db\n .prepare(`SELECT COUNT(*) as c FROM files WHERE 1=1${sourceFilter.sql}`)\n .get(...sourceFilter.params) as { c: number };\n const chunks = this.db\n .prepare(`SELECT COUNT(*) as c FROM chunks WHERE 1=1${sourceFilter.sql}`)\n .get(...sourceFilter.params) as { c: number };\n const sourceCounts = (() => {\n const sources = Array.from(this.config.sources);\n if (sources.length === 0) {\n return [];\n }\n const bySource = new Map<\"memory\" | \"sessions\", { files: number; chunks: number }>();\n for (const source of sources) {\n bySource.set(source, { files: 0, chunks: 0 });\n }\n const fileRows = this.db\n .prepare(\n `SELECT source, COUNT(*) as c FROM files WHERE 1=1${sourceFilter.sql} GROUP BY source`,\n )\n .all(...sourceFilter.params) as Array<{ source: \"memory\" | \"sessions\"; c: number }>;\n for (const row of fileRows) {\n const entry = bySource.get(row.source) ?? { files: 0, chunks: 0 };\n entry.files = row.c ?? 0;\n bySource.set(row.source, entry);\n }\n const chunkRows = this.db\n .prepare(\n `SELECT source, COUNT(*) as c FROM chunks WHERE 1=1${sourceFilter.sql} GROUP BY source`,\n )\n .all(...sourceFilter.params) as Array<{ source: \"memory\" | \"sessions\"; c: number }>;\n for (const row of chunkRows) {\n const entry = bySource.get(row.source) ?? { files: 0, chunks: 0 };\n entry.chunks = row.c ?? 0;\n bySource.set(row.source, entry);\n }\n return sources.map((source) => Object.assign({ source }, bySource.get(source)!));\n })();\n\n const searchMode = this.provider ? \"hybrid\" : \"fts-only\";\n const cacheEntries = this.config.cache.enabled\n ? (\n this.db.prepare(`SELECT COUNT(*) as c FROM ${EMBEDDING_CACHE_TABLE}`).get() as\n | { c: number }\n | undefined\n )?.c ?? 0\n : undefined;\n\n return {\n backend: \"builtin\",\n files: files?.c ?? 0,\n chunks: chunks?.c ?? 0,\n dirty: this.dirty || this.sessionsDirty,\n workspaceDir: this.memoryRoot,\n dbPath: this.storePath,\n provider: this.provider.id,\n model: this.provider.model,\n sources: Array.from(this.config.sources),\n sourceCounts,\n cache: this.config.cache.enabled\n ? { enabled: true, entries: cacheEntries, maxEntries: this.config.cache.maxEntries }\n : { enabled: false, maxEntries: this.config.cache.maxEntries },\n fts: {\n enabled: this.config.hybrid.enabled,\n available: this.ftsAvailable,\n error: this.ftsError,\n },\n vector: {\n enabled: this.vector.enabled,\n available: this.vector.available ?? undefined,\n extensionPath: this.vector.extensionPath,\n loadError: this.vector.loadError,\n dims: this.vector.dims,\n },\n custom: { searchMode },\n };\n }\n\n async probeEmbeddingAvailability(): Promise<{ ok: boolean; error?: string }> {\n try {\n await this.provider.embedBatch([\"ping\"]);\n return { ok: true };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { ok: false, error: message };\n }\n }\n\n async probeVectorAvailability(): Promise<boolean> {\n if (!this.vector.enabled) {\n return false;\n }\n return await this.ensureVectorReady();\n }\n\n async search(query: string): Promise<MemorySearchResult[]> {\n const cleaned = query.trim();\n if (!cleaned) {\n return [];\n }\n\n const meta = this.readMeta();\n if (!meta) {\n await this.sync({ reason: \"boot\" });\n } else if (this.config.sync.onSearch && (this.dirty || this.sessionsDirty)) {\n void this.sync({ reason: \"search\" }).catch(() => {});\n }\n\n const hybrid = this.config.hybrid;\n const candidates = Math.min(\n 200,\n Math.max(1, Math.floor(this.config.maxResults * hybrid.candidateMultiplier)),\n );\n\n const keywordResults =\n hybrid.enabled && this.ftsAvailable\n ? await this.searchKeyword(cleaned, candidates).catch(() => [])\n : [];\n\n const queryVec = await this.provider.embedQuery(cleaned);\n const hasVector = queryVec.some((v) => v !== 0);\n const vectorResults = hasVector\n ? await this.searchVector(queryVec, candidates).catch(() => [])\n : [];\n\n if (!hybrid.enabled || !this.ftsAvailable) {\n return vectorResults\n .filter((entry) => entry.score >= this.config.minScore)\n .slice(0, this.config.maxResults);\n }\n\n const merged = await mergeHybridResults({\n vector: vectorResults.map((r) => ({\n id: `${r.path}:${r.startLine}:${r.endLine}:${r.source}`,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n vectorScore: r.score,\n })),\n keyword: keywordResults.map((r) => ({\n id: `${r.path}:${r.startLine}:${r.endLine}:${r.source}`,\n path: r.path,\n startLine: r.startLine,\n endLine: r.endLine,\n source: r.source,\n snippet: r.snippet,\n textScore: r.textScore,\n })),\n vectorWeight: hybrid.vectorWeight,\n textWeight: hybrid.textWeight,\n mmr: hybrid.mmr,\n temporalDecay: hybrid.temporalDecay,\n memoryRoot: this.memoryRoot,\n });\n\n const strict = merged.filter((entry) => entry.score >= this.config.minScore) as Array<{\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: \"memory\" | \"sessions\";\n }>;\n if (strict.length > 0 || keywordResults.length === 0) {\n return this.decorateCitations(strict.slice(0, this.config.maxResults)) as any;\n }\n\n const relaxedMinScore = Math.min(this.config.minScore, hybrid.textWeight);\n const relaxedResults = merged\n .filter((entry) => entry.score >= relaxedMinScore)\n .slice(0, this.config.maxResults) as Array<{\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n snippet: string;\n source: \"memory\" | \"sessions\";\n }>;\n return this.decorateCitations(relaxedResults) as any;\n }\n\n async readFile(params: { relPath: string; from?: number; lines?: number }) {\n const rawPath = params.relPath.trim();\n if (!rawPath) {\n throw new Error(\"path required\");\n }\n const absPath = path.isAbsolute(rawPath)\n ? path.resolve(rawPath)\n : path.resolve(this.memoryRoot, rawPath);\n const relPath = path.relative(this.memoryRoot, absPath).replace(/\\\\/g, \"/\");\n const inWorkspace =\n relPath.length > 0 && !relPath.startsWith(\"..\") && !path.isAbsolute(relPath);\n const allowed = inWorkspace && isMemoryPath(relPath);\n if (!allowed) {\n throw new Error(\"path required\");\n }\n if (!absPath.endsWith(\".md\")) {\n throw new Error(\"path required\");\n }\n const statResult = await statRegularFile(absPath);\n if (statResult.missing) {\n return { text: \"\", path: relPath };\n }\n let content: string;\n try {\n content = await fs.readFile(absPath, \"utf-8\");\n } catch (err) {\n if (isFileMissingError(err)) {\n return { text: \"\", path: relPath };\n }\n throw err;\n }\n if (!params.from && !params.lines) {\n return { text: content, path: relPath };\n }\n const lines = content.split(\"\\n\");\n const start = Math.max(1, params.from ?? 1);\n const count = Math.max(1, params.lines ?? lines.length);\n const slice = lines.slice(start - 1, start - 1 + count);\n return { text: slice.join(\"\\n\"), path: relPath };\n }\n\n async appendToMemory(content: string): Promise<void> {\n const dir = this.memoryRoot;\n await fs.mkdir(dir, { recursive: true });\n const filePath = path.join(dir, \"MEMORY.md\");\n const entry = content.endsWith(\"\\n\") ? content : `${content}\\n`;\n await fs.appendFile(filePath, entry, \"utf-8\");\n this.dirty = true;\n }\n\n private openDatabase(): DatabaseSync {\n ensureDir(path.dirname(this.storePath));\n const { DatabaseSync } = requireNodeSqlite();\n return new DatabaseSync(this.storePath, { allowExtension: this.vector.enabled });\n }\n\n private ensureSchema(): void {\n const result = ensureMemoryIndexSchema({\n db: this.db,\n embeddingCacheTable: EMBEDDING_CACHE_TABLE,\n ftsTable: FTS_TABLE,\n ftsEnabled: this.config.hybrid.enabled,\n });\n this.ftsAvailable = result.ftsAvailable;\n if (result.ftsError) {\n this.ftsError = result.ftsError;\n }\n }\n\n private async ensureVectorReady(dimensions?: number): Promise<boolean> {\n if (!this.vector.enabled) {\n return false;\n }\n if (!this.vectorReady) {\n this.vectorReady = this.withTimeout(\n this.loadVectorExtension(),\n VECTOR_LOAD_TIMEOUT_MS,\n `sqlite-vec load timed out after ${Math.round(VECTOR_LOAD_TIMEOUT_MS / 1000)}s`,\n );\n }\n let ready = false;\n try {\n ready = (await this.vectorReady) || false;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.vector.available = false;\n this.vector.loadError = message;\n this.vectorReady = null;\n return false;\n }\n if (ready && typeof dimensions === \"number\" && dimensions > 0) {\n this.ensureVectorTable(dimensions);\n }\n return ready;\n }\n\n private async loadVectorExtension(): Promise<boolean> {\n if (this.vector.available !== null) {\n return this.vector.available;\n }\n if (!this.vector.enabled) {\n this.vector.available = false;\n return false;\n }\n try {\n const resolvedPath = this.vector.extensionPath?.trim()\n ? this.vector.extensionPath.trim()\n : undefined;\n const loaded = await loadSqliteVecExtension({ db: this.db, extensionPath: resolvedPath });\n if (!loaded.ok) {\n throw new Error(loaded.error ?? \"unknown sqlite-vec load error\");\n }\n this.vector.extensionPath = loaded.extensionPath;\n this.vector.available = true;\n return true;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.vector.available = false;\n this.vector.loadError = message;\n return false;\n }\n }\n\n private ensureVectorTable(dimensions: number): void {\n if (this.vector.dims === dimensions) {\n return;\n }\n if (this.vector.dims && this.vector.dims !== dimensions) {\n this.dropVectorTable();\n }\n this.db.exec(\n `CREATE VIRTUAL TABLE IF NOT EXISTS ${VECTOR_TABLE} USING vec0(\\n` +\n ` id TEXT PRIMARY KEY,\\n` +\n ` embedding FLOAT[${dimensions}]\\n` +\n `)`,\n );\n this.vector.dims = dimensions;\n }\n\n private dropVectorTable(): void {\n try {\n this.db.exec(`DROP TABLE IF EXISTS ${VECTOR_TABLE}`);\n } catch {}\n }\n\n private async withTimeout<T>(promise: Promise<T>, timeoutMs: number, message: string): Promise<T> {\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n return await promise;\n }\n let timer: NodeJS.Timeout | null = null;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(message)), timeoutMs);\n });\n try {\n return (await Promise.race([promise, timeoutPromise])) as T;\n } finally {\n if (timer) {\n clearTimeout(timer);\n }\n }\n }\n\n private ensureWatcher(): void {\n if (!this.config.sync.watch || this.watchers.length > 0) {\n return;\n }\n const watchTargets = [this.memoryRoot, path.join(this.memoryRoot, \"memory\")];\n const onChange = () => {\n this.dirty = true;\n this.scheduleWatchSync();\n };\n for (const target of watchTargets) {\n try {\n const watcher = fsSync.watch(target, { recursive: false }, onChange);\n this.watchers.push(watcher);\n } catch {\n // Ignore missing/unwatchable paths.\n }\n }\n }\n\n private scheduleWatchSync(): void {\n if (!this.config.sync.watch) {\n return;\n }\n if (this.watchTimer) {\n clearTimeout(this.watchTimer);\n }\n this.watchTimer = setTimeout(() => {\n this.watchTimer = null;\n void this.sync({ reason: \"watch\" }).catch(() => {});\n }, this.config.sync.watchDebounceMs);\n }\n\n private ensureSessionListener(): void {\n if (!this.config.experimental.sessionMemory) {\n return;\n }\n const sessionsRoot = path.join(this.dataDir, \".pingclaw\", \"sessions\");\n try {\n const watcher = fsSync.watch(sessionsRoot, { recursive: true }, (_event, filename) => {\n if (!filename || !filename.endsWith(\"transcript.jsonl\")) {\n return;\n }\n const abs = path.join(sessionsRoot, filename);\n this.scheduleSessionDirty(abs);\n });\n this.watchers.push(watcher);\n } catch {\n // Ignore missing/unwatchable sessions dir.\n }\n }\n\n private scheduleSessionDirty(sessionFile: string) {\n if (!this.config.experimental.sessionMemory) {\n return;\n }\n this.sessionPendingFiles.add(sessionFile);\n if (this.sessionWatchTimer) {\n return;\n }\n this.sessionWatchTimer = setTimeout(() => {\n this.sessionWatchTimer = null;\n void this.processSessionDeltaBatch().catch(() => {});\n }, 5000);\n }\n\n private async processSessionDeltaBatch(): Promise<void> {\n if (this.sessionPendingFiles.size === 0) {\n return;\n }\n const pending = Array.from(this.sessionPendingFiles);\n this.sessionPendingFiles.clear();\n let shouldSync = false;\n for (const sessionFile of pending) {\n const delta = await this.updateSessionDelta(sessionFile);\n if (!delta) {\n continue;\n }\n const bytesThreshold = delta.deltaBytes;\n const messagesThreshold = delta.deltaMessages;\n const bytesHit =\n bytesThreshold <= 0 ? delta.pendingBytes > 0 : delta.pendingBytes >= bytesThreshold;\n const messagesHit =\n messagesThreshold <= 0\n ? delta.pendingMessages > 0\n : delta.pendingMessages >= messagesThreshold;\n if (!bytesHit && !messagesHit) {\n continue;\n }\n this.sessionsDirtyFiles.add(sessionFile);\n this.sessionsDirty = true;\n delta.pendingBytes =\n bytesThreshold > 0 ? Math.max(0, delta.pendingBytes - bytesThreshold) : 0;\n delta.pendingMessages =\n messagesThreshold > 0 ? Math.max(0, delta.pendingMessages - messagesThreshold) : 0;\n shouldSync = true;\n }\n if (shouldSync) {\n void this.sync({ reason: \"session-delta\" }).catch(() => {});\n }\n }\n\n private async updateSessionDelta(sessionFile: string): Promise<{\n deltaBytes: number;\n deltaMessages: number;\n pendingBytes: number;\n pendingMessages: number;\n } | null> {\n const thresholds = this.config.sync.sessions;\n if (!thresholds) {\n return null;\n }\n let stat: { size: number };\n try {\n stat = await fs.stat(sessionFile);\n } catch {\n return null;\n }\n const size = stat.size;\n let state = this.sessionDeltas.get(sessionFile);\n if (!state) {\n state = { lastSize: 0, pendingBytes: 0, pendingMessages: 0 };\n this.sessionDeltas.set(sessionFile, state);\n }\n const deltaBytes = Math.max(0, size - state.lastSize);\n if (deltaBytes === 0 && size === state.lastSize) {\n return {\n deltaBytes: thresholds.deltaBytes,\n deltaMessages: thresholds.deltaMessages,\n pendingBytes: state.pendingBytes,\n pendingMessages: state.pendingMessages,\n };\n }\n if (size < state.lastSize) {\n state.lastSize = size;\n state.pendingBytes += size;\n const shouldCountMessages =\n thresholds.deltaMessages > 0 &&\n (thresholds.deltaBytes <= 0 || state.pendingBytes < thresholds.deltaBytes);\n if (shouldCountMessages) {\n state.pendingMessages += await this.countNewlines(sessionFile, 0, size);\n }\n } else {\n state.pendingBytes += deltaBytes;\n const shouldCountMessages =\n thresholds.deltaMessages > 0 &&\n (thresholds.deltaBytes <= 0 || state.pendingBytes < thresholds.deltaBytes);\n if (shouldCountMessages) {\n state.pendingMessages += await this.countNewlines(sessionFile, state.lastSize, size);\n }\n state.lastSize = size;\n }\n this.sessionDeltas.set(sessionFile, state);\n return {\n deltaBytes: thresholds.deltaBytes,\n deltaMessages: thresholds.deltaMessages,\n pendingBytes: state.pendingBytes,\n pendingMessages: state.pendingMessages,\n };\n }\n\n private async countNewlines(absPath: string, start: number, end: number): Promise<number> {\n if (end <= start) {\n return 0;\n }\n let handle;\n try {\n handle = await fs.open(absPath, \"r\");\n } catch {\n return 0;\n }\n try {\n let offset = start;\n let count = 0;\n const buffer = Buffer.alloc(64 * 1024);\n while (offset < end) {\n const toRead = Math.min(buffer.length, end - offset);\n const { bytesRead } = await handle.read(buffer, 0, toRead, offset);\n if (bytesRead <= 0) {\n break;\n }\n for (let i = 0; i < bytesRead; i += 1) {\n if (buffer[i] === 10) {\n count += 1;\n }\n }\n offset += bytesRead;\n }\n return count;\n } finally {\n await handle.close();\n }\n }\n\n private computeProviderKey(): string {\n return hashText(\n JSON.stringify({ provider: this.provider.id, model: this.provider.model }),\n );\n }\n\n private readMeta(): MemoryIndexMeta | null {\n const row = this.db.prepare(`SELECT value FROM meta WHERE key = ?`).get(META_KEY) as\n | { value: string }\n | undefined;\n if (!row?.value) {\n return null;\n }\n try {\n return JSON.parse(row.value) as MemoryIndexMeta;\n } catch {\n return null;\n }\n }\n\n private writeMeta(meta: MemoryIndexMeta): void {\n const value = JSON.stringify(meta);\n this.db\n .prepare(\n `INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value`,\n )\n .run(META_KEY, value);\n }\n\n private loadEmbeddingCache(hashes: string[]): Map<string, number[]> {\n if (!this.config.cache.enabled || hashes.length === 0) {\n return new Map();\n }\n const unique = Array.from(new Set(hashes.filter(Boolean)));\n if (unique.length === 0) {\n return new Map();\n }\n const out = new Map<string, number[]>();\n const baseParams = [this.provider.id, this.provider.model, this.providerKey];\n const batchSize = 400;\n for (let start = 0; start < unique.length; start += batchSize) {\n const batch = unique.slice(start, start + batchSize);\n const placeholders = batch.map(() => \"?\").join(\", \");\n const rows = this.db\n .prepare(\n `SELECT hash, embedding FROM ${EMBEDDING_CACHE_TABLE}\\n` +\n ` WHERE provider = ? AND model = ? AND provider_key = ? AND hash IN (${placeholders})`,\n )\n .all(...baseParams, ...batch) as Array<{ hash: string; embedding: string }>;\n for (const row of rows) {\n out.set(row.hash, parseEmbedding(row.embedding));\n }\n }\n return out;\n }\n\n private upsertEmbeddingCache(entries: Array<{ hash: string; embedding: number[] }>): void {\n if (!this.config.cache.enabled || entries.length === 0) {\n return;\n }\n const now = Date.now();\n const stmt = this.db.prepare(\n `INSERT INTO ${EMBEDDING_CACHE_TABLE} (provider, model, provider_key, hash, embedding, dims, updated_at)\\n` +\n ` VALUES (?, ?, ?, ?, ?, ?, ?)\\n` +\n ` ON CONFLICT(provider, model, provider_key, hash) DO UPDATE SET\\n` +\n ` embedding=excluded.embedding,\\n` +\n ` dims=excluded.dims,\\n` +\n ` updated_at=excluded.updated_at`,\n );\n for (const entry of entries) {\n const embedding = entry.embedding ?? [];\n stmt.run(\n this.provider.id,\n this.provider.model,\n this.providerKey,\n entry.hash,\n JSON.stringify(embedding),\n embedding.length,\n now,\n );\n }\n }\n\n private async embedChunks(chunks: { text: string; hash: string }[]): Promise<number[][]> {\n if (chunks.length === 0) {\n return [];\n }\n const cached = this.loadEmbeddingCache(chunks.map((chunk) => chunk.hash));\n const embeddings: number[][] = Array.from({ length: chunks.length }, () => []);\n const missing: Array<{ index: number; chunk: { text: string; hash: string } }> = [];\n\n for (let i = 0; i < chunks.length; i += 1) {\n const chunk = chunks[i];\n const hit = chunk?.hash ? cached.get(chunk.hash) : undefined;\n if (hit && hit.length > 0) {\n embeddings[i] = hit;\n } else if (chunk) {\n missing.push({ index: i, chunk });\n }\n }\n\n if (missing.length === 0) {\n return embeddings;\n }\n\n const batchEmbeddings = await this.provider.embedBatch(missing.map((m) => m.chunk.text));\n const toCache: Array<{ hash: string; embedding: number[] }> = [];\n for (let i = 0; i < missing.length; i += 1) {\n const item = missing[i];\n const embedding = batchEmbeddings[i] ?? [];\n embeddings[item.index] = embedding;\n toCache.push({ hash: item.chunk.hash, embedding });\n }\n this.upsertEmbeddingCache(toCache);\n return embeddings;\n }\n\n private async indexFile(\n entry: { path: string; absPath: string; hash: string; mtimeMs: number; size: number },\n options: { source: \"memory\" | \"sessions\"; content?: string; lineMap?: number[] },\n ) {\n const content = options.content ?? (await fs.readFile(entry.absPath, \"utf-8\"));\n const chunks = chunkMarkdown(content, {\n tokens: this.config.chunkTokens,\n overlap: this.config.chunkOverlap,\n }).filter((chunk) => chunk.text.trim().length > 0);\n if (options.source === \"sessions\") {\n remapChunkLines(chunks, options.lineMap);\n }\n\n const embeddings = await this.embedChunks(chunks);\n const sample = embeddings.find((embedding) => embedding.length > 0);\n const vectorReady = sample ? await this.ensureVectorReady(sample.length) : false;\n const now = Date.now();\n\n if (vectorReady) {\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`,\n )\n .run(entry.path, options.source);\n } catch {}\n }\n if (this.ftsAvailable) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(entry.path, options.source, this.provider.model);\n } catch {}\n }\n this.db\n .prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`)\n .run(entry.path, options.source);\n\n for (let i = 0; i < chunks.length; i += 1) {\n const chunk = chunks[i];\n const embedding = embeddings[i] ?? [];\n const id = hashText(\n `${options.source}:${entry.path}:${chunk.startLine}:${chunk.endLine}:${chunk.hash}:${this.provider.model}`,\n );\n this.db\n .prepare(\n `INSERT INTO chunks (id, path, source, start_line, end_line, hash, model, text, embedding, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n hash=excluded.hash,\n model=excluded.model,\n text=excluded.text,\n embedding=excluded.embedding,\n updated_at=excluded.updated_at`,\n )\n .run(\n id,\n entry.path,\n options.source,\n chunk.startLine,\n chunk.endLine,\n chunk.hash,\n this.provider.model,\n chunk.text,\n JSON.stringify(embedding),\n now,\n );\n if (vectorReady && embedding.length > 0) {\n try {\n this.db.prepare(`DELETE FROM ${VECTOR_TABLE} WHERE id = ?`).run(id);\n } catch {}\n this.db\n .prepare(`INSERT INTO ${VECTOR_TABLE} (id, embedding) VALUES (?, ?)`)\n .run(id, Buffer.from(new Float32Array(embedding).buffer));\n }\n if (this.ftsAvailable) {\n this.db\n .prepare(\n `INSERT INTO ${FTS_TABLE} (text, id, path, source, model, start_line, end_line)\\n` +\n ` VALUES (?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n chunk.text,\n id,\n entry.path,\n options.source,\n this.provider.model,\n chunk.startLine,\n chunk.endLine,\n );\n }\n }\n this.db\n .prepare(\n `INSERT INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(path) DO UPDATE SET\n source=excluded.source,\n hash=excluded.hash,\n mtime=excluded.mtime,\n size=excluded.size`,\n )\n .run(entry.path, options.source, entry.hash, entry.mtimeMs, entry.size);\n }\n\n private buildSourceFilter(): { sql: string; params: string[] } {\n const sources = this.config.sources;\n if (!sources.length) {\n return { sql: \"\", params: [] };\n }\n const placeholders = sources.map(() => \"?\").join(\", \");\n return { sql: ` AND source IN (${placeholders})`, params: sources };\n }\n\n private async searchVector(queryVec: number[], limit: number) {\n return await searchVector({\n db: this.db,\n vectorTable: VECTOR_TABLE,\n providerModel: this.provider.model,\n queryVec,\n limit,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n ensureVectorReady: async (dimensions) => await this.ensureVectorReady(dimensions),\n sourceFilterVec: this.buildSourceFilter(),\n sourceFilterChunks: this.buildSourceFilter(),\n });\n }\n\n private async searchKeyword(query: string, limit: number) {\n if (!this.ftsAvailable) {\n return [];\n }\n return await searchKeyword({\n db: this.db,\n ftsTable: FTS_TABLE,\n providerModel: this.provider.model,\n query,\n limit,\n snippetMaxChars: SNIPPET_MAX_CHARS,\n sourceFilter: this.buildSourceFilter(),\n buildFtsQuery: (raw) => buildFtsQuery(raw),\n bm25RankToScore,\n });\n }\n\n private resetIndex(): void {\n this.db.exec(`DELETE FROM files`);\n this.db.exec(`DELETE FROM chunks`);\n if (this.ftsAvailable) {\n try {\n this.db.exec(`DELETE FROM ${FTS_TABLE}`);\n } catch {}\n }\n this.dropVectorTable();\n this.vector.dims = undefined;\n this.sessionsDirtyFiles.clear();\n }\n\n async sync(params?: { reason?: string }): Promise<void> {\n const meta = this.readMeta();\n const needsFullReindex =\n !meta ||\n meta.model !== this.provider.model ||\n meta.provider !== this.provider.id ||\n meta.providerKey !== this.providerKey ||\n meta.chunkTokens !== this.config.chunkTokens ||\n meta.chunkOverlap !== this.config.chunkOverlap ||\n (this.vector.available && !meta?.vectorDims);\n\n if (needsFullReindex) {\n this.resetIndex();\n }\n\n const files = await listMemoryFiles(this.memoryRoot);\n const fileEntries = (\n await Promise.all(files.map(async (file) => buildFileEntry(file, this.memoryRoot)))\n ).filter((entry): entry is NonNullable<typeof entry> => entry !== null);\n\n const activePaths = new Set(fileEntries.map((entry) => entry.path));\n\n const tasks = fileEntries.map((entry) => async () => {\n const record = this.db\n .prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`)\n .get(entry.path, \"memory\") as { hash: string } | undefined;\n if (!needsFullReindex && record?.hash === entry.hash) {\n return;\n }\n await this.indexFile(entry, { source: \"memory\" });\n });\n\n for (const task of tasks) {\n await task();\n }\n\n const staleRows = this.db\n .prepare(`SELECT path FROM files WHERE source = ?`)\n .all(\"memory\") as Array<{ path: string }>;\n for (const stale of staleRows) {\n if (activePaths.has(stale.path)) {\n continue;\n }\n this.db.prepare(`DELETE FROM files WHERE path = ? AND source = ?`).run(stale.path, \"memory\");\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`,\n )\n .run(stale.path, \"memory\");\n } catch {}\n this.db.prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`).run(stale.path, \"memory\");\n if (this.ftsAvailable) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(stale.path, \"memory\", this.provider.model);\n } catch {}\n }\n }\n\n if (this.config.experimental.sessionMemory && (needsFullReindex || this.sessionsDirty)) {\n await this.syncSessionFiles(needsFullReindex);\n }\n\n this.writeMeta({\n model: this.provider.model,\n provider: this.provider.id,\n providerKey: this.providerKey,\n chunkTokens: this.config.chunkTokens,\n chunkOverlap: this.config.chunkOverlap,\n ...(this.vector.available && this.vector.dims ? { vectorDims: this.vector.dims } : {}),\n });\n\n this.dirty = false;\n }\n\n private async syncSessionFiles(needsFullReindex: boolean): Promise<void> {\n const files = await listSessionFilesForAgent(this.dataDir);\n const entries = (\n await Promise.all(files.map(async (absPath) => buildSessionEntry(this.dataDir, absPath)))\n ).filter((entry): entry is NonNullable<typeof entry> => entry !== null);\n const activePaths = new Set(entries.map((entry) => entry.path));\n const indexAll = needsFullReindex || this.sessionsDirtyFiles.size === 0;\n\n for (const entry of entries) {\n if (!indexAll && !this.sessionsDirtyFiles.has(entry.absPath)) {\n continue;\n }\n const record = this.db\n .prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`)\n .get(entry.path, \"sessions\") as { hash: string } | undefined;\n if (!needsFullReindex && record?.hash === entry.hash) {\n this.resetSessionDelta(entry.absPath, entry.size);\n continue;\n }\n await this.indexFile(entry, {\n source: \"sessions\",\n content: entry.content,\n lineMap: entry.lineMap,\n });\n this.resetSessionDelta(entry.absPath, entry.size);\n }\n\n const staleRows = this.db\n .prepare(`SELECT path FROM files WHERE source = ?`)\n .all(\"sessions\") as Array<{ path: string }>;\n for (const stale of staleRows) {\n if (activePaths.has(stale.path)) {\n continue;\n }\n this.db\n .prepare(`DELETE FROM files WHERE path = ? AND source = ?`)\n .run(stale.path, \"sessions\");\n try {\n this.db\n .prepare(\n `DELETE FROM ${VECTOR_TABLE} WHERE id IN (SELECT id FROM chunks WHERE path = ? AND source = ?)`,\n )\n .run(stale.path, \"sessions\");\n } catch {}\n this.db\n .prepare(`DELETE FROM chunks WHERE path = ? AND source = ?`)\n .run(stale.path, \"sessions\");\n if (this.ftsAvailable) {\n try {\n this.db\n .prepare(`DELETE FROM ${FTS_TABLE} WHERE path = ? AND source = ? AND model = ?`)\n .run(stale.path, \"sessions\", this.provider.model);\n } catch {}\n }\n }\n\n this.sessionsDirty = false;\n this.sessionsDirtyFiles.clear();\n }\n\n private resetSessionDelta(absPath: string, size: number): void {\n const state = this.sessionDeltas.get(absPath);\n if (!state) {\n return;\n }\n state.lastSize = size;\n state.pendingBytes = 0;\n state.pendingMessages = 0;\n }\n\n private decorateCitations(results: Array<MemorySearchResult>): Array<MemorySearchResult> {\n if (this.config.citations === \"off\") {\n return results;\n }\n return results.map((entry) => {\n const citation = `Source: ${entry.path}#L${entry.startLine}-L${entry.endLine}`;\n if (this.config.citations === \"on\") {\n return { ...entry, citation, snippet: `${entry.snippet}\\n\\n${citation}` };\n }\n return { ...entry, citation };\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/message.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { UserEntry, UserMessage, UserMessagePart } from "./types.js";
|
|
2
|
-
export declare function createTextMessage(text: string): UserMessage;
|
|
3
|
-
export declare function isTextPart(part: UserMessagePart): part is Extract<UserMessagePart, {
|
|
4
|
-
type: "text";
|
|
5
|
-
}>;
|
|
6
|
-
export declare function messageToPlainText(message: UserMessage): string;
|
|
7
|
-
export declare function messageToTranscriptText(message: UserMessage): string;
|
|
8
|
-
export declare function hasSlashCommandPrefix(message: UserMessage): boolean;
|
|
9
|
-
export declare function replaceMessageFirstText(message: UserMessage, text: string): UserMessage;
|
|
10
|
-
export declare function userEntryToMessage(entry: UserEntry): UserMessage;
|
|
11
|
-
//# sourceMappingURL=message.d.ts.map
|
package/dist/message.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../src/message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAE3D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAEpG;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAM/D;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAWpE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAGnE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CASvF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAKhE"}
|
package/dist/message.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
export function createTextMessage(text) {
|
|
2
|
-
return [{ type: "text", text }];
|
|
3
|
-
}
|
|
4
|
-
export function isTextPart(part) {
|
|
5
|
-
return part.type === "text";
|
|
6
|
-
}
|
|
7
|
-
export function messageToPlainText(message) {
|
|
8
|
-
return message
|
|
9
|
-
.filter(isTextPart)
|
|
10
|
-
.map((part) => part.text)
|
|
11
|
-
.join("\n\n")
|
|
12
|
-
.trim();
|
|
13
|
-
}
|
|
14
|
-
export function messageToTranscriptText(message) {
|
|
15
|
-
const rendered = message.map((part, index) => {
|
|
16
|
-
if (part.type === "text") {
|
|
17
|
-
return part.text.trim();
|
|
18
|
-
}
|
|
19
|
-
const prefix = message.filter((candidate) => candidate.type === "image_url").length > 1
|
|
20
|
-
? `[image ${message.slice(0, index + 1).filter((candidate) => candidate.type === "image_url").length}: `
|
|
21
|
-
: "[image: ";
|
|
22
|
-
return `${prefix}${part.image_url.url}]`;
|
|
23
|
-
}).filter((part) => part.length > 0);
|
|
24
|
-
return rendered.join("\n\n").trim();
|
|
25
|
-
}
|
|
26
|
-
export function hasSlashCommandPrefix(message) {
|
|
27
|
-
const first = message[0];
|
|
28
|
-
return first?.type === "text" && first.text.trimStart().startsWith("/");
|
|
29
|
-
}
|
|
30
|
-
export function replaceMessageFirstText(message, text) {
|
|
31
|
-
if (message.length === 0) {
|
|
32
|
-
return createTextMessage(text);
|
|
33
|
-
}
|
|
34
|
-
const [first, ...rest] = message;
|
|
35
|
-
if (first?.type === "text") {
|
|
36
|
-
return [{ type: "text", text }, ...rest];
|
|
37
|
-
}
|
|
38
|
-
return [{ type: "text", text }, ...message];
|
|
39
|
-
}
|
|
40
|
-
export function userEntryToMessage(entry) {
|
|
41
|
-
if (entry.parts && entry.parts.length > 0) {
|
|
42
|
-
return entry.parts;
|
|
43
|
-
}
|
|
44
|
-
return createTextMessage(entry.content);
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=message.js.map
|
package/dist/message.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","sourceRoot":"","sources":["../src/message.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAqB;IAC9C,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAoB;IACrD,OAAO,OAAO;SACX,MAAM,CAAC,UAAU,CAAC;SAClB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SACxB,IAAI,CAAC,MAAM,CAAC;SACZ,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAoB;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC3C,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC;YACrF,CAAC,CAAC,UAAU,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,MAAM,IAAI;YACxG,CAAC,CAAC,UAAU,CAAC;QACf,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC;IAC3C,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAoB;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,OAAO,KAAK,EAAE,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAoB,EAAE,IAAY;IACxE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IACD,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC;IACjC,IAAI,KAAK,EAAE,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAgB;IACjD,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IACD,OAAO,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { CommandDangerousRulesPolicy, ParsedCommandSegment } from "./command-policy-types.js";
|
|
2
|
-
export declare function matchDangerousExecutable(segment: ParsedCommandSegment, policy: CommandDangerousRulesPolicy): string | null;
|
|
3
|
-
export declare function matchDangerousShellPattern(command: string, policy: CommandDangerousRulesPolicy): string | null;
|
|
4
|
-
//# sourceMappingURL=command-dangerous-rules.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"command-dangerous-rules.d.ts","sourceRoot":"","sources":["../../src/security/command-dangerous-rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAUnG,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,2BAA2B,GAClC,MAAM,GAAG,IAAI,CAMf;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,2BAA2B,GAClC,MAAM,GAAG,IAAI,CAUf"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
function normalizeExecutable(executable) {
|
|
2
|
-
if (!executable) {
|
|
3
|
-
return "";
|
|
4
|
-
}
|
|
5
|
-
const parts = executable.split(/[\\/]/);
|
|
6
|
-
return (parts[parts.length - 1] ?? executable).toLowerCase();
|
|
7
|
-
}
|
|
8
|
-
export function matchDangerousExecutable(segment, policy) {
|
|
9
|
-
const executable = normalizeExecutable(segment.executable);
|
|
10
|
-
if (!executable) {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
return policy.denyExecutables.find((entry) => entry.toLowerCase() === executable) ?? null;
|
|
14
|
-
}
|
|
15
|
-
export function matchDangerousShellPattern(command, policy) {
|
|
16
|
-
const normalized = command.replace(/\s+/g, " ").toLowerCase();
|
|
17
|
-
for (const pattern of policy.denyShellPatterns) {
|
|
18
|
-
const compact = pattern.replace(/\s+/g, "").toLowerCase();
|
|
19
|
-
const folded = normalized.replace(/\s+/g, "");
|
|
20
|
-
if (folded.includes(compact)) {
|
|
21
|
-
return pattern;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
//# sourceMappingURL=command-dangerous-rules.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"command-dangerous-rules.js","sourceRoot":"","sources":["../../src/security/command-dangerous-rules.ts"],"names":[],"mappings":"AAEA,SAAS,mBAAmB,CAAC,UAAyB;IACpD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,OAA6B,EAC7B,MAAmC;IAEnC,MAAM,UAAU,GAAG,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,IAAI,IAAI,CAAC;AAC5F,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,OAAe,EACf,MAAmC;IAEnC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC9D,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"command-parser.d.ts","sourceRoot":"","sources":["../../src/security/command-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,2BAA2B,CAAC;AAqMrF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAiBlE"}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
function hasUnsupportedShellSyntax(command) {
|
|
2
|
-
return (command.includes("$(") ||
|
|
3
|
-
command.includes("`") ||
|
|
4
|
-
command.includes("<<") ||
|
|
5
|
-
command.includes("<(") ||
|
|
6
|
-
command.includes(">("));
|
|
7
|
-
}
|
|
8
|
-
function splitTopLevel(command) {
|
|
9
|
-
const segments = [];
|
|
10
|
-
let current = "";
|
|
11
|
-
let quote = null;
|
|
12
|
-
let escaped = false;
|
|
13
|
-
for (let index = 0; index < command.length; index += 1) {
|
|
14
|
-
const char = command[index];
|
|
15
|
-
const next = command[index + 1];
|
|
16
|
-
if (escaped) {
|
|
17
|
-
current += char;
|
|
18
|
-
escaped = false;
|
|
19
|
-
continue;
|
|
20
|
-
}
|
|
21
|
-
if (char === "\\") {
|
|
22
|
-
current += char;
|
|
23
|
-
escaped = true;
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
if (quote) {
|
|
27
|
-
current += char;
|
|
28
|
-
if (char === quote) {
|
|
29
|
-
quote = null;
|
|
30
|
-
}
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
if (char === "'" || char === '"') {
|
|
34
|
-
quote = char;
|
|
35
|
-
current += char;
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
if (char === "|" && next === "|") {
|
|
39
|
-
segments.push(current.trim());
|
|
40
|
-
current = "";
|
|
41
|
-
index += 1;
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
if (char === "&" && next === "&") {
|
|
45
|
-
segments.push(current.trim());
|
|
46
|
-
current = "";
|
|
47
|
-
index += 1;
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (char === ";" || char === "|") {
|
|
51
|
-
segments.push(current.trim());
|
|
52
|
-
current = "";
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
current += char;
|
|
56
|
-
}
|
|
57
|
-
if (quote || escaped) {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
if (current.trim().length > 0) {
|
|
61
|
-
segments.push(current.trim());
|
|
62
|
-
}
|
|
63
|
-
return segments.filter((segment) => segment.length > 0);
|
|
64
|
-
}
|
|
65
|
-
function tokenize(segment) {
|
|
66
|
-
const tokens = [];
|
|
67
|
-
let current = "";
|
|
68
|
-
let quote = null;
|
|
69
|
-
let escaped = false;
|
|
70
|
-
for (let index = 0; index < segment.length; index += 1) {
|
|
71
|
-
const char = segment[index];
|
|
72
|
-
if (escaped) {
|
|
73
|
-
current += char;
|
|
74
|
-
escaped = false;
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (char === "\\") {
|
|
78
|
-
escaped = true;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
if (quote) {
|
|
82
|
-
if (char === quote) {
|
|
83
|
-
quote = null;
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
current += char;
|
|
87
|
-
}
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
if (char === "'" || char === '"') {
|
|
91
|
-
quote = char;
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
if (/\s/.test(char)) {
|
|
95
|
-
if (current.length > 0) {
|
|
96
|
-
tokens.push(current);
|
|
97
|
-
current = "";
|
|
98
|
-
}
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
if (char === ">" || char === "<") {
|
|
102
|
-
if (current.length > 0) {
|
|
103
|
-
tokens.push(current);
|
|
104
|
-
current = "";
|
|
105
|
-
}
|
|
106
|
-
const next = segment[index + 1];
|
|
107
|
-
if ((char === ">" || char === "<") && next === char) {
|
|
108
|
-
tokens.push(char + next);
|
|
109
|
-
index += 1;
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
tokens.push(char);
|
|
113
|
-
}
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
if (char === "2" && segment[index + 1] === ">") {
|
|
117
|
-
if (current.length > 0) {
|
|
118
|
-
tokens.push(current);
|
|
119
|
-
current = "";
|
|
120
|
-
}
|
|
121
|
-
tokens.push("2>");
|
|
122
|
-
index += 1;
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
current += char;
|
|
126
|
-
}
|
|
127
|
-
if (quote || escaped) {
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
if (current.length > 0) {
|
|
131
|
-
tokens.push(current);
|
|
132
|
-
}
|
|
133
|
-
return tokens;
|
|
134
|
-
}
|
|
135
|
-
function unwrapEnv(tokens) {
|
|
136
|
-
if (tokens[0] !== "env") {
|
|
137
|
-
return tokens;
|
|
138
|
-
}
|
|
139
|
-
let index = 1;
|
|
140
|
-
while (index < tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[index])) {
|
|
141
|
-
index += 1;
|
|
142
|
-
}
|
|
143
|
-
return tokens.slice(index);
|
|
144
|
-
}
|
|
145
|
-
function buildSegment(raw) {
|
|
146
|
-
const tokens = tokenize(raw);
|
|
147
|
-
if (!tokens || tokens.length === 0) {
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
const redirections = [];
|
|
151
|
-
const argv = [];
|
|
152
|
-
for (let index = 0; index < tokens.length; index += 1) {
|
|
153
|
-
const token = tokens[index];
|
|
154
|
-
if (token === ">" || token === ">>" || token === "<" || token === "2>") {
|
|
155
|
-
const target = tokens[index + 1];
|
|
156
|
-
if (!target) {
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
redirections.push({ operator: token, target });
|
|
160
|
-
index += 1;
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
argv.push(token);
|
|
164
|
-
}
|
|
165
|
-
const unwrapped = unwrapEnv(argv);
|
|
166
|
-
return {
|
|
167
|
-
raw,
|
|
168
|
-
argv,
|
|
169
|
-
executable: unwrapped[0] ?? null,
|
|
170
|
-
redirections,
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
export function parseCommand(command) {
|
|
174
|
-
if (!command.trim() || hasUnsupportedShellSyntax(command)) {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
const rawSegments = splitTopLevel(command);
|
|
178
|
-
if (!rawSegments || rawSegments.length === 0) {
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
const segments = [];
|
|
182
|
-
for (const raw of rawSegments) {
|
|
183
|
-
const segment = buildSegment(raw);
|
|
184
|
-
if (!segment) {
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
segments.push(segment);
|
|
188
|
-
}
|
|
189
|
-
return { segments };
|
|
190
|
-
}
|
|
191
|
-
//# sourceMappingURL=command-parser.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"command-parser.js","sourceRoot":"","sources":["../../src/security/command-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { CommandPathPolicy, ParsedCommandSegment } from "./command-policy-types.js";
|
|
2
|
-
import type { CommandAllowlistPolicy } from "./command-policy-types.js";
|
|
3
|
-
export declare function validateCommandPaths(params: {
|
|
4
|
-
cwd: string;
|
|
5
|
-
allowedRoot: string;
|
|
6
|
-
pathPolicy: CommandPathPolicy;
|
|
7
|
-
segment: ParsedCommandSegment;
|
|
8
|
-
allowlist: CommandAllowlistPolicy;
|
|
9
|
-
}): string | null;
|
|
10
|
-
//# sourceMappingURL=command-path-guard.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"command-path-guard.d.ts","sourceRoot":"","sources":["../../src/security/command-path-guard.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEzF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAiGxE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,OAAO,EAAE,oBAAoB,CAAC;IAC9B,SAAS,EAAE,sBAAsB,CAAC;CACnC,GAAG,MAAM,GAAG,IAAI,CA0ChB"}
|