@sparkleideas/claude-flow-patch 3.1.0-alpha.44.patch.10
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/AGENTS.md +162 -0
- package/CLAUDE.md +506 -0
- package/README.md +351 -0
- package/bin/claude-flow-patch.mjs +148 -0
- package/check-patches.sh +195 -0
- package/lib/categories.json +15 -0
- package/lib/common.py +97 -0
- package/lib/discover.mjs +181 -0
- package/lib/discover.sh +160 -0
- package/package.json +86 -0
- package/patch/010-CF-001-doctor-yaml/README.md +11 -0
- package/patch/010-CF-001-doctor-yaml/fix.py +20 -0
- package/patch/010-CF-001-doctor-yaml/sentinel +1 -0
- package/patch/020-CF-002-config-export-yaml/README.md +11 -0
- package/patch/020-CF-002-config-export-yaml/fix.py +130 -0
- package/patch/020-CF-002-config-export-yaml/sentinel +1 -0
- package/patch/030-DM-001-daemon-log-zero/README.md +12 -0
- package/patch/030-DM-001-daemon-log-zero/fix.py +37 -0
- package/patch/030-DM-001-daemon-log-zero/sentinel +1 -0
- package/patch/040-DM-002-cpu-load-threshold/README.md +11 -0
- package/patch/040-DM-002-cpu-load-threshold/fix.py +6 -0
- package/patch/040-DM-002-cpu-load-threshold/sentinel +1 -0
- package/patch/050-DM-003-macos-freemem/README.md +11 -0
- package/patch/050-DM-003-macos-freemem/fix.py +7 -0
- package/patch/050-DM-003-macos-freemem/sentinel +1 -0
- package/patch/060-DM-004-preload-worker-stub/README.md +11 -0
- package/patch/060-DM-004-preload-worker-stub/fix.py +34 -0
- package/patch/060-DM-004-preload-worker-stub/sentinel +1 -0
- package/patch/070-DM-005-consolidation-worker-stub/README.md +11 -0
- package/patch/070-DM-005-consolidation-worker-stub/fix.py +46 -0
- package/patch/070-DM-005-consolidation-worker-stub/sentinel +1 -0
- package/patch/080-EM-001-embedding-ignores-config/README.md +11 -0
- package/patch/080-EM-001-embedding-ignores-config/fix.py +111 -0
- package/patch/080-EM-001-embedding-ignores-config/sentinel +1 -0
- package/patch/090-EM-002-transformers-cache-eacces/README.md +11 -0
- package/patch/090-EM-002-transformers-cache-eacces/fix.sh +12 -0
- package/patch/090-EM-002-transformers-cache-eacces/sentinel +1 -0
- package/patch/100-GV-001-hnsw-ghost-vectors/README.md +11 -0
- package/patch/100-GV-001-hnsw-ghost-vectors/fix.py +34 -0
- package/patch/100-GV-001-hnsw-ghost-vectors/sentinel +1 -0
- package/patch/110-HK-001-post-edit-file-path/README.md +44 -0
- package/patch/110-HK-001-post-edit-file-path/fix.py +23 -0
- package/patch/110-HK-001-post-edit-file-path/sentinel +1 -0
- package/patch/120-HK-002-hooks-tools-stub/README.md +36 -0
- package/patch/120-HK-002-hooks-tools-stub/fix.py +155 -0
- package/patch/120-HK-002-hooks-tools-stub/sentinel +1 -0
- package/patch/130-HK-003-metrics-hardcoded/README.md +30 -0
- package/patch/130-HK-003-metrics-hardcoded/fix.py +82 -0
- package/patch/130-HK-003-metrics-hardcoded/sentinel +1 -0
- package/patch/135-HK-004-respect-daemon-autostart/README.md +11 -0
- package/patch/135-HK-004-respect-daemon-autostart/fix.py +14 -0
- package/patch/135-HK-004-respect-daemon-autostart/sentinel +1 -0
- package/patch/137-HK-005-daemon-pid-guard/README.md +11 -0
- package/patch/137-HK-005-daemon-pid-guard/fix.py +53 -0
- package/patch/137-HK-005-daemon-pid-guard/sentinel +2 -0
- package/patch/140-HW-001-stdin-hang/README.md +11 -0
- package/patch/140-HW-001-stdin-hang/fix.py +6 -0
- package/patch/140-HW-001-stdin-hang/sentinel +1 -0
- package/patch/150-HW-002-failures-swallowed/README.md +11 -0
- package/patch/150-HW-002-failures-swallowed/fix.py +42 -0
- package/patch/150-HW-002-failures-swallowed/sentinel +1 -0
- package/patch/160-HW-003-aggressive-intervals/README.md +11 -0
- package/patch/160-HW-003-aggressive-intervals/fix.py +52 -0
- package/patch/160-HW-003-aggressive-intervals/sentinel +3 -0
- package/patch/170-IN-001-intelligence-stub/README.md +64 -0
- package/patch/170-IN-001-intelligence-stub/fix.py +63 -0
- package/patch/170-IN-001-intelligence-stub/sentinel +1 -0
- package/patch/180-MM-001-memory-persist-path/README.md +27 -0
- package/patch/180-MM-001-memory-persist-path/fix.py +54 -0
- package/patch/180-MM-001-memory-persist-path/sentinel +1 -0
- package/patch/190-NS-001-discovery-default-namespace/README.md +16 -0
- package/patch/190-NS-001-discovery-default-namespace/fix.py +68 -0
- package/patch/190-NS-001-discovery-default-namespace/sentinel +2 -0
- package/patch/200-NS-002-targeted-require-namespace/README.md +19 -0
- package/patch/200-NS-002-targeted-require-namespace/fix.py +158 -0
- package/patch/200-NS-002-targeted-require-namespace/sentinel +2 -0
- package/patch/210-NS-003-namespace-typo-pattern/README.md +15 -0
- package/patch/210-NS-003-namespace-typo-pattern/fix.py +23 -0
- package/patch/210-NS-003-namespace-typo-pattern/sentinel +1 -0
- package/patch/220-RS-001-better-sqlite3-node24/README.md +54 -0
- package/patch/220-RS-001-better-sqlite3-node24/fix.py +27 -0
- package/patch/220-RS-001-better-sqlite3-node24/rebuild.sh +31 -0
- package/patch/220-RS-001-better-sqlite3-node24/sentinel +2 -0
- package/patch/230-RV-001-force-learn-tick/README.md +31 -0
- package/patch/230-RV-001-force-learn-tick/fix.py +14 -0
- package/patch/230-RV-001-force-learn-tick/sentinel +2 -0
- package/patch/240-RV-002-trajectory-load/README.md +28 -0
- package/patch/240-RV-002-trajectory-load/fix.py +14 -0
- package/patch/240-RV-002-trajectory-load/sentinel +2 -0
- package/patch/250-RV-003-trajectory-stats-sync/README.md +31 -0
- package/patch/250-RV-003-trajectory-stats-sync/fix.py +18 -0
- package/patch/250-RV-003-trajectory-stats-sync/sentinel +2 -0
- package/patch/260-SG-001-init-settings/README.md +29 -0
- package/patch/260-SG-001-init-settings/fix.py +143 -0
- package/patch/260-SG-001-init-settings/sentinel +4 -0
- package/patch/270-SG-003-init-helpers-all-paths/README.md +60 -0
- package/patch/270-SG-003-init-helpers-all-paths/fix.py +165 -0
- package/patch/270-SG-003-init-helpers-all-paths/sentinel +3 -0
- package/patch/280-UI-001-intelligence-stats-crash/README.md +11 -0
- package/patch/280-UI-001-intelligence-stats-crash/fix.py +57 -0
- package/patch/280-UI-001-intelligence-stats-crash/sentinel +1 -0
- package/patch/290-UI-002-neural-status-not-loaded/README.md +11 -0
- package/patch/290-UI-002-neural-status-not-loaded/fix.py +19 -0
- package/patch/290-UI-002-neural-status-not-loaded/sentinel +1 -0
- package/patch/300-DM-006-log-rotation/README.md +12 -0
- package/patch/300-DM-006-log-rotation/fix.py +72 -0
- package/patch/300-DM-006-log-rotation/sentinel +2 -0
- package/patch/310-HW-004-runwithtimeout-orphan/README.md +11 -0
- package/patch/310-HW-004-runwithtimeout-orphan/fix.py +10 -0
- package/patch/310-HW-004-runwithtimeout-orphan/sentinel +1 -0
- package/patch/320-SG-004-wizard-parity/README.md +40 -0
- package/patch/320-SG-004-wizard-parity/fix.py +208 -0
- package/patch/320-SG-004-wizard-parity/sentinel +3 -0
- package/patch/330-SG-005-start-all-subcommand/README.md +32 -0
- package/patch/330-SG-005-start-all-subcommand/fix.py +58 -0
- package/patch/330-SG-005-start-all-subcommand/sentinel +1 -0
- package/patch-all.sh +199 -0
- package/repair-post-init.sh +263 -0
- package/scripts/preflight.mjs +249 -0
- package/scripts/upstream-log.mjs +257 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# HW-003: Worker scheduling intervals too aggressive
|
|
2
|
+
# GitHub: #1113
|
|
3
|
+
patch("3: audit 30m",
|
|
4
|
+
WD,
|
|
5
|
+
"type: 'audit', intervalMs: 10 * 60 * 1000",
|
|
6
|
+
"type: 'audit', intervalMs: 30 * 60 * 1000")
|
|
7
|
+
|
|
8
|
+
patch("3: optimize 60m",
|
|
9
|
+
WD,
|
|
10
|
+
"type: 'optimize', intervalMs: 15 * 60 * 1000",
|
|
11
|
+
"type: 'optimize', intervalMs: 60 * 60 * 1000")
|
|
12
|
+
|
|
13
|
+
patch("3: testgaps 60m",
|
|
14
|
+
WD,
|
|
15
|
+
"type: 'testgaps', intervalMs: 20 * 60 * 1000",
|
|
16
|
+
"type: 'testgaps', intervalMs: 60 * 60 * 1000")
|
|
17
|
+
|
|
18
|
+
# HW-003 extension: Read daemon.schedules from .claude/settings.json
|
|
19
|
+
# and merge user-configured intervals into worker defaults
|
|
20
|
+
patch("3: settings-driven intervals",
|
|
21
|
+
WD,
|
|
22
|
+
" workers: config?.workers ?? DEFAULT_WORKERS,",
|
|
23
|
+
""" workers: (() => {
|
|
24
|
+
const base = config?.workers ?? DEFAULT_WORKERS;
|
|
25
|
+
try {
|
|
26
|
+
const sp = join(projectRoot, '.claude', 'settings.json');
|
|
27
|
+
const s = JSON.parse(readFileSync(sp, 'utf-8'));
|
|
28
|
+
const schedules = s?.claudeFlow?.daemon?.schedules;
|
|
29
|
+
if (!schedules || typeof schedules !== 'object') return base;
|
|
30
|
+
const parseInterval = (v) => {
|
|
31
|
+
if (typeof v === 'number') return v;
|
|
32
|
+
if (typeof v !== 'string') return null;
|
|
33
|
+
const m = v.match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)$/i);
|
|
34
|
+
if (!m) return null;
|
|
35
|
+
const n = parseFloat(m[1]);
|
|
36
|
+
switch (m[2].toLowerCase()) {
|
|
37
|
+
case 'ms': return n;
|
|
38
|
+
case 's': return n * 1000;
|
|
39
|
+
case 'm': return n * 60 * 1000;
|
|
40
|
+
case 'h': return n * 3600 * 1000;
|
|
41
|
+
default: return null;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return base.map(w => {
|
|
45
|
+
const sched = schedules[w.type];
|
|
46
|
+
if (!sched) return w;
|
|
47
|
+
const iv = parseInterval(sched.interval ?? sched.intervalMs);
|
|
48
|
+
const en = typeof sched.enabled === 'boolean' ? sched.enabled : w.enabled;
|
|
49
|
+
return { ...w, ...(iv !== null ? { intervalMs: iv } : {}), enabled: en };
|
|
50
|
+
});
|
|
51
|
+
} catch { return base; }
|
|
52
|
+
})(),""")
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# IN-001: intelligence.cjs is a stub that doesn't actually learn
|
|
2
|
+
|
|
3
|
+
**Severity**: Critical
|
|
4
|
+
**GitHub**: [#1154](https://github.com/ruvnet/claude-flow/issues/1154)
|
|
5
|
+
**Status**: RESOLVED
|
|
6
|
+
|
|
7
|
+
## Root Cause
|
|
8
|
+
|
|
9
|
+
`findSourceHelpersDir()` in `dist/src/init/executor.js` (line 855) fails to resolve the package's `.claude/helpers/` directory when running via npx. It tries 4 path strategies, all fail with npx-cached installs. The comment at line 395 says it explicitly: *"Source not found (npx with broken paths) — use generated fallbacks"*.
|
|
10
|
+
|
|
11
|
+
This causes `executeUpgrade()` to call `generateIntelligenceStub()` (from `helpers-generator.js` line 557) instead of copying the real file. The stub is 197 lines with:
|
|
12
|
+
- `feedback()` as a no-op
|
|
13
|
+
- `consolidate()` that counts lines and wipes the file
|
|
14
|
+
- `getContext()` using simple Jaccard word overlap with no learning
|
|
15
|
+
- No PageRank, no graph, no confidence tracking
|
|
16
|
+
|
|
17
|
+
## The Full Version Exists in the Package
|
|
18
|
+
|
|
19
|
+
The **916-line full `intelligence.cjs`** ships in the `@claude-flow/cli` package at:
|
|
20
|
+
```
|
|
21
|
+
node_modules/@claude-flow/cli/.claude/helpers/intelligence.cjs
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
It implements:
|
|
25
|
+
- PageRank-ranked memory graph (nodes, edges, power iteration with damping)
|
|
26
|
+
- Trigram matching with stop-word filtering
|
|
27
|
+
- Confidence feedback loop (boost on success, decay on failure)
|
|
28
|
+
- Consolidation: insight generation for hot files, confidence decay for stale entries, graph rebuild
|
|
29
|
+
- Snapshot-based trend tracking (up to 50 snapshots)
|
|
30
|
+
- Bootstrap from MEMORY.md files when store is empty
|
|
31
|
+
- Same 6-method API: `{ init, getContext, recordEdit, feedback, consolidate, stats }`
|
|
32
|
+
- Same data directory: `.claude-flow/data/`
|
|
33
|
+
|
|
34
|
+
## Fix
|
|
35
|
+
|
|
36
|
+
Copy the full `intelligence.cjs` from the package to replace the stub:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Find the package's helpers directory
|
|
40
|
+
SRC=$(find ~/.npm/_npx -path '*/@claude-flow/cli/.claude/helpers/intelligence.cjs' 2>/dev/null | head -1)
|
|
41
|
+
|
|
42
|
+
# Copy to project
|
|
43
|
+
cp "$SRC" .claude/helpers/intelligence.cjs
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This is a drop-in replacement — same export signature, same data files, additive new files (`graph-state.json`, `intelligence-snapshot.json`).
|
|
47
|
+
|
|
48
|
+
## Verification
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Should show nodes > 0, edges > 0 (stub always showed edges: 0)
|
|
52
|
+
node .claude/helpers/intelligence.cjs stats
|
|
53
|
+
|
|
54
|
+
# Should show PageRank sum ~1.0
|
|
55
|
+
node .claude/helpers/intelligence.cjs stats --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Files Patched
|
|
59
|
+
|
|
60
|
+
- `init/executor.js`
|
|
61
|
+
|
|
62
|
+
## Ops
|
|
63
|
+
|
|
64
|
+
2 ops in fix.py
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# IN-001: intelligence.cjs generated as stub instead of full version
|
|
2
|
+
# GitHub: #1154
|
|
3
|
+
#
|
|
4
|
+
# When findSourceHelpersDir() fails (npx broken paths), the fallback calls
|
|
5
|
+
# generateIntelligenceStub() — a 197-line no-op. The full 916-line version
|
|
6
|
+
# ships in the package at .claude/helpers/intelligence.cjs.
|
|
7
|
+
#
|
|
8
|
+
# Fix: In both fallback paths, try reading the real file from the package
|
|
9
|
+
# root (via __dirname) before falling back to the stub.
|
|
10
|
+
# 2 ops: upgrade path (line ~398) + writeHelpers path (line ~943)
|
|
11
|
+
|
|
12
|
+
# Op 1: Upgrade path — when findSourceHelpersDir() returns null
|
|
13
|
+
# old/new strings stop BEFORE generatedCritical to avoid overlap with SG-003j
|
|
14
|
+
patch("IN-001a: upgrade fallback reads real intelligence.cjs",
|
|
15
|
+
EXECUTOR,
|
|
16
|
+
""" else {
|
|
17
|
+
// Source not found (npx with broken paths) — use generated fallbacks
|
|
18
|
+
const generatedCritical = {""",
|
|
19
|
+
""" else {
|
|
20
|
+
// Source not found (npx with broken paths) — use generated fallbacks
|
|
21
|
+
// IN-001: Try reading real intelligence.cjs from package before using stub
|
|
22
|
+
let intelligenceContent = generateIntelligenceStub();
|
|
23
|
+
try {
|
|
24
|
+
const realPath = path.resolve(__dirname, '..', '..', '..', '.claude', 'helpers', 'intelligence.cjs');
|
|
25
|
+
if (fs.existsSync(realPath)) {
|
|
26
|
+
intelligenceContent = fs.readFileSync(realPath, 'utf-8');
|
|
27
|
+
}
|
|
28
|
+
} catch { /* use stub */ }
|
|
29
|
+
const generatedCritical = {""")
|
|
30
|
+
|
|
31
|
+
# Op 2: writeHelpers path — fresh init when source dir not found
|
|
32
|
+
patch("IN-001b: writeHelpers fallback reads real intelligence.cjs",
|
|
33
|
+
EXECUTOR,
|
|
34
|
+
""" // Fall back to generating helpers if source not available
|
|
35
|
+
const helpers = {
|
|
36
|
+
'pre-commit': generatePreCommitHook(),
|
|
37
|
+
'post-commit': generatePostCommitHook(),
|
|
38
|
+
'session.js': generateSessionManager(),
|
|
39
|
+
'router.js': generateAgentRouter(),
|
|
40
|
+
'memory.js': generateMemoryHelper(),
|
|
41
|
+
'hook-handler.cjs': generateHookHandler(),
|
|
42
|
+
'intelligence.cjs': generateIntelligenceStub(),
|
|
43
|
+
'auto-memory-hook.mjs': generateAutoMemoryHook(),
|
|
44
|
+
};""",
|
|
45
|
+
""" // Fall back to generating helpers if source not available
|
|
46
|
+
// IN-001: Try reading real intelligence.cjs from package before using stub
|
|
47
|
+
let intelligenceForInit = generateIntelligenceStub();
|
|
48
|
+
try {
|
|
49
|
+
const realIntelPath = path.resolve(__dirname, '..', '..', '..', '.claude', 'helpers', 'intelligence.cjs');
|
|
50
|
+
if (fs.existsSync(realIntelPath)) {
|
|
51
|
+
intelligenceForInit = fs.readFileSync(realIntelPath, 'utf-8');
|
|
52
|
+
}
|
|
53
|
+
} catch { /* use stub */ }
|
|
54
|
+
const helpers = {
|
|
55
|
+
'pre-commit': generatePreCommitHook(),
|
|
56
|
+
'post-commit': generatePostCommitHook(),
|
|
57
|
+
'session.cjs': generateSessionManager(),
|
|
58
|
+
'router.cjs': generateAgentRouter(),
|
|
59
|
+
'memory.cjs': generateMemoryHelper(),
|
|
60
|
+
'hook-handler.cjs': generateHookHandler(),
|
|
61
|
+
'intelligence.cjs': intelligenceForInit,
|
|
62
|
+
'auto-memory-hook.mjs': generateAutoMemoryHook(),
|
|
63
|
+
};""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "intelligenceContent" init/executor.js
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# MM-001: Remove dead persistPath config option
|
|
2
|
+
|
|
3
|
+
**Severity**: Low
|
|
4
|
+
**GitHub**: [#1152](https://github.com/ruvnet/claude-flow/issues/1152)
|
|
5
|
+
|
|
6
|
+
## Root Cause
|
|
7
|
+
|
|
8
|
+
The `init` command generates a `persistPath: .claude-flow/data` setting in config.yaml, but **nothing reads it**. All memory storage code (15+ locations across memory-initializer.js and ruvector modules) uses hardcoded `.swarm/` paths.
|
|
9
|
+
|
|
10
|
+
This creates user confusion: the config suggests data goes to `.claude-flow/data/` but it actually goes to `.swarm/`.
|
|
11
|
+
|
|
12
|
+
## Fix
|
|
13
|
+
|
|
14
|
+
Rather than patching 15+ files to respect the config, we:
|
|
15
|
+
1. Remove the misleading `persistPath` line from the generated config.yaml
|
|
16
|
+
2. Revert any previous attempts to read this config (restore `.swarm/` hardcoding)
|
|
17
|
+
|
|
18
|
+
This aligns the config with actual behavior - all data lives in `.swarm/`.
|
|
19
|
+
|
|
20
|
+
## Files Patched
|
|
21
|
+
|
|
22
|
+
- init/executor.js (remove persistPath from config template)
|
|
23
|
+
- memory/memory-initializer.js (revert config-reading code if present)
|
|
24
|
+
|
|
25
|
+
## Ops
|
|
26
|
+
|
|
27
|
+
2 ops in fix.py
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# MM-001: Remove dead persistPath config from init command
|
|
2
|
+
# The persistPath setting is generated but never consumed - all code uses hardcoded .swarm/
|
|
3
|
+
# Rather than patching 15+ files to respect it, we remove the misleading config option.
|
|
4
|
+
|
|
5
|
+
# First: Revert any previous MM-001 patch that tried to read persistPath
|
|
6
|
+
patch("MM-001: revert config reading (restore .swarm/ hardcoding)",
|
|
7
|
+
MI,
|
|
8
|
+
""" // MM-001: Read persistPath from config instead of hardcoding .swarm/
|
|
9
|
+
let dataDir = path.join(process.cwd(), '.swarm'); // fallback
|
|
10
|
+
try {
|
|
11
|
+
const configJsonPath = path.join(process.cwd(), '.claude-flow', 'config.json');
|
|
12
|
+
const configYamlPath = path.join(process.cwd(), '.claude-flow', 'config.yaml');
|
|
13
|
+
if (fs.existsSync(configJsonPath)) {
|
|
14
|
+
const config = JSON.parse(fs.readFileSync(configJsonPath, 'utf-8'));
|
|
15
|
+
const persistPath = config.values?.['memory.persistPath'];
|
|
16
|
+
if (persistPath) {
|
|
17
|
+
dataDir = path.isAbsolute(persistPath) ? persistPath : path.join(process.cwd(), persistPath);
|
|
18
|
+
}
|
|
19
|
+
} else if (fs.existsSync(configYamlPath)) {
|
|
20
|
+
const yamlContent = fs.readFileSync(configYamlPath, 'utf-8');
|
|
21
|
+
const match = yamlContent.match(/persistPath:\\s*([^\\n]+)/);
|
|
22
|
+
if (match) {
|
|
23
|
+
const persistPath = match[1].trim();
|
|
24
|
+
dataDir = path.isAbsolute(persistPath) ? persistPath : path.join(process.cwd(), persistPath);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} catch { /* use fallback */ }
|
|
28
|
+
if (!fs.existsSync(dataDir)) {
|
|
29
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
const hnswPath = path.join(dataDir, 'hnsw.index');
|
|
32
|
+
const metadataPath = path.join(dataDir, 'hnsw.metadata.json');
|
|
33
|
+
const dbPath = options?.dbPath || path.join(dataDir, 'memory.db');""",
|
|
34
|
+
""" // Persistent storage paths
|
|
35
|
+
const swarmDir = path.join(process.cwd(), '.swarm');
|
|
36
|
+
if (!fs.existsSync(swarmDir)) {
|
|
37
|
+
fs.mkdirSync(swarmDir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
const hnswPath = path.join(swarmDir, 'hnsw.index');
|
|
40
|
+
const metadataPath = path.join(swarmDir, 'hnsw.metadata.json');
|
|
41
|
+
const dbPath = options?.dbPath || path.join(swarmDir, 'memory.db');""")
|
|
42
|
+
|
|
43
|
+
# Second: Remove persistPath from generated config.yaml (init/executor.js)
|
|
44
|
+
patch("MM-001: remove persistPath from config.yaml template",
|
|
45
|
+
EXECUTOR,
|
|
46
|
+
"""memory:
|
|
47
|
+
backend: ${options.runtime.memoryBackend}
|
|
48
|
+
enableHNSW: ${options.runtime.enableHNSW}
|
|
49
|
+
persistPath: .claude-flow/data
|
|
50
|
+
cacheSize: 100""",
|
|
51
|
+
"""memory:
|
|
52
|
+
backend: ${options.runtime.memoryBackend}
|
|
53
|
+
enableHNSW: ${options.runtime.enableHNSW}
|
|
54
|
+
cacheSize: 100""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
absent "persistPath: .claude-flow/data" init/executor.js
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# NS-001: Discovery ops default to wrong namespace
|
|
2
|
+
**Severity**: Critical
|
|
3
|
+
**GitHub**: [#1123](https://github.com/ruvnet/claude-flow/issues/1123)
|
|
4
|
+
## Root Cause
|
|
5
|
+
MCP `memory_search` defaulted to `namespace='default'`, but entries live in 'patterns', 'solutions', etc. Every MCP search returned 0 results. MCP `memory_list` had no 'all' support — truthiness check treated 'all' as truthy, generating `WHERE namespace = 'all'` which returns 0 results.
|
|
6
|
+
## Rule
|
|
7
|
+
Discovery ops (search, list) default to 'all' — search across all namespaces.
|
|
8
|
+
## Fix
|
|
9
|
+
MCP search, core searchEntries(), embeddings search, MCP list, CLI list all default to 'all'. Core listEntries() uses nsFilter variable to distinguish between 'all' sentinel and real namespace filtering.
|
|
10
|
+
## Files Patched
|
|
11
|
+
- mcp-tools/memory-tools.js (search + list)
|
|
12
|
+
- mcp-tools/embeddings-tools.js (search)
|
|
13
|
+
- memory/memory-initializer.js (searchEntries, listEntries)
|
|
14
|
+
- commands/memory.js (CLI list)
|
|
15
|
+
## Ops
|
|
16
|
+
10 ops in fix.py (19a-e + 21c,d,g,i,j)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# NS-001: Discovery ops (search + list) default to wrong namespace
|
|
2
|
+
# GitHub: #1123
|
|
3
|
+
# Rule: Default to 'all' (search across all namespaces)
|
|
4
|
+
# 10 ops: 19a-e (search) + 21c,d,g,i,j (list)
|
|
5
|
+
|
|
6
|
+
# ── Search ops (from old Patch 19) ──
|
|
7
|
+
|
|
8
|
+
# 19a: MCP search handler — change default from 'default' to 'all'
|
|
9
|
+
patch("19a: MCP search namespace default",
|
|
10
|
+
MCP_MEMORY,
|
|
11
|
+
"const query = input.query;\n const namespace = input.namespace || 'default';",
|
|
12
|
+
"const query = input.query;\n const namespace = input.namespace || 'all';")
|
|
13
|
+
|
|
14
|
+
# 19b: MCP search schema — update description to reflect 'all' default
|
|
15
|
+
patch("19b: MCP search namespace description",
|
|
16
|
+
MCP_MEMORY,
|
|
17
|
+
"""namespace: { type: 'string', description: 'Namespace to search (default: "default")' }""",
|
|
18
|
+
"""namespace: { type: 'string', description: 'Namespace to search (default: "all" = all namespaces)' }""")
|
|
19
|
+
|
|
20
|
+
# 19c: Core searchEntries() — change function default from 'default' to 'all'
|
|
21
|
+
patch("19c: searchEntries default all",
|
|
22
|
+
MI,
|
|
23
|
+
"const { query, namespace = 'default', limit = 10, threshold = 0.3, dbPath: customPath } = options;",
|
|
24
|
+
"const { query, namespace = 'all', limit = 10, threshold = 0.3, dbPath: customPath } = options;")
|
|
25
|
+
|
|
26
|
+
# 19d: Embeddings search — pass 'all' instead of 'default' to searchEntries
|
|
27
|
+
patch("19d: embeddings search namespace all",
|
|
28
|
+
EMB_TOOLS,
|
|
29
|
+
"namespace: namespace || 'default'\n });",
|
|
30
|
+
"namespace: namespace || 'all'\n });")
|
|
31
|
+
|
|
32
|
+
# 19e: Embeddings metadata — all occurrences of namespace fallback
|
|
33
|
+
patch_all("19e: embeddings metadata namespace all",
|
|
34
|
+
EMB_TOOLS,
|
|
35
|
+
"namespace: namespace || 'default',",
|
|
36
|
+
"namespace: namespace || 'all',")
|
|
37
|
+
|
|
38
|
+
# ── List ops (from old Patch 21) ──
|
|
39
|
+
|
|
40
|
+
# 21c: MCP list — update description to reflect 'all' default
|
|
41
|
+
patch("21c: MCP list namespace description",
|
|
42
|
+
MCP_MEMORY,
|
|
43
|
+
"namespace: { type: 'string', description: 'Filter by namespace' },",
|
|
44
|
+
"namespace: { type: 'string', description: 'Namespace to list (default: \"all\" = all namespaces)' },")
|
|
45
|
+
|
|
46
|
+
# 21d: MCP list — default to 'all' (read-only discovery, like search)
|
|
47
|
+
patch("21d: MCP list namespace default all",
|
|
48
|
+
MCP_MEMORY,
|
|
49
|
+
"const { listEntries } = await getMemoryFunctions();\n const namespace = input.namespace;\n const limit = input.limit || 50;",
|
|
50
|
+
"const { listEntries } = await getMemoryFunctions();\n const namespace = input.namespace || 'all';\n const limit = input.limit || 50;")
|
|
51
|
+
|
|
52
|
+
# 21g: CLI list — default to 'all' (read-only discovery, like search)
|
|
53
|
+
patch("21g: CLI list namespace default all",
|
|
54
|
+
CLI_MEMORY,
|
|
55
|
+
" const namespace = ctx.flags.namespace;\n const limit = ctx.flags.limit;\n // Use sql.js directly for consistent data access",
|
|
56
|
+
" const namespace = ctx.flags.namespace || 'all';\n const limit = ctx.flags.limit;\n // Use sql.js directly for consistent data access")
|
|
57
|
+
|
|
58
|
+
# 21i: Core listEntries() — use nsFilter variable instead of truthiness check
|
|
59
|
+
patch("21i: listEntries nsFilter variable",
|
|
60
|
+
MI,
|
|
61
|
+
" // Get total count\n const countQuery = namespace",
|
|
62
|
+
" // Get total count\n const nsFilter = namespace && namespace !== 'all';\n const countQuery = nsFilter")
|
|
63
|
+
|
|
64
|
+
# 21j: Core listEntries() — use nsFilter in list query too
|
|
65
|
+
patch("21j: listEntries listQuery all support",
|
|
66
|
+
MI,
|
|
67
|
+
" ${namespace ? `AND namespace",
|
|
68
|
+
" ${nsFilter ? `AND namespace")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# NS-002: Store/delete/retrieve fall back to 'default' + accept 'all'
|
|
2
|
+
**Severity**: Critical
|
|
3
|
+
**GitHub**: [#581](https://github.com/ruvnet/claude-flow/issues/581)
|
|
4
|
+
## Root Cause
|
|
5
|
+
MCP/CLI/Core used `namespace || 'default'`, silently routing entries to wrong namespace. Also accepted 'all' (search/list sentinel) as a write namespace, creating invisible entries.
|
|
6
|
+
## Rule
|
|
7
|
+
Targeted ops (store, delete, retrieve) require explicit namespace. Block 'all' with clear error.
|
|
8
|
+
## Fix
|
|
9
|
+
Remove fallback. Add 'namespace' to MCP schema required fields. Add runtime throw for missing/invalid namespace. CLI commands check before executing. Core functions throw on missing namespace.
|
|
10
|
+
## Files Patched
|
|
11
|
+
- mcp-tools/memory-tools.js (store, delete, retrieve)
|
|
12
|
+
- commands/memory.js (store, delete, retrieve)
|
|
13
|
+
- memory/memory-initializer.js (storeEntry, deleteEntry, getEntry)
|
|
14
|
+
## Dependencies
|
|
15
|
+
|
|
16
|
+
Depends on NS-001 (190) — NS-002 builds on the namespace discovery changes from NS-001.
|
|
17
|
+
|
|
18
|
+
## Ops
|
|
19
|
+
14 ops in fix.py (20a-i + 21a,b,e,f,h)
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# NS-002: Targeted ops (store/delete/retrieve) accept wrong namespace
|
|
2
|
+
# GitHub: #581
|
|
3
|
+
# Rule: Require explicit namespace, block 'all'
|
|
4
|
+
# 14 ops: 20a-i (store/delete) + 21a,b,e,f,h (retrieve)
|
|
5
|
+
|
|
6
|
+
# ── Store ops (from old Patch 20) ──
|
|
7
|
+
|
|
8
|
+
# 20a: MCP store — add 'namespace' to required fields in schema
|
|
9
|
+
patch("20a: MCP store require namespace",
|
|
10
|
+
MCP_MEMORY,
|
|
11
|
+
"required: ['key', 'value'],",
|
|
12
|
+
"required: ['key', 'value', 'namespace'],")
|
|
13
|
+
|
|
14
|
+
# 20b: MCP store — remove || 'default' fallback + add runtime throw
|
|
15
|
+
patch("20b: MCP store namespace no fallback",
|
|
16
|
+
MCP_MEMORY,
|
|
17
|
+
"const namespace = input.namespace || 'default';\n const value = typeof",
|
|
18
|
+
"const namespace = input.namespace;\n if (!namespace || namespace === 'all') {\n throw new Error('Namespace is required (cannot be \"all\"). Use namespace: \"patterns\", \"solutions\", or \"tasks\"');\n }\n const value = typeof")
|
|
19
|
+
|
|
20
|
+
# 20c: MCP delete — add 'namespace' to required + update description
|
|
21
|
+
patch("20c: MCP delete require namespace",
|
|
22
|
+
MCP_MEMORY,
|
|
23
|
+
""" description: 'Delete a memory entry by key',
|
|
24
|
+
category: 'memory',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
key: { type: 'string', description: 'Memory key' },
|
|
29
|
+
namespace: { type: 'string', description: 'Namespace (default: "default")' },
|
|
30
|
+
},
|
|
31
|
+
required: ['key'],""",
|
|
32
|
+
""" description: 'Delete a memory entry by key',
|
|
33
|
+
category: 'memory',
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
key: { type: 'string', description: 'Memory key' },
|
|
38
|
+
namespace: { type: 'string', description: 'Namespace (e.g. "patterns", "solutions", "tasks")' },
|
|
39
|
+
},
|
|
40
|
+
required: ['key', 'namespace'],""")
|
|
41
|
+
|
|
42
|
+
# 20d: MCP delete — remove || 'default' fallback + add runtime throw
|
|
43
|
+
patch("20d: MCP delete namespace no fallback",
|
|
44
|
+
MCP_MEMORY,
|
|
45
|
+
"const { deleteEntry } = await getMemoryFunctions();\n const key = input.key;\n const namespace = input.namespace || 'default';",
|
|
46
|
+
"const { deleteEntry } = await getMemoryFunctions();\n const key = input.key;\n const namespace = input.namespace;\n if (!namespace || namespace === 'all') {\n throw new Error('Namespace is required (cannot be \"all\"). Use namespace: \"patterns\", \"solutions\", or \"tasks\"');\n }")
|
|
47
|
+
|
|
48
|
+
# 20e: CLI store — add namespace-required check after key check
|
|
49
|
+
patch("20e: CLI store require namespace",
|
|
50
|
+
CLI_MEMORY,
|
|
51
|
+
""" if (!key) {
|
|
52
|
+
output.printError('Key is required. Use --key or -k');
|
|
53
|
+
return { success: false, exitCode: 1 };
|
|
54
|
+
}
|
|
55
|
+
if (!value && ctx.interactive) {""",
|
|
56
|
+
""" if (!key) {
|
|
57
|
+
output.printError('Key is required. Use --key or -k');
|
|
58
|
+
return { success: false, exitCode: 1 };
|
|
59
|
+
}
|
|
60
|
+
if (!namespace || namespace === 'all') {
|
|
61
|
+
output.printError('Namespace is required (cannot be "all"). Use --namespace or -n (e.g. "patterns", "solutions", "tasks")');
|
|
62
|
+
return { success: false, exitCode: 1 };
|
|
63
|
+
}
|
|
64
|
+
if (!value && ctx.interactive) {""")
|
|
65
|
+
|
|
66
|
+
# 20f: CLI delete — remove || 'default' fallback and fix error message
|
|
67
|
+
patch("20f: CLI delete namespace no fallback",
|
|
68
|
+
CLI_MEMORY,
|
|
69
|
+
"const namespace = ctx.flags.namespace || 'default';\n const force = ctx.flags.force;\n if (!key) {\n output.printError('Key is required. Use: memory delete -k \"key\" [-n \"namespace\"]');",
|
|
70
|
+
"const namespace = ctx.flags.namespace;\n const force = ctx.flags.force;\n if (!key) {\n output.printError('Key is required. Use: memory delete -k \"key\" -n \"namespace\"');")
|
|
71
|
+
|
|
72
|
+
# 20g: CLI delete — add namespace-required check
|
|
73
|
+
patch("20g: CLI delete namespace check",
|
|
74
|
+
CLI_MEMORY,
|
|
75
|
+
""" output.printError('Key is required. Use: memory delete -k "key" -n "namespace"');
|
|
76
|
+
return { success: false, exitCode: 1 };
|
|
77
|
+
}
|
|
78
|
+
if (!force && ctx.interactive) {""",
|
|
79
|
+
""" output.printError('Key is required. Use: memory delete -k "key" -n "namespace"');
|
|
80
|
+
return { success: false, exitCode: 1 };
|
|
81
|
+
}
|
|
82
|
+
if (!namespace || namespace === 'all') {
|
|
83
|
+
output.printError('Namespace is required (cannot be "all"). Use: memory delete -k "key" -n "namespace" (e.g. "patterns", "solutions", "tasks")');
|
|
84
|
+
return { success: false, exitCode: 1 };
|
|
85
|
+
}
|
|
86
|
+
if (!force && ctx.interactive) {""")
|
|
87
|
+
|
|
88
|
+
# 20h: Core storeEntry() — remove dead 'default' parameter default + throw
|
|
89
|
+
patch("20h: storeEntry no default namespace",
|
|
90
|
+
MI,
|
|
91
|
+
"const { key, value, namespace = 'default', generateEmbeddingFlag = true, tags = [], ttl, dbPath: customPath, upsert = false } = options;",
|
|
92
|
+
"const { key, value, namespace, generateEmbeddingFlag = true, tags = [], ttl, dbPath: customPath, upsert = false } = options;\n if (!namespace || namespace === 'all') throw new Error('storeEntry: namespace is required (cannot be \"all\")');")
|
|
93
|
+
|
|
94
|
+
# 20i: Core deleteEntry() — remove dead 'default' parameter default + throw
|
|
95
|
+
patch("20i: deleteEntry no default namespace",
|
|
96
|
+
MI,
|
|
97
|
+
"export async function deleteEntry(options) {\n const { key, namespace = 'default', dbPath: customPath } = options;\n const swarmDir = path.join(process.cwd(), '.swarm');\n const dbPath = customPath || path.join(swarmDir, 'memory.db');",
|
|
98
|
+
"export async function deleteEntry(options) {\n const { key, namespace, dbPath: customPath } = options;\n if (!namespace || namespace === 'all') throw new Error('deleteEntry: namespace is required (cannot be \"all\")');\n const swarmDir = path.join(process.cwd(), '.swarm');\n const dbPath = customPath || path.join(swarmDir, 'memory.db');")
|
|
99
|
+
|
|
100
|
+
# ── Retrieve ops (from old Patch 21) ──
|
|
101
|
+
|
|
102
|
+
# 21a: MCP retrieve — add 'namespace' to required + update description
|
|
103
|
+
patch("21a: MCP retrieve require namespace",
|
|
104
|
+
MCP_MEMORY,
|
|
105
|
+
""" description: 'Retrieve a value from memory by key',
|
|
106
|
+
category: 'memory',
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: {
|
|
110
|
+
key: { type: 'string', description: 'Memory key' },
|
|
111
|
+
namespace: { type: 'string', description: 'Namespace (default: "default")' },
|
|
112
|
+
},
|
|
113
|
+
required: ['key'],""",
|
|
114
|
+
""" description: 'Retrieve a value from memory by key',
|
|
115
|
+
category: 'memory',
|
|
116
|
+
inputSchema: {
|
|
117
|
+
type: 'object',
|
|
118
|
+
properties: {
|
|
119
|
+
key: { type: 'string', description: 'Memory key' },
|
|
120
|
+
namespace: { type: 'string', description: 'Namespace (e.g. "patterns", "solutions", "tasks")' },
|
|
121
|
+
},
|
|
122
|
+
required: ['key', 'namespace'],""")
|
|
123
|
+
|
|
124
|
+
# 21b: MCP retrieve — remove || 'default' fallback + add runtime throw
|
|
125
|
+
patch("21b: MCP retrieve namespace no fallback",
|
|
126
|
+
MCP_MEMORY,
|
|
127
|
+
"const { getEntry } = await getMemoryFunctions();\n const key = input.key;\n const namespace = input.namespace || 'default';",
|
|
128
|
+
"const { getEntry } = await getMemoryFunctions();\n const key = input.key;\n const namespace = input.namespace;\n if (!namespace || namespace === 'all') {\n throw new Error('Namespace is required (cannot be \"all\"). Use namespace: \"patterns\", \"solutions\", or \"tasks\"');\n }")
|
|
129
|
+
|
|
130
|
+
# 21e: CLI retrieve — remove default: 'default' from flag definition
|
|
131
|
+
patch("21e: CLI retrieve remove default",
|
|
132
|
+
CLI_MEMORY,
|
|
133
|
+
" type: 'string',\n default: 'default'\n }\n ],\n action: async (ctx) => {\n const key = ctx.flags.key || ctx.args[0];\n const namespace = ctx.flags.namespace;\n if (!key) {\n output.printError('Key is required');",
|
|
134
|
+
" type: 'string'\n }\n ],\n action: async (ctx) => {\n const key = ctx.flags.key || ctx.args[0];\n const namespace = ctx.flags.namespace;\n if (!key) {\n output.printError('Key is required');")
|
|
135
|
+
|
|
136
|
+
# 21f: CLI retrieve — add namespace-required check
|
|
137
|
+
patch("21f: CLI retrieve namespace check",
|
|
138
|
+
CLI_MEMORY,
|
|
139
|
+
""" if (!key) {
|
|
140
|
+
output.printError('Key is required');
|
|
141
|
+
return { success: false, exitCode: 1 };
|
|
142
|
+
}
|
|
143
|
+
// Use sql.js directly for consistent data access""",
|
|
144
|
+
""" if (!key) {
|
|
145
|
+
output.printError('Key is required');
|
|
146
|
+
return { success: false, exitCode: 1 };
|
|
147
|
+
}
|
|
148
|
+
if (!namespace || namespace === 'all') {
|
|
149
|
+
output.printError('Namespace is required (cannot be "all"). Use --namespace or -n (e.g. "patterns", "solutions", "tasks")');
|
|
150
|
+
return { success: false, exitCode: 1 };
|
|
151
|
+
}
|
|
152
|
+
// Use sql.js directly for consistent data access""")
|
|
153
|
+
|
|
154
|
+
# 21h: Core getEntry() — remove dead 'default' parameter default + throw
|
|
155
|
+
patch("21h: getEntry no default namespace",
|
|
156
|
+
MI,
|
|
157
|
+
"const { key, namespace = 'default', dbPath: customPath } = options;\n const swarmDir = path.join(process.cwd(), '.swarm');\n const dbPath = customPath || path.join(swarmDir, 'memory.db');",
|
|
158
|
+
"const { key, namespace, dbPath: customPath } = options;\n if (!namespace || namespace === 'all') throw new Error('getEntry: namespace is required (cannot be \"all\")');\n const swarmDir = path.join(process.cwd(), '.swarm');\n const dbPath = customPath || path.join(swarmDir, 'memory.db');")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# NS-003: Namespace typo 'pattern' vs 'patterns'
|
|
2
|
+
**Severity**: Medium
|
|
3
|
+
**GitHub**: [#1136](https://github.com/ruvnet/claude-flow/issues/1136)
|
|
4
|
+
## Root Cause
|
|
5
|
+
hooks-tools.js used singular 'pattern' in 4 locations while every other file (memory-tools.js, CLI, README) uses 'patterns' (plural). Patterns stored via hooks were invisible to search.
|
|
6
|
+
## Fix
|
|
7
|
+
Replace all 4 occurrences of 'pattern' with 'patterns' in hooks-tools.js.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- mcp-tools/hooks-tools.js
|
|
10
|
+
## Dependencies
|
|
11
|
+
|
|
12
|
+
Depends on NS-002 (200) — NS-003 fixes typos in code paths that NS-002 modifies.
|
|
13
|
+
|
|
14
|
+
## Ops
|
|
15
|
+
4 ops in fix.py (22a-d)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# NS-003: Namespace typo 'pattern' vs 'patterns'
|
|
2
|
+
# GitHub: #1136
|
|
3
|
+
# 4 ops: 22a-d
|
|
4
|
+
|
|
5
|
+
patch("22a: hooks pattern-store namespace",
|
|
6
|
+
MCP_HOOKS,
|
|
7
|
+
"namespace: 'pattern',",
|
|
8
|
+
"namespace: 'patterns',")
|
|
9
|
+
|
|
10
|
+
patch("22b: hooks pattern-search default",
|
|
11
|
+
MCP_HOOKS,
|
|
12
|
+
"const namespace = params.namespace || 'pattern';",
|
|
13
|
+
"const namespace = params.namespace || 'patterns';")
|
|
14
|
+
|
|
15
|
+
patch("22c: hooks pattern-search description",
|
|
16
|
+
MCP_HOOKS,
|
|
17
|
+
"description: 'Namespace to search (default: pattern)'",
|
|
18
|
+
"description: 'Namespace to search (default: patterns)'")
|
|
19
|
+
|
|
20
|
+
patch("22d: hooks pattern-search note",
|
|
21
|
+
MCP_HOOKS,
|
|
22
|
+
'namespace "pattern".',
|
|
23
|
+
'namespace "patterns".')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "|| 'patterns'" mcp-tools/hooks-tools.js
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# RS-001: ruv-swarm MCP fails on Node 24 — better-sqlite3 missing native bindings
|
|
2
|
+
|
|
3
|
+
**Severity**: Critical
|
|
4
|
+
**Package**: `ruv-swarm@1.0.20`
|
|
5
|
+
**GitHub**: [ruv-FANN#185](https://github.com/ruvnet/ruv-FANN/issues/185)
|
|
6
|
+
|
|
7
|
+
## Symptoms
|
|
8
|
+
|
|
9
|
+
`ruv-swarm mcp start` crashes immediately with:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Could not locate the bindings file. Tried:
|
|
13
|
+
→ .../better-sqlite3/lib/binding/node-v137-linux-x64/better_sqlite3.node
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The MCP server never starts. All ruv-swarm MCP tools are unavailable.
|
|
17
|
+
|
|
18
|
+
## Root Cause
|
|
19
|
+
|
|
20
|
+
`ruv-swarm@1.0.20` declares `"better-sqlite3": "^11.6.0"` in `package.json`.
|
|
21
|
+
When installed via `npx`, npm resolves this to `better-sqlite3@11.10.0`.
|
|
22
|
+
|
|
23
|
+
`better-sqlite3` 11.x does **not** ship prebuilt binaries for Node 24
|
|
24
|
+
(ABI version `node-v137`). The native addon compilation fails silently
|
|
25
|
+
during `npx` install — `build/Release/` contains intermediate `obj/`
|
|
26
|
+
directories but no `better_sqlite3.node` binary.
|
|
27
|
+
|
|
28
|
+
`better-sqlite3` 12.x (`^12.0.0`) added Node 24 to its supported engines
|
|
29
|
+
and ships prebuilt binaries for `node-v137-linux-x64`.
|
|
30
|
+
|
|
31
|
+
## Why @claude-flow/cli is unaffected
|
|
32
|
+
|
|
33
|
+
`@claude-flow/cli` uses `sql.js` (pure WASM SQLite) instead of `better-sqlite3`.
|
|
34
|
+
WASM has no native bindings and works on any Node version.
|
|
35
|
+
|
|
36
|
+
## Fix
|
|
37
|
+
|
|
38
|
+
Bump the dependency from `^11.6.0` to `^12.0.0` in `ruv-swarm/package.json`.
|
|
39
|
+
|
|
40
|
+
## Files Patched
|
|
41
|
+
|
|
42
|
+
- `ruv-swarm` `package.json` (in npx cache)
|
|
43
|
+
|
|
44
|
+
## Ops
|
|
45
|
+
|
|
46
|
+
1 op in fix.py (JSON string replacement in package.json)
|
|
47
|
+
1 op: `npm rebuild better-sqlite3` in the npx cache directory
|
|
48
|
+
|
|
49
|
+
## Verification
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx -y ruv-swarm --version
|
|
53
|
+
# Should print version without crashing
|
|
54
|
+
```
|