@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.
- package/dist/src/cli/commands/skills.js +3 -1
- package/dist/src/cli/commands/skills.js.map +2 -2
- package/dist/src/core/database/database-adapter.js +4 -0
- package/dist/src/core/database/database-adapter.js.map +2 -2
- package/dist/src/core/database/sqlite-adapter.js +3 -0
- package/dist/src/core/database/sqlite-adapter.js.map +2 -2
- package/dist/src/core/database/transformers-embedding-provider.js +55 -0
- package/dist/src/core/database/transformers-embedding-provider.js.map +7 -0
- package/dist/src/core/retrieval/context-retriever.js +28 -19
- package/dist/src/core/retrieval/context-retriever.js.map +2 -2
- package/dist/src/daemon/daemon-config.js.map +2 -2
- package/dist/src/daemon/services/maintenance-service.js +31 -3
- package/dist/src/daemon/services/maintenance-service.js.map +2 -2
- package/dist/src/integrations/claude-code/task-coordinator.js +7 -2
- package/dist/src/integrations/claude-code/task-coordinator.js.map +2 -2
- package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +6 -2
- package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js.map +2 -2
- package/package.json +2 -1
|
@@ -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": ";;;;AAKA,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,YAAY;AACrB,SAAS,eAAe;
|
|
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.
|
|
149
|
-
|
|
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
|
-
|
|
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
|
|
5
|
-
"mappings": ";;;;AAMA,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AACrB,SAAS,eAAe;
|
|
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
|
-
|
|
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, {
|
|
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
|
-
|
|
750
|
+
const embeddingProvider = await createTransformersProvider() ?? void 0;
|
|
751
|
+
return new SQLiteAdapter(projectId, { dbPath, embeddingProvider });
|
|
748
752
|
}
|
|
749
753
|
/**
|
|
750
754
|
* Additional helper methods
|