claude-flow 2.7.18 → 2.7.20
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/bin/claude-flow +1 -1
- package/dist/src/cli/help-formatter.js +0 -3
- package/dist/src/cli/help-formatter.js.map +1 -1
- package/dist/src/cli/simple-cli.js +182 -172
- package/dist/src/cli/simple-cli.js.map +1 -1
- package/dist/src/cli/simple-commands/config.js +137 -119
- package/dist/src/cli/simple-commands/config.js.map +1 -1
- package/dist/src/cli/simple-commands/memory.js +10 -1
- package/dist/src/cli/simple-commands/memory.js.map +1 -1
- package/dist/src/cli/validation-helper.js.map +1 -1
- package/dist/src/reasoningbank/reasoningbank-adapter.js +22 -4
- package/dist/src/reasoningbank/reasoningbank-adapter.js.map +1 -1
- package/dist/src/utils/key-redactor.js.map +1 -1
- package/dist/src/utils/metrics-reader.js +37 -39
- package/dist/src/utils/metrics-reader.js.map +1 -1
- package/docs/NPX_MEMORY_FIX_v2.7.19.md +305 -0
- package/package.json +2 -2
- package/scripts/fix-agentic-flow-sqlite.sh +30 -0
- package/src/cli/simple-commands/memory.js +15 -1
- package/src/reasoningbank/reasoningbank-adapter.js +30 -4
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from 'path';
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
3
|
import { exec } from 'child_process';
|
|
4
4
|
import { promisify } from 'util';
|
|
5
5
|
const execAsync = promisify(exec);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
this.sessionsDir = '.claude-flow/sessions';
|
|
10
|
-
}
|
|
6
|
+
export class MetricsReader {
|
|
7
|
+
metricsDir = '.claude-flow/metrics';
|
|
8
|
+
sessionsDir = '.claude-flow/sessions';
|
|
11
9
|
async getSystemMetrics() {
|
|
12
10
|
try {
|
|
13
11
|
const filePath = path.join(this.metricsDir, 'system-metrics.json');
|
|
@@ -18,15 +16,6 @@ let MetricsReader = class MetricsReader {
|
|
|
18
16
|
return null;
|
|
19
17
|
}
|
|
20
18
|
}
|
|
21
|
-
async getTaskQueue() {
|
|
22
|
-
try {
|
|
23
|
-
const queueFile = '.claude-flow/tasks/queue.json';
|
|
24
|
-
const content = await fs.readFile(queueFile, 'utf8');
|
|
25
|
-
return JSON.parse(content);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
return [];
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
19
|
async getTaskMetrics() {
|
|
31
20
|
try {
|
|
32
21
|
const filePath = path.join(this.metricsDir, 'task-metrics.json');
|
|
@@ -47,30 +36,30 @@ let MetricsReader = class MetricsReader {
|
|
|
47
36
|
}
|
|
48
37
|
async getActiveAgents() {
|
|
49
38
|
try {
|
|
39
|
+
const perfMetrics = await this.getPerformanceMetrics();
|
|
40
|
+
const sessionFiles = await this.getSessionFiles();
|
|
50
41
|
const agents = [];
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
const content = await fs.readFile(path.join(agentsDir, file), 'utf8');
|
|
58
|
-
const agent = JSON.parse(content);
|
|
59
|
-
agents.push(agent);
|
|
60
|
-
} catch {}
|
|
42
|
+
for (const file of sessionFiles){
|
|
43
|
+
try {
|
|
44
|
+
const content = await fs.readFile(path.join(this.sessionsDir, 'pair', file), 'utf8');
|
|
45
|
+
const sessionData = JSON.parse(content);
|
|
46
|
+
if (sessionData.agents && Array.isArray(sessionData.agents)) {
|
|
47
|
+
agents.push(...sessionData.agents);
|
|
61
48
|
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (agents.length === 0) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
49
|
+
} catch {}
|
|
50
|
+
}
|
|
51
|
+
if (agents.length === 0 && perfMetrics) {
|
|
52
|
+
const activeCount = perfMetrics.activeAgents || 0;
|
|
53
|
+
const totalCount = perfMetrics.totalAgents || 0;
|
|
54
|
+
for(let i = 0; i < totalCount; i++){
|
|
55
|
+
agents.push({
|
|
56
|
+
id: `agent-${i + 1}`,
|
|
57
|
+
name: `Agent ${i + 1}`,
|
|
58
|
+
type: i === 0 ? 'orchestrator' : 'worker',
|
|
59
|
+
status: i < activeCount ? 'active' : 'idle',
|
|
60
|
+
activeTasks: i < activeCount ? 1 : 0,
|
|
61
|
+
lastActivity: Date.now() - i * 1000
|
|
62
|
+
});
|
|
74
63
|
}
|
|
75
64
|
}
|
|
76
65
|
return agents;
|
|
@@ -146,7 +135,7 @@ let MetricsReader = class MetricsReader {
|
|
|
146
135
|
}
|
|
147
136
|
async getMCPServerStatus() {
|
|
148
137
|
try {
|
|
149
|
-
const { stdout } = await execAsync('ps aux | grep -E "mcp" | grep -v grep | wc -l');
|
|
138
|
+
const { stdout } = await execAsync('ps aux | grep -E "mcp-server\\.js|claude-flow mcp start" | grep -v grep | wc -l');
|
|
150
139
|
const processCount = parseInt(stdout.trim(), 10);
|
|
151
140
|
const { stdout: orchestratorOut } = await execAsync('ps aux | grep -E "claude-flow start" | grep -v grep | wc -l');
|
|
152
141
|
const orchestratorRunning = parseInt(orchestratorOut.trim(), 10) > 0;
|
|
@@ -175,6 +164,15 @@ let MetricsReader = class MetricsReader {
|
|
|
175
164
|
};
|
|
176
165
|
}
|
|
177
166
|
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
//# sourceMappingURL=metrics-reader.js.map processCount: 0,
|
|
170
|
+
orchestratorRunning: false,
|
|
171
|
+
port: null,
|
|
172
|
+
connections: 0
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
178
176
|
};
|
|
179
177
|
export { MetricsReader };
|
|
180
178
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/metrics-reader.js"],"sourcesContent":["import { promises as fs } from 'fs';\nimport path from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\nclass MetricsReader {\n constructor() {\n this.metricsDir = '.claude-flow/metrics';\n this.sessionsDir = '.claude-flow/sessions';\n }\n\n async getSystemMetrics() {\n try {\n const filePath = path.join(this.metricsDir, 'system-metrics.json');\n const content = await fs.readFile(filePath, 'utf8');\n const metrics = JSON.parse(content);\n \n // Return the most recent metric\n return metrics.length > 0 ? metrics[metrics.length - 1] : null;\n } catch (error) {\n return null;\n }\n }\n\n async getTaskQueue() {\n try {\n const queueFile = '.claude-flow/tasks/queue.json';\n const content = await fs.readFile(queueFile, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return [];\n }\n }\n\n async getTaskMetrics() {\n try {\n const filePath = path.join(this.metricsDir, 'task-metrics.json');\n const content = await fs.readFile(filePath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return [];\n }\n }\n\n async getPerformanceMetrics() {\n try {\n const filePath = path.join(this.metricsDir, 'performance.json');\n const content = await fs.readFile(filePath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n async getActiveAgents() {\n try {\n const agents = [];\n \n // Check for agents in the .claude-flow/agents directory\n const agentsDir = '.claude-flow/agents';\n try {\n const agentFiles = await fs.readdir(agentsDir);\n for (const file of agentFiles) {\n if (file.endsWith('.json')) {\n try {\n const content = await fs.readFile(path.join(agentsDir, file), 'utf8');\n const agent = JSON.parse(content);\n agents.push(agent);\n } catch {\n // Skip invalid agent files\n }\n }\n }\n } catch {\n // Agents directory doesn't exist yet\n }\n \n // If no agents found in directory, check session files\n if (agents.length === 0) {\n const sessionFiles = await this.getSessionFiles();\n for (const file of sessionFiles) {\n try {\n const content = await fs.readFile(path.join(this.sessionsDir, 'pair', file), 'utf8');\n const sessionData = JSON.parse(content);\n \n if (sessionData.agents && Array.isArray(sessionData.agents)) {\n agents.push(...sessionData.agents);\n }\n } catch {\n // Skip invalid session files\n }\n }\n }\n \n return agents;\n } catch (error) {\n return [];\n }\n }\n\n async getSessionStatus() {\n try {\n const sessionFiles = await this.getSessionFiles();\n \n if (sessionFiles.length === 0) {\n return null;\n }\n \n // Get the most recent session\n const mostRecentFile = sessionFiles[sessionFiles.length - 1];\n const content = await fs.readFile(path.join(this.sessionsDir, 'pair', mostRecentFile), 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n async getRecentTasks(limit = 10) {\n try {\n const taskMetrics = await this.getTaskMetrics();\n \n // Sort by timestamp descending and take the limit\n return taskMetrics\n .sort((a, b) => b.timestamp - a.timestamp)\n .slice(0, limit)\n .map(task => ({\n id: task.id,\n type: task.type,\n status: task.success ? 'completed' : 'failed',\n startTime: task.timestamp - task.duration,\n endTime: task.timestamp,\n duration: task.duration\n }));\n } catch (error) {\n return [];\n }\n }\n\n async getOverallHealth() {\n try {\n const systemMetrics = await this.getSystemMetrics();\n const perfMetrics = await this.getPerformanceMetrics();\n \n if (!systemMetrics && !perfMetrics) {\n return 'error';\n }\n \n // Check memory usage\n if (systemMetrics && systemMetrics.memoryUsagePercent > 90) {\n return 'error';\n }\n \n if (systemMetrics && systemMetrics.memoryUsagePercent > 75) {\n return 'warning';\n }\n \n // Check CPU load\n if (systemMetrics && systemMetrics.cpuLoad > 0.8) {\n return 'warning';\n }\n \n // Check task failure rate\n if (perfMetrics && perfMetrics.totalTasks > 0) {\n const failureRate = perfMetrics.failedTasks / perfMetrics.totalTasks;\n if (failureRate > 0.5) {\n return 'error';\n }\n if (failureRate > 0.2) {\n return 'warning';\n }\n }\n \n return 'healthy';\n } catch (error) {\n return 'error';\n }\n }\n\n async getSessionFiles() {\n try {\n const files = await fs.readdir(path.join(this.sessionsDir, 'pair'));\n return files.filter(f => f.endsWith('.json')).sort();\n } catch (error) {\n return [];\n }\n }\n\n async getMCPServerStatus() {\n try {\n // Check if MCP server process is running (including flow-nexus and other MCP variants)\n const { stdout } = await execAsync('ps aux | grep -E \"mcp\" | grep -v grep | wc -l');\n const processCount = parseInt(stdout.trim(), 10);\n \n // Check for orchestrator running\n const { stdout: orchestratorOut } = await execAsync('ps aux | grep -E \"claude-flow start\" | grep -v grep | wc -l');\n const orchestratorRunning = parseInt(orchestratorOut.trim(), 10) > 0;\n \n // Determine status\n const isRunning = processCount > 0;\n \n // Try to get port from process (default is 3000)\n let port = 3000;\n try {\n const { stdout: portOut } = await execAsync('lsof -i :3000 2>/dev/null | grep LISTEN | wc -l');\n if (parseInt(portOut.trim(), 10) === 0) {\n // If port 3000 not listening, check other common ports\n port = null;\n }\n } catch {\n // lsof might not be available or port not in use\n }\n \n return {\n running: isRunning,\n processCount,\n orchestratorRunning,\n port,\n connections: processCount > 0 ? Math.max(1, processCount - 1) : 0 // Estimate connections\n };\n } catch (error) {\n // Fallback if commands fail\n return {\n running: false,\n processCount: 0,\n orchestratorRunning: false,\n port: null,\n connections: 0\n };\n }\n }\n}\n\nexport { MetricsReader };"],"names":["promises","fs","path","exec","promisify","execAsync","MetricsReader","metricsDir","sessionsDir","getSystemMetrics","filePath","join","content","readFile","metrics","JSON","parse","length","error","getTaskQueue","queueFile","getTaskMetrics","getPerformanceMetrics","getActiveAgents","agents","agentsDir","agentFiles","readdir","file","endsWith","agent","push","sessionFiles","getSessionFiles","sessionData","Array","isArray","getSessionStatus","mostRecentFile","getRecentTasks","limit","taskMetrics","sort","a","b","timestamp","slice","map","task","id","type","status","success","startTime","duration","endTime","getOverallHealth","systemMetrics","perfMetrics","memoryUsagePercent","cpuLoad","totalTasks","failureRate","failedTasks","files","filter","f","getMCPServerStatus","stdout","processCount","parseInt","trim","orchestratorOut","orchestratorRunning","isRunning","port","portOut","running","connections","Math","max"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/metrics-reader.ts"],"sourcesContent":["import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\ninterface SystemMetrics {\n timestamp: number;\n memoryTotal: number;\n memoryUsed: number;\n memoryFree: number;\n memoryUsagePercent: number;\n memoryEfficiency: number;\n cpuCount: number;\n cpuLoad: number;\n platform: string;\n uptime: number;\n}\n\ninterface TaskMetric {\n id: string;\n type: string;\n success: boolean;\n duration: number;\n timestamp: number;\n metadata: Record<string, any>;\n}\n\ninterface PerformanceMetrics {\n startTime: number;\n totalTasks: number;\n successfulTasks: number;\n failedTasks: number;\n totalAgents: number;\n activeAgents: number;\n neuralEvents: number;\n}\n\ninterface Agent {\n id: string;\n name: string;\n type: string;\n status: 'active' | 'idle' | 'busy';\n activeTasks: number;\n lastActivity?: number;\n}\n\ninterface SessionData {\n id: string;\n startTime: number;\n endTime?: number;\n agents: Agent[];\n tasks: any[];\n status: 'active' | 'completed' | 'paused';\n}\n\ninterface MCPServerStatus {\n running: boolean;\n processCount: number;\n orchestratorRunning: boolean;\n port: number | null;\n connections: number;\n}\n\nexport class MetricsReader {\n private metricsDir = '.claude-flow/metrics';\n private sessionsDir = '.claude-flow/sessions';\n\n async getSystemMetrics(): Promise<SystemMetrics | null> {\n try {\n const filePath = path.join(this.metricsDir, 'system-metrics.json');\n const content = await fs.readFile(filePath, 'utf8');\n const metrics: SystemMetrics[] = JSON.parse(content);\n \n // Return the most recent metric\n return metrics.length > 0 ? metrics[metrics.length - 1] : null;\n } catch (error) {\n return null;\n }\n }\n\n async getTaskMetrics(): Promise<TaskMetric[]> {\n try {\n const filePath = path.join(this.metricsDir, 'task-metrics.json');\n const content = await fs.readFile(filePath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return [];\n }\n }\n\n async getPerformanceMetrics(): Promise<PerformanceMetrics | null> {\n try {\n const filePath = path.join(this.metricsDir, 'performance.json');\n const content = await fs.readFile(filePath, 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n async getActiveAgents(): Promise<Agent[]> {\n try {\n // First check performance metrics for agent count\n const perfMetrics = await this.getPerformanceMetrics();\n \n // Also check session files for more detailed agent info\n const sessionFiles = await this.getSessionFiles();\n const agents: Agent[] = [];\n \n for (const file of sessionFiles) {\n try {\n const content = await fs.readFile(path.join(this.sessionsDir, 'pair', file), 'utf8');\n const sessionData = JSON.parse(content);\n \n if (sessionData.agents && Array.isArray(sessionData.agents)) {\n agents.push(...sessionData.agents);\n }\n } catch {\n // Skip invalid session files\n }\n }\n \n // If no agents found in sessions, create mock agents based on performance metrics\n if (agents.length === 0 && perfMetrics) {\n const activeCount = perfMetrics.activeAgents || 0;\n const totalCount = perfMetrics.totalAgents || 0;\n \n for (let i = 0; i < totalCount; i++) {\n agents.push({\n id: `agent-${i + 1}`,\n name: `Agent ${i + 1}`,\n type: i === 0 ? 'orchestrator' : 'worker',\n status: i < activeCount ? 'active' : 'idle',\n activeTasks: i < activeCount ? 1 : 0,\n lastActivity: Date.now() - (i * 1000)\n });\n }\n }\n \n return agents;\n } catch (error) {\n return [];\n }\n }\n\n async getSessionStatus(): Promise<SessionData | null> {\n try {\n const sessionFiles = await this.getSessionFiles();\n \n if (sessionFiles.length === 0) {\n return null;\n }\n \n // Get the most recent session\n const mostRecentFile = sessionFiles[sessionFiles.length - 1];\n const content = await fs.readFile(path.join(this.sessionsDir, 'pair', mostRecentFile), 'utf8');\n return JSON.parse(content);\n } catch (error) {\n return null;\n }\n }\n\n async getRecentTasks(limit: number = 10): Promise<any[]> {\n try {\n const taskMetrics = await this.getTaskMetrics();\n \n // Sort by timestamp descending and take the limit\n return taskMetrics\n .sort((a, b) => b.timestamp - a.timestamp)\n .slice(0, limit)\n .map(task => ({\n id: task.id,\n type: task.type,\n status: task.success ? 'completed' : 'failed',\n startTime: task.timestamp - task.duration,\n endTime: task.timestamp,\n duration: task.duration\n }));\n } catch (error) {\n return [];\n }\n }\n\n async getOverallHealth(): Promise<'healthy' | 'warning' | 'error'> {\n try {\n const systemMetrics = await this.getSystemMetrics();\n const perfMetrics = await this.getPerformanceMetrics();\n \n if (!systemMetrics && !perfMetrics) {\n return 'error';\n }\n \n // Check memory usage\n if (systemMetrics && systemMetrics.memoryUsagePercent > 90) {\n return 'error';\n }\n \n if (systemMetrics && systemMetrics.memoryUsagePercent > 75) {\n return 'warning';\n }\n \n // Check CPU load\n if (systemMetrics && systemMetrics.cpuLoad > 0.8) {\n return 'warning';\n }\n \n // Check task failure rate\n if (perfMetrics && perfMetrics.totalTasks > 0) {\n const failureRate = perfMetrics.failedTasks / perfMetrics.totalTasks;\n if (failureRate > 0.5) {\n return 'error';\n }\n if (failureRate > 0.2) {\n return 'warning';\n }\n }\n \n return 'healthy';\n } catch (error) {\n return 'error';\n }\n }\n\n private async getSessionFiles(): Promise<string[]> {\n try {\n const files = await fs.readdir(path.join(this.sessionsDir, 'pair'));\n return files.filter(f => f.endsWith('.json')).sort();\n } catch (error) {\n return [];\n }\n }\n\n async getMCPServerStatus(): Promise<MCPServerStatus> {\n try {\n // Check if MCP server process is running\n const { stdout } = await execAsync('ps aux | grep -E \"mcp-server\\\\.js|claude-flow mcp start\" | grep -v grep | wc -l');\n const processCount = parseInt(stdout.trim(), 10);\n \n // Check for orchestrator running\n const { stdout: orchestratorOut } = await execAsync('ps aux | grep -E \"claude-flow start\" | grep -v grep | wc -l');\n const orchestratorRunning = parseInt(orchestratorOut.trim(), 10) > 0;\n \n // Determine status\n const isRunning = processCount > 0;\n \n // Try to get port from process (default is 3000)\n let port: number | null = 3000;\n try {\n const { stdout: portOut } = await execAsync('lsof -i :3000 2>/dev/null | grep LISTEN | wc -l');\n if (parseInt(portOut.trim(), 10) === 0) {\n // If port 3000 not listening, check other common ports\n port = null;\n }\n } catch {\n // lsof might not be available or port not in use\n }\n \n return {\n running: isRunning,\n processCount,\n orchestratorRunning,\n port,\n connections: processCount > 0 ? Math.max(1, processCount - 1) : 0 // Estimate connections\n };\n } catch (error) {\n // Fallback if commands fail\n return {\n running: false,\n processCount: 0,\n orchestratorRunning: false,\n port: null,\n connections: 0\n };\n }\n }\n}"],"names":["fs","path","exec","promisify","execAsync","MetricsReader","metricsDir","sessionsDir","getSystemMetrics","filePath","join","content","readFile","metrics","JSON","parse","length","error","getTaskMetrics","getPerformanceMetrics","getActiveAgents","perfMetrics","sessionFiles","getSessionFiles","agents","file","sessionData","Array","isArray","push","activeCount","activeAgents","totalCount","totalAgents","i","id","name","type","status","activeTasks","lastActivity","Date","now","getSessionStatus","mostRecentFile","getRecentTasks","limit","taskMetrics","sort","a","b","timestamp","slice","map","task","success","startTime","duration","endTime","getOverallHealth","systemMetrics","memoryUsagePercent","cpuLoad","totalTasks","failureRate","failedTasks","files","readdir","filter","f","endsWith","getMCPServerStatus","stdout","processCount","parseInt","trim","orchestratorOut","orchestratorRunning","isRunning","port","portOut","running","connections","Math","max"],"mappings":"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"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# NPX Memory Command Fix - v2.7.19 Final Solution
|
|
2
|
+
|
|
3
|
+
**Issue:** `npx claude-flow@alpha memory` commands fail with BetterSqlite3 constructor error
|
|
4
|
+
**Status:** ✅ **FIXED in v2.7.19**
|
|
5
|
+
**Date:** 2025-10-25
|
|
6
|
+
**Versions:** v2.7.16 → v2.7.17 → v2.7.18 → **v2.7.19 (WORKING)**
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Problem Summary
|
|
11
|
+
|
|
12
|
+
When users run memory commands via `npx claude-flow@alpha memory store ...`, they encounter:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
TypeError: BetterSqlite3 is not a constructor
|
|
16
|
+
Migration error: TypeError: BetterSqlite3 is not a constructor
|
|
17
|
+
❌ Failed to store: Failed to initialize ReasoningBank: could not run migrations
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Root Cause
|
|
21
|
+
|
|
22
|
+
1. **npx installs packages in temporary directories** (`/home/user/.npm/_npx/{hash}/`)
|
|
23
|
+
2. **Optional dependencies are not installed** in npx temp directories
|
|
24
|
+
3. **better-sqlite3 is an optional dependency** required by ReasoningBank
|
|
25
|
+
4. **ReasoningBank initialization fails** when better-sqlite3 is missing
|
|
26
|
+
5. **Command crashes** instead of falling back gracefully
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Solution Evolution
|
|
31
|
+
|
|
32
|
+
### ❌ v2.7.16 (First Attempt)
|
|
33
|
+
**What was done:**
|
|
34
|
+
- Added npx detection in `reasoningbank-adapter.js`
|
|
35
|
+
- Showed helpful error message
|
|
36
|
+
- **Problem:** Still threw error, preventing fallback
|
|
37
|
+
|
|
38
|
+
### ❌ v2.7.17 (Second Attempt)
|
|
39
|
+
**What was done:**
|
|
40
|
+
- Expanded error detection to include "could not run migrations"
|
|
41
|
+
- **Problem:** Still throwing error at ensureInitialized()
|
|
42
|
+
|
|
43
|
+
### ❌ v2.7.18 (Third Attempt)
|
|
44
|
+
**What was done:**
|
|
45
|
+
- Changed `ensureInitialized()` to return `false` instead of throwing
|
|
46
|
+
- **Problem:** `detectMemoryMode()` didn't check return value, still tried to use ReasoningBank
|
|
47
|
+
|
|
48
|
+
### ✅ v2.7.19 (WORKING SOLUTION)
|
|
49
|
+
**What was done:**
|
|
50
|
+
1. `ensureInitialized()` returns `false` when initialization fails in npx (instead of throwing)
|
|
51
|
+
2. `detectMemoryMode()` checks if initialization returned `false` and falls back to JSON
|
|
52
|
+
3. Shows helpful error message with 3 solutions
|
|
53
|
+
4. Command completes successfully with JSON storage
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Technical Implementation
|
|
58
|
+
|
|
59
|
+
### File 1: `src/reasoningbank/reasoningbank-adapter.js`
|
|
60
|
+
|
|
61
|
+
**Change:** Return `false` instead of throwing error on npx failure
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
initPromise = (async () => {
|
|
65
|
+
try {
|
|
66
|
+
await ReasoningBank.initialize();
|
|
67
|
+
backendInitialized = true;
|
|
68
|
+
return true;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
const isSqliteError = error.message?.includes('BetterSqlite3 is not a constructor') ||
|
|
71
|
+
error.message?.includes('better-sqlite3') ||
|
|
72
|
+
error.message?.includes('could not run migrations');
|
|
73
|
+
const isNpx = process.env.npm_config_user_agent?.includes('npx') ||
|
|
74
|
+
process.cwd().includes('_npx');
|
|
75
|
+
|
|
76
|
+
if (isSqliteError && isNpx) {
|
|
77
|
+
// Show helpful message but DON'T throw - allow fallback
|
|
78
|
+
console.error('\n⚠️ NPX LIMITATION DETECTED\n');
|
|
79
|
+
console.error('ReasoningBank requires better-sqlite3, not available in npx.\n');
|
|
80
|
+
console.error('📚 Solutions:\n');
|
|
81
|
+
console.error(' 1. LOCAL INSTALL: npm install && node_modules/.bin/claude-flow\n');
|
|
82
|
+
console.error(' 2. USE MCP TOOLS: mcp__claude-flow__memory_usage(...)\n');
|
|
83
|
+
console.error(' 3. USE JSON FALLBACK (automatic): Command will continue...\n');
|
|
84
|
+
return false; // Signal failure but allow fallback
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Other errors - throw normally
|
|
88
|
+
throw new Error(`Failed to initialize ReasoningBank: ${error.message}`);
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### File 2: `src/cli/simple-commands/memory.js`
|
|
94
|
+
|
|
95
|
+
**Change:** Check initialization result before using ReasoningBank
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
async function detectMemoryMode(flags, subArgs) {
|
|
99
|
+
// ... [earlier code]
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const { initializeReasoningBank } = await import('../../reasoningbank/reasoningbank-adapter.js');
|
|
103
|
+
const initialized = await initializeReasoningBank();
|
|
104
|
+
|
|
105
|
+
// Check if initialization succeeded
|
|
106
|
+
if (!initialized) {
|
|
107
|
+
// Initialization failed - fall back to JSON
|
|
108
|
+
const isNpx = process.env.npm_config_user_agent?.includes('npx') ||
|
|
109
|
+
process.cwd().includes('_npx');
|
|
110
|
+
if (isNpx) {
|
|
111
|
+
console.log('\n✅ Automatically using JSON fallback for this command\n');
|
|
112
|
+
} else {
|
|
113
|
+
printWarning(`⚠️ SQLite unavailable, using JSON fallback`);
|
|
114
|
+
}
|
|
115
|
+
return 'basic'; // Use JSON mode
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Success - use ReasoningBank
|
|
119
|
+
printInfo('🗄️ Initialized SQLite backend (.swarm/memory.db)');
|
|
120
|
+
return 'reasoningbank';
|
|
121
|
+
} catch (error) {
|
|
122
|
+
// Handle other errors...
|
|
123
|
+
return 'basic';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Expected User Experience (v2.7.19+)
|
|
131
|
+
|
|
132
|
+
### With npx (Automatic Fallback)
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
$ npx claude-flow@alpha memory store "api-design" "REST with JWT auth"
|
|
136
|
+
|
|
137
|
+
⚠️ NPX LIMITATION DETECTED
|
|
138
|
+
|
|
139
|
+
ReasoningBank requires better-sqlite3, not available in npx temp directories.
|
|
140
|
+
|
|
141
|
+
📚 Solutions:
|
|
142
|
+
1. LOCAL INSTALL (Recommended):
|
|
143
|
+
npm install && node_modules/.bin/claude-flow memory store "key" "value"
|
|
144
|
+
|
|
145
|
+
2. USE MCP TOOLS instead:
|
|
146
|
+
mcp__claude-flow__memory_usage({ action: "store", key: "test", value: "data" })
|
|
147
|
+
|
|
148
|
+
3. USE JSON FALLBACK (automatic):
|
|
149
|
+
Command will continue with JSON storage...
|
|
150
|
+
|
|
151
|
+
✅ Automatically using JSON fallback for this command
|
|
152
|
+
|
|
153
|
+
✅ Stored successfully
|
|
154
|
+
📝 Key: api-design
|
|
155
|
+
📦 Namespace: default
|
|
156
|
+
💾 Size: 18 bytes
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### With Local Install (Full Features)
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
$ npm install
|
|
163
|
+
$ node_modules/.bin/claude-flow memory store "api-design" "REST with JWT auth"
|
|
164
|
+
|
|
165
|
+
🗄️ Initialized SQLite backend (.swarm/memory.db)
|
|
166
|
+
✅ Stored successfully in ReasoningBank
|
|
167
|
+
📝 Key: api-design
|
|
168
|
+
🧠 Memory ID: abc123...
|
|
169
|
+
📦 Namespace: default
|
|
170
|
+
💾 Size: 18 bytes
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Validation Tests
|
|
176
|
+
|
|
177
|
+
### Test 1: Version Check
|
|
178
|
+
```bash
|
|
179
|
+
$ npx claude-flow@alpha --version
|
|
180
|
+
v2.7.19
|
|
181
|
+
✅ PASS
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Test 2: Memory Store (npx)
|
|
185
|
+
```bash
|
|
186
|
+
$ npx claude-flow@alpha memory store "test-key" "test-value"
|
|
187
|
+
⚠️ NPX LIMITATION DETECTED
|
|
188
|
+
✅ Automatically using JSON fallback for this command
|
|
189
|
+
✅ Stored successfully
|
|
190
|
+
✅ PASS
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Test 3: Memory Query (npx)
|
|
194
|
+
```bash
|
|
195
|
+
$ npx claude-flow@alpha memory query "test"
|
|
196
|
+
✅ Found 1 result(s):
|
|
197
|
+
test-key = test-value (namespace: default)
|
|
198
|
+
✅ PASS
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Test 4: Memory Stats (npx)
|
|
202
|
+
```bash
|
|
203
|
+
$ npx claude-flow@alpha memory stats
|
|
204
|
+
✅ Memory Bank Statistics:
|
|
205
|
+
Total Entries: 1
|
|
206
|
+
Namespaces: 1
|
|
207
|
+
Size: 10 bytes
|
|
208
|
+
✅ PASS
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Files Changed
|
|
214
|
+
|
|
215
|
+
1. **src/reasoningbank/reasoningbank-adapter.js**
|
|
216
|
+
- Modified `ensureInitialized()` to return false instead of throwing
|
|
217
|
+
- Added npx detection and helpful error messages
|
|
218
|
+
- Lines changed: 36-76
|
|
219
|
+
|
|
220
|
+
2. **src/cli/simple-commands/memory.js**
|
|
221
|
+
- Modified `detectMemoryMode()` to check initialization return value
|
|
222
|
+
- Added automatic fallback logic
|
|
223
|
+
- Lines changed: 418-457
|
|
224
|
+
|
|
225
|
+
3. **package.json**
|
|
226
|
+
- Version: 2.7.16 → 2.7.19
|
|
227
|
+
|
|
228
|
+
4. **docs/MEMORY_COMMAND_FIX.md**
|
|
229
|
+
- Updated with v2.7.19 solution
|
|
230
|
+
- Documented automatic fallback behavior
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Why Previous Versions Failed
|
|
235
|
+
|
|
236
|
+
### v2.7.16 → v2.7.17
|
|
237
|
+
- Error detection worked
|
|
238
|
+
- Error message showed
|
|
239
|
+
- **But:** Still threw error, command failed
|
|
240
|
+
|
|
241
|
+
### v2.7.18
|
|
242
|
+
- Stopped throwing error (returned false)
|
|
243
|
+
- **But:** `detectMemoryMode()` didn't check return value
|
|
244
|
+
- Still tried to use ReasoningBank, called `storeMemory()`, which failed
|
|
245
|
+
|
|
246
|
+
### v2.7.19 ✅
|
|
247
|
+
- Returns false on failure
|
|
248
|
+
- **AND:** Checks return value before using ReasoningBank
|
|
249
|
+
- Falls back to JSON successfully
|
|
250
|
+
- Command completes without error
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Key Learnings
|
|
255
|
+
|
|
256
|
+
1. **npx limitation is real:** Optional dependencies never install in temp directories
|
|
257
|
+
2. **Silent failures are better than crashes:** Return false, don't throw
|
|
258
|
+
3. **Check all return values:** Even if initialization "succeeds", verify the result
|
|
259
|
+
4. **Graceful degradation:** JSON fallback works fine for most use cases
|
|
260
|
+
5. **Clear error messages:** Tell users exactly what happened and how to fix it
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Recommended Usage
|
|
265
|
+
|
|
266
|
+
### For Quick Testing (npx)
|
|
267
|
+
```bash
|
|
268
|
+
npx claude-flow@alpha memory store "key" "value"
|
|
269
|
+
# Works with JSON fallback - no installation required
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### For Production (local install)
|
|
273
|
+
```bash
|
|
274
|
+
npm install claude-flow@alpha
|
|
275
|
+
node_modules/.bin/claude-flow memory store "key" "value"
|
|
276
|
+
# Uses SQLite with full ReasoningBank features
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### For Workflows (MCP tools)
|
|
280
|
+
```javascript
|
|
281
|
+
// In Claude Code / Claude Desktop
|
|
282
|
+
mcp__claude-flow__memory_usage({
|
|
283
|
+
action: "store",
|
|
284
|
+
key: "api-pattern",
|
|
285
|
+
value: "REST with JWT auth",
|
|
286
|
+
namespace: "default"
|
|
287
|
+
})
|
|
288
|
+
// Best integration, no dependency issues
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Summary
|
|
294
|
+
|
|
295
|
+
**Problem:** npx memory commands crashed due to missing better-sqlite3
|
|
296
|
+
**Solution:** Detect npx, return false instead of throwing, check return value, fall back to JSON
|
|
297
|
+
**Result:** Commands work via npx with helpful error messages and automatic JSON fallback
|
|
298
|
+
|
|
299
|
+
**Status:** ✅ **FIXED AND VALIDATED**
|
|
300
|
+
**Version:** v2.7.19
|
|
301
|
+
**Date:** 2025-10-25
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
**All npx memory commands now work correctly with automatic JSON fallback!**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.20",
|
|
4
4
|
"description": "Enterprise-grade AI agent orchestration with WASM-powered ReasoningBank memory and AgentDB vector database (always uses latest agentic-flow)",
|
|
5
5
|
"mcpName": "io.github.ruvnet/claude-flow",
|
|
6
6
|
"main": "cli.mjs",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"format": "prettier --write 'src/**/*.{ts,js,json}'",
|
|
51
51
|
"diagnostics": "node -e \"import('./dist/monitoring/diagnostics.js').then(m => m.DiagnosticManager.quickDiagnostic().then(console.log))\"",
|
|
52
52
|
"health-check": "node -e \"import('./dist/monitoring/health-check.js').then(m => new m.HealthCheckManager().performHealthCheck().then(console.log))\"",
|
|
53
|
-
"postinstall": "node scripts/install-arm64.js || true && bash scripts/fix-agentdb-imports.sh || true",
|
|
53
|
+
"postinstall": "node scripts/install-arm64.js || true && bash scripts/fix-agentdb-imports.sh || true && bash scripts/fix-agentic-flow-sqlite.sh || true",
|
|
54
54
|
"prepublishOnly": "npm run update-version",
|
|
55
55
|
"publish:alpha": "npm publish --tag alpha",
|
|
56
56
|
"publish:major": "npm version major && npm publish",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Fix agentic-flow's broken better-sqlite3 import
|
|
3
|
+
# The dist/reasoningbank/db/queries.js file has BetterSqlite3 = null
|
|
4
|
+
# This script patches it to properly import better-sqlite3
|
|
5
|
+
|
|
6
|
+
QUERIES_FILE="node_modules/agentic-flow/dist/reasoningbank/db/queries.js"
|
|
7
|
+
|
|
8
|
+
if [ ! -f "$QUERIES_FILE" ]; then
|
|
9
|
+
echo "❌ File not found: $QUERIES_FILE"
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
echo "🔧 Fixing agentic-flow better-sqlite3 import..."
|
|
14
|
+
|
|
15
|
+
# Check if already fixed
|
|
16
|
+
if grep -q "import Database from 'better-sqlite3'" "$QUERIES_FILE"; then
|
|
17
|
+
echo "✅ Already fixed!"
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Backup original
|
|
22
|
+
cp "$QUERIES_FILE" "${QUERIES_FILE}.backup"
|
|
23
|
+
|
|
24
|
+
# Replace the broken import
|
|
25
|
+
sed -i '5s/const BetterSqlite3 = null; \/\/ Not used/import Database from '\''better-sqlite3'\'';/' "$QUERIES_FILE"
|
|
26
|
+
sed -i 's/new BetterSqlite3(/new Database(/g' "$QUERIES_FILE"
|
|
27
|
+
|
|
28
|
+
echo "✅ Fixed agentic-flow better-sqlite3 import!"
|
|
29
|
+
echo " Patched: $QUERIES_FILE"
|
|
30
|
+
echo " Backup: ${QUERIES_FILE}.backup"
|
|
@@ -418,7 +418,21 @@ async function detectMemoryMode(flags, subArgs) {
|
|
|
418
418
|
// Not initialized yet - try to auto-initialize on first use
|
|
419
419
|
try {
|
|
420
420
|
const { initializeReasoningBank } = await import('../../reasoningbank/reasoningbank-adapter.js');
|
|
421
|
-
await initializeReasoningBank();
|
|
421
|
+
const initialized = await initializeReasoningBank();
|
|
422
|
+
|
|
423
|
+
// Check if initialization succeeded (returns true) or failed (returns false)
|
|
424
|
+
if (!initialized) {
|
|
425
|
+
// Initialization failed but didn't throw - fall back to JSON
|
|
426
|
+
const isNpx = process.env.npm_config_user_agent?.includes('npx') ||
|
|
427
|
+
process.cwd().includes('_npx');
|
|
428
|
+
if (isNpx) {
|
|
429
|
+
console.log('\n✅ Automatically using JSON fallback for this command\n');
|
|
430
|
+
} else {
|
|
431
|
+
printWarning(`⚠️ SQLite unavailable, using JSON fallback`);
|
|
432
|
+
}
|
|
433
|
+
return 'basic';
|
|
434
|
+
}
|
|
435
|
+
|
|
422
436
|
printInfo('🗄️ Initialized SQLite backend (.swarm/memory.db)');
|
|
423
437
|
return 'reasoningbank';
|
|
424
438
|
} catch (error) {
|
|
@@ -95,7 +95,12 @@ export async function initializeReasoningBank() {
|
|
|
95
95
|
* - confidence -> confidence score
|
|
96
96
|
*/
|
|
97
97
|
export async function storeMemory(key, value, options = {}) {
|
|
98
|
-
await ensureInitialized();
|
|
98
|
+
const initialized = await ensureInitialized();
|
|
99
|
+
|
|
100
|
+
// If initialization failed, throw with clear message
|
|
101
|
+
if (!initialized) {
|
|
102
|
+
throw new Error('ReasoningBank not available (better-sqlite3 missing). Use JSON mode instead.');
|
|
103
|
+
}
|
|
99
104
|
|
|
100
105
|
try {
|
|
101
106
|
const memoryId = options.id || uuidv4();
|
|
@@ -159,7 +164,12 @@ export async function queryMemories(searchQuery, options = {}) {
|
|
|
159
164
|
return cached;
|
|
160
165
|
}
|
|
161
166
|
|
|
162
|
-
await ensureInitialized();
|
|
167
|
+
const initialized = await ensureInitialized();
|
|
168
|
+
|
|
169
|
+
// If initialization failed, return empty results
|
|
170
|
+
if (!initialized) {
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
163
173
|
const limit = options.limit || 10;
|
|
164
174
|
// Accept both 'namespace' and 'domain' for compatibility
|
|
165
175
|
const namespace = options.namespace || options.domain || 'default';
|
|
@@ -247,7 +257,12 @@ export async function queryMemories(searchQuery, options = {}) {
|
|
|
247
257
|
* List all memories (using Node.js backend database query)
|
|
248
258
|
*/
|
|
249
259
|
export async function listMemories(options = {}) {
|
|
250
|
-
await ensureInitialized();
|
|
260
|
+
const initialized = await ensureInitialized();
|
|
261
|
+
|
|
262
|
+
// If initialization failed, return empty list
|
|
263
|
+
if (!initialized) {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
251
266
|
const limit = options.limit || 10;
|
|
252
267
|
const namespace = options.namespace;
|
|
253
268
|
|
|
@@ -284,7 +299,18 @@ export async function listMemories(options = {}) {
|
|
|
284
299
|
* Get ReasoningBank statistics (Node.js backend)
|
|
285
300
|
*/
|
|
286
301
|
export async function getStatus() {
|
|
287
|
-
await ensureInitialized();
|
|
302
|
+
const initialized = await ensureInitialized();
|
|
303
|
+
|
|
304
|
+
// If initialization failed, return error status
|
|
305
|
+
if (!initialized) {
|
|
306
|
+
return {
|
|
307
|
+
total_memories: 0,
|
|
308
|
+
total_categories: 0,
|
|
309
|
+
storage_backend: 'Unavailable',
|
|
310
|
+
error: 'ReasoningBank initialization failed (better-sqlite3 not available)',
|
|
311
|
+
fallback_available: true
|
|
312
|
+
};
|
|
313
|
+
}
|
|
288
314
|
|
|
289
315
|
try {
|
|
290
316
|
const db = ReasoningBank.db.getDb();
|