@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,57 @@
|
|
|
1
|
+
# UI-001: intelligence stats crashes on .toFixed() of undefined
|
|
2
|
+
# Absorbed from old patch-17. Applied via sed to npx cache.
|
|
3
|
+
|
|
4
|
+
# SONA component null checks
|
|
5
|
+
patch("17a: SONA learningTimeMs null check",
|
|
6
|
+
HOOKS_CMD,
|
|
7
|
+
"{ metric: 'Learning Time', value: `${result.components.sona.learningTimeMs.toFixed(3)}ms` }",
|
|
8
|
+
"{ metric: 'Learning Time', value: result.components.sona.learningTimeMs != null ? `${result.components.sona.learningTimeMs.toFixed(3)}ms` : 'N/A' }")
|
|
9
|
+
|
|
10
|
+
patch("17b: SONA adaptationTimeMs null check",
|
|
11
|
+
HOOKS_CMD,
|
|
12
|
+
"{ metric: 'Adaptation Time', value: `${result.components.sona.adaptationTimeMs.toFixed(3)}ms` }",
|
|
13
|
+
"{ metric: 'Adaptation Time', value: result.components.sona.adaptationTimeMs != null ? `${result.components.sona.adaptationTimeMs.toFixed(3)}ms` : 'N/A' }")
|
|
14
|
+
|
|
15
|
+
patch("17c: SONA avgQuality null check",
|
|
16
|
+
HOOKS_CMD,
|
|
17
|
+
"{ metric: 'Avg Quality', value: `${(result.components.sona.avgQuality * 100).toFixed(1)}%` }",
|
|
18
|
+
"{ metric: 'Avg Quality', value: result.components.sona.avgQuality != null ? `${(result.components.sona.avgQuality * 100).toFixed(1)}%` : 'N/A' }")
|
|
19
|
+
|
|
20
|
+
# MoE component null checks
|
|
21
|
+
patch("17d: MoE routingAccuracy null check",
|
|
22
|
+
HOOKS_CMD,
|
|
23
|
+
"{ metric: 'Routing Accuracy', value: `${(result.components.moe.routingAccuracy * 100).toFixed(1)}%` }",
|
|
24
|
+
"{ metric: 'Routing Accuracy', value: result.components.moe.routingAccuracy != null ? `${(result.components.moe.routingAccuracy * 100).toFixed(1)}%` : 'N/A' }")
|
|
25
|
+
|
|
26
|
+
patch("17e: MoE loadBalance null check",
|
|
27
|
+
HOOKS_CMD,
|
|
28
|
+
"{ metric: 'Load Balance', value: `${(result.components.moe.loadBalance * 100).toFixed(1)}%` }",
|
|
29
|
+
"{ metric: 'Load Balance', value: result.components.moe.loadBalance != null ? `${(result.components.moe.loadBalance * 100).toFixed(1)}%` : 'N/A' }")
|
|
30
|
+
|
|
31
|
+
# Embeddings null check
|
|
32
|
+
patch("17f: embeddings cacheHitRate null check",
|
|
33
|
+
HOOKS_CMD,
|
|
34
|
+
"{ metric: 'Cache Hit Rate', value: `${(result.components.embeddings.cacheHitRate * 100).toFixed(1)}%` }",
|
|
35
|
+
"{ metric: 'Cache Hit Rate', value: result.components.embeddings.cacheHitRate != null ? `${(result.components.embeddings.cacheHitRate * 100).toFixed(1)}%` : 'N/A' }")
|
|
36
|
+
|
|
37
|
+
# Performance section null guard
|
|
38
|
+
patch("17g: performance section null guard",
|
|
39
|
+
HOOKS_CMD,
|
|
40
|
+
""" output.printList([
|
|
41
|
+
`Flash Attention: ${output.success(result.performance.flashAttention)}`,
|
|
42
|
+
`Memory Reduction: ${output.success(result.performance.memoryReduction)}`,
|
|
43
|
+
`Search Improvement: ${output.success(result.performance.searchImprovement)}`,
|
|
44
|
+
`Token Reduction: ${output.success(result.performance.tokenReduction)}`,
|
|
45
|
+
`SWE-Bench Score: ${output.success(result.performance.sweBenchScore)}`
|
|
46
|
+
]);""",
|
|
47
|
+
""" if (result.performance) {
|
|
48
|
+
output.printList([
|
|
49
|
+
`Flash Attention: ${output.success(result.performance.flashAttention || 'N/A')}`,
|
|
50
|
+
`Memory Reduction: ${output.success(result.performance.memoryReduction || 'N/A')}`,
|
|
51
|
+
`Search Improvement: ${output.success(result.performance.searchImprovement || 'N/A')}`,
|
|
52
|
+
`Token Reduction: ${output.success(result.performance.tokenReduction || 'N/A')}`,
|
|
53
|
+
`SWE-Bench Score: ${output.success(result.performance.sweBenchScore || 'N/A')}`
|
|
54
|
+
]);
|
|
55
|
+
} else {
|
|
56
|
+
output.writeln(output.dim(' No performance data available'));
|
|
57
|
+
}""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "learningTimeMs != null" commands/hooks.js
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# UI-002: neural status shows "Not loaded"
|
|
2
|
+
**Severity**: Low (cosmetic)
|
|
3
|
+
**GitHub**: [#1146](https://github.com/ruvnet/claude-flow/issues/1146)
|
|
4
|
+
## Root Cause
|
|
5
|
+
`neural status` reads module-level flags (`initialized`, `sonaAvailable`, `hnswIndex`) without calling their init functions. RuVector WASM, SONA Engine, and HNSW Index always show "Not loaded" even when packages are installed and working.
|
|
6
|
+
## Fix
|
|
7
|
+
Add `initializeTraining()` and `getHNSWIndex()` calls before reading status. Update import to include `getHNSWIndex`.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- commands/neural.js
|
|
10
|
+
## Ops
|
|
11
|
+
2 ops in fix.py
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# UI-002: neural status shows "Not loaded" for installed components
|
|
2
|
+
# Absorbed from old patch-18. Applied manually to npx cache.
|
|
3
|
+
|
|
4
|
+
# Update import to include getHNSWIndex
|
|
5
|
+
patch("18a: neural.js import getHNSWIndex",
|
|
6
|
+
NEURAL,
|
|
7
|
+
"const { getHNSWStatus, loadEmbeddingModel } = await import('../memory/memory-initializer.js');",
|
|
8
|
+
"const { getHNSWIndex, getHNSWStatus, loadEmbeddingModel } = await import('../memory/memory-initializer.js');")
|
|
9
|
+
|
|
10
|
+
# Add initialization calls before status reads
|
|
11
|
+
patch("18b: neural.js init before status",
|
|
12
|
+
NEURAL,
|
|
13
|
+
" const ruvectorStats = ruvector.getTrainingStats();",
|
|
14
|
+
""" // Patch 18: Initialize RuVector WASM + SONA + HNSW so status reflects reality
|
|
15
|
+
if (!ruvector.getTrainingStats().initialized) {
|
|
16
|
+
await ruvector.initializeTraining({ useSona: true }).catch(() => {});
|
|
17
|
+
}
|
|
18
|
+
await getHNSWIndex().catch(() => null);
|
|
19
|
+
const ruvectorStats = ruvector.getTrainingStats();""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "getHNSWIndex" commands/neural.js
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# DM-006: No log rotation — logs grow unbounded
|
|
2
|
+
**Severity**: Medium
|
|
3
|
+
**GitHub**: [#1114](https://github.com/ruvnet/claude-flow/issues/1114)
|
|
4
|
+
## Root Cause
|
|
5
|
+
(Headless) `logExecution()` in `headless-worker-executor.js` creates 2-3 log files per worker run (~75 KB each) but has zero cleanup. No rotation, no max file count, no TTL. At current daemon intervals this accumulates ~23 MB/day, ~702 MB/month. (Main) `startBackgroundDaemon()` in `daemon.js` opens `daemon.log` in append mode and never truncates. A single long-running daemon can grow daemon.log to 100+ GB.
|
|
6
|
+
## Fix
|
|
7
|
+
(A) Add `unlinkSync` and `statSync` to the headless executor ESM import. (B) Call `cleanupOldLogs()` from `ensureLogDir()` so cleanup runs on each headless execution cycle. (C) Add `cleanupOldLogs()` method: removes `.log` files older than 7 days or beyond a 500-file cap, keeping newest files. (D) In `daemon.js`, before opening `daemon.log` for append, check its size with `fs.statSync()` and rotate to `daemon.log.1` if > 50MB.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- services/headless-worker-executor.js
|
|
10
|
+
- commands/daemon.js
|
|
11
|
+
## Ops
|
|
12
|
+
4 ops in fix.py
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# DM-006: No log rotation — headless execution logs grow unbounded
|
|
2
|
+
# GitHub: #1114
|
|
3
|
+
|
|
4
|
+
# A: Add unlinkSync and statSync to ESM import
|
|
5
|
+
patch("DM-006a: add unlinkSync/statSync to fs import",
|
|
6
|
+
HWE,
|
|
7
|
+
"import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync } from 'fs';",
|
|
8
|
+
"import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync, unlinkSync, statSync } from 'fs';")
|
|
9
|
+
|
|
10
|
+
# B: Call cleanupOldLogs() from ensureLogDir()
|
|
11
|
+
patch("DM-006b: call cleanup from ensureLogDir",
|
|
12
|
+
HWE,
|
|
13
|
+
""" ensureLogDir() {
|
|
14
|
+
try {
|
|
15
|
+
if (!existsSync(this.config.logDir)) {
|
|
16
|
+
mkdirSync(this.config.logDir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
this.emit('warning', { message: 'Failed to create log directory', error });
|
|
21
|
+
}
|
|
22
|
+
}""",
|
|
23
|
+
""" ensureLogDir() {
|
|
24
|
+
try {
|
|
25
|
+
if (!existsSync(this.config.logDir)) {
|
|
26
|
+
mkdirSync(this.config.logDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
this.cleanupOldLogs();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
this.emit('warning', { message: 'Failed to create log directory', error });
|
|
32
|
+
}
|
|
33
|
+
}""")
|
|
34
|
+
|
|
35
|
+
# C: Add cleanupOldLogs() method before logExecution()
|
|
36
|
+
patch("DM-006c: add cleanupOldLogs method",
|
|
37
|
+
HWE,
|
|
38
|
+
""" logExecution(executionId, type, content) {""",
|
|
39
|
+
""" cleanupOldLogs(maxAgeDays = 7, maxFiles = 500) {
|
|
40
|
+
try {
|
|
41
|
+
const files = readdirSync(this.config.logDir)
|
|
42
|
+
.filter(f => f.endsWith('.log'))
|
|
43
|
+
.map(f => {
|
|
44
|
+
try { return { name: f, mtime: statSync(join(this.config.logDir, f)).mtimeMs }; }
|
|
45
|
+
catch { return null; }
|
|
46
|
+
})
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
49
|
+
const cutoff = Date.now() - maxAgeDays * 86400000;
|
|
50
|
+
for (let i = 0; i < files.length; i++) {
|
|
51
|
+
if (files[i].mtime < cutoff || i >= maxFiles) {
|
|
52
|
+
try { unlinkSync(join(this.config.logDir, files[i].name)); } catch {}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch { /* ignore cleanup errors */ }
|
|
57
|
+
}
|
|
58
|
+
logExecution(executionId, type, content) {""")
|
|
59
|
+
|
|
60
|
+
# DM-006 extension: Main daemon.log rotation in daemon.js
|
|
61
|
+
# Before opening daemon.log for append, check size and rotate if > 50MB
|
|
62
|
+
patch("DM-006d: main daemon.log rotation",
|
|
63
|
+
DJ,
|
|
64
|
+
" const logFile = join(logsDir, 'daemon.log');",
|
|
65
|
+
""" const logFile = join(logsDir, 'daemon.log');
|
|
66
|
+
// Rotate main daemon.log if > 50MB
|
|
67
|
+
try {
|
|
68
|
+
const logStat = fs.statSync(logFile);
|
|
69
|
+
if (logStat.size > 50 * 1024 * 1024) {
|
|
70
|
+
fs.renameSync(logFile, logFile + '.1');
|
|
71
|
+
}
|
|
72
|
+
} catch { /* file doesn't exist yet or stat failed — ignore */ }""")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# HW-004: runWithTimeout rejects but does not kill child process
|
|
2
|
+
**Severity**: Medium
|
|
3
|
+
**GitHub**: [#1117](https://github.com/ruvnet/claude-flow/issues/1117)
|
|
4
|
+
## Root Cause
|
|
5
|
+
`runWithTimeout()` in `worker-daemon.js` has `DEFAULT_WORKER_TIMEOUT_MS = 5 * 60 * 1000` (5 min), but the headless executor's per-worker timeouts range from 5-15 minutes. When the daemon timeout fires first, the promise rejects but the underlying `claude --print` child process keeps running as an orphan until the executor's own timeout fires minutes later.
|
|
6
|
+
## Fix
|
|
7
|
+
Raise `DEFAULT_WORKER_TIMEOUT_MS` from 5 minutes to 16 minutes so the daemon timeout never fires before the executor's own per-worker timeout (max 15 min for audit/refactor workers). The executor handles its own child process cleanup on timeout.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- services/worker-daemon.js
|
|
10
|
+
## Ops
|
|
11
|
+
1 op in fix.py
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# HW-004: runWithTimeout rejects but does not kill child process
|
|
2
|
+
# GitHub: #1117
|
|
3
|
+
|
|
4
|
+
# A: Raise daemon worker timeout above max headless timeout (15 min)
|
|
5
|
+
patch("HW-004a: raise worker timeout to 16 min",
|
|
6
|
+
WD,
|
|
7
|
+
"""// Worker timeout (5 minutes max per worker)
|
|
8
|
+
const DEFAULT_WORKER_TIMEOUT_MS = 5 * 60 * 1000;""",
|
|
9
|
+
"""// Worker timeout — must exceed max headless timeout (15 min for audit/refactor)
|
|
10
|
+
const DEFAULT_WORKER_TIMEOUT_MS = 16 * 60 * 1000;""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "16 \* 60 \* 1000" services/worker-daemon.js
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# SG-004: init wizard lacks parity with init
|
|
2
|
+
|
|
3
|
+
**Severity**: High
|
|
4
|
+
**GitHub**: [#1181](https://github.com/ruvnet/claude-flow/issues/1181)
|
|
5
|
+
|
|
6
|
+
## Root Cause
|
|
7
|
+
|
|
8
|
+
The `wizardCommand.action` in `commands/init.js` was implemented as a
|
|
9
|
+
standalone code path that diverges from the parent `initAction`. It skips the
|
|
10
|
+
already-initialized guard, ignores `--force`, `--start-all`, `--start-daemon`,
|
|
11
|
+
`--codex`, and `--dual` flags, and never shows "Next steps" hints. The wizard
|
|
12
|
+
is also only reachable as a subcommand of `init` with no `options` array, so
|
|
13
|
+
the parser cannot validate flags for the wizard context.
|
|
14
|
+
|
|
15
|
+
## Fix
|
|
16
|
+
|
|
17
|
+
Ten ops bring the wizard to full parity with `init` and promote it to a
|
|
18
|
+
top-level command (`claude-flow wizard`):
|
|
19
|
+
|
|
20
|
+
| Op | What it does |
|
|
21
|
+
|----|-------------|
|
|
22
|
+
| SG-004a | Adds the already-initialized guard before prompts + passes `--force` to options |
|
|
23
|
+
| SG-004b | Adds `--codex`/`--dual` handling after executeInit succeeds |
|
|
24
|
+
| SG-004c | Adds `--start-all`/`--start-daemon` service startup + "Next steps" hints |
|
|
25
|
+
| SG-004d | Fixes catch block — catches errors cleanly instead of re-throwing |
|
|
26
|
+
| SG-004e | Exports `wizardCommand` from init.js, adds `options` + `examples` arrays |
|
|
27
|
+
| SG-004f | Imports `wizardCommand` in the command registry (`commands/index.js`) |
|
|
28
|
+
| SG-004g | Adds wizard to `commandLoaders` for lazy-loading |
|
|
29
|
+
| SG-004h | Pre-populates wizard in the loaded commands cache |
|
|
30
|
+
| SG-004i | Adds `wizardCommand` to the `commands` array (parser registration) |
|
|
31
|
+
| SG-004j | Adds `wizardCommand` to `commandsByCategory.primary` for help display |
|
|
32
|
+
|
|
33
|
+
## Files Patched
|
|
34
|
+
|
|
35
|
+
- `commands/init.js`
|
|
36
|
+
- `commands/index.js`
|
|
37
|
+
|
|
38
|
+
## Ops
|
|
39
|
+
|
|
40
|
+
10 ops in fix.py
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# SG-004: init wizard lacks parity with init
|
|
2
|
+
# GitHub: #1181
|
|
3
|
+
#
|
|
4
|
+
# The wizard was implemented as a standalone code path that ignores
|
|
5
|
+
# --force, --start-all, --start-daemon, --codex, --dual, and skips
|
|
6
|
+
# the already-initialized guard and "Next steps" hints. It is also only
|
|
7
|
+
# reachable as a subcommand of `init` with no options array, so the parser
|
|
8
|
+
# cannot validate flags for the wizard context.
|
|
9
|
+
#
|
|
10
|
+
# 10 ops: init-guard + force (a), codex/dual (b), start-all + next-steps (c),
|
|
11
|
+
# catch-block error handling (d), export + options (e),
|
|
12
|
+
# import in registry (f), loaders (g), cache (h),
|
|
13
|
+
# commands array (i), category (j)
|
|
14
|
+
|
|
15
|
+
# Op 1: Add already-initialized guard + pass --force to executeInit options
|
|
16
|
+
patch("SG-004a: wizard init-guard + --force",
|
|
17
|
+
INIT_CMD,
|
|
18
|
+
""" try {
|
|
19
|
+
// Start with base options
|
|
20
|
+
const options = { ...DEFAULT_INIT_OPTIONS, targetDir: ctx.cwd };""",
|
|
21
|
+
""" try {
|
|
22
|
+
// SG-004: Check if already initialized (respects --force)
|
|
23
|
+
const force = ctx.flags.force;
|
|
24
|
+
const initialized = isInitialized(ctx.cwd);
|
|
25
|
+
const hasExisting = initialized.claude || initialized.claudeFlow;
|
|
26
|
+
if (hasExisting && !force) {
|
|
27
|
+
output.printWarning('Claude Flow appears to be already initialized');
|
|
28
|
+
if (initialized.claude) output.printInfo(' Found: .claude/settings.json');
|
|
29
|
+
if (initialized.claudeFlow) output.printInfo(' Found: .claude-flow/config.yaml');
|
|
30
|
+
output.printInfo('Use --force to reinitialize');
|
|
31
|
+
const proceed = await confirm({
|
|
32
|
+
message: 'Do you want to reinitialize? This will overwrite existing configuration.',
|
|
33
|
+
default: false,
|
|
34
|
+
});
|
|
35
|
+
if (!proceed) {
|
|
36
|
+
return { success: true, message: 'Wizard cancelled' };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Start with base options
|
|
40
|
+
const options = { ...DEFAULT_INIT_OPTIONS, targetDir: ctx.cwd, force: ctx.flags.force };""")
|
|
41
|
+
|
|
42
|
+
# Op 2: Add --codex / --dual handling after executeInit succeeds
|
|
43
|
+
patch("SG-004b: wizard --codex/--dual support",
|
|
44
|
+
INIT_CMD,
|
|
45
|
+
""" spinner.succeed('Setup complete!');
|
|
46
|
+
// Initialize embeddings if enabled
|
|
47
|
+
let embeddingsInitialized = false;""",
|
|
48
|
+
""" spinner.succeed('Setup complete!');
|
|
49
|
+
// SG-004: Respect --codex / --dual in wizard
|
|
50
|
+
const codexMode = ctx.flags.codex;
|
|
51
|
+
const dualMode = ctx.flags.dual;
|
|
52
|
+
if (codexMode || dualMode) {
|
|
53
|
+
try {
|
|
54
|
+
output.writeln(output.dim(' Initializing Codex integration...'));
|
|
55
|
+
await initCodexAction(ctx, { codexMode, dualMode, force: ctx.flags.force, minimal: false, full: false });
|
|
56
|
+
} catch (err) {
|
|
57
|
+
output.printWarning(`Codex initialization: ${err instanceof Error ? err.message : String(err)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Initialize embeddings if enabled
|
|
61
|
+
let embeddingsInitialized = false;""")
|
|
62
|
+
|
|
63
|
+
# Op 3: Add --start-all / --start-daemon + "Next steps" hints before final return
|
|
64
|
+
patch("SG-004c: wizard --start-all + next-steps",
|
|
65
|
+
INIT_CMD,
|
|
66
|
+
""" });
|
|
67
|
+
return { success: true, data: result };
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error instanceof Error && error.message === 'User cancelled') {""",
|
|
71
|
+
""" });
|
|
72
|
+
// SG-004: Respect --start-all / --start-daemon in wizard
|
|
73
|
+
const startAll = ctx.flags['start-all'] || ctx.flags.startAll;
|
|
74
|
+
const startDaemon = ctx.flags['start-daemon'] || ctx.flags.startDaemon || startAll;
|
|
75
|
+
if (startDaemon || startAll) {
|
|
76
|
+
output.writeln();
|
|
77
|
+
output.printInfo('Starting services...');
|
|
78
|
+
const { execSync } = await import('child_process');
|
|
79
|
+
if (startAll) {
|
|
80
|
+
try {
|
|
81
|
+
output.writeln(output.dim(' Initializing memory database...'));
|
|
82
|
+
execSync('npx @claude-flow/cli@latest memory init 2>/dev/null', {
|
|
83
|
+
stdio: 'pipe', cwd: ctx.cwd, timeout: 30000
|
|
84
|
+
});
|
|
85
|
+
output.writeln(output.success(' \\u2713 Memory initialized'));
|
|
86
|
+
} catch { output.writeln(output.dim(' Memory database already exists')); }
|
|
87
|
+
}
|
|
88
|
+
if (startDaemon) {
|
|
89
|
+
try {
|
|
90
|
+
output.writeln(output.dim(' Starting daemon...'));
|
|
91
|
+
execSync('npx @claude-flow/cli@latest daemon start 2>/dev/null &', {
|
|
92
|
+
stdio: 'pipe', cwd: ctx.cwd, timeout: 10000
|
|
93
|
+
});
|
|
94
|
+
output.writeln(output.success(' \\u2713 Daemon started'));
|
|
95
|
+
} catch { output.writeln(output.warning(' Daemon may already be running')); }
|
|
96
|
+
}
|
|
97
|
+
if (startAll) {
|
|
98
|
+
try {
|
|
99
|
+
output.writeln(output.dim(' Initializing swarm...'));
|
|
100
|
+
execSync('npx @claude-flow/cli@latest swarm init --topology hierarchical 2>/dev/null', {
|
|
101
|
+
stdio: 'pipe', cwd: ctx.cwd, timeout: 30000
|
|
102
|
+
});
|
|
103
|
+
output.writeln(output.success(' \\u2713 Swarm initialized'));
|
|
104
|
+
} catch { output.writeln(output.dim(' Swarm initialization skipped')); }
|
|
105
|
+
}
|
|
106
|
+
output.writeln();
|
|
107
|
+
output.printSuccess('All services started');
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
output.writeln(output.bold('Next steps:'));
|
|
111
|
+
output.printList([
|
|
112
|
+
`Run ${output.highlight('claude-flow daemon start')} to start background workers`,
|
|
113
|
+
`Run ${output.highlight('claude-flow memory init')} to initialize memory database`,
|
|
114
|
+
`Run ${output.highlight('claude-flow swarm init')} to initialize a swarm`,
|
|
115
|
+
`Or re-run with ${output.highlight('--start-all')} to do all of the above`,
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
return { success: true, data: result };
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error instanceof Error && error.message === 'User cancelled') {""")
|
|
122
|
+
|
|
123
|
+
# Op 4: Fix wizard catch block — re-throws instead of clean error message
|
|
124
|
+
# spinner is declared inside the try block so we can't call spinner.fail() here
|
|
125
|
+
patch("SG-004d: wizard catch block handles errors cleanly",
|
|
126
|
+
INIT_CMD,
|
|
127
|
+
""" if (error instanceof Error && error.message === 'User cancelled') {
|
|
128
|
+
output.printInfo('Setup cancelled');
|
|
129
|
+
return { success: true };
|
|
130
|
+
}
|
|
131
|
+
throw error;""",
|
|
132
|
+
""" if (error instanceof Error && error.message === 'User cancelled') {
|
|
133
|
+
output.printInfo('Setup cancelled');
|
|
134
|
+
return { success: true };
|
|
135
|
+
}
|
|
136
|
+
output.printError(`Failed to initialize: ${error instanceof Error ? error.message : String(error)}`);
|
|
137
|
+
return { success: false, exitCode: 1 };""")
|
|
138
|
+
|
|
139
|
+
# ── Promote wizard to top-level command ──
|
|
140
|
+
# Ops e–j: export wizardCommand with options, register in command registry
|
|
141
|
+
|
|
142
|
+
# Op 5: Export wizardCommand + add options/examples arrays
|
|
143
|
+
patch("SG-004e: export wizardCommand with options",
|
|
144
|
+
INIT_CMD,
|
|
145
|
+
"""// Wizard subcommand for interactive setup
|
|
146
|
+
const wizardCommand = {
|
|
147
|
+
name: 'wizard',
|
|
148
|
+
description: 'Interactive setup wizard for comprehensive configuration',
|
|
149
|
+
action: async (ctx) => {""",
|
|
150
|
+
"""// Wizard — top-level command + init subcommand — SG-004
|
|
151
|
+
export const wizardCommand = {
|
|
152
|
+
name: 'wizard',
|
|
153
|
+
aliases: ['wiz'],
|
|
154
|
+
description: 'Interactive setup wizard for comprehensive configuration',
|
|
155
|
+
options: [
|
|
156
|
+
{ name: 'force', short: 'f', description: 'Overwrite existing configuration', type: 'boolean', default: false },
|
|
157
|
+
{ name: 'start-all', description: 'Auto-start daemon, memory, and swarm after init', type: 'boolean', default: false },
|
|
158
|
+
{ name: 'start-daemon', description: 'Auto-start daemon after init', type: 'boolean', default: false },
|
|
159
|
+
{ name: 'codex', description: 'Initialize for OpenAI Codex CLI', type: 'boolean', default: false },
|
|
160
|
+
{ name: 'dual', description: 'Initialize for both Claude Code and Codex', type: 'boolean', default: false },
|
|
161
|
+
{ name: 'with-embeddings', description: 'Initialize ONNX embedding subsystem', type: 'boolean', default: false },
|
|
162
|
+
{ name: 'embedding-model', description: 'ONNX embedding model', type: 'string', default: 'all-MiniLM-L6-v2', choices: ['all-MiniLM-L6-v2', 'all-mpnet-base-v2'] },
|
|
163
|
+
],
|
|
164
|
+
examples: [
|
|
165
|
+
{ command: 'claude-flow wizard', description: 'Run interactive setup wizard' },
|
|
166
|
+
{ command: 'claude-flow wizard --start-all', description: 'Wizard then start all services' },
|
|
167
|
+
{ command: 'claude-flow wizard --force', description: 'Reinitialize with wizard' },
|
|
168
|
+
{ command: 'claude-flow wizard --codex', description: 'Wizard with Codex integration' },
|
|
169
|
+
],
|
|
170
|
+
action: async (ctx) => {""")
|
|
171
|
+
|
|
172
|
+
# Op 6: Import wizardCommand in command registry
|
|
173
|
+
patch("SG-004f: import wizardCommand in command registry",
|
|
174
|
+
CMDS_INDEX,
|
|
175
|
+
"""import { initCommand } from './init.js';""",
|
|
176
|
+
"""import { initCommand, wizardCommand } from './init.js';""")
|
|
177
|
+
|
|
178
|
+
# Op 7: Add wizard to commandLoaders for lazy loading
|
|
179
|
+
patch("SG-004g: add wizard to commandLoaders",
|
|
180
|
+
CMDS_INDEX,
|
|
181
|
+
""" init: () => import('./init.js'),""",
|
|
182
|
+
""" init: () => import('./init.js'),
|
|
183
|
+
wizard: () => import('./init.js'),""")
|
|
184
|
+
|
|
185
|
+
# Op 8: Pre-populate wizard in loadedCommands cache
|
|
186
|
+
patch("SG-004h: cache wizard command",
|
|
187
|
+
CMDS_INDEX,
|
|
188
|
+
"""loadedCommands.set('init', initCommand);""",
|
|
189
|
+
"""loadedCommands.set('init', initCommand);
|
|
190
|
+
loadedCommands.set('wizard', wizardCommand);""")
|
|
191
|
+
|
|
192
|
+
# Op 9: Add wizardCommand to commands array (triggers parser registration)
|
|
193
|
+
patch("SG-004i: register wizard in commands array",
|
|
194
|
+
CMDS_INDEX,
|
|
195
|
+
""" initCommand,
|
|
196
|
+
startCommand,""",
|
|
197
|
+
""" initCommand,
|
|
198
|
+
wizardCommand,
|
|
199
|
+
startCommand,""")
|
|
200
|
+
|
|
201
|
+
# Op 10: Add wizardCommand to commandsByCategory.primary for help display
|
|
202
|
+
patch("SG-004j: add wizard to primary category",
|
|
203
|
+
CMDS_INDEX,
|
|
204
|
+
""" primary: [
|
|
205
|
+
initCommand,""",
|
|
206
|
+
""" primary: [
|
|
207
|
+
initCommand,
|
|
208
|
+
wizardCommand,""")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# SG-005: add 'start all' subcommand to start everything at once
|
|
2
|
+
|
|
3
|
+
**Severity**: Enhancement
|
|
4
|
+
**GitHub**: [#1177](https://github.com/ruvnet/claude-flow/issues/1177)
|
|
5
|
+
|
|
6
|
+
## Root Cause
|
|
7
|
+
|
|
8
|
+
There is no single command to start the full Claude Flow stack (memory +
|
|
9
|
+
daemon + swarm + MCP) on an already-initialized project. `claude-flow start`
|
|
10
|
+
only initializes the swarm and MCP server. Users must run `memory init`,
|
|
11
|
+
`daemon start`, and `start` separately, or re-run `init --start-all` which
|
|
12
|
+
also re-creates project files.
|
|
13
|
+
|
|
14
|
+
## Fix
|
|
15
|
+
|
|
16
|
+
Add an `allCommand` subcommand to the `start` command so that
|
|
17
|
+
`claude-flow start all` initializes memory, starts the daemon, then runs the
|
|
18
|
+
normal `startAction` (swarm + MCP + health checks).
|
|
19
|
+
|
|
20
|
+
| Op | What it does |
|
|
21
|
+
|----|-------------|
|
|
22
|
+
| SG-005a | Adds `allCommand` subcommand definition before `quickCommand` |
|
|
23
|
+
| SG-005b | Registers `allCommand` in the `subcommands` array |
|
|
24
|
+
| SG-005c | Adds `start all` to the examples array for `--help` output |
|
|
25
|
+
|
|
26
|
+
## Files Patched
|
|
27
|
+
|
|
28
|
+
- `commands/start.js`
|
|
29
|
+
|
|
30
|
+
## Ops
|
|
31
|
+
|
|
32
|
+
3 ops in fix.py
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# SG-005: add 'start all' subcommand to start everything at once
|
|
2
|
+
# GitHub: #1177
|
|
3
|
+
|
|
4
|
+
patch("SG-005a: add allCommand subcommand definition",
|
|
5
|
+
START_CMD,
|
|
6
|
+
"""// Quick start subcommand
|
|
7
|
+
const quickCommand = {""",
|
|
8
|
+
"""// Start-all subcommand — SG-005
|
|
9
|
+
const allCommand = {
|
|
10
|
+
name: 'all',
|
|
11
|
+
aliases: ['everything'],
|
|
12
|
+
description: 'Start memory, daemon, swarm, and MCP server',
|
|
13
|
+
action: async (ctx) => {
|
|
14
|
+
// Check initialization
|
|
15
|
+
if (!isInitialized(ctx.cwd)) {
|
|
16
|
+
output.printError('Claude Flow is not initialized in this directory');
|
|
17
|
+
output.printInfo('Run "claude-flow init" first, or use "claude-flow start quick"');
|
|
18
|
+
return { success: false, exitCode: 1 };
|
|
19
|
+
}
|
|
20
|
+
output.writeln();
|
|
21
|
+
output.writeln(output.bold('Starting all Claude Flow services'));
|
|
22
|
+
output.writeln();
|
|
23
|
+
const { execSync } = await import('child_process');
|
|
24
|
+
// Step 1: Initialize memory
|
|
25
|
+
try {
|
|
26
|
+
output.writeln(output.dim(' Initializing memory database...'));
|
|
27
|
+
execSync('npx @claude-flow/cli@latest memory init 2>/dev/null', {
|
|
28
|
+
stdio: 'pipe', cwd: ctx.cwd, timeout: 30000
|
|
29
|
+
});
|
|
30
|
+
output.writeln(' \\u2713 Memory initialized');
|
|
31
|
+
} catch { output.writeln(' Memory database already exists'); }
|
|
32
|
+
// Step 2: Start daemon
|
|
33
|
+
try {
|
|
34
|
+
output.writeln(output.dim(' Starting daemon...'));
|
|
35
|
+
execSync('npx @claude-flow/cli@latest daemon start 2>/dev/null &', {
|
|
36
|
+
stdio: 'pipe', cwd: ctx.cwd, timeout: 10000
|
|
37
|
+
});
|
|
38
|
+
output.writeln(' \\u2713 Daemon started');
|
|
39
|
+
} catch { output.writeln(' Daemon may already be running'); }
|
|
40
|
+
// Step 3: Start swarm + MCP via normal startAction
|
|
41
|
+
return startAction(ctx);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// Quick start subcommand
|
|
45
|
+
const quickCommand = {""")
|
|
46
|
+
|
|
47
|
+
patch("SG-005b: register allCommand in subcommands array",
|
|
48
|
+
START_CMD,
|
|
49
|
+
""" subcommands: [stopCommand, restartCommand, quickCommand],""",
|
|
50
|
+
""" subcommands: [stopCommand, restartCommand, quickCommand, allCommand],""")
|
|
51
|
+
|
|
52
|
+
patch("SG-005c: add 'start all' to examples array",
|
|
53
|
+
START_CMD,
|
|
54
|
+
""" { command: 'claude-flow start stop', description: 'Stop the running system' }
|
|
55
|
+
],""",
|
|
56
|
+
""" { command: 'claude-flow start stop', description: 'Stop the running system' },
|
|
57
|
+
{ command: 'claude-flow start all', description: 'Start memory, daemon, swarm, and MCP' }
|
|
58
|
+
],""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "allCommand" commands/start.js
|