claude-flow 2.7.31 → 2.7.33
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/.claude/skills/agentic-jujutsu/SKILL.md +645 -0
- package/CHANGELOG.md +19 -0
- package/bin/claude-flow +1 -1
- package/dist/src/cli/simple-cli.js +173 -79
- package/dist/src/cli/simple-cli.js.map +1 -1
- package/dist/src/cli/simple-commands/init/agent-copier.js +3 -9
- package/dist/src/cli/simple-commands/init/agent-copier.js.map +1 -1
- package/dist/src/cli/simple-commands/memory.js +67 -17
- package/dist/src/cli/simple-commands/memory.js.map +1 -1
- package/dist/src/core/version.js +1 -1
- package/dist/src/core/version.js.map +1 -1
- package/dist/src/utils/key-redactor.js.map +1 -1
- package/docs/AGENT_FOLDER_STRUCTURE_FIX.md +192 -0
- package/docs/BUG_REPORT_MEMORY_STATS.md +355 -0
- package/docs/FIX_VERIFICATION_MEMORY_STATS.md +235 -0
- package/docs/RECENT_RELEASES_SUMMARY.md +375 -0
- package/docs/V2.7.31_RELEASE_NOTES.md +375 -0
- package/package.json +2 -1
- package/src/cli/simple-commands/init/agent-copier.js +5 -10
- package/src/cli/simple-commands/memory.js +93 -19
- /package/.claude/agents/analysis/{code-review/analyze-code-quality.md → analyze-code-quality.md} +0 -0
- /package/.claude/agents/architecture/{system-design/arch-system-design.md → arch-system-design.md} +0 -0
- /package/.claude/agents/data/{ml/data-ml-model.md → data-ml-model.md} +0 -0
- /package/.claude/agents/development/{backend/dev-backend-api.md → dev-backend-api.md} +0 -0
- /package/.claude/agents/devops/{ci-cd/ops-cicd-github.md → ops-cicd-github.md} +0 -0
- /package/.claude/agents/documentation/{api-docs/docs-api-openapi.md → docs-api-openapi.md} +0 -0
- /package/.claude/agents/specialized/{mobile/spec-mobile-react-native.md → spec-mobile-react-native.md} +0 -0
- /package/.claude/agents/testing/{validation/production-validator.md → production-validator.md} +0 -0
- /package/.claude/agents/testing/{unit/tdd-london-swarm.md → tdd-london-swarm.md} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/key-redactor.
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/key-redactor.ts"],"sourcesContent":["/**\n * API Key Redaction Utility\n * Prevents sensitive data from leaking into logs, memory, or git commits\n */\n\nexport interface RedactionConfig {\n patterns: RegExp[];\n replacement: string;\n maskLength: number;\n}\n\nexport class KeyRedactor {\n private static readonly API_KEY_PATTERNS = [\n // Anthropic API keys\n /sk-ant-[a-zA-Z0-9_-]{95,}/gi,\n\n // OpenRouter API keys\n /sk-or-[a-zA-Z0-9_-]{32,}/gi,\n\n // Google/Gemini API keys\n /AIza[a-zA-Z0-9_-]{35}/gi,\n\n // Generic API keys\n /[a-zA-Z0-9_-]{20,}API[a-zA-Z0-9_-]{20,}/gi,\n\n // Bearer tokens\n /Bearer\\s+[a-zA-Z0-9_\\-\\.]{20,}/gi,\n\n // Environment variable format\n /([A-Z_]+_API_KEY|[A-Z_]+_TOKEN|[A-Z_]+_SECRET)=[\"']?([^\"'\\s]+)[\"']?/gi,\n\n // Supabase keys\n /eyJ[a-zA-Z0-9_-]*\\.eyJ[a-zA-Z0-9_-]*\\.[a-zA-Z0-9_-]*/gi,\n ];\n\n private static readonly SENSITIVE_FIELDS = [\n 'apiKey',\n 'api_key',\n 'token',\n 'secret',\n 'password',\n 'private_key',\n 'privateKey',\n 'accessToken',\n 'access_token',\n 'refreshToken',\n 'refresh_token',\n ];\n\n /**\n * Redact API keys and sensitive data from text\n */\n static redact(text: string, showPrefix = true): string {\n if (!text) return text;\n\n let redacted = text;\n\n // Redact using patterns\n this.API_KEY_PATTERNS.forEach(pattern => {\n redacted = redacted.replace(pattern, (match) => {\n if (showPrefix && match.length > 8) {\n const prefix = match.substring(0, 8);\n return `${prefix}...[REDACTED]`;\n }\n return '[REDACTED_API_KEY]';\n });\n });\n\n return redacted;\n }\n\n /**\n * Redact sensitive fields in objects\n */\n static redactObject<T extends Record<string, any>>(obj: T, deep = true): T {\n if (!obj || typeof obj !== 'object') return obj;\n\n const redacted = { ...obj };\n\n Object.keys(redacted).forEach(key => {\n const lowerKey = key.toLowerCase();\n\n // Check if field name is sensitive\n const isSensitive = this.SENSITIVE_FIELDS.some(field =>\n lowerKey.includes(field)\n );\n\n if (isSensitive && typeof redacted[key] === 'string') {\n const value = redacted[key] as string;\n if (value && value.length > 8) {\n redacted[key] = `${value.substring(0, 4)}...[REDACTED]` as any;\n } else {\n redacted[key] = '[REDACTED]' as any;\n }\n } else if (deep && typeof redacted[key] === 'object' && redacted[key] !== null) {\n redacted[key] = this.redactObject(redacted[key], deep);\n } else if (typeof redacted[key] === 'string') {\n // Redact any API keys in string values\n redacted[key] = this.redact(redacted[key]) as any;\n }\n });\n\n return redacted;\n }\n\n /**\n * Sanitize text for safe logging\n */\n static sanitize(text: string): string {\n return this.redact(text, true);\n }\n\n /**\n * Sanitize command arguments\n */\n static sanitizeArgs(args: string[]): string[] {\n return args.map(arg => {\n // Check if arg is a flag value pair\n if (arg.includes('key') || arg.includes('token') || arg.includes('secret')) {\n return this.redact(arg);\n }\n return arg;\n });\n }\n\n /**\n * Check if text contains unredacted sensitive data\n */\n static containsSensitiveData(text: string): boolean {\n return this.API_KEY_PATTERNS.some(pattern => pattern.test(text));\n }\n\n /**\n * Validate that text is safe for logging/storage\n */\n static validate(text: string): { safe: boolean; warnings: string[] } {\n const warnings: string[] = [];\n\n this.API_KEY_PATTERNS.forEach((pattern, index) => {\n if (pattern.test(text)) {\n warnings.push(`Potential API key detected (pattern ${index + 1})`);\n }\n });\n\n return {\n safe: warnings.length === 0,\n warnings,\n };\n }\n\n /**\n * Redact environment variables\n */\n static redactEnv(env: Record<string, string | undefined>): Record<string, string> {\n const redacted: Record<string, string> = {};\n\n Object.keys(env).forEach(key => {\n const value = env[key];\n if (!value) {\n redacted[key] = '';\n return;\n }\n\n const lowerKey = key.toLowerCase();\n const isSensitive = lowerKey.includes('key') ||\n lowerKey.includes('token') ||\n lowerKey.includes('secret') ||\n lowerKey.includes('password');\n\n if (isSensitive) {\n redacted[key] = value.length > 8\n ? `${value.substring(0, 4)}...[REDACTED]`\n : '[REDACTED]';\n } else {\n redacted[key] = value;\n }\n });\n\n return redacted;\n }\n}\n\n// Export singleton instance\nexport const redactor = KeyRedactor;\n"],"names":["KeyRedactor","API_KEY_PATTERNS","SENSITIVE_FIELDS","redact","text","showPrefix","redacted","forEach","pattern","replace","match","length","prefix","substring","redactObject","obj","deep","Object","keys","key","lowerKey","toLowerCase","isSensitive","some","field","includes","value","sanitize","sanitizeArgs","args","map","arg","containsSensitiveData","test","validate","warnings","index","push","safe","redactEnv","env","redactor"],"mappings":"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"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Agent Folder Structure Fix
|
|
2
|
+
|
|
3
|
+
## Issue
|
|
4
|
+
|
|
5
|
+
The `.claude/agents` folder was being generated with unnecessary nested subdirectories (e.g., `.claude/agents/analysis/code-review/`, `.claude/agents/architecture/system-design/`), creating too many hierarchy levels.
|
|
6
|
+
|
|
7
|
+
## Required Structure
|
|
8
|
+
|
|
9
|
+
All agent `.md` files should be directly in their category folders:
|
|
10
|
+
- ✅ `.claude/agents/analysis/code-analyzer.md`
|
|
11
|
+
- ✅ `.claude/agents/architecture/arch-system-design.md`
|
|
12
|
+
- ✅ `.claude/agents/development/dev-backend-api.md`
|
|
13
|
+
- ❌ ~~`.claude/agents/analysis/code-review/analyze-code-quality.md`~~ (too nested)
|
|
14
|
+
|
|
15
|
+
## Fix Applied
|
|
16
|
+
|
|
17
|
+
**File**: `src/cli/simple-commands/init/agent-copier.js`
|
|
18
|
+
|
|
19
|
+
**Function**: `createAgentDirectories()` (lines 137-164)
|
|
20
|
+
|
|
21
|
+
### Changes Made
|
|
22
|
+
|
|
23
|
+
Removed nested subdirectories from the `agentDirs` array:
|
|
24
|
+
|
|
25
|
+
```diff
|
|
26
|
+
const agentDirs = [
|
|
27
|
+
'.claude',
|
|
28
|
+
'.claude/agents',
|
|
29
|
+
'.claude/agents/core',
|
|
30
|
+
'.claude/agents/swarm',
|
|
31
|
+
'.claude/agents/hive-mind',
|
|
32
|
+
'.claude/agents/consensus',
|
|
33
|
+
'.claude/agents/optimization',
|
|
34
|
+
'.claude/agents/github',
|
|
35
|
+
'.claude/agents/sparc',
|
|
36
|
+
'.claude/agents/testing',
|
|
37
|
+
- '.claude/agents/testing/unit',
|
|
38
|
+
- '.claude/agents/testing/validation',
|
|
39
|
+
'.claude/agents/templates',
|
|
40
|
+
'.claude/agents/analysis',
|
|
41
|
+
- '.claude/agents/analysis/code-review',
|
|
42
|
+
'.claude/agents/architecture',
|
|
43
|
+
- '.claude/agents/architecture/system-design',
|
|
44
|
+
'.claude/agents/data',
|
|
45
|
+
- '.claude/agents/data/ml',
|
|
46
|
+
'.claude/agents/development',
|
|
47
|
+
- '.claude/agents/development/backend',
|
|
48
|
+
'.claude/agents/devops',
|
|
49
|
+
- '.claude/agents/devops/ci-cd',
|
|
50
|
+
'.claude/agents/documentation',
|
|
51
|
+
- '.claude/agents/documentation/api-docs',
|
|
52
|
+
'.claude/agents/specialized',
|
|
53
|
+
- '.claude/agents/specialized/mobile',
|
|
54
|
+
'.claude/agents/flow-nexus',
|
|
55
|
+
+ '.claude/agents/goal',
|
|
56
|
+
+ '.claude/agents/neural',
|
|
57
|
+
+ '.claude/agents/reasoning',
|
|
58
|
+
'.claude/commands',
|
|
59
|
+
'.claude/commands/flow-nexus'
|
|
60
|
+
];
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Changes Summary
|
|
64
|
+
|
|
65
|
+
**Removed** (11 nested directories):
|
|
66
|
+
- `.claude/agents/testing/unit`
|
|
67
|
+
- `.claude/agents/testing/validation`
|
|
68
|
+
- `.claude/agents/analysis/code-review`
|
|
69
|
+
- `.claude/agents/architecture/system-design`
|
|
70
|
+
- `.claude/agents/data/ml`
|
|
71
|
+
- `.claude/agents/development/backend`
|
|
72
|
+
- `.claude/agents/devops/ci-cd`
|
|
73
|
+
- `.claude/agents/documentation/api-docs`
|
|
74
|
+
- `.claude/agents/specialized/mobile`
|
|
75
|
+
|
|
76
|
+
**Added** (3 missing categories):
|
|
77
|
+
- `.claude/agents/goal`
|
|
78
|
+
- `.claude/agents/neural`
|
|
79
|
+
- `.claude/agents/reasoning`
|
|
80
|
+
|
|
81
|
+
**Total directories**: Reduced from 30 to 24 (flat structure)
|
|
82
|
+
|
|
83
|
+
## Test Results
|
|
84
|
+
|
|
85
|
+
### Test Execution
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
$ node -e "import { createAgentDirectories, copyAgentFiles } from './dist/src/cli/simple-commands/init/agent-copier.js';
|
|
89
|
+
async function test() {
|
|
90
|
+
const targetDir = 'tests/agent-structure-test';
|
|
91
|
+
await createAgentDirectories(targetDir, false);
|
|
92
|
+
await copyAgentFiles(targetDir, { force: true });
|
|
93
|
+
}
|
|
94
|
+
test().catch(console.error);"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Verification
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Count nested directories (should be 0)
|
|
101
|
+
$ find tests/agent-structure-test/.claude/agents -type d -mindepth 2 | wc -l
|
|
102
|
+
0
|
|
103
|
+
|
|
104
|
+
# Verify files copied correctly
|
|
105
|
+
$ find tests/agent-structure-test/.claude/agents -type f -name "*.md" | wc -l
|
|
106
|
+
76
|
|
107
|
+
|
|
108
|
+
# Check category structure
|
|
109
|
+
$ find tests/agent-structure-test/.claude/agents -type d | wc -l
|
|
110
|
+
22 # 1 base + 21 categories = 22 total
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Verified Folder Contents
|
|
114
|
+
|
|
115
|
+
✅ **Analysis** (flat):
|
|
116
|
+
- `analyze-code-quality.md`
|
|
117
|
+
- `code-analyzer.md`
|
|
118
|
+
|
|
119
|
+
✅ **Architecture** (flat):
|
|
120
|
+
- `arch-system-design.md`
|
|
121
|
+
|
|
122
|
+
✅ **Development** (flat):
|
|
123
|
+
- `dev-backend-api.md`
|
|
124
|
+
|
|
125
|
+
✅ **Testing** (flat):
|
|
126
|
+
- `production-validator.md`
|
|
127
|
+
- `tdd-london-swarm.md`
|
|
128
|
+
|
|
129
|
+
## Impact
|
|
130
|
+
|
|
131
|
+
### Before Fix ❌
|
|
132
|
+
```
|
|
133
|
+
.claude/agents/
|
|
134
|
+
├── analysis/
|
|
135
|
+
│ ├── code-review/ # ❌ Unnecessary nesting
|
|
136
|
+
│ │ └── analyze-code-quality.md
|
|
137
|
+
│ └── code-analyzer.md
|
|
138
|
+
├── architecture/
|
|
139
|
+
│ ├── system-design/ # ❌ Unnecessary nesting
|
|
140
|
+
│ │ └── arch-system-design.md
|
|
141
|
+
└── development/
|
|
142
|
+
└── backend/ # ❌ Unnecessary nesting
|
|
143
|
+
└── dev-backend-api.md
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### After Fix ✅
|
|
147
|
+
```
|
|
148
|
+
.claude/agents/
|
|
149
|
+
├── analysis/
|
|
150
|
+
│ ├── analyze-code-quality.md # ✅ Flat structure
|
|
151
|
+
│ └── code-analyzer.md # ✅ Flat structure
|
|
152
|
+
├── architecture/
|
|
153
|
+
│ └── arch-system-design.md # ✅ Flat structure
|
|
154
|
+
└── development/
|
|
155
|
+
└── dev-backend-api.md # ✅ Flat structure
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Benefits
|
|
159
|
+
|
|
160
|
+
1. **Simpler Structure**: Reduced nesting depth from 3-4 levels to 2 levels
|
|
161
|
+
2. **Easier Navigation**: All agents in a category are immediately visible
|
|
162
|
+
3. **Consistent Naming**: Agent files can be found at predictable paths
|
|
163
|
+
4. **Better Organization**: Clear separation between categories without over-structuring
|
|
164
|
+
5. **Maintenance**: Easier to add/remove agents without managing subdirectories
|
|
165
|
+
|
|
166
|
+
## Backward Compatibility
|
|
167
|
+
|
|
168
|
+
✅ **No Breaking Changes**
|
|
169
|
+
- The `copyRecursive()` function preserves the existing source structure
|
|
170
|
+
- Agent files are copied exactly as they exist in source
|
|
171
|
+
- Only the directory creation is affected
|
|
172
|
+
- Users with existing `.claude/agents` folders are unaffected
|
|
173
|
+
|
|
174
|
+
## Files Modified
|
|
175
|
+
|
|
176
|
+
- `src/cli/simple-commands/init/agent-copier.js` (lines 137-164)
|
|
177
|
+
|
|
178
|
+
## Testing
|
|
179
|
+
|
|
180
|
+
**Test Directory**: `tests/agent-structure-test/`
|
|
181
|
+
|
|
182
|
+
**Status**: ✅ All tests passed
|
|
183
|
+
- 0 nested subdirectories created
|
|
184
|
+
- 76 agent files copied successfully
|
|
185
|
+
- 21 category folders created
|
|
186
|
+
- All files in correct flat structure
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
**Status**: ✅ **FIXED AND VERIFIED**
|
|
191
|
+
|
|
192
|
+
**Ready for**: Next release (v2.7.33 or patch)
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# Bug Report: `memory stats` Command Returns Zero for ReasoningBank Data
|
|
2
|
+
|
|
3
|
+
## Executive Summary
|
|
4
|
+
|
|
5
|
+
The `memory stats` command always returns zero entries/namespaces/size, even when ReasoningBank contains data. This is caused by the command exclusively reading from the legacy JSON file (`./memory/memory-store.json`) instead of querying the active ReasoningBank SQLite database.
|
|
6
|
+
|
|
7
|
+
## Bug Details
|
|
8
|
+
|
|
9
|
+
### Issue
|
|
10
|
+
- **Command**: `npx claude-flow@alpha memory stats`
|
|
11
|
+
- **Expected**: Shows statistics for ReasoningBank database (19 entries found via direct SQL query)
|
|
12
|
+
- **Actual**: Returns all zeros (0 entries, 0 namespaces, 0.00 KB)
|
|
13
|
+
- **Severity**: High - Users cannot see their stored data statistics
|
|
14
|
+
- **Affected Versions**: v2.7.30 and likely earlier
|
|
15
|
+
|
|
16
|
+
### Evidence
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Command returns zeros
|
|
20
|
+
$ npx claude-flow@alpha memory stats
|
|
21
|
+
✅ Memory Bank Statistics:
|
|
22
|
+
Total Entries: 0
|
|
23
|
+
Namespaces: 0
|
|
24
|
+
Size: 0.00 KB
|
|
25
|
+
|
|
26
|
+
# But ReasoningBank list shows 10+ entries
|
|
27
|
+
$ npx claude-flow@alpha memory list --reasoningbank
|
|
28
|
+
✅ ReasoningBank memories (10 shown):
|
|
29
|
+
📌 test-key
|
|
30
|
+
📌 test-sqlite
|
|
31
|
+
📌 api-design
|
|
32
|
+
[... 16 more entries]
|
|
33
|
+
|
|
34
|
+
# Direct SQL query confirms 19 entries exist
|
|
35
|
+
$ sqlite3 .swarm/memory.db "SELECT COUNT(*) FROM patterns WHERE type = 'reasoning_memory';"
|
|
36
|
+
19
|
|
37
|
+
|
|
38
|
+
# ReasoningBank status confirms data exists
|
|
39
|
+
$ npx claude-flow@alpha memory status --reasoningbank
|
|
40
|
+
✅ 📊 ReasoningBank Status:
|
|
41
|
+
Total memories: 19
|
|
42
|
+
Average confidence: 80.0%
|
|
43
|
+
Embeddings: 19
|
|
44
|
+
Trajectories: 0
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Root Cause Analysis
|
|
48
|
+
|
|
49
|
+
### Code Analysis (src/cli/simple-commands/memory.js)
|
|
50
|
+
|
|
51
|
+
**Problem Location**: Lines 217-244
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
async function showMemoryStats(loadMemory) {
|
|
55
|
+
try {
|
|
56
|
+
const data = await loadMemory(); // ❌ Only reads JSON file
|
|
57
|
+
let totalEntries = 0;
|
|
58
|
+
const namespaceStats = {};
|
|
59
|
+
|
|
60
|
+
for (const [namespace, entries] of Object.entries(data)) {
|
|
61
|
+
namespaceStats[namespace] = entries.length;
|
|
62
|
+
totalEntries += entries.length;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
printSuccess('Memory Bank Statistics:');
|
|
66
|
+
console.log(` Total Entries: ${totalEntries}`);
|
|
67
|
+
console.log(` Namespaces: ${Object.keys(data).length}`);
|
|
68
|
+
console.log(` Size: ${(new TextEncoder().encode(JSON.stringify(data)).length / 1024).toFixed(2)} KB`);
|
|
69
|
+
// ...
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**The `loadMemory()` function** (line 26-33):
|
|
75
|
+
```javascript
|
|
76
|
+
async function loadMemory() {
|
|
77
|
+
try {
|
|
78
|
+
const content = await fs.readFile(memoryStore, 'utf8'); // hardcoded JSON path
|
|
79
|
+
return JSON.parse(content);
|
|
80
|
+
} catch {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Where `memoryStore = './memory/memory-store.json'` (line 14)
|
|
87
|
+
|
|
88
|
+
### Why It's Broken
|
|
89
|
+
|
|
90
|
+
1. **Hardcoded JSON File**: `showMemoryStats()` only reads from `./memory/memory-store.json`
|
|
91
|
+
2. **No Mode Detection**: Unlike other commands (`store`, `query`, `list`), `stats` doesn't call `detectMemoryMode()` (line 23)
|
|
92
|
+
3. **No ReasoningBank Support**: The switch statement (lines 56-87) routes `stats` directly to `showMemoryStats()` without checking if ReasoningBank is active
|
|
93
|
+
4. **Inconsistent with Other Commands**: `store`, `query`, and `list` all support `--reasoningbank` flag via `handleReasoningBankCommand()`, but `stats` doesn't
|
|
94
|
+
|
|
95
|
+
### Working Commands for Comparison
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
// ✅ These commands properly detect mode and support ReasoningBank
|
|
99
|
+
case 'store':
|
|
100
|
+
await storeMemory(subArgs, loadMemory, saveMemory, namespace, enableRedaction);
|
|
101
|
+
break;
|
|
102
|
+
|
|
103
|
+
case 'query':
|
|
104
|
+
await queryMemory(subArgs, loadMemory, namespace, enableRedaction);
|
|
105
|
+
break;
|
|
106
|
+
|
|
107
|
+
case 'list':
|
|
108
|
+
await listNamespaces(loadMemory);
|
|
109
|
+
break;
|
|
110
|
+
|
|
111
|
+
// ❌ This command ignores mode detection
|
|
112
|
+
case 'stats':
|
|
113
|
+
await showMemoryStats(loadMemory); // Never checks ReasoningBank!
|
|
114
|
+
break;
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Expected Behavior
|
|
118
|
+
|
|
119
|
+
The `memory stats` command should:
|
|
120
|
+
|
|
121
|
+
1. **Detect the active memory mode** (basic JSON vs ReasoningBank SQLite)
|
|
122
|
+
2. **Show appropriate statistics** based on the active mode:
|
|
123
|
+
- **ReasoningBank mode**: Query SQLite database for accurate counts
|
|
124
|
+
- **Basic mode**: Read JSON file (current behavior)
|
|
125
|
+
- **Auto mode**: Check both and show combined statistics
|
|
126
|
+
3. **Support `--reasoningbank` flag** to force ReasoningBank stats
|
|
127
|
+
4. **Display backend information**: Show which storage backend is being used
|
|
128
|
+
|
|
129
|
+
### Proposed Output
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Auto mode (should detect ReasoningBank if initialized)
|
|
133
|
+
$ npx claude-flow@alpha memory stats
|
|
134
|
+
✅ Memory Bank Statistics:
|
|
135
|
+
Storage Backend: ReasoningBank (SQLite)
|
|
136
|
+
Total Entries: 19
|
|
137
|
+
Namespaces: 3
|
|
138
|
+
Size: 9.14 MB
|
|
139
|
+
|
|
140
|
+
📁 Namespace Breakdown:
|
|
141
|
+
default: 12 entries
|
|
142
|
+
test-namespace: 5 entries
|
|
143
|
+
api: 2 entries
|
|
144
|
+
|
|
145
|
+
💡 Use 'memory stats --basic' for JSON statistics
|
|
146
|
+
|
|
147
|
+
# Force ReasoningBank mode
|
|
148
|
+
$ npx claude-flow@alpha memory stats --reasoningbank
|
|
149
|
+
✅ ReasoningBank Statistics:
|
|
150
|
+
Database: .swarm/memory.db
|
|
151
|
+
Total Memories: 19
|
|
152
|
+
Total Embeddings: 19
|
|
153
|
+
Average Confidence: 80.0%
|
|
154
|
+
Trajectories: 0
|
|
155
|
+
Links: 0
|
|
156
|
+
Database Size: 9.14 MB
|
|
157
|
+
|
|
158
|
+
# Force basic mode
|
|
159
|
+
$ npx claude-flow@alpha memory stats --basic
|
|
160
|
+
✅ JSON Memory Statistics:
|
|
161
|
+
Total Entries: 0
|
|
162
|
+
Namespaces: 0
|
|
163
|
+
Size: 0.00 KB
|
|
164
|
+
⚠️ Consider migrating to ReasoningBank for better performance
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Proposed Solution
|
|
168
|
+
|
|
169
|
+
### Option 1: Add ReasoningBank Support to stats (Recommended)
|
|
170
|
+
|
|
171
|
+
Modify `src/cli/simple-commands/memory.js`:
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
// Line 65-67: Add mode detection to stats case
|
|
175
|
+
case 'stats':
|
|
176
|
+
if (mode === 'reasoningbank') {
|
|
177
|
+
await handleReasoningBankStats(getStatus);
|
|
178
|
+
} else {
|
|
179
|
+
await showMemoryStats(loadMemory);
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
|
|
183
|
+
// Add new handler function (around line 718)
|
|
184
|
+
async function handleReasoningBankStats(getStatus) {
|
|
185
|
+
try {
|
|
186
|
+
const stats = await getStatus();
|
|
187
|
+
|
|
188
|
+
printSuccess('ReasoningBank Statistics:');
|
|
189
|
+
console.log(` Database: ${stats.database_path || '.swarm/memory.db'}`);
|
|
190
|
+
console.log(` Total Memories: ${stats.total_memories}`);
|
|
191
|
+
console.log(` Total Categories: ${stats.total_categories}`);
|
|
192
|
+
console.log(` Average Confidence: ${(stats.avg_confidence * 100).toFixed(1)}%`);
|
|
193
|
+
console.log(` Embeddings: ${stats.total_embeddings}`);
|
|
194
|
+
console.log(` Trajectories: ${stats.total_trajectories}`);
|
|
195
|
+
console.log(` Links: ${stats.total_links || 0}`);
|
|
196
|
+
console.log(` Storage Backend: ${stats.storage_backend}`);
|
|
197
|
+
|
|
198
|
+
if (stats.database_path) {
|
|
199
|
+
const dbSize = await getFileSize(stats.database_path);
|
|
200
|
+
console.log(` Database Size: ${(dbSize / 1024 / 1024).toFixed(2)} MB`);
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
printError(`Failed to get ReasoningBank stats: ${error.message}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Helper function
|
|
208
|
+
async function getFileSize(path) {
|
|
209
|
+
try {
|
|
210
|
+
const stats = await fs.stat(path);
|
|
211
|
+
return stats.size;
|
|
212
|
+
} catch {
|
|
213
|
+
return 0;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Option 2: Create Unified Stats Command
|
|
219
|
+
|
|
220
|
+
Show both JSON and ReasoningBank statistics in one output:
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
async function showMemoryStats(loadMemory, mode) {
|
|
224
|
+
const rbInitialized = await isReasoningBankInitialized();
|
|
225
|
+
|
|
226
|
+
printSuccess('Memory Bank Statistics:\n');
|
|
227
|
+
|
|
228
|
+
// Show JSON stats
|
|
229
|
+
const jsonData = await loadMemory();
|
|
230
|
+
let totalEntries = Object.values(jsonData).reduce((sum, arr) => sum + arr.length, 0);
|
|
231
|
+
|
|
232
|
+
console.log('📁 JSON Storage (./memory/memory-store.json):');
|
|
233
|
+
console.log(` Total Entries: ${totalEntries}`);
|
|
234
|
+
console.log(` Namespaces: ${Object.keys(jsonData).length}`);
|
|
235
|
+
console.log(` Size: ${(new TextEncoder().encode(JSON.stringify(jsonData)).length / 1024).toFixed(2)} KB`);
|
|
236
|
+
|
|
237
|
+
// Show ReasoningBank stats if initialized
|
|
238
|
+
if (rbInitialized) {
|
|
239
|
+
const { getStatus } = await import('../../reasoningbank/reasoningbank-adapter.js');
|
|
240
|
+
const rbStats = await getStatus();
|
|
241
|
+
|
|
242
|
+
console.log('\n🧠 ReasoningBank Storage (.swarm/memory.db):');
|
|
243
|
+
console.log(` Total Memories: ${rbStats.total_memories}`);
|
|
244
|
+
console.log(` Categories: ${rbStats.total_categories}`);
|
|
245
|
+
console.log(` Average Confidence: ${(rbStats.avg_confidence * 100).toFixed(1)}%`);
|
|
246
|
+
console.log(` Embeddings: ${rbStats.total_embeddings}`);
|
|
247
|
+
|
|
248
|
+
console.log('\n💡 Active Mode: ReasoningBank (auto-selected)');
|
|
249
|
+
} else {
|
|
250
|
+
console.log('\n⚠️ ReasoningBank not initialized (using JSON storage)');
|
|
251
|
+
console.log(' Run "memory init --reasoningbank" to enable AI features');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Testing Plan
|
|
257
|
+
|
|
258
|
+
### Test Cases
|
|
259
|
+
|
|
260
|
+
1. **Test with empty JSON, empty ReasoningBank**
|
|
261
|
+
```bash
|
|
262
|
+
rm -rf memory/ .swarm/
|
|
263
|
+
npx claude-flow@alpha memory stats
|
|
264
|
+
# Expected: Show zeros for both backends
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
2. **Test with data in ReasoningBank only**
|
|
268
|
+
```bash
|
|
269
|
+
npx claude-flow@alpha memory store "test" "value" --reasoningbank
|
|
270
|
+
npx claude-flow@alpha memory stats
|
|
271
|
+
# Expected: Show ReasoningBank stats with 1 entry
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
3. **Test with data in JSON only**
|
|
275
|
+
```bash
|
|
276
|
+
npx claude-flow@alpha memory store "test" "value" --basic
|
|
277
|
+
npx claude-flow@alpha memory stats
|
|
278
|
+
# Expected: Show JSON stats with 1 entry
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
4. **Test with data in both backends**
|
|
282
|
+
```bash
|
|
283
|
+
npx claude-flow@alpha memory store "json-key" "json-value" --basic
|
|
284
|
+
npx claude-flow@alpha memory store "rb-key" "rb-value" --reasoningbank
|
|
285
|
+
npx claude-flow@alpha memory stats
|
|
286
|
+
# Expected: Show stats for both backends
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
5. **Test with flags**
|
|
290
|
+
```bash
|
|
291
|
+
npx claude-flow@alpha memory stats --reasoningbank
|
|
292
|
+
npx claude-flow@alpha memory stats --basic
|
|
293
|
+
npx claude-flow@alpha memory stats --auto
|
|
294
|
+
# Expected: Respect mode flags
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Impact Assessment
|
|
298
|
+
|
|
299
|
+
### User Impact: High
|
|
300
|
+
- Users relying on `memory stats` are seeing incorrect information
|
|
301
|
+
- New users testing ReasoningBank features think it's not working
|
|
302
|
+
- Migration from JSON to ReasoningBank appears unsuccessful
|
|
303
|
+
|
|
304
|
+
### Workarounds
|
|
305
|
+
Users can check ReasoningBank data using:
|
|
306
|
+
1. `memory status --reasoningbank` - Shows basic stats
|
|
307
|
+
2. `memory list --reasoningbank` - Lists all entries
|
|
308
|
+
3. Direct SQLite query: `sqlite3 .swarm/memory.db "SELECT COUNT(*) FROM patterns;"`
|
|
309
|
+
|
|
310
|
+
## Related Issues
|
|
311
|
+
|
|
312
|
+
- Memory mode detection works correctly for `store`, `query`, `list` commands
|
|
313
|
+
- The `status --reasoningbank` command works and shows accurate statistics
|
|
314
|
+
- This bug affects only the `stats` command (without flags)
|
|
315
|
+
|
|
316
|
+
## Files to Modify
|
|
317
|
+
|
|
318
|
+
1. **src/cli/simple-commands/memory.js**
|
|
319
|
+
- Lines 65-67: Add mode detection to `stats` case
|
|
320
|
+
- Lines 217-244: Modify `showMemoryStats()` to support ReasoningBank
|
|
321
|
+
- Add new `handleReasoningBankStats()` function (around line 718)
|
|
322
|
+
|
|
323
|
+
## Backward Compatibility
|
|
324
|
+
|
|
325
|
+
✅ No breaking changes - existing JSON-based stats will continue to work
|
|
326
|
+
✅ New flag `--reasoningbank` is optional
|
|
327
|
+
✅ Auto mode will fall back to JSON if ReasoningBank not initialized
|
|
328
|
+
|
|
329
|
+
## Priority Recommendation
|
|
330
|
+
|
|
331
|
+
**Priority: High** - This is a user-facing bug that makes a primary feature (statistics) non-functional for ReasoningBank users.
|
|
332
|
+
|
|
333
|
+
**Suggested for**: v2.7.31 hotfix
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Additional Context
|
|
338
|
+
|
|
339
|
+
### System Information
|
|
340
|
+
- Version: v2.7.30 (and likely earlier)
|
|
341
|
+
- Database: SQLite 3.x at `.swarm/memory.db`
|
|
342
|
+
- ReasoningBank: Initialized and contains 19 entries
|
|
343
|
+
- JSON Storage: Empty (0 entries)
|
|
344
|
+
|
|
345
|
+
### Reproduction Steps
|
|
346
|
+
1. Initialize ReasoningBank: `npx claude-flow@alpha memory init --reasoningbank`
|
|
347
|
+
2. Store data: `npx claude-flow@alpha memory store test-key "test value" --reasoningbank`
|
|
348
|
+
3. Verify storage: `npx claude-flow@alpha memory list --reasoningbank` (shows data)
|
|
349
|
+
4. Run stats: `npx claude-flow@alpha memory stats` (shows zeros ❌)
|
|
350
|
+
|
|
351
|
+
### Related Files
|
|
352
|
+
- `/workspaces/claude-code-flow/src/cli/simple-commands/memory.js` (main bug location)
|
|
353
|
+
- `/workspaces/claude-code-flow/src/reasoningbank/reasoningbank-adapter.js` (working `getStatus()` function)
|
|
354
|
+
- `.swarm/memory.db` (SQLite database with 19 entries)
|
|
355
|
+
- `./memory/memory-store.json` (empty JSON file)
|