@stackmemoryai/stackmemory 0.6.1 → 0.6.3

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/daemon/daemon-config.ts"],
4
- "sourcesContent": ["/**\n * Daemon Configuration Management\n * Handles loading, saving, and validating daemon configuration\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\n\nexport interface DaemonServiceConfig {\n enabled: boolean;\n interval: number; // minutes\n}\n\nexport interface ContextServiceConfig extends DaemonServiceConfig {\n checkpointMessage?: string;\n}\n\nexport interface LinearServiceConfig extends DaemonServiceConfig {\n quietHours?: {\n start: number; // hour 0-23\n end: number;\n };\n retryAttempts: number;\n retryDelay: number; // ms\n}\n\nexport interface MaintenanceServiceConfig extends DaemonServiceConfig {\n staleFrameThresholdDays: number;\n ftsRebuildInterval: number; // hours\n embeddingBatchSize: number;\n vacuumInterval: number; // hours\n}\n\nexport interface FileWatchConfig extends DaemonServiceConfig {\n paths: string[];\n extensions: string[];\n ignore: string[];\n debounceMs: number;\n}\n\nexport interface DaemonConfig {\n version: string;\n context: ContextServiceConfig;\n linear: LinearServiceConfig;\n maintenance: MaintenanceServiceConfig;\n fileWatch: FileWatchConfig;\n heartbeatInterval: number; // seconds\n inactivityTimeout: number; // minutes, 0 = disabled\n logLevel: 'debug' | 'info' | 'warn' | 'error';\n}\n\nexport const DEFAULT_DAEMON_CONFIG: DaemonConfig = {\n version: '1.0.0',\n context: {\n enabled: true,\n interval: 15, // 15 minutes\n checkpointMessage: 'Auto-checkpoint',\n },\n linear: {\n enabled: false, // Disabled by default, requires setup\n interval: 60, // 60 minutes\n quietHours: { start: 22, end: 7 },\n retryAttempts: 3,\n retryDelay: 30000,\n },\n maintenance: {\n enabled: true,\n interval: 360, // 6 hours\n staleFrameThresholdDays: 30,\n ftsRebuildInterval: 24, // hours\n embeddingBatchSize: 50,\n vacuumInterval: 168, // weekly\n },\n fileWatch: {\n enabled: false, // Disabled by default\n interval: 0, // Not interval-based\n paths: ['.'],\n extensions: ['.ts', '.js', '.tsx', '.jsx', '.py', '.go', '.rs'],\n ignore: ['node_modules', '.git', 'dist', 'build', '.stackmemory'],\n debounceMs: 2000,\n },\n heartbeatInterval: 60, // 1 minute\n inactivityTimeout: 0, // Disabled by default\n logLevel: 'info',\n};\n\nexport interface DaemonStatus {\n running: boolean;\n pid?: number;\n startTime?: number;\n uptime?: number;\n services: {\n context: { enabled: boolean; lastRun?: number; saveCount?: number };\n linear: { enabled: boolean; lastRun?: number; syncCount?: number };\n maintenance: {\n enabled: boolean;\n lastRun?: number;\n staleFramesCleaned?: number;\n ftsRebuilds?: number;\n embeddingsGenerated?: number;\n };\n fileWatch: { enabled: boolean; eventsProcessed?: number };\n };\n errors: string[];\n}\n\n/**\n * Get the daemon directory path\n */\nexport function getDaemonDir(): string {\n const dir = join(homedir(), '.stackmemory', 'daemon');\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n return dir;\n}\n\n/**\n * Get the logs directory path\n */\nexport function getLogsDir(): string {\n const dir = join(homedir(), '.stackmemory', 'logs');\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n return dir;\n}\n\n/**\n * Get daemon file paths\n */\nexport function getDaemonPaths() {\n const daemonDir = getDaemonDir();\n const logsDir = getLogsDir();\n return {\n pidFile: join(daemonDir, 'daemon.pid'),\n statusFile: join(daemonDir, 'daemon.status'),\n configFile: join(daemonDir, 'config.json'),\n logFile: join(logsDir, 'daemon.log'),\n };\n}\n\n/**\n * Load daemon configuration\n */\nexport function loadDaemonConfig(): DaemonConfig {\n const { configFile } = getDaemonPaths();\n\n if (!existsSync(configFile)) {\n return { ...DEFAULT_DAEMON_CONFIG };\n }\n\n try {\n const content = readFileSync(configFile, 'utf8');\n const config = JSON.parse(content) as Partial<DaemonConfig>;\n return {\n ...DEFAULT_DAEMON_CONFIG,\n ...config,\n context: { ...DEFAULT_DAEMON_CONFIG.context, ...config.context },\n linear: { ...DEFAULT_DAEMON_CONFIG.linear, ...config.linear },\n maintenance: {\n ...DEFAULT_DAEMON_CONFIG.maintenance,\n ...config.maintenance,\n },\n fileWatch: { ...DEFAULT_DAEMON_CONFIG.fileWatch, ...config.fileWatch },\n };\n } catch {\n return { ...DEFAULT_DAEMON_CONFIG };\n }\n}\n\n/**\n * Save daemon configuration\n */\nexport function saveDaemonConfig(config: Partial<DaemonConfig>): void {\n const { configFile } = getDaemonPaths();\n const currentConfig = loadDaemonConfig();\n const newConfig = {\n ...currentConfig,\n ...config,\n context: { ...currentConfig.context, ...config.context },\n linear: { ...currentConfig.linear, ...config.linear },\n maintenance: { ...currentConfig.maintenance, ...config.maintenance },\n fileWatch: { ...currentConfig.fileWatch, ...config.fileWatch },\n };\n writeFileSync(configFile, JSON.stringify(newConfig, null, 2));\n}\n\n/**\n * Read daemon status\n */\nexport function readDaemonStatus(): DaemonStatus {\n const { statusFile, pidFile } = getDaemonPaths();\n\n const defaultStatus: DaemonStatus = {\n running: false,\n services: {\n context: { enabled: false },\n linear: { enabled: false },\n maintenance: { enabled: false },\n fileWatch: { enabled: false },\n },\n errors: [],\n };\n\n // Check PID file first\n if (!existsSync(pidFile)) {\n return defaultStatus;\n }\n\n try {\n const pidContent = readFileSync(pidFile, 'utf8').trim();\n const pid = parseInt(pidContent, 10);\n\n // Check if process is running\n try {\n process.kill(pid, 0);\n } catch {\n // Process not running\n return defaultStatus;\n }\n\n // Read status file\n if (!existsSync(statusFile)) {\n return { ...defaultStatus, running: true, pid };\n }\n\n const content = readFileSync(statusFile, 'utf8');\n const status = JSON.parse(content) as DaemonStatus;\n return {\n ...status,\n running: true,\n pid,\n uptime: status.startTime ? Date.now() - status.startTime : undefined,\n };\n } catch {\n return defaultStatus;\n }\n}\n\n/**\n * Write daemon status\n */\nexport function writeDaemonStatus(status: Partial<DaemonStatus>): void {\n const { statusFile } = getDaemonPaths();\n const currentStatus = readDaemonStatus();\n const newStatus = { ...currentStatus, ...status };\n writeFileSync(statusFile, JSON.stringify(newStatus, null, 2));\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Daemon Configuration Management\n * Handles loading, saving, and validating daemon configuration\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\n\nexport interface DaemonServiceConfig {\n enabled: boolean;\n interval: number; // minutes\n}\n\nexport interface ContextServiceConfig extends DaemonServiceConfig {\n checkpointMessage?: string;\n}\n\nexport interface LinearServiceConfig extends DaemonServiceConfig {\n quietHours?: {\n start: number; // hour 0-23\n end: number;\n };\n retryAttempts: number;\n retryDelay: number; // ms\n}\n\nexport interface MaintenanceServiceConfig extends DaemonServiceConfig {\n staleFrameThresholdDays: number;\n ftsRebuildInterval: number; // hours\n embeddingBatchSize: number;\n vacuumInterval: number; // hours\n embeddingModel?: string; // default: 'Xenova/all-MiniLM-L6-v2'\n}\n\nexport interface FileWatchConfig extends DaemonServiceConfig {\n paths: string[];\n extensions: string[];\n ignore: string[];\n debounceMs: number;\n}\n\nexport interface DaemonConfig {\n version: string;\n context: ContextServiceConfig;\n linear: LinearServiceConfig;\n maintenance: MaintenanceServiceConfig;\n fileWatch: FileWatchConfig;\n heartbeatInterval: number; // seconds\n inactivityTimeout: number; // minutes, 0 = disabled\n logLevel: 'debug' | 'info' | 'warn' | 'error';\n}\n\nexport const DEFAULT_DAEMON_CONFIG: DaemonConfig = {\n version: '1.0.0',\n context: {\n enabled: true,\n interval: 15, // 15 minutes\n checkpointMessage: 'Auto-checkpoint',\n },\n linear: {\n enabled: false, // Disabled by default, requires setup\n interval: 60, // 60 minutes\n quietHours: { start: 22, end: 7 },\n retryAttempts: 3,\n retryDelay: 30000,\n },\n maintenance: {\n enabled: true,\n interval: 360, // 6 hours\n staleFrameThresholdDays: 30,\n ftsRebuildInterval: 24, // hours\n embeddingBatchSize: 50,\n vacuumInterval: 168, // weekly\n },\n fileWatch: {\n enabled: false, // Disabled by default\n interval: 0, // Not interval-based\n paths: ['.'],\n extensions: ['.ts', '.js', '.tsx', '.jsx', '.py', '.go', '.rs'],\n ignore: ['node_modules', '.git', 'dist', 'build', '.stackmemory'],\n debounceMs: 2000,\n },\n heartbeatInterval: 60, // 1 minute\n inactivityTimeout: 0, // Disabled by default\n logLevel: 'info',\n};\n\nexport interface DaemonStatus {\n running: boolean;\n pid?: number;\n startTime?: number;\n uptime?: number;\n services: {\n context: { enabled: boolean; lastRun?: number; saveCount?: number };\n linear: { enabled: boolean; lastRun?: number; syncCount?: number };\n maintenance: {\n enabled: boolean;\n lastRun?: number;\n staleFramesCleaned?: number;\n ftsRebuilds?: number;\n embeddingsGenerated?: number;\n };\n fileWatch: { enabled: boolean; eventsProcessed?: number };\n };\n errors: string[];\n}\n\n/**\n * Get the daemon directory path\n */\nexport function getDaemonDir(): string {\n const dir = join(homedir(), '.stackmemory', 'daemon');\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n return dir;\n}\n\n/**\n * Get the logs directory path\n */\nexport function getLogsDir(): string {\n const dir = join(homedir(), '.stackmemory', 'logs');\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n return dir;\n}\n\n/**\n * Get daemon file paths\n */\nexport function getDaemonPaths() {\n const daemonDir = getDaemonDir();\n const logsDir = getLogsDir();\n return {\n pidFile: join(daemonDir, 'daemon.pid'),\n statusFile: join(daemonDir, 'daemon.status'),\n configFile: join(daemonDir, 'config.json'),\n logFile: join(logsDir, 'daemon.log'),\n };\n}\n\n/**\n * Load daemon configuration\n */\nexport function loadDaemonConfig(): DaemonConfig {\n const { configFile } = getDaemonPaths();\n\n if (!existsSync(configFile)) {\n return { ...DEFAULT_DAEMON_CONFIG };\n }\n\n try {\n const content = readFileSync(configFile, 'utf8');\n const config = JSON.parse(content) as Partial<DaemonConfig>;\n return {\n ...DEFAULT_DAEMON_CONFIG,\n ...config,\n context: { ...DEFAULT_DAEMON_CONFIG.context, ...config.context },\n linear: { ...DEFAULT_DAEMON_CONFIG.linear, ...config.linear },\n maintenance: {\n ...DEFAULT_DAEMON_CONFIG.maintenance,\n ...config.maintenance,\n },\n fileWatch: { ...DEFAULT_DAEMON_CONFIG.fileWatch, ...config.fileWatch },\n };\n } catch {\n return { ...DEFAULT_DAEMON_CONFIG };\n }\n}\n\n/**\n * Save daemon configuration\n */\nexport function saveDaemonConfig(config: Partial<DaemonConfig>): void {\n const { configFile } = getDaemonPaths();\n const currentConfig = loadDaemonConfig();\n const newConfig = {\n ...currentConfig,\n ...config,\n context: { ...currentConfig.context, ...config.context },\n linear: { ...currentConfig.linear, ...config.linear },\n maintenance: { ...currentConfig.maintenance, ...config.maintenance },\n fileWatch: { ...currentConfig.fileWatch, ...config.fileWatch },\n };\n writeFileSync(configFile, JSON.stringify(newConfig, null, 2));\n}\n\n/**\n * Read daemon status\n */\nexport function readDaemonStatus(): DaemonStatus {\n const { statusFile, pidFile } = getDaemonPaths();\n\n const defaultStatus: DaemonStatus = {\n running: false,\n services: {\n context: { enabled: false },\n linear: { enabled: false },\n maintenance: { enabled: false },\n fileWatch: { enabled: false },\n },\n errors: [],\n };\n\n // Check PID file first\n if (!existsSync(pidFile)) {\n return defaultStatus;\n }\n\n try {\n const pidContent = readFileSync(pidFile, 'utf8').trim();\n const pid = parseInt(pidContent, 10);\n\n // Check if process is running\n try {\n process.kill(pid, 0);\n } catch {\n // Process not running\n return defaultStatus;\n }\n\n // Read status file\n if (!existsSync(statusFile)) {\n return { ...defaultStatus, running: true, pid };\n }\n\n const content = readFileSync(statusFile, 'utf8');\n const status = JSON.parse(content) as DaemonStatus;\n return {\n ...status,\n running: true,\n pid,\n uptime: status.startTime ? Date.now() - status.startTime : undefined,\n };\n } catch {\n return defaultStatus;\n }\n}\n\n/**\n * Write daemon status\n */\nexport function writeDaemonStatus(status: Partial<DaemonStatus>): void {\n const { statusFile } = getDaemonPaths();\n const currentStatus = readDaemonStatus();\n const newStatus = { ...currentStatus, ...status };\n writeFileSync(statusFile, JSON.stringify(newStatus, null, 2));\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -8,6 +8,7 @@ import { homedir } from "os";
8
8
  class DaemonMaintenanceService {
9
9
  config;
10
10
  state;
11
+ embeddingProvider = null;
11
12
  intervalId;
12
13
  isRunning = false;
13
14
  onLog;
@@ -141,12 +142,32 @@ class DaemonMaintenanceService {
141
142
  try {
142
143
  if (typeof db.getFramesMissingEmbeddings !== "function") return;
143
144
  if (!db.getFeatures?.().supportsVectorSearch) return;
145
+ if (!this.embeddingProvider) return;
144
146
  const frames = await db.getFramesMissingEmbeddings(
145
147
  this.config.embeddingBatchSize
146
148
  );
147
149
  if (frames.length === 0) return;
148
- this.state.embeddingsGenerated += frames.length;
149
- this.onLog("INFO", `Found ${frames.length} frames needing embeddings`);
150
+ this.onLog("INFO", `Generating embeddings for ${frames.length} frames`);
151
+ let generated = 0;
152
+ for (const frame of frames) {
153
+ try {
154
+ const text = [
155
+ frame.name,
156
+ frame.digest_text,
157
+ JSON.stringify(frame.inputs)
158
+ ].filter(Boolean).join(" ");
159
+ if (!text.trim()) continue;
160
+ const embedding = await this.embeddingProvider.embed(text);
161
+ await db.storeEmbedding(frame.frame_id, embedding);
162
+ generated++;
163
+ } catch (err) {
164
+ this.addError(
165
+ `Embedding frame ${frame.frame_id}: ${err instanceof Error ? err.message : String(err)}`
166
+ );
167
+ }
168
+ }
169
+ this.state.embeddingsGenerated += generated;
170
+ this.onLog("INFO", `Generated ${generated} embeddings`);
150
171
  } catch (err) {
151
172
  this.addError(
152
173
  `Embedding backfill: ${err instanceof Error ? err.message : String(err)}`
@@ -188,12 +209,19 @@ class DaemonMaintenanceService {
188
209
  async getDatabase() {
189
210
  try {
190
211
  const { SQLiteAdapter } = await import("../../core/database/sqlite-adapter.js");
212
+ const { createTransformersProvider } = await import("../../core/database/transformers-embedding-provider.js");
191
213
  const dbPath = this.findDatabasePath();
192
214
  if (!dbPath) {
193
215
  this.onLog("WARN", "No database found for maintenance");
194
216
  return null;
195
217
  }
196
- const adapter = new SQLiteAdapter("maintenance", { dbPath });
218
+ if (!this.embeddingProvider) {
219
+ this.embeddingProvider = await createTransformersProvider(this.config.embeddingModel) ?? null;
220
+ }
221
+ const adapter = new SQLiteAdapter("maintenance", {
222
+ dbPath,
223
+ embeddingProvider: this.embeddingProvider ?? void 0
224
+ });
197
225
  await adapter.connect();
198
226
  await adapter.initializeSchema();
199
227
  return adapter;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/daemon/services/maintenance-service.ts"],
4
- "sourcesContent": ["/**\n * Database Maintenance Service\n * Background housekeeping: stale frame cleanup, FTS rebuild,\n * embedding backfill, VACUUM, and digest generation\n */\n\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport type { MaintenanceServiceConfig } from '../daemon-config.js';\n\nexport interface MaintenanceServiceState {\n lastRunTime: number;\n lastFtsRebuild: number;\n lastVacuum: number;\n staleFramesCleaned: number;\n embeddingsGenerated: number;\n ftsRebuilds: number;\n errors: string[];\n}\n\nexport class DaemonMaintenanceService {\n private config: MaintenanceServiceConfig;\n private state: MaintenanceServiceState;\n private intervalId?: NodeJS.Timeout;\n private isRunning = false;\n private onLog: (level: string, message: string, data?: unknown) => void;\n\n constructor(\n config: MaintenanceServiceConfig,\n onLog: (level: string, message: string, data?: unknown) => void\n ) {\n this.config = config;\n this.onLog = onLog;\n this.state = {\n lastRunTime: 0,\n lastFtsRebuild: 0,\n lastVacuum: 0,\n staleFramesCleaned: 0,\n embeddingsGenerated: 0,\n ftsRebuilds: 0,\n errors: [],\n };\n }\n\n start(): void {\n if (this.isRunning || !this.config.enabled) {\n return;\n }\n\n this.isRunning = true;\n const intervalMs = this.config.interval * 60 * 1000;\n\n this.onLog('INFO', 'Maintenance service started', {\n interval: this.config.interval,\n staleThresholdDays: this.config.staleFrameThresholdDays,\n ftsRebuildInterval: this.config.ftsRebuildInterval,\n vacuumInterval: this.config.vacuumInterval,\n });\n\n // Schedule periodic maintenance\n this.intervalId = setInterval(() => {\n this.runMaintenance().catch((err) => {\n this.addError(\n `Maintenance cycle failed: ${err instanceof Error ? err.message : String(err)}`\n );\n });\n }, intervalMs);\n }\n\n stop(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = undefined;\n }\n this.isRunning = false;\n this.onLog('INFO', 'Maintenance service stopped');\n }\n\n getState(): MaintenanceServiceState {\n return { ...this.state };\n }\n\n updateConfig(config: Partial<MaintenanceServiceConfig>): void {\n const wasRunning = this.isRunning;\n if (wasRunning) {\n this.stop();\n }\n\n this.config = { ...this.config, ...config };\n\n if (wasRunning && this.config.enabled) {\n this.start();\n }\n }\n\n /**\n * Force-run all maintenance tasks immediately\n */\n async forceRun(): Promise<void> {\n await this.runMaintenance();\n }\n\n /**\n * Run all maintenance tasks in sequence\n */\n async runMaintenance(): Promise<void> {\n const startTime = Date.now();\n this.onLog('INFO', 'Starting maintenance cycle');\n\n try {\n const db = await this.getDatabase();\n if (!db) {\n this.onLog('WARN', 'No database available for maintenance');\n return;\n }\n\n // Task 1: Stale frame cleanup\n await this.cleanStaleFrames(db);\n\n // Task 2: FTS rebuild (if due)\n await this.maybeRebuildFts(db);\n\n // Task 3: Embedding backfill (if provider configured)\n await this.backfillEmbeddings(db);\n\n // Task 4: VACUUM (if due)\n await this.maybeVacuum(db);\n\n // Task 5: Digest generation for frames missing digest_text\n await this.generateMissingDigests(db);\n\n await db.disconnect();\n\n this.state.lastRunTime = Date.now();\n this.onLog('INFO', 'Maintenance cycle completed', {\n durationMs: Date.now() - startTime,\n staleFramesCleaned: this.state.staleFramesCleaned,\n ftsRebuilds: this.state.ftsRebuilds,\n embeddingsGenerated: this.state.embeddingsGenerated,\n });\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n this.addError(errorMsg);\n this.onLog('ERROR', 'Maintenance cycle failed', { error: errorMsg });\n }\n }\n\n private async cleanStaleFrames(db: any): Promise<void> {\n try {\n const thresholdSec =\n Math.floor(Date.now() / 1000) -\n this.config.staleFrameThresholdDays * 24 * 3600;\n\n const rawDb = db.getRawDatabase?.();\n if (!rawDb) return;\n\n const result = rawDb\n .prepare(\n \"UPDATE frames SET state = 'stale' WHERE state = 'active' AND created_at < ?\"\n )\n .run(thresholdSec);\n\n const cleaned = result.changes || 0;\n this.state.staleFramesCleaned += cleaned;\n\n if (cleaned > 0) {\n this.onLog('INFO', `Marked ${cleaned} stale frames`);\n }\n } catch (err) {\n this.addError(\n `Stale frame cleanup: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async maybeRebuildFts(db: any): Promise<void> {\n try {\n const hoursSinceLastRebuild =\n (Date.now() - this.state.lastFtsRebuild) / (1000 * 3600);\n\n if (hoursSinceLastRebuild < this.config.ftsRebuildInterval) return;\n\n if (typeof db.rebuildFtsIndex === 'function') {\n await db.rebuildFtsIndex();\n this.state.lastFtsRebuild = Date.now();\n this.state.ftsRebuilds++;\n this.onLog('INFO', 'FTS index rebuilt');\n }\n } catch (err) {\n this.addError(\n `FTS rebuild: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async backfillEmbeddings(db: any): Promise<void> {\n try {\n if (typeof db.getFramesMissingEmbeddings !== 'function') return;\n if (!db.getFeatures?.().supportsVectorSearch) return;\n\n const frames = await db.getFramesMissingEmbeddings(\n this.config.embeddingBatchSize\n );\n\n if (frames.length === 0) return;\n\n // Embedding generation requires the provider, which lives on the adapter\n // The adapter handles this internally via storeEmbedding\n this.state.embeddingsGenerated += frames.length;\n this.onLog('INFO', `Found ${frames.length} frames needing embeddings`);\n } catch (err) {\n this.addError(\n `Embedding backfill: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async maybeVacuum(db: any): Promise<void> {\n try {\n const hoursSinceLastVacuum =\n (Date.now() - this.state.lastVacuum) / (1000 * 3600);\n\n if (hoursSinceLastVacuum < this.config.vacuumInterval) return;\n\n const rawDb = db.getRawDatabase?.();\n if (!rawDb) return;\n\n rawDb.pragma('optimize');\n rawDb.pragma('vacuum');\n\n this.state.lastVacuum = Date.now();\n this.onLog('INFO', 'Database optimized and vacuumed');\n } catch (err) {\n this.addError(\n `VACUUM: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async generateMissingDigests(db: any): Promise<void> {\n try {\n const rawDb = db.getRawDatabase?.();\n if (!rawDb) return;\n\n const count = (\n rawDb\n .prepare(\n \"SELECT COUNT(*) as count FROM frames WHERE digest_text IS NULL AND state = 'active'\"\n )\n .get() as { count: number }\n ).count;\n\n if (count > 0) {\n this.onLog('INFO', `Found ${count} frames missing digest_text`);\n }\n } catch (err) {\n this.addError(\n `Digest generation: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async getDatabase(): Promise<any> {\n try {\n const { SQLiteAdapter } =\n await import('../../core/database/sqlite-adapter.js');\n\n const dbPath = this.findDatabasePath();\n if (!dbPath) {\n this.onLog('WARN', 'No database found for maintenance');\n return null;\n }\n\n const adapter = new SQLiteAdapter('maintenance', { dbPath });\n await adapter.connect();\n await adapter.initializeSchema();\n return adapter;\n } catch (err) {\n this.addError(\n `Database init: ${err instanceof Error ? err.message : String(err)}`\n );\n return null;\n }\n }\n\n private findDatabasePath(): string | null {\n const homeDir = homedir();\n const candidates = [\n join(process.cwd(), '.stackmemory', 'stackmemory.db'),\n join(homeDir, '.stackmemory', 'stackmemory.db'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n }\n\n private addError(msg: string): void {\n this.state.errors.push(msg);\n if (this.state.errors.length > 10) {\n this.state.errors = this.state.errors.slice(-10);\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Database Maintenance Service\n * Background housekeeping: stale frame cleanup, FTS rebuild,\n * embedding backfill, VACUUM, and digest generation\n */\n\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport type { MaintenanceServiceConfig } from '../daemon-config.js';\nimport type { EmbeddingProvider } from '../../core/database/embedding-provider.js';\n\nexport interface MaintenanceServiceState {\n lastRunTime: number;\n lastFtsRebuild: number;\n lastVacuum: number;\n staleFramesCleaned: number;\n embeddingsGenerated: number;\n ftsRebuilds: number;\n errors: string[];\n}\n\nexport class DaemonMaintenanceService {\n private config: MaintenanceServiceConfig;\n private state: MaintenanceServiceState;\n private embeddingProvider: EmbeddingProvider | null = null;\n private intervalId?: NodeJS.Timeout;\n private isRunning = false;\n private onLog: (level: string, message: string, data?: unknown) => void;\n\n constructor(\n config: MaintenanceServiceConfig,\n onLog: (level: string, message: string, data?: unknown) => void\n ) {\n this.config = config;\n this.onLog = onLog;\n this.state = {\n lastRunTime: 0,\n lastFtsRebuild: 0,\n lastVacuum: 0,\n staleFramesCleaned: 0,\n embeddingsGenerated: 0,\n ftsRebuilds: 0,\n errors: [],\n };\n }\n\n start(): void {\n if (this.isRunning || !this.config.enabled) {\n return;\n }\n\n this.isRunning = true;\n const intervalMs = this.config.interval * 60 * 1000;\n\n this.onLog('INFO', 'Maintenance service started', {\n interval: this.config.interval,\n staleThresholdDays: this.config.staleFrameThresholdDays,\n ftsRebuildInterval: this.config.ftsRebuildInterval,\n vacuumInterval: this.config.vacuumInterval,\n });\n\n // Schedule periodic maintenance\n this.intervalId = setInterval(() => {\n this.runMaintenance().catch((err) => {\n this.addError(\n `Maintenance cycle failed: ${err instanceof Error ? err.message : String(err)}`\n );\n });\n }, intervalMs);\n }\n\n stop(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = undefined;\n }\n this.isRunning = false;\n this.onLog('INFO', 'Maintenance service stopped');\n }\n\n getState(): MaintenanceServiceState {\n return { ...this.state };\n }\n\n updateConfig(config: Partial<MaintenanceServiceConfig>): void {\n const wasRunning = this.isRunning;\n if (wasRunning) {\n this.stop();\n }\n\n this.config = { ...this.config, ...config };\n\n if (wasRunning && this.config.enabled) {\n this.start();\n }\n }\n\n /**\n * Force-run all maintenance tasks immediately\n */\n async forceRun(): Promise<void> {\n await this.runMaintenance();\n }\n\n /**\n * Run all maintenance tasks in sequence\n */\n async runMaintenance(): Promise<void> {\n const startTime = Date.now();\n this.onLog('INFO', 'Starting maintenance cycle');\n\n try {\n const db = await this.getDatabase();\n if (!db) {\n this.onLog('WARN', 'No database available for maintenance');\n return;\n }\n\n // Task 1: Stale frame cleanup\n await this.cleanStaleFrames(db);\n\n // Task 2: FTS rebuild (if due)\n await this.maybeRebuildFts(db);\n\n // Task 3: Embedding backfill (if provider configured)\n await this.backfillEmbeddings(db);\n\n // Task 4: VACUUM (if due)\n await this.maybeVacuum(db);\n\n // Task 5: Digest generation for frames missing digest_text\n await this.generateMissingDigests(db);\n\n await db.disconnect();\n\n this.state.lastRunTime = Date.now();\n this.onLog('INFO', 'Maintenance cycle completed', {\n durationMs: Date.now() - startTime,\n staleFramesCleaned: this.state.staleFramesCleaned,\n ftsRebuilds: this.state.ftsRebuilds,\n embeddingsGenerated: this.state.embeddingsGenerated,\n });\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n this.addError(errorMsg);\n this.onLog('ERROR', 'Maintenance cycle failed', { error: errorMsg });\n }\n }\n\n private async cleanStaleFrames(db: any): Promise<void> {\n try {\n const thresholdSec =\n Math.floor(Date.now() / 1000) -\n this.config.staleFrameThresholdDays * 24 * 3600;\n\n const rawDb = db.getRawDatabase?.();\n if (!rawDb) return;\n\n const result = rawDb\n .prepare(\n \"UPDATE frames SET state = 'stale' WHERE state = 'active' AND created_at < ?\"\n )\n .run(thresholdSec);\n\n const cleaned = result.changes || 0;\n this.state.staleFramesCleaned += cleaned;\n\n if (cleaned > 0) {\n this.onLog('INFO', `Marked ${cleaned} stale frames`);\n }\n } catch (err) {\n this.addError(\n `Stale frame cleanup: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async maybeRebuildFts(db: any): Promise<void> {\n try {\n const hoursSinceLastRebuild =\n (Date.now() - this.state.lastFtsRebuild) / (1000 * 3600);\n\n if (hoursSinceLastRebuild < this.config.ftsRebuildInterval) return;\n\n if (typeof db.rebuildFtsIndex === 'function') {\n await db.rebuildFtsIndex();\n this.state.lastFtsRebuild = Date.now();\n this.state.ftsRebuilds++;\n this.onLog('INFO', 'FTS index rebuilt');\n }\n } catch (err) {\n this.addError(\n `FTS rebuild: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async backfillEmbeddings(db: any): Promise<void> {\n try {\n if (typeof db.getFramesMissingEmbeddings !== 'function') return;\n if (!db.getFeatures?.().supportsVectorSearch) return;\n if (!this.embeddingProvider) return;\n\n const frames = await db.getFramesMissingEmbeddings(\n this.config.embeddingBatchSize\n );\n\n if (frames.length === 0) return;\n\n this.onLog('INFO', `Generating embeddings for ${frames.length} frames`);\n\n let generated = 0;\n for (const frame of frames) {\n try {\n const text = [\n frame.name,\n frame.digest_text,\n JSON.stringify(frame.inputs),\n ]\n .filter(Boolean)\n .join(' ');\n if (!text.trim()) continue;\n\n const embedding = await this.embeddingProvider.embed(text);\n await db.storeEmbedding(frame.frame_id, embedding);\n generated++;\n } catch (err) {\n this.addError(\n `Embedding frame ${frame.frame_id}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n this.state.embeddingsGenerated += generated;\n this.onLog('INFO', `Generated ${generated} embeddings`);\n } catch (err) {\n this.addError(\n `Embedding backfill: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async maybeVacuum(db: any): Promise<void> {\n try {\n const hoursSinceLastVacuum =\n (Date.now() - this.state.lastVacuum) / (1000 * 3600);\n\n if (hoursSinceLastVacuum < this.config.vacuumInterval) return;\n\n const rawDb = db.getRawDatabase?.();\n if (!rawDb) return;\n\n rawDb.pragma('optimize');\n rawDb.pragma('vacuum');\n\n this.state.lastVacuum = Date.now();\n this.onLog('INFO', 'Database optimized and vacuumed');\n } catch (err) {\n this.addError(\n `VACUUM: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async generateMissingDigests(db: any): Promise<void> {\n try {\n const rawDb = db.getRawDatabase?.();\n if (!rawDb) return;\n\n const count = (\n rawDb\n .prepare(\n \"SELECT COUNT(*) as count FROM frames WHERE digest_text IS NULL AND state = 'active'\"\n )\n .get() as { count: number }\n ).count;\n\n if (count > 0) {\n this.onLog('INFO', `Found ${count} frames missing digest_text`);\n }\n } catch (err) {\n this.addError(\n `Digest generation: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n private async getDatabase(): Promise<any> {\n try {\n const { SQLiteAdapter } =\n await import('../../core/database/sqlite-adapter.js');\n const { createTransformersProvider } =\n await import('../../core/database/transformers-embedding-provider.js');\n\n const dbPath = this.findDatabasePath();\n if (!dbPath) {\n this.onLog('WARN', 'No database found for maintenance');\n return null;\n }\n\n if (!this.embeddingProvider) {\n this.embeddingProvider =\n (await createTransformersProvider(this.config.embeddingModel)) ??\n null;\n }\n\n const adapter = new SQLiteAdapter('maintenance', {\n dbPath,\n embeddingProvider: this.embeddingProvider ?? undefined,\n });\n await adapter.connect();\n await adapter.initializeSchema();\n return adapter;\n } catch (err) {\n this.addError(\n `Database init: ${err instanceof Error ? err.message : String(err)}`\n );\n return null;\n }\n }\n\n private findDatabasePath(): string | null {\n const homeDir = homedir();\n const candidates = [\n join(process.cwd(), '.stackmemory', 'stackmemory.db'),\n join(homeDir, '.stackmemory', 'stackmemory.db'),\n ];\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n }\n\n private addError(msg: string): void {\n this.state.errors.push(msg);\n if (this.state.errors.length > 10) {\n this.state.errors = this.state.errors.slice(-10);\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -184,12 +184,17 @@ class ClaudeCodeTaskCoordinator {
184
184
  * Execute with timeout wrapper
185
185
  */
186
186
  async executeWithTimeout(fn, timeoutMs) {
187
+ let timer;
187
188
  const timeoutPromise = new Promise((_, reject) => {
188
- setTimeout(() => {
189
+ timer = setTimeout(() => {
189
190
  reject(new Error(`Task execution timeout after ${timeoutMs}ms`));
190
191
  }, timeoutMs);
191
192
  });
192
- return Promise.race([fn(), timeoutPromise]);
193
+ try {
194
+ return await Promise.race([fn(), timeoutPromise]);
195
+ } finally {
196
+ clearTimeout(timer);
197
+ }
193
198
  }
194
199
  /**
195
200
  * Invoke Claude Code agent (integration point)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/integrations/claude-code/task-coordinator.ts"],
4
- "sourcesContent": ["/**\n * Claude Code Task Coordinator\n *\n * Coordinates task execution between StackMemory and Claude Code's Task tool.\n * Handles agent invocation, result processing, and error recovery.\n */\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { ClaudeCodeAgent } from './agent-bridge.js';\n\nexport interface TaskExecution {\n id: string;\n agentName: string;\n agentType: 'oracle' | 'worker' | 'reviewer';\n prompt: string;\n startTime: number;\n endTime?: number;\n status: 'pending' | 'running' | 'completed' | 'failed';\n result?: string;\n error?: string;\n retryCount: number;\n estimatedCost: number;\n actualTokens?: number;\n}\n\nexport interface CoordinationMetrics {\n totalTasks: number;\n completedTasks: number;\n failedTasks: number;\n averageExecutionTime: number;\n totalCost: number;\n successRate: number;\n agentUtilization: Record<string, number>;\n}\n\n/**\n * Claude Code Task Coordinator\n * Manages task execution and coordination with Claude Code agents\n */\nexport class ClaudeCodeTaskCoordinator {\n private activeTasks: Map<string, TaskExecution> = new Map();\n private completedTasks: TaskExecution[] = [];\n private metrics: CoordinationMetrics;\n\n constructor() {\n this.metrics = {\n totalTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n averageExecutionTime: 0,\n totalCost: 0,\n successRate: 0,\n agentUtilization: {},\n };\n }\n\n /**\n * Execute task with Claude Code agent\n */\n async executeTask(\n agentName: string,\n agentConfig: ClaudeCodeAgent,\n prompt: string,\n options: {\n maxRetries?: number;\n timeout?: number;\n priority?: 'low' | 'medium' | 'high';\n } = {}\n ): Promise<string> {\n const taskId = uuidv4();\n const { maxRetries = 2, timeout = 300000, priority = 'medium' } = options;\n\n const task: TaskExecution = {\n id: taskId,\n agentName,\n agentType: agentConfig.type,\n prompt,\n startTime: Date.now(),\n status: 'pending',\n retryCount: 0,\n estimatedCost: this.estimateTaskCost(prompt, agentConfig),\n };\n\n this.activeTasks.set(taskId, task);\n this.metrics.totalTasks++;\n\n logger.info('Starting Claude Code task execution', {\n taskId,\n agentName,\n agentType: agentConfig.type,\n promptLength: prompt.length,\n estimatedCost: task.estimatedCost,\n priority,\n });\n\n try {\n // Execute with retries\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n task.retryCount = attempt;\n task.status = 'running';\n\n // Execute the task with timeout\n const result = await this.executeWithTimeout(\n () => this.invokeClaudeCodeAgent(agentName, prompt, agentConfig),\n timeout\n );\n\n // Task completed successfully\n task.status = 'completed';\n task.result = result;\n task.endTime = Date.now();\n task.actualTokens = this.estimateTokenUsage(prompt, result);\n\n this.completeTask(task);\n return result;\n } catch (error) {\n lastError = error as Error;\n task.status = 'failed';\n\n logger.warn(`Claude Code task attempt ${attempt + 1} failed`, {\n taskId,\n agentName,\n error: lastError.message,\n attempt: attempt + 1,\n maxRetries: maxRetries + 1,\n });\n\n // Don't retry if it's the last attempt\n if (attempt === maxRetries) {\n break;\n }\n\n // Wait before retry with exponential backoff\n const backoffMs = Math.min(1000 * Math.pow(2, attempt), 10000);\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n }\n }\n\n // All retries exhausted\n task.error = lastError?.message || 'Unknown error';\n task.endTime = Date.now();\n this.failTask(task, lastError!);\n throw lastError;\n } finally {\n this.activeTasks.delete(taskId);\n }\n }\n\n /**\n * Execute multiple tasks in parallel with coordination\n */\n async executeParallelTasks(\n tasks: {\n agentName: string;\n agentConfig: ClaudeCodeAgent;\n prompt: string;\n priority?: 'low' | 'medium' | 'high';\n }[]\n ): Promise<{ results: string[]; failures: Error[] }> {\n logger.info('Executing parallel Claude Code tasks', {\n taskCount: tasks.length,\n agents: tasks.map((t) => t.agentName),\n });\n\n // Group tasks by priority\n const priorityGroups = {\n high: tasks.filter((t) => t.priority === 'high'),\n medium: tasks.filter((t) => t.priority === 'medium'),\n low: tasks.filter((t) => t.priority === 'low'),\n };\n\n const results: string[] = [];\n const failures: Error[] = [];\n\n // Execute high priority tasks first\n for (const priorityLevel of ['high', 'medium', 'low'] as const) {\n const priorityTasks = priorityGroups[priorityLevel];\n if (priorityTasks.length === 0) continue;\n\n logger.info(`Executing ${priorityLevel} priority tasks`, {\n count: priorityTasks.length,\n });\n\n // Execute tasks in this priority level concurrently\n const promises = priorityTasks.map(async (task) => {\n try {\n const result = await this.executeTask(\n task.agentName,\n task.agentConfig,\n task.prompt,\n { priority: task.priority }\n );\n return { success: true, result };\n } catch (error) {\n return { success: false, error: error as Error };\n }\n });\n\n const outcomes = await Promise.allSettled(promises);\n\n for (const outcome of outcomes) {\n if (outcome.status === 'fulfilled') {\n if (outcome.value.success) {\n results.push(outcome.value.result);\n } else {\n failures.push(outcome.value.error);\n }\n } else {\n failures.push(new Error(outcome.reason));\n }\n }\n }\n\n logger.info('Parallel task execution completed', {\n totalTasks: tasks.length,\n successful: results.length,\n failed: failures.length,\n successRate: ((results.length / tasks.length) * 100).toFixed(1),\n });\n\n return { results, failures };\n }\n\n /**\n * Get coordination metrics and health status\n */\n getCoordinationMetrics(): CoordinationMetrics & {\n activeTasks: number;\n recentErrors: string[];\n performanceTrend: 'improving' | 'stable' | 'degrading';\n } {\n // Calculate recent error rate for performance trend\n const recentTasks = this.completedTasks.slice(-10);\n const recentErrorRate =\n recentTasks.length > 0\n ? recentTasks.filter((t) => t.status === 'failed').length /\n recentTasks.length\n : 0;\n\n const performanceTrend =\n recentErrorRate < 0.1\n ? 'improving'\n : recentErrorRate < 0.3\n ? 'stable'\n : 'degrading';\n\n const recentErrors = this.completedTasks\n .slice(-5)\n .filter((t) => t.status === 'failed')\n .map((t) => t.error || 'Unknown error');\n\n return {\n ...this.metrics,\n activeTasks: this.activeTasks.size,\n recentErrors,\n performanceTrend,\n };\n }\n\n /**\n * Clean up resources and reset metrics\n */\n async cleanup(): Promise<void> {\n logger.info('Cleaning up Claude Code Task Coordinator', {\n activeTasks: this.activeTasks.size,\n completedTasks: this.completedTasks.length,\n });\n\n // Wait for active tasks to complete or force cleanup after timeout\n if (this.activeTasks.size > 0) {\n const timeoutPromise = new Promise((resolve) =>\n setTimeout(resolve, 30000)\n );\n const completionPromise = this.waitForTaskCompletion();\n\n await Promise.race([completionPromise, timeoutPromise]);\n\n if (this.activeTasks.size > 0) {\n logger.warn('Force terminating active tasks', {\n remainingTasks: this.activeTasks.size,\n });\n }\n }\n\n this.activeTasks.clear();\n this.completedTasks = [];\n this.resetMetrics();\n }\n\n /**\n * Execute with timeout wrapper\n */\n private async executeWithTimeout<T>(\n fn: () => Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n const timeoutPromise = new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Task execution timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n\n return Promise.race([fn(), timeoutPromise]);\n }\n\n /**\n * Invoke Claude Code agent (integration point)\n */\n private async invokeClaudeCodeAgent(\n agentName: string,\n prompt: string,\n agentConfig: ClaudeCodeAgent\n ): Promise<string> {\n logger.debug('Invoking Claude Code agent', {\n agentName,\n agentType: agentConfig.type,\n promptTokens: this.estimateTokenUsage(prompt, ''),\n });\n\n // TODO: Replace with actual Claude Code Task tool invocation\n // This is where we would call Claude Code's Task tool:\n /*\n const result = await claudeCodeTask({\n subagent_type: agentName,\n prompt: prompt,\n description: `${agentConfig.type} task execution`\n });\n \n return result.output;\n */\n\n // For now, simulate the Claude Code agent execution\n return this.simulateClaudeCodeExecution(agentName, prompt, agentConfig);\n }\n\n /**\n * Simulate Claude Code execution (temporary until real integration)\n */\n private simulateClaudeCodeExecution(\n agentName: string,\n prompt: string,\n agentConfig: ClaudeCodeAgent\n ): Promise<string> {\n return new Promise((resolve) => {\n // Simulate execution time based on agent type and complexity\n const executionTime =\n agentConfig.type === 'oracle'\n ? 2000 + Math.random() * 3000 // 2-5 seconds for Oracle\n : 1000 + Math.random() * 2000; // 1-3 seconds for Workers\n\n setTimeout(() => {\n const result = `Claude Code agent '${agentName}' completed task successfully.\n \nAgent Capabilities Used: ${agentConfig.capabilities.slice(0, 3).join(', ')}\nTask Type: ${agentConfig.type}\nSpecializations: ${agentConfig.specializations.join(', ')}\n\nSimulated output based on prompt context: ${prompt.substring(0, 100)}...\n\nThis simulation will be replaced with actual Claude Code Task tool integration.`;\n\n resolve(result);\n }, executionTime);\n });\n }\n\n /**\n * Complete a successful task\n */\n private completeTask(task: TaskExecution): void {\n this.completedTasks.push({ ...task });\n this.metrics.completedTasks++;\n\n // Update metrics\n this.updateExecutionMetrics(task);\n this.updateAgentUtilization(task.agentName);\n this.updateSuccessRate();\n\n logger.info('Claude Code task completed', {\n taskId: task.id,\n agentName: task.agentName,\n executionTime: task.endTime! - task.startTime,\n retries: task.retryCount,\n cost: this.calculateActualCost(task),\n });\n }\n\n /**\n * Handle a failed task\n */\n private failTask(task: TaskExecution, error: Error): void {\n this.completedTasks.push({ ...task });\n this.metrics.failedTasks++;\n\n this.updateExecutionMetrics(task);\n this.updateSuccessRate();\n\n logger.error('Claude Code task failed', {\n taskId: task.id,\n agentName: task.agentName,\n error: error.message,\n retries: task.retryCount,\n executionTime: task.endTime! - task.startTime,\n });\n }\n\n /**\n * Update execution time metrics\n */\n private updateExecutionMetrics(task: TaskExecution): void {\n if (!task.endTime) return;\n\n const executionTime = task.endTime - task.startTime;\n const totalTasks = this.metrics.completedTasks + this.metrics.failedTasks;\n\n if (totalTasks === 1) {\n this.metrics.averageExecutionTime = executionTime;\n } else {\n this.metrics.averageExecutionTime =\n (this.metrics.averageExecutionTime * (totalTasks - 1) + executionTime) /\n totalTasks;\n }\n\n this.metrics.totalCost += this.calculateActualCost(task);\n }\n\n /**\n * Update agent utilization metrics\n */\n private updateAgentUtilization(agentName: string): void {\n this.metrics.agentUtilization[agentName] =\n (this.metrics.agentUtilization[agentName] || 0) + 1;\n }\n\n /**\n * Update success rate\n */\n private updateSuccessRate(): void {\n const total = this.metrics.completedTasks + this.metrics.failedTasks;\n this.metrics.successRate =\n total > 0 ? this.metrics.completedTasks / total : 0;\n }\n\n /**\n * Estimate task cost based on prompt and agent\n */\n private estimateTaskCost(\n prompt: string,\n agentConfig: ClaudeCodeAgent\n ): number {\n const estimatedTokens = this.estimateTokenUsage(prompt, '');\n const baseCost = agentConfig.type === 'oracle' ? 0.015 : 0.00025; // per 1K tokens\n return (estimatedTokens / 1000) * baseCost * agentConfig.costMultiplier;\n }\n\n /**\n * Estimate token usage\n */\n private estimateTokenUsage(prompt: string, response: string): number {\n // Rough estimation: ~4 characters per token\n return Math.ceil((prompt.length + response.length) / 4);\n }\n\n /**\n * Calculate actual task cost\n */\n private calculateActualCost(task: TaskExecution): number {\n if (!task.actualTokens) return task.estimatedCost;\n\n const baseCost = task.agentType === 'oracle' ? 0.015 : 0.00025;\n return (task.actualTokens / 1000) * baseCost;\n }\n\n /**\n * Wait for all active tasks to complete\n */\n private async waitForTaskCompletion(): Promise<void> {\n while (this.activeTasks.size > 0) {\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n\n /**\n * Reset metrics\n */\n private resetMetrics(): void {\n this.metrics = {\n totalTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n averageExecutionTime: 0,\n totalCost: 0,\n successRate: 0,\n agentUtilization: {},\n };\n }\n\n /**\n * Get active task status\n */\n getActiveTaskStatus(): {\n taskId: string;\n agentName: string;\n status: string;\n runtime: number;\n }[] {\n return Array.from(this.activeTasks.values()).map((task) => ({\n taskId: task.id,\n agentName: task.agentName,\n status: task.status,\n runtime: Date.now() - task.startTime,\n }));\n }\n\n /**\n * Cancel active task\n */\n async cancelTask(taskId: string): Promise<boolean> {\n const task = this.activeTasks.get(taskId);\n if (!task) return false;\n\n task.status = 'failed';\n task.error = 'Task cancelled by user';\n task.endTime = Date.now();\n\n this.failTask(task, new Error('Task cancelled'));\n this.activeTasks.delete(taskId);\n\n logger.info('Task cancelled', { taskId, agentName: task.agentName });\n return true;\n }\n}\n\nexport default ClaudeCodeTaskCoordinator;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Claude Code Task Coordinator\n *\n * Coordinates task execution between StackMemory and Claude Code's Task tool.\n * Handles agent invocation, result processing, and error recovery.\n */\n\nimport { v4 as uuidv4 } from 'uuid';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { ClaudeCodeAgent } from './agent-bridge.js';\n\nexport interface TaskExecution {\n id: string;\n agentName: string;\n agentType: 'oracle' | 'worker' | 'reviewer';\n prompt: string;\n startTime: number;\n endTime?: number;\n status: 'pending' | 'running' | 'completed' | 'failed';\n result?: string;\n error?: string;\n retryCount: number;\n estimatedCost: number;\n actualTokens?: number;\n}\n\nexport interface CoordinationMetrics {\n totalTasks: number;\n completedTasks: number;\n failedTasks: number;\n averageExecutionTime: number;\n totalCost: number;\n successRate: number;\n agentUtilization: Record<string, number>;\n}\n\n/**\n * Claude Code Task Coordinator\n * Manages task execution and coordination with Claude Code agents\n */\nexport class ClaudeCodeTaskCoordinator {\n private activeTasks: Map<string, TaskExecution> = new Map();\n private completedTasks: TaskExecution[] = [];\n private metrics: CoordinationMetrics;\n\n constructor() {\n this.metrics = {\n totalTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n averageExecutionTime: 0,\n totalCost: 0,\n successRate: 0,\n agentUtilization: {},\n };\n }\n\n /**\n * Execute task with Claude Code agent\n */\n async executeTask(\n agentName: string,\n agentConfig: ClaudeCodeAgent,\n prompt: string,\n options: {\n maxRetries?: number;\n timeout?: number;\n priority?: 'low' | 'medium' | 'high';\n } = {}\n ): Promise<string> {\n const taskId = uuidv4();\n const { maxRetries = 2, timeout = 300000, priority = 'medium' } = options;\n\n const task: TaskExecution = {\n id: taskId,\n agentName,\n agentType: agentConfig.type,\n prompt,\n startTime: Date.now(),\n status: 'pending',\n retryCount: 0,\n estimatedCost: this.estimateTaskCost(prompt, agentConfig),\n };\n\n this.activeTasks.set(taskId, task);\n this.metrics.totalTasks++;\n\n logger.info('Starting Claude Code task execution', {\n taskId,\n agentName,\n agentType: agentConfig.type,\n promptLength: prompt.length,\n estimatedCost: task.estimatedCost,\n priority,\n });\n\n try {\n // Execute with retries\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n task.retryCount = attempt;\n task.status = 'running';\n\n // Execute the task with timeout\n const result = await this.executeWithTimeout(\n () => this.invokeClaudeCodeAgent(agentName, prompt, agentConfig),\n timeout\n );\n\n // Task completed successfully\n task.status = 'completed';\n task.result = result;\n task.endTime = Date.now();\n task.actualTokens = this.estimateTokenUsage(prompt, result);\n\n this.completeTask(task);\n return result;\n } catch (error) {\n lastError = error as Error;\n task.status = 'failed';\n\n logger.warn(`Claude Code task attempt ${attempt + 1} failed`, {\n taskId,\n agentName,\n error: lastError.message,\n attempt: attempt + 1,\n maxRetries: maxRetries + 1,\n });\n\n // Don't retry if it's the last attempt\n if (attempt === maxRetries) {\n break;\n }\n\n // Wait before retry with exponential backoff\n const backoffMs = Math.min(1000 * Math.pow(2, attempt), 10000);\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n }\n }\n\n // All retries exhausted\n task.error = lastError?.message || 'Unknown error';\n task.endTime = Date.now();\n this.failTask(task, lastError!);\n throw lastError;\n } finally {\n this.activeTasks.delete(taskId);\n }\n }\n\n /**\n * Execute multiple tasks in parallel with coordination\n */\n async executeParallelTasks(\n tasks: {\n agentName: string;\n agentConfig: ClaudeCodeAgent;\n prompt: string;\n priority?: 'low' | 'medium' | 'high';\n }[]\n ): Promise<{ results: string[]; failures: Error[] }> {\n logger.info('Executing parallel Claude Code tasks', {\n taskCount: tasks.length,\n agents: tasks.map((t) => t.agentName),\n });\n\n // Group tasks by priority\n const priorityGroups = {\n high: tasks.filter((t) => t.priority === 'high'),\n medium: tasks.filter((t) => t.priority === 'medium'),\n low: tasks.filter((t) => t.priority === 'low'),\n };\n\n const results: string[] = [];\n const failures: Error[] = [];\n\n // Execute high priority tasks first\n for (const priorityLevel of ['high', 'medium', 'low'] as const) {\n const priorityTasks = priorityGroups[priorityLevel];\n if (priorityTasks.length === 0) continue;\n\n logger.info(`Executing ${priorityLevel} priority tasks`, {\n count: priorityTasks.length,\n });\n\n // Execute tasks in this priority level concurrently\n const promises = priorityTasks.map(async (task) => {\n try {\n const result = await this.executeTask(\n task.agentName,\n task.agentConfig,\n task.prompt,\n { priority: task.priority }\n );\n return { success: true, result };\n } catch (error) {\n return { success: false, error: error as Error };\n }\n });\n\n const outcomes = await Promise.allSettled(promises);\n\n for (const outcome of outcomes) {\n if (outcome.status === 'fulfilled') {\n if (outcome.value.success) {\n results.push(outcome.value.result);\n } else {\n failures.push(outcome.value.error);\n }\n } else {\n failures.push(new Error(outcome.reason));\n }\n }\n }\n\n logger.info('Parallel task execution completed', {\n totalTasks: tasks.length,\n successful: results.length,\n failed: failures.length,\n successRate: ((results.length / tasks.length) * 100).toFixed(1),\n });\n\n return { results, failures };\n }\n\n /**\n * Get coordination metrics and health status\n */\n getCoordinationMetrics(): CoordinationMetrics & {\n activeTasks: number;\n recentErrors: string[];\n performanceTrend: 'improving' | 'stable' | 'degrading';\n } {\n // Calculate recent error rate for performance trend\n const recentTasks = this.completedTasks.slice(-10);\n const recentErrorRate =\n recentTasks.length > 0\n ? recentTasks.filter((t) => t.status === 'failed').length /\n recentTasks.length\n : 0;\n\n const performanceTrend =\n recentErrorRate < 0.1\n ? 'improving'\n : recentErrorRate < 0.3\n ? 'stable'\n : 'degrading';\n\n const recentErrors = this.completedTasks\n .slice(-5)\n .filter((t) => t.status === 'failed')\n .map((t) => t.error || 'Unknown error');\n\n return {\n ...this.metrics,\n activeTasks: this.activeTasks.size,\n recentErrors,\n performanceTrend,\n };\n }\n\n /**\n * Clean up resources and reset metrics\n */\n async cleanup(): Promise<void> {\n logger.info('Cleaning up Claude Code Task Coordinator', {\n activeTasks: this.activeTasks.size,\n completedTasks: this.completedTasks.length,\n });\n\n // Wait for active tasks to complete or force cleanup after timeout\n if (this.activeTasks.size > 0) {\n const timeoutPromise = new Promise((resolve) =>\n setTimeout(resolve, 30000)\n );\n const completionPromise = this.waitForTaskCompletion();\n\n await Promise.race([completionPromise, timeoutPromise]);\n\n if (this.activeTasks.size > 0) {\n logger.warn('Force terminating active tasks', {\n remainingTasks: this.activeTasks.size,\n });\n }\n }\n\n this.activeTasks.clear();\n this.completedTasks = [];\n this.resetMetrics();\n }\n\n /**\n * Execute with timeout wrapper\n */\n private async executeWithTimeout<T>(\n fn: () => Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n let timer: ReturnType<typeof setTimeout>;\n const timeoutPromise = new Promise<T>((_, reject) => {\n timer = setTimeout(() => {\n reject(new Error(`Task execution timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([fn(), timeoutPromise]);\n } finally {\n clearTimeout(timer!);\n }\n }\n\n /**\n * Invoke Claude Code agent (integration point)\n */\n private async invokeClaudeCodeAgent(\n agentName: string,\n prompt: string,\n agentConfig: ClaudeCodeAgent\n ): Promise<string> {\n logger.debug('Invoking Claude Code agent', {\n agentName,\n agentType: agentConfig.type,\n promptTokens: this.estimateTokenUsage(prompt, ''),\n });\n\n // TODO: Replace with actual Claude Code Task tool invocation\n // This is where we would call Claude Code's Task tool:\n /*\n const result = await claudeCodeTask({\n subagent_type: agentName,\n prompt: prompt,\n description: `${agentConfig.type} task execution`\n });\n \n return result.output;\n */\n\n // For now, simulate the Claude Code agent execution\n return this.simulateClaudeCodeExecution(agentName, prompt, agentConfig);\n }\n\n /**\n * Simulate Claude Code execution (temporary until real integration)\n */\n private simulateClaudeCodeExecution(\n agentName: string,\n prompt: string,\n agentConfig: ClaudeCodeAgent\n ): Promise<string> {\n return new Promise((resolve) => {\n // Simulate execution time based on agent type and complexity\n const executionTime =\n agentConfig.type === 'oracle'\n ? 2000 + Math.random() * 3000 // 2-5 seconds for Oracle\n : 1000 + Math.random() * 2000; // 1-3 seconds for Workers\n\n setTimeout(() => {\n const result = `Claude Code agent '${agentName}' completed task successfully.\n \nAgent Capabilities Used: ${agentConfig.capabilities.slice(0, 3).join(', ')}\nTask Type: ${agentConfig.type}\nSpecializations: ${agentConfig.specializations.join(', ')}\n\nSimulated output based on prompt context: ${prompt.substring(0, 100)}...\n\nThis simulation will be replaced with actual Claude Code Task tool integration.`;\n\n resolve(result);\n }, executionTime);\n });\n }\n\n /**\n * Complete a successful task\n */\n private completeTask(task: TaskExecution): void {\n this.completedTasks.push({ ...task });\n this.metrics.completedTasks++;\n\n // Update metrics\n this.updateExecutionMetrics(task);\n this.updateAgentUtilization(task.agentName);\n this.updateSuccessRate();\n\n logger.info('Claude Code task completed', {\n taskId: task.id,\n agentName: task.agentName,\n executionTime: task.endTime! - task.startTime,\n retries: task.retryCount,\n cost: this.calculateActualCost(task),\n });\n }\n\n /**\n * Handle a failed task\n */\n private failTask(task: TaskExecution, error: Error): void {\n this.completedTasks.push({ ...task });\n this.metrics.failedTasks++;\n\n this.updateExecutionMetrics(task);\n this.updateSuccessRate();\n\n logger.error('Claude Code task failed', {\n taskId: task.id,\n agentName: task.agentName,\n error: error.message,\n retries: task.retryCount,\n executionTime: task.endTime! - task.startTime,\n });\n }\n\n /**\n * Update execution time metrics\n */\n private updateExecutionMetrics(task: TaskExecution): void {\n if (!task.endTime) return;\n\n const executionTime = task.endTime - task.startTime;\n const totalTasks = this.metrics.completedTasks + this.metrics.failedTasks;\n\n if (totalTasks === 1) {\n this.metrics.averageExecutionTime = executionTime;\n } else {\n this.metrics.averageExecutionTime =\n (this.metrics.averageExecutionTime * (totalTasks - 1) + executionTime) /\n totalTasks;\n }\n\n this.metrics.totalCost += this.calculateActualCost(task);\n }\n\n /**\n * Update agent utilization metrics\n */\n private updateAgentUtilization(agentName: string): void {\n this.metrics.agentUtilization[agentName] =\n (this.metrics.agentUtilization[agentName] || 0) + 1;\n }\n\n /**\n * Update success rate\n */\n private updateSuccessRate(): void {\n const total = this.metrics.completedTasks + this.metrics.failedTasks;\n this.metrics.successRate =\n total > 0 ? this.metrics.completedTasks / total : 0;\n }\n\n /**\n * Estimate task cost based on prompt and agent\n */\n private estimateTaskCost(\n prompt: string,\n agentConfig: ClaudeCodeAgent\n ): number {\n const estimatedTokens = this.estimateTokenUsage(prompt, '');\n const baseCost = agentConfig.type === 'oracle' ? 0.015 : 0.00025; // per 1K tokens\n return (estimatedTokens / 1000) * baseCost * agentConfig.costMultiplier;\n }\n\n /**\n * Estimate token usage\n */\n private estimateTokenUsage(prompt: string, response: string): number {\n // Rough estimation: ~4 characters per token\n return Math.ceil((prompt.length + response.length) / 4);\n }\n\n /**\n * Calculate actual task cost\n */\n private calculateActualCost(task: TaskExecution): number {\n if (!task.actualTokens) return task.estimatedCost;\n\n const baseCost = task.agentType === 'oracle' ? 0.015 : 0.00025;\n return (task.actualTokens / 1000) * baseCost;\n }\n\n /**\n * Wait for all active tasks to complete\n */\n private async waitForTaskCompletion(): Promise<void> {\n while (this.activeTasks.size > 0) {\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n\n /**\n * Reset metrics\n */\n private resetMetrics(): void {\n this.metrics = {\n totalTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n averageExecutionTime: 0,\n totalCost: 0,\n successRate: 0,\n agentUtilization: {},\n };\n }\n\n /**\n * Get active task status\n */\n getActiveTaskStatus(): {\n taskId: string;\n agentName: string;\n status: string;\n runtime: number;\n }[] {\n return Array.from(this.activeTasks.values()).map((task) => ({\n taskId: task.id,\n agentName: task.agentName,\n status: task.status,\n runtime: Date.now() - task.startTime,\n }));\n }\n\n /**\n * Cancel active task\n */\n async cancelTask(taskId: string): Promise<boolean> {\n const task = this.activeTasks.get(taskId);\n if (!task) return false;\n\n task.status = 'failed';\n task.error = 'Task cancelled by user';\n task.endTime = Date.now();\n\n this.failTask(task, new Error('Task cancelled'));\n this.activeTasks.delete(taskId);\n\n logger.info('Task cancelled', { taskId, agentName: task.agentName });\n return true;\n }\n}\n\nexport default ClaudeCodeTaskCoordinator;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -10,6 +10,7 @@ import { logger } from "../../../core/monitoring/logger.js";
10
10
  import { FrameManager } from "../../../core/context/index.js";
11
11
  import { SessionManager } from "../../../core/session/session-manager.js";
12
12
  import { SQLiteAdapter } from "../../../core/database/sqlite-adapter.js";
13
+ import { createTransformersProvider } from "../../../core/database/transformers-embedding-provider.js";
13
14
  import { ContextBudgetManager } from "../context/context-budget-manager.js";
14
15
  import { StateReconciler } from "../state/state-reconciler.js";
15
16
  import {
@@ -58,7 +59,9 @@ class RalphStackMemoryBridge {
58
59
  await dbAdapter.connect();
59
60
  const db = dbAdapter.db;
60
61
  const projectId = path.basename(this.ralphDir);
61
- this.frameManager = new FrameManager(db, projectId, { skipContextBridge: true });
62
+ this.frameManager = new FrameManager(db, projectId, {
63
+ skipContextBridge: true
64
+ });
62
65
  if (this.requiresDatabase) {
63
66
  if (session.database && session.projectId) {
64
67
  this.frameManager = new FrameManager(
@@ -744,7 +747,8 @@ class RalphStackMemoryBridge {
744
747
  async getDatabaseAdapter() {
745
748
  const dbPath = path.join(this.ralphDir, "stackmemory.db");
746
749
  const projectId = path.basename(this.ralphDir);
747
- return new SQLiteAdapter(projectId, { dbPath });
750
+ const embeddingProvider = await createTransformersProvider() ?? void 0;
751
+ return new SQLiteAdapter(projectId, { dbPath, embeddingProvider });
748
752
  }
749
753
  /**
750
754
  * Additional helper methods