@sparkleideas/claude-flow-patch 3.1.0-alpha.44.patch.5 → 3.1.0-alpha.44.patch.7
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 +1 -1
- package/CLAUDE.md +54 -9
- package/README.md +8 -4
- package/check-patches.sh +6 -2
- package/lib/common.py +1 -0
- package/package.json +4 -3
- 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/160-HW-003-aggressive-intervals/README.md +4 -4
- package/patch/160-HW-003-aggressive-intervals/fix.py +36 -0
- package/patch/160-HW-003-aggressive-intervals/sentinel +3 -1
- package/patch/300-DM-006-log-rotation/README.md +5 -4
- package/patch/300-DM-006-log-rotation/fix.py +14 -0
- package/patch/300-DM-006-log-rotation/sentinel +1 -0
- package/patch/320-SG-004-wizard-parity/README.md +32 -0
- package/patch/320-SG-004-wizard-parity/fix.py +133 -0
- package/patch/320-SG-004-wizard-parity/sentinel +1 -0
- package/patch/330-SG-005-start-all-subcommand/README.md +29 -0
- package/patch/330-SG-005-start-all-subcommand/fix.py +50 -0
- package/patch/330-SG-005-start-all-subcommand/sentinel +1 -0
- package/scripts/{update-docs.mjs → preflight.mjs} +74 -33
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @sparkleideas/claude-flow-patch
|
|
2
2
|
|
|
3
|
-
> Runtime patches for `@claude-flow/cli` v3.1.0-alpha.
|
|
3
|
+
> Runtime patches for `@claude-flow/cli` v3.1.0-alpha.41, `ruvector`, and `ruv-swarm` v1.0.20
|
|
4
4
|
|
|
5
5
|
**Claude Code instructions are in [CLAUDE.md](CLAUDE.md). Project-specific instructions (defect index, workflows, policies) are in [README.md](README.md).**
|
|
6
6
|
|
package/CLAUDE.md
CHANGED
|
@@ -24,6 +24,7 @@ Runtime patches for `@claude-flow/cli` **v3.1.0-alpha.41**, `ruvector`, and `ruv
|
|
|
24
24
|
- NEVER reuse a defect ID that was previously assigned to a different GitHub issue
|
|
25
25
|
- ONE defect directory and ONE fix.py per GitHub issue -- do not combine multiple GitHub issues into one defect or split one GitHub issue across multiple defects
|
|
26
26
|
- ALWAYS verify with `bash check-patches.sh` after applying
|
|
27
|
+
- ALWAYS run `npm run preflight` before staging — the pre-commit hook (`hooks/pre-commit`) enforces this via `--check` mode
|
|
27
28
|
- ALWAYS update ALL listing files when adding/removing a defect (see checklist)
|
|
28
29
|
- Execution order is determined by the numeric prefix on each defect directory name. Dependencies between defects are expressed by assigning lower numbers to prerequisites.
|
|
29
30
|
|
|
@@ -38,7 +39,7 @@ lib/
|
|
|
38
39
|
discover.mjs # Dynamic discovery: scans patch/*/ → structured JSON
|
|
39
40
|
categories.json # Prefix-to-label mapping (one line per category)
|
|
40
41
|
scripts/
|
|
41
|
-
|
|
42
|
+
preflight.mjs # Pre-commit sync: doc tables, versions, config (npm run preflight)
|
|
42
43
|
upstream-log.mjs # Show recent upstream releases (npm run upstream-log [count])
|
|
43
44
|
patch/
|
|
44
45
|
{NNN}-{PREFIX}-{NNN}-{slug}/ # NNN = 3-digit execution order
|
|
@@ -90,7 +91,13 @@ gh issue comment <NUMBER> --repo ruvnet/claude-flow --body "$(cat <<'EOF'
|
|
|
90
91
|
|
|
91
92
|
Defect **{PREFIX}-{NNN}** in [claude-flow-patch](https://github.com/sparkling/claude-flow-patch).
|
|
92
93
|
|
|
94
|
+
**Root cause:** <1-2 sentences explaining why the bug occurs at the code level>
|
|
95
|
+
|
|
93
96
|
<What the patch does. Be specific. Include a table if multiple ops.>
|
|
97
|
+
|
|
98
|
+
**Affected versions:** `@claude-flow/cli` 3.1.0-alpha.44 through current
|
|
99
|
+
|
|
100
|
+
**Related issues:** #NNN, #NNN
|
|
94
101
|
EOF
|
|
95
102
|
)"
|
|
96
103
|
```
|
|
@@ -114,6 +121,12 @@ gh issue create --repo ruvnet/claude-flow \
|
|
|
114
121
|
|
|
115
122
|
## Files Affected
|
|
116
123
|
- <dist/src/path/to/file.js>
|
|
124
|
+
|
|
125
|
+
## Affected Versions
|
|
126
|
+
`@claude-flow/cli` 3.1.0-alpha.44 through current
|
|
127
|
+
|
|
128
|
+
## Related Issues
|
|
129
|
+
- #NNN — <short description of relationship>
|
|
117
130
|
EOF
|
|
118
131
|
)"
|
|
119
132
|
```
|
|
@@ -123,6 +136,7 @@ Save the returned GitHub issue number for the defect README.md.
|
|
|
123
136
|
### Comment hygiene:
|
|
124
137
|
|
|
125
138
|
- One comment per defect, describing the patch. No meta-commentary.
|
|
139
|
+
- Every comment/body MUST include affected versions and related issues (use "None" if truly standalone).
|
|
126
140
|
- If you need to replace a comment, delete the old one first (`gh api -X DELETE`).
|
|
127
141
|
- Do not reference defect history, deletion/restoration, or internal decisions.
|
|
128
142
|
|
|
@@ -135,17 +149,17 @@ Save the returned GitHub issue number for the defect README.md.
|
|
|
135
149
|
| DM | Daemon & Workers | 6 |
|
|
136
150
|
| EM | Embeddings & HNSW | 2 |
|
|
137
151
|
| GV | Ghost Vectors | 1 |
|
|
138
|
-
| HK | Hooks |
|
|
152
|
+
| HK | Hooks | 5 |
|
|
139
153
|
| HW | Headless Worker | 4 |
|
|
140
154
|
| IN | Intelligence | 1 |
|
|
141
155
|
| MM | Memory Management | 1 |
|
|
142
156
|
| NS | Memory Namespace | 3 |
|
|
143
157
|
| RS | ruv-swarm | 1 |
|
|
144
158
|
| RV | RuVector Intelligence | 3 |
|
|
145
|
-
| SG | Settings Generator |
|
|
159
|
+
| SG | Settings Generator | 4 |
|
|
146
160
|
| UI | Display & Cosmetic | 2 |
|
|
147
161
|
|
|
148
|
-
## All
|
|
162
|
+
## All 35 Defects
|
|
149
163
|
|
|
150
164
|
| ID | GitHub Issue | Severity |
|
|
151
165
|
|----|-------------|----------|
|
|
@@ -162,9 +176,11 @@ Save the returned GitHub issue number for the defect README.md.
|
|
|
162
176
|
| HK-001 | [#1155 post-edit hook records file_path as "unknown"](https://github.com/ruvnet/claude-flow/issues/1155) | Medium |
|
|
163
177
|
| HK-002 | [#1058 MCP hook handlers are stubs that don't persist data](https://github.com/ruvnet/claude-flow/issues/1058) | High |
|
|
164
178
|
| HK-003 | [#1158 hooks_metrics MCP handler returns hardcoded fake data](https://github.com/ruvnet/claude-flow/issues/1158) | High |
|
|
179
|
+
| HK-004 | [#1175 hooks_session-start ignores daemon.autoStart from settings.json](https://github.com/ruvnet/claude-flow/issues/1175) | High |
|
|
180
|
+
| HK-005 | [#1171 Multiple MCP servers start independent in-process daemons](https://github.com/ruvnet/claude-flow/issues/1171) | Critical |
|
|
165
181
|
| HW-001 | [#1111 Headless workers hang — stdin pipe never closed](https://github.com/ruvnet/claude-flow/issues/1111) | Critical |
|
|
166
182
|
| HW-002 | [#1112 Headless failures silently swallowed as success](https://github.com/ruvnet/claude-flow/issues/1112) | High |
|
|
167
|
-
| HW-003 | [#1113 Worker scheduling intervals too aggressive](https://github.com/ruvnet/claude-flow/issues/1113) | High |
|
|
183
|
+
| HW-003 | [#1113 Worker scheduling intervals too aggressive + settings ignored](https://github.com/ruvnet/claude-flow/issues/1113) | High |
|
|
168
184
|
| IN-001 | [#1154 intelligence.cjs is a stub that doesn't actually learn](https://github.com/ruvnet/claude-flow/issues/1154) | Critical |
|
|
169
185
|
| MM-001 | [#1152 Remove dead persistPath config option](https://github.com/ruvnet/claude-flow/issues/1152) | Low |
|
|
170
186
|
| NS-001 | [#1123 Discovery ops default to wrong namespace](https://github.com/ruvnet/claude-flow/issues/1123) | Critical |
|
|
@@ -178,8 +194,10 @@ Save the returned GitHub issue number for the defect README.md.
|
|
|
178
194
|
| SG-003 | [#1169 Init missing helpers for --dual, --minimal, hooks, and upgrade paths](https://github.com/ruvnet/claude-flow/issues/1169) | Critical |
|
|
179
195
|
| UI-001 | [#1145 intelligence stats crashes on .toFixed()](https://github.com/ruvnet/claude-flow/issues/1145) | Critical |
|
|
180
196
|
| UI-002 | [#1146 neural status shows "Not loaded"](https://github.com/ruvnet/claude-flow/issues/1146) | Low |
|
|
181
|
-
| DM-006 | [#1114 No log rotation —
|
|
197
|
+
| DM-006 | [#1114 No log rotation — logs grow unbounded](https://github.com/ruvnet/claude-flow/issues/1114) | Medium |
|
|
182
198
|
| HW-004 | [#1117 runWithTimeout rejects but does not kill child process](https://github.com/ruvnet/claude-flow/issues/1117) | Medium |
|
|
199
|
+
| SG-004 | [#1181 init wizard lacks parity with init](https://github.com/ruvnet/claude-flow/issues/1181) | High |
|
|
200
|
+
| SG-005 | [#1177 add 'start all' subcommand to start everything at once](https://github.com/ruvnet/claude-flow/issues/1177) | Enhancement |
|
|
183
201
|
<!-- GENERATED:defect-tables:end -->
|
|
184
202
|
|
|
185
203
|
---
|
|
@@ -305,6 +323,8 @@ Both are idempotent: skip if `new` already present, warn if `old` not found.
|
|
|
305
323
|
| `SETTINGS_GEN` | `init/settings-generator.js` | @claude-flow/cli |
|
|
306
324
|
| `HELPERS_GEN` | `init/helpers-generator.js` | @claude-flow/cli |
|
|
307
325
|
| `EXECUTOR` | `init/executor.js` | @claude-flow/cli |
|
|
326
|
+
| `INIT_CMD` | `commands/init.js` | @claude-flow/cli |
|
|
327
|
+
| `START_CMD` | `commands/start.js` | @claude-flow/cli |
|
|
308
328
|
| `ruvector_cli` | `bin/cli.js` | ruvector |
|
|
309
329
|
|
|
310
330
|
To target a new file, add a variable to `lib/common.py` following the existing pattern.
|
|
@@ -313,7 +333,7 @@ To target a new file, add a variable to `lib/common.py` following the existing p
|
|
|
313
333
|
|
|
314
334
|
```bash
|
|
315
335
|
# Regenerate all documentation from dynamic discovery
|
|
316
|
-
npm run
|
|
336
|
+
npm run preflight
|
|
317
337
|
|
|
318
338
|
# Apply -- should show "Applied: ..."
|
|
319
339
|
bash patch-all.sh --global
|
|
@@ -339,7 +359,7 @@ npm test
|
|
|
339
359
|
- [ ] `patch/{PREFIX}-{NNN}-{slug}/sentinel` created with verification directives
|
|
340
360
|
- [ ] Path variable added to `lib/common.py` (if targeting a new file)
|
|
341
361
|
- [ ] If new category prefix: add one line to `lib/categories.json`
|
|
342
|
-
- [ ] `npm run
|
|
362
|
+
- [ ] `npm run preflight` regenerates all doc tables
|
|
343
363
|
- [ ] `bash patch-all.sh` applies successfully
|
|
344
364
|
- [ ] `bash patch-all.sh` is idempotent (0 applied on re-run)
|
|
345
365
|
- [ ] `bash check-patches.sh` shows OK
|
|
@@ -355,7 +375,7 @@ Before removing any defect:
|
|
|
355
375
|
1. Confirm the bug is genuinely fixed upstream or the patch is truly unreachable.
|
|
356
376
|
2. Do NOT remove a defect just because a local workaround exists -- the MCP-level patch may still be needed.
|
|
357
377
|
3. If removing, retire the defect ID permanently. Never reassign a deleted ID to a different GitHub issue.
|
|
358
|
-
4. Run `npm run
|
|
378
|
+
4. Run `npm run preflight` to regenerate all documentation.
|
|
359
379
|
|
|
360
380
|
---
|
|
361
381
|
|
|
@@ -450,6 +470,31 @@ Two dependency chains exist:
|
|
|
450
470
|
|
|
451
471
|
All other patches are independent.
|
|
452
472
|
|
|
473
|
+
## Preflight & Pre-Commit Hook
|
|
474
|
+
|
|
475
|
+
A git pre-commit hook at `hooks/pre-commit` runs automatically on every commit. It calls `npm run preflight:check` (read-only) and `npm test`. If anything is stale or tests fail, the commit is blocked.
|
|
476
|
+
|
|
477
|
+
**Setup** (one-time, already done for this clone):
|
|
478
|
+
```bash
|
|
479
|
+
git config core.hooksPath hooks
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
**Before staging**, run:
|
|
483
|
+
```bash
|
|
484
|
+
npm run preflight # Syncs doc tables, defect counts, version strings, config
|
|
485
|
+
npm test # Runs all tests
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Then `git add -u` to stage the regenerated files.
|
|
489
|
+
|
|
490
|
+
**What `preflight` syncs**:
|
|
491
|
+
- Defect tables in README.md, CLAUDE.md, npm/README.md (from `patch/*/README.md`)
|
|
492
|
+
- Defect counts in `npm/config.json` (from discovery)
|
|
493
|
+
- `npm/config.json` version.current (from `package.json`)
|
|
494
|
+
- Upstream baseline version in prose (from `npm/config.json` targets)
|
|
495
|
+
|
|
496
|
+
Manual edits to generated sections (`<!-- GENERATED:*:begin/end -->`) will be overwritten.
|
|
497
|
+
|
|
453
498
|
## Key Design Decisions
|
|
454
499
|
|
|
455
500
|
- **Idempotent**: `patch()` checks if `new` string is already present before replacing.
|
package/README.md
CHANGED
|
@@ -158,7 +158,7 @@ claude-flow-patch/
|
|
|
158
158
|
discover.mjs # Dynamic patch discovery — single source of truth
|
|
159
159
|
categories.json # Prefix-to-label mapping (e.g. HW → Headless Worker)
|
|
160
160
|
scripts/
|
|
161
|
-
|
|
161
|
+
preflight.mjs # Pre-commit sync: doc tables, versions, config
|
|
162
162
|
patch/
|
|
163
163
|
{NNN}-{PREFIX}-{NNN}-{slug}/ # NNN = 3-digit execution order
|
|
164
164
|
README.md # Defect report: title, severity, root cause, fix
|
|
@@ -173,7 +173,7 @@ claude-flow-patch/
|
|
|
173
173
|
## Defect Index
|
|
174
174
|
|
|
175
175
|
<!-- GENERATED:defect-index:begin -->
|
|
176
|
-
|
|
176
|
+
35 defects across 13 categories.
|
|
177
177
|
|
|
178
178
|
### CF -- Config & Doctor
|
|
179
179
|
|
|
@@ -191,7 +191,7 @@ claude-flow-patch/
|
|
|
191
191
|
| [DM‑003](patch/050-DM-003-macos-freemem/) | macOS freemem() always ~0% — workers blocked | Critical | [#1077](https://github.com/ruvnet/claude-flow/issues/1077) |
|
|
192
192
|
| [DM‑004](patch/060-DM-004-preload-worker-stub/) | Preload worker stub + missing from defaults | Enhancement | [#1139](https://github.com/ruvnet/claude-flow/issues/1139) |
|
|
193
193
|
| [DM‑005](patch/070-DM-005-consolidation-worker-stub/) | Consolidation worker stub (no decay/rebuild) | Enhancement | [#1140](https://github.com/ruvnet/claude-flow/issues/1140) |
|
|
194
|
-
| [DM‑006](patch/300-DM-006-log-rotation/) | No log rotation —
|
|
194
|
+
| [DM‑006](patch/300-DM-006-log-rotation/) | No log rotation — logs grow unbounded | Medium | [#1114](https://github.com/ruvnet/claude-flow/issues/1114) |
|
|
195
195
|
|
|
196
196
|
### EM -- Embeddings & HNSW
|
|
197
197
|
|
|
@@ -213,6 +213,8 @@ claude-flow-patch/
|
|
|
213
213
|
| [HK‑001](patch/110-HK-001-post-edit-file-path/) | post-edit hook records file_path as "unknown" | Medium | [#1155](https://github.com/ruvnet/claude-flow/issues/1155) |
|
|
214
214
|
| [HK‑002](patch/120-HK-002-hooks-tools-stub/) | MCP hook handlers are stubs that don't persist data | High | [#1058](https://github.com/ruvnet/claude-flow/issues/1058) |
|
|
215
215
|
| [HK‑003](patch/130-HK-003-metrics-hardcoded/) | hooks_metrics MCP handler returns hardcoded fake data | High | [#1158](https://github.com/ruvnet/claude-flow/issues/1158) |
|
|
216
|
+
| [HK‑004](patch/135-HK-004-respect-daemon-autostart/) | hooks_session-start ignores daemon.autoStart from settings.json | High | [#1175](https://github.com/ruvnet/claude-flow/issues/1175) |
|
|
217
|
+
| [HK‑005](patch/137-HK-005-daemon-pid-guard/) | Multiple MCP servers start independent in-process daemons | Critical | [#1171](https://github.com/ruvnet/claude-flow/issues/1171) |
|
|
216
218
|
|
|
217
219
|
### HW -- Headless Worker
|
|
218
220
|
|
|
@@ -220,7 +222,7 @@ claude-flow-patch/
|
|
|
220
222
|
|----|-------------|----------|--------------|
|
|
221
223
|
| [HW‑001](patch/140-HW-001-stdin-hang/) | Headless workers hang — stdin pipe never closed | Critical | [#1111](https://github.com/ruvnet/claude-flow/issues/1111) |
|
|
222
224
|
| [HW‑002](patch/150-HW-002-failures-swallowed/) | Headless failures silently swallowed as success | High | [#1112](https://github.com/ruvnet/claude-flow/issues/1112) |
|
|
223
|
-
| [HW‑003](patch/160-HW-003-aggressive-intervals/) | Worker scheduling intervals too aggressive | High | [#1113](https://github.com/ruvnet/claude-flow/issues/1113) |
|
|
225
|
+
| [HW‑003](patch/160-HW-003-aggressive-intervals/) | Worker scheduling intervals too aggressive + settings ignored | High | [#1113](https://github.com/ruvnet/claude-flow/issues/1113) |
|
|
224
226
|
| [HW‑004](patch/310-HW-004-runwithtimeout-orphan/) | runWithTimeout rejects but does not kill child process | Medium | [#1117](https://github.com/ruvnet/claude-flow/issues/1117) |
|
|
225
227
|
|
|
226
228
|
### IN -- Intelligence
|
|
@@ -263,6 +265,8 @@ claude-flow-patch/
|
|
|
263
265
|
|----|-------------|----------|--------------|
|
|
264
266
|
| [SG‑001](patch/260-SG-001-init-settings/) | Init generates invalid settings | High | [#1150](https://github.com/ruvnet/claude-flow/issues/1150) |
|
|
265
267
|
| [SG‑003](patch/270-SG-003-init-helpers-all-paths/) | Init missing helpers for --dual, --minimal, hooks, and upgrade paths | Critical | [#1169](https://github.com/ruvnet/claude-flow/issues/1169) |
|
|
268
|
+
| [SG‑004](patch/320-SG-004-wizard-parity/) | init wizard lacks parity with init | High | [#1181](https://github.com/ruvnet/claude-flow/issues/1181) |
|
|
269
|
+
| [SG‑005](patch/330-SG-005-start-all-subcommand/) | add 'start all' subcommand to start everything at once | Enhancement | [#1177](https://github.com/ruvnet/claude-flow/issues/1177) |
|
|
266
270
|
|
|
267
271
|
### UI -- Display & Cosmetic
|
|
268
272
|
|
package/check-patches.sh
CHANGED
|
@@ -165,10 +165,14 @@ if [ -x "$SCRIPT_DIR/patch-all.sh" ]; then
|
|
|
165
165
|
if [[ -n "$TARGET_DIR" ]]; then REAPPLY_ARGS+=(--target "$TARGET_DIR"); fi
|
|
166
166
|
bash "$SCRIPT_DIR/patch-all.sh" "${REAPPLY_ARGS[@]}"
|
|
167
167
|
echo ""
|
|
168
|
-
echo "[PATCHES] Auto-reapplied.
|
|
168
|
+
echo "[PATCHES] Auto-reapplied. Stopping existing daemons..."
|
|
169
169
|
npx @claude-flow/cli@latest daemon stop 2>/dev/null
|
|
170
|
+
# Fallback: kill by PID file if daemon stop missed an orphan (project-scoped, not global)
|
|
171
|
+
_pid=$(cat .claude-flow/daemon.pid 2>/dev/null)
|
|
172
|
+
if [ -n "$_pid" ]; then kill "$_pid" 2>/dev/null || true; rm -f .claude-flow/daemon.pid; fi
|
|
173
|
+
sleep 1
|
|
170
174
|
npx @claude-flow/cli@latest daemon start 2>/dev/null
|
|
171
|
-
echo "[PATCHES] Daemon restarted
|
|
175
|
+
echo "[PATCHES] Daemon restarted in background (PID: $(cat .claude-flow/daemon.pid 2>/dev/null || echo 'unknown'))"
|
|
172
176
|
echo ""
|
|
173
177
|
else
|
|
174
178
|
echo "[PATCHES] ERROR: patch-all.sh not found at $SCRIPT_DIR"
|
package/lib/common.py
CHANGED
|
@@ -83,6 +83,7 @@ HELPERS_GEN = init + "/helpers-generator.js" if init else ""
|
|
|
83
83
|
EXECUTOR = init + "/executor.js" if init else ""
|
|
84
84
|
TYPES = init + "/types.js" if init else ""
|
|
85
85
|
INIT_CMD = commands + "/init.js" if commands else ""
|
|
86
|
+
START_CMD = commands + "/start.js" if commands else ""
|
|
86
87
|
|
|
87
88
|
# Source helpers (shipped with package, copied by writeHelpers when source dir found)
|
|
88
89
|
_pkg_root = os.path.dirname(os.path.dirname(base)) if base else ""
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sparkleideas/claude-flow-patch",
|
|
3
|
-
"version": "3.1.0-alpha.44.patch.
|
|
3
|
+
"version": "3.1.0-alpha.44.patch.7",
|
|
4
4
|
"description": "Patch toolkit for @claude-flow/cli init/runtime defects with verify and post-init repair commands",
|
|
5
5
|
"scripts": {
|
|
6
|
+
"preflight": "node scripts/preflight.mjs",
|
|
7
|
+
"preflight:check": "node scripts/preflight.mjs --check",
|
|
8
|
+
"prepublishOnly": "npm run preflight && npm test",
|
|
6
9
|
"test": "node --test tests/*.test.mjs",
|
|
7
10
|
"package": "bash npm/package.sh",
|
|
8
11
|
"package:dry": "bash npm/package.sh --dry-run",
|
|
9
12
|
"publish:npm": "bash npm/publish.sh",
|
|
10
13
|
"publish:dry": "bash npm/publish.sh --dry-run",
|
|
11
|
-
"update-docs": "node scripts/update-docs.mjs",
|
|
12
|
-
"update-docs:check": "node scripts/update-docs.mjs --check",
|
|
13
14
|
"upstream-log": "node scripts/upstream-log.mjs",
|
|
14
15
|
"guidance:analyze": "guidance analyze",
|
|
15
16
|
"guidance:optimize": "guidance autopilot --once --apply --source manual",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# HK-004: hooks_session-start ignores daemon.autoStart from settings.json
|
|
2
|
+
**Severity**: High
|
|
3
|
+
**GitHub**: [#1175](https://github.com/ruvnet/claude-flow/issues/1175)
|
|
4
|
+
## Root Cause
|
|
5
|
+
`hooks_session-start` handler in `hooks-tools.js` (line ~1216) determines daemon auto-start solely from the MCP call parameter: `const shouldStartDaemon = params.startDaemon !== false;`. It never reads `claudeFlow.daemon.autoStart` from `.claude/settings.json`. Setting `autoStart: false` in settings.json has no effect — the daemon always starts on session-start.
|
|
6
|
+
## Fix
|
|
7
|
+
Wrap the `shouldStartDaemon` assignment in an IIFE that first checks the MCP parameter, then reads settings.json. If `claudeFlow.daemon.autoStart === false`, returns false. Falls back to true on any read/parse error.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- mcp-tools/hooks-tools.js
|
|
10
|
+
## Ops
|
|
11
|
+
1 op in fix.py
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# HK-004: hooks_session-start ignores daemon.autoStart from settings.json
|
|
2
|
+
# GitHub: #1175
|
|
3
|
+
patch("HK-004: respect daemon autoStart setting",
|
|
4
|
+
MCP_HOOKS,
|
|
5
|
+
" const shouldStartDaemon = params.startDaemon !== false;",
|
|
6
|
+
""" const shouldStartDaemon = (() => {
|
|
7
|
+
if (params.startDaemon === false) return false;
|
|
8
|
+
try {
|
|
9
|
+
const sp = join(process.cwd(), '.claude', 'settings.json');
|
|
10
|
+
const s = JSON.parse(readFileSync(sp, 'utf-8'));
|
|
11
|
+
if (s?.claudeFlow?.daemon?.autoStart === false) return false;
|
|
12
|
+
} catch { /* no settings or unreadable — default to true */ }
|
|
13
|
+
return true;
|
|
14
|
+
})();""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "claudeFlow?.daemon?.autoStart" mcp-tools/hooks-tools.js
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# HK-005: Multiple MCP servers start independent in-process daemons
|
|
2
|
+
**Severity**: Critical
|
|
3
|
+
**GitHub**: [#1171](https://github.com/ruvnet/claude-flow/issues/1171)
|
|
4
|
+
## Root Cause
|
|
5
|
+
`hooks_session-start` calls `startDaemon()` (worker-daemon.js) which creates an in-process `WorkerDaemon` singleton per Node.js process. Each MCP server is a separate process with its own singleton — no cross-process coordination. The CLI background daemon path (`daemon.js`) has PID-file coordination but the MCP hook path bypasses it entirely. Result: N MCP servers per project = N daemon instances = N × 6 workers.
|
|
6
|
+
## Fix
|
|
7
|
+
Add PID-file guard to the MCP hook path using `.claude-flow/daemon.pid` (same file the CLI path uses). Before calling `startDaemon()`, check PID file: if a different process owns it and is alive, skip (reuse). If the PID is our own process or stale, proceed and overwrite. No cleanup on session-end — stale PIDs self-heal via `kill(pid, 0)` on next start. The PID file becomes a universal one-daemon-per-project lock across both MCP and CLI paths.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- mcp-tools/hooks-tools.js
|
|
10
|
+
## Ops
|
|
11
|
+
2 ops in fix.py
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# HK-005: Multiple MCP servers start independent in-process daemons
|
|
2
|
+
# No cross-process coordination on the hooks_session-start path.
|
|
3
|
+
# GitHub: #1171
|
|
4
|
+
|
|
5
|
+
# Op 1: Add PID-file guard before startDaemon()
|
|
6
|
+
patch("HK-005a: cross-process daemon PID guard",
|
|
7
|
+
MCP_HOOKS,
|
|
8
|
+
""" // Auto-start daemon if enabled
|
|
9
|
+
let daemonStatus = { started: false };
|
|
10
|
+
if (shouldStartDaemon) {
|
|
11
|
+
try {
|
|
12
|
+
// Dynamic import to avoid circular dependencies
|
|
13
|
+
const { startDaemon } = await import('../services/worker-daemon.js');
|
|
14
|
+
const daemon = await startDaemon(process.cwd());""",
|
|
15
|
+
""" // Auto-start daemon if enabled
|
|
16
|
+
let daemonStatus = { started: false };
|
|
17
|
+
if (shouldStartDaemon) {
|
|
18
|
+
try {
|
|
19
|
+
// HK-005: PID-file guard — one daemon per project across processes
|
|
20
|
+
const _pidDir = join(process.cwd(), '.claude-flow');
|
|
21
|
+
const _pidPath = join(_pidDir, 'daemon.pid');
|
|
22
|
+
let _skipDaemon = false;
|
|
23
|
+
try {
|
|
24
|
+
const _xPid = parseInt(readFileSync(_pidPath, 'utf-8').trim(), 10);
|
|
25
|
+
if (!isNaN(_xPid) && _xPid !== process.pid) {
|
|
26
|
+
try { process.kill(_xPid, 0); _skipDaemon = true; daemonStatus = { started: true, pid: _xPid, reused: true }; }
|
|
27
|
+
catch { /* stale PID from dead process — proceed */ }
|
|
28
|
+
}
|
|
29
|
+
} catch { /* no PID file — proceed */ }
|
|
30
|
+
if (!_skipDaemon) {
|
|
31
|
+
// Dynamic import to avoid circular dependencies
|
|
32
|
+
const { startDaemon } = await import('../services/worker-daemon.js');
|
|
33
|
+
const daemon = await startDaemon(process.cwd());""")
|
|
34
|
+
|
|
35
|
+
# Op 2: Write PID after successful start + close guard block
|
|
36
|
+
patch("HK-005b: write PID after daemon start",
|
|
37
|
+
MCP_HOOKS,
|
|
38
|
+
""" const status = daemon.getStatus();
|
|
39
|
+
daemonStatus = {
|
|
40
|
+
started: true,
|
|
41
|
+
pid: status.pid,
|
|
42
|
+
};""",
|
|
43
|
+
""" const status = daemon.getStatus();
|
|
44
|
+
// HK-005: Write PID so other processes detect this daemon
|
|
45
|
+
try {
|
|
46
|
+
if (!existsSync(_pidDir)) { mkdirSync(_pidDir, { recursive: true }); }
|
|
47
|
+
writeFileSync(_pidPath, String(status.pid || process.pid));
|
|
48
|
+
} catch { /* best-effort */ }
|
|
49
|
+
daemonStatus = {
|
|
50
|
+
started: true,
|
|
51
|
+
pid: status.pid,
|
|
52
|
+
};
|
|
53
|
+
} // end HK-005 guard""")
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# HW-003: Worker scheduling intervals too aggressive
|
|
1
|
+
# HW-003: Worker scheduling intervals too aggressive + settings ignored
|
|
2
2
|
**Severity**: High
|
|
3
3
|
**GitHub**: [#1113](https://github.com/ruvnet/claude-flow/issues/1113)
|
|
4
4
|
## Root Cause
|
|
5
|
-
`DEFAULT_WORKERS` uses pre-headless intervals (audit: 10m, optimize: 15m, testgaps: 20m). ADR-020 specifies longer intervals (30/60/60m) for headless workers that invoke Claude.
|
|
5
|
+
`DEFAULT_WORKERS` uses pre-headless intervals (audit: 10m, optimize: 15m, testgaps: 20m). ADR-020 specifies longer intervals (30/60/60m) for headless workers that invoke Claude. Additionally, `daemon.schedules` from `.claude/settings.json` is never read — user-configured intervals are completely ignored.
|
|
6
6
|
## Fix
|
|
7
|
-
Align intervals to ADR-020: audit 30m, optimize 60m, testgaps 60m.
|
|
7
|
+
(A) Align hardcoded intervals to ADR-020: audit 30m, optimize 60m, testgaps 60m. (B) After setting default workers, read `claudeFlow.daemon.schedules` from `.claude/settings.json` and merge user-configured intervals/enabled flags into matching workers. Supports string formats ("1h", "30m", "10s") and raw milliseconds.
|
|
8
8
|
## Files Patched
|
|
9
9
|
- services/worker-daemon.js
|
|
10
10
|
## Ops
|
|
11
|
-
|
|
11
|
+
4 ops in fix.py
|
|
@@ -14,3 +14,39 @@ patch("3: testgaps 60m",
|
|
|
14
14
|
WD,
|
|
15
15
|
"type: 'testgaps', intervalMs: 20 * 60 * 1000",
|
|
16
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
|
+
})(),""")
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
# DM-006: No log rotation —
|
|
1
|
+
# DM-006: No log rotation — logs grow unbounded
|
|
2
2
|
**Severity**: Medium
|
|
3
3
|
**GitHub**: [#1114](https://github.com/ruvnet/claude-flow/issues/1114)
|
|
4
4
|
## Root Cause
|
|
5
|
-
`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.
|
|
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
6
|
## Fix
|
|
7
|
-
(A) Add `unlinkSync` and `statSync` to the ESM import. (B) Call `cleanupOldLogs()` from `ensureLogDir()` so cleanup runs on each execution cycle. (C) Add `cleanupOldLogs()` method: removes `.log` files older than 7 days or beyond a 500-file cap, keeping newest files.
|
|
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
8
|
## Files Patched
|
|
9
9
|
- services/headless-worker-executor.js
|
|
10
|
+
- commands/daemon.js
|
|
10
11
|
## Ops
|
|
11
|
-
|
|
12
|
+
4 ops in fix.py
|
|
@@ -56,3 +56,17 @@ patch("DM-006c: add cleanupOldLogs method",
|
|
|
56
56
|
catch { /* ignore cleanup errors */ }
|
|
57
57
|
}
|
|
58
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,32 @@
|
|
|
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 conceptually "init with interactive value selection" but behaves as a
|
|
13
|
+
completely separate command.
|
|
14
|
+
|
|
15
|
+
## Fix
|
|
16
|
+
|
|
17
|
+
Four ops bring the wizard to full parity with `init`:
|
|
18
|
+
|
|
19
|
+
| Op | What it does |
|
|
20
|
+
|----|-------------|
|
|
21
|
+
| SG-004a | Adds the already-initialized guard before prompts + passes `--force` to options |
|
|
22
|
+
| SG-004b | Adds `--codex`/`--dual` handling after executeInit succeeds |
|
|
23
|
+
| SG-004c | Adds `--start-all`/`--start-daemon` service startup + "Next steps" hints |
|
|
24
|
+
| SG-004d | Fixes catch block — catches errors cleanly instead of re-throwing |
|
|
25
|
+
|
|
26
|
+
## Files Patched
|
|
27
|
+
|
|
28
|
+
- `commands/init.js`
|
|
29
|
+
|
|
30
|
+
## Ops
|
|
31
|
+
|
|
32
|
+
4 ops in fix.py
|
|
@@ -0,0 +1,133 @@
|
|
|
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.
|
|
7
|
+
#
|
|
8
|
+
# 4 ops: init-guard + force (a), codex/dual (b), start-all + next-steps (c),
|
|
9
|
+
# catch-block error handling (d)
|
|
10
|
+
|
|
11
|
+
# Op 1: Add already-initialized guard + pass --force to executeInit options
|
|
12
|
+
patch("SG-004a: wizard init-guard + --force",
|
|
13
|
+
INIT_CMD,
|
|
14
|
+
""" try {
|
|
15
|
+
// Start with base options
|
|
16
|
+
const options = { ...DEFAULT_INIT_OPTIONS, targetDir: ctx.cwd };""",
|
|
17
|
+
""" try {
|
|
18
|
+
// SG-004: Check if already initialized (respects --force)
|
|
19
|
+
const force = ctx.flags.force;
|
|
20
|
+
const initialized = isInitialized(ctx.cwd);
|
|
21
|
+
const hasExisting = initialized.claude || initialized.claudeFlow;
|
|
22
|
+
if (hasExisting && !force) {
|
|
23
|
+
output.printWarning('Claude Flow appears to be already initialized');
|
|
24
|
+
if (initialized.claude) output.printInfo(' Found: .claude/settings.json');
|
|
25
|
+
if (initialized.claudeFlow) output.printInfo(' Found: .claude-flow/config.yaml');
|
|
26
|
+
output.printInfo('Use --force to reinitialize');
|
|
27
|
+
const proceed = await confirm({
|
|
28
|
+
message: 'Do you want to reinitialize? This will overwrite existing configuration.',
|
|
29
|
+
default: false,
|
|
30
|
+
});
|
|
31
|
+
if (!proceed) {
|
|
32
|
+
return { success: true, message: 'Wizard cancelled' };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Start with base options
|
|
36
|
+
const options = { ...DEFAULT_INIT_OPTIONS, targetDir: ctx.cwd, force: ctx.flags.force };""")
|
|
37
|
+
|
|
38
|
+
# Op 2: Add --codex / --dual handling after executeInit succeeds
|
|
39
|
+
patch("SG-004b: wizard --codex/--dual support",
|
|
40
|
+
INIT_CMD,
|
|
41
|
+
""" spinner.succeed('Setup complete!');
|
|
42
|
+
// Initialize embeddings if enabled
|
|
43
|
+
let embeddingsInitialized = false;""",
|
|
44
|
+
""" spinner.succeed('Setup complete!');
|
|
45
|
+
// SG-004: Respect --codex / --dual in wizard
|
|
46
|
+
const codexMode = ctx.flags.codex;
|
|
47
|
+
const dualMode = ctx.flags.dual;
|
|
48
|
+
if (codexMode || dualMode) {
|
|
49
|
+
try {
|
|
50
|
+
output.writeln(output.dim(' Initializing Codex integration...'));
|
|
51
|
+
await initCodexAction(ctx, { codexMode, dualMode, force: ctx.flags.force, minimal: false, full: false });
|
|
52
|
+
} catch (err) {
|
|
53
|
+
output.printWarning(`Codex initialization: ${err instanceof Error ? err.message : String(err)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Initialize embeddings if enabled
|
|
57
|
+
let embeddingsInitialized = false;""")
|
|
58
|
+
|
|
59
|
+
# Op 3: Add --start-all / --start-daemon + "Next steps" hints before final return
|
|
60
|
+
patch("SG-004c: wizard --start-all + next-steps",
|
|
61
|
+
INIT_CMD,
|
|
62
|
+
""" });
|
|
63
|
+
return { success: true, data: result };
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof Error && error.message === 'User cancelled') {""",
|
|
67
|
+
""" });
|
|
68
|
+
// SG-004: Respect --start-all / --start-daemon in wizard
|
|
69
|
+
const startAll = ctx.flags['start-all'] || ctx.flags.startAll;
|
|
70
|
+
const startDaemon = ctx.flags['start-daemon'] || ctx.flags.startDaemon || startAll;
|
|
71
|
+
if (startDaemon || startAll) {
|
|
72
|
+
output.writeln();
|
|
73
|
+
output.printInfo('Starting services...');
|
|
74
|
+
const { execSync } = await import('child_process');
|
|
75
|
+
if (startAll) {
|
|
76
|
+
try {
|
|
77
|
+
output.writeln(output.dim(' Initializing memory database...'));
|
|
78
|
+
execSync('npx @claude-flow/cli@latest memory init 2>/dev/null', {
|
|
79
|
+
stdio: 'pipe', cwd: ctx.cwd, timeout: 30000
|
|
80
|
+
});
|
|
81
|
+
output.writeln(output.success(' \\u2713 Memory initialized'));
|
|
82
|
+
} catch { output.writeln(output.dim(' Memory database already exists')); }
|
|
83
|
+
}
|
|
84
|
+
if (startDaemon) {
|
|
85
|
+
try {
|
|
86
|
+
output.writeln(output.dim(' Starting daemon...'));
|
|
87
|
+
execSync('npx @claude-flow/cli@latest daemon start 2>/dev/null &', {
|
|
88
|
+
stdio: 'pipe', cwd: ctx.cwd, timeout: 10000
|
|
89
|
+
});
|
|
90
|
+
output.writeln(output.success(' \\u2713 Daemon started'));
|
|
91
|
+
} catch { output.writeln(output.warning(' Daemon may already be running')); }
|
|
92
|
+
}
|
|
93
|
+
if (startAll) {
|
|
94
|
+
try {
|
|
95
|
+
output.writeln(output.dim(' Initializing swarm...'));
|
|
96
|
+
execSync('npx @claude-flow/cli@latest swarm init --topology hierarchical 2>/dev/null', {
|
|
97
|
+
stdio: 'pipe', cwd: ctx.cwd, timeout: 30000
|
|
98
|
+
});
|
|
99
|
+
output.writeln(output.success(' \\u2713 Swarm initialized'));
|
|
100
|
+
} catch { output.writeln(output.dim(' Swarm initialization skipped')); }
|
|
101
|
+
}
|
|
102
|
+
output.writeln();
|
|
103
|
+
output.printSuccess('All services started');
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
output.writeln(output.bold('Next steps:'));
|
|
107
|
+
output.printList([
|
|
108
|
+
`Run ${output.highlight('claude-flow daemon start')} to start background workers`,
|
|
109
|
+
`Run ${output.highlight('claude-flow memory init')} to initialize memory database`,
|
|
110
|
+
`Run ${output.highlight('claude-flow swarm init')} to initialize a swarm`,
|
|
111
|
+
`Or re-run with ${output.highlight('--start-all')} to do all of the above`,
|
|
112
|
+
]);
|
|
113
|
+
}
|
|
114
|
+
return { success: true, data: result };
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
if (error instanceof Error && error.message === 'User cancelled') {""")
|
|
118
|
+
|
|
119
|
+
# Op 4: Fix wizard catch block — re-throws instead of clean error message
|
|
120
|
+
# spinner is declared inside the try block so we can't call spinner.fail() here
|
|
121
|
+
patch("SG-004d: wizard catch block handles errors cleanly",
|
|
122
|
+
INIT_CMD,
|
|
123
|
+
""" if (error instanceof Error && error.message === 'User cancelled') {
|
|
124
|
+
output.printInfo('Setup cancelled');
|
|
125
|
+
return { success: true };
|
|
126
|
+
}
|
|
127
|
+
throw error;""",
|
|
128
|
+
""" if (error instanceof Error && error.message === 'User cancelled') {
|
|
129
|
+
output.printInfo('Setup cancelled');
|
|
130
|
+
return { success: true };
|
|
131
|
+
}
|
|
132
|
+
output.printError(`Failed to initialize: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
|
+
return { success: false, exitCode: 1 };""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "SG-004" commands/init.js
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
Also adds the subcommand to the `subcommands` array and a corresponding
|
|
21
|
+
example entry.
|
|
22
|
+
|
|
23
|
+
## Files Patched
|
|
24
|
+
|
|
25
|
+
- `commands/start.js`
|
|
26
|
+
|
|
27
|
+
## Ops
|
|
28
|
+
|
|
29
|
+
2 ops in fix.py
|
|
@@ -0,0 +1,50 @@
|
|
|
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 and add example",
|
|
48
|
+
START_CMD,
|
|
49
|
+
""" subcommands: [stopCommand, restartCommand, quickCommand],""",
|
|
50
|
+
""" subcommands: [stopCommand, restartCommand, quickCommand, allCommand],""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "allCommand" commands/start.js
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// scripts/
|
|
3
|
-
//
|
|
2
|
+
// scripts/preflight.mjs — Pre-commit/pre-publish consistency check.
|
|
3
|
+
// Syncs: doc tables, defect counts, version strings across all files.
|
|
4
|
+
// Source of truth: package.json (version), npm/config.json (targets), patch/*/ (defects).
|
|
4
5
|
//
|
|
5
|
-
// Usage: node scripts/
|
|
6
|
-
// --check Exit 1 if
|
|
6
|
+
// Usage: node scripts/preflight.mjs [--check]
|
|
7
|
+
// --check Exit 1 if anything is out of date (for hooks/CI), don't write.
|
|
7
8
|
|
|
8
9
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
9
10
|
import { resolve, dirname } from 'node:path';
|
|
@@ -17,6 +18,14 @@ const checkOnly = process.argv.includes('--check');
|
|
|
17
18
|
const data = discover();
|
|
18
19
|
const { patches, categories, stats } = data;
|
|
19
20
|
|
|
21
|
+
// ── Sources of truth ──
|
|
22
|
+
|
|
23
|
+
const pkgJson = JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf-8'));
|
|
24
|
+
const configJson = JSON.parse(readFileSync(resolve(ROOT, 'npm', 'config.json'), 'utf-8'));
|
|
25
|
+
const pkgVersion = pkgJson.version;
|
|
26
|
+
const cliTarget = configJson.targets['@claude-flow/cli'];
|
|
27
|
+
const swarmTarget = configJson.targets['ruv-swarm'];
|
|
28
|
+
|
|
20
29
|
// ── Helpers ──
|
|
21
30
|
|
|
22
31
|
/** Group patches by prefix, preserving sort order. */
|
|
@@ -57,6 +66,20 @@ function replaceMarkerSection(filePath, markerName, newContent) {
|
|
|
57
66
|
return true;
|
|
58
67
|
}
|
|
59
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Replace all occurrences of a version string in a file.
|
|
71
|
+
* Returns true if content changed.
|
|
72
|
+
*/
|
|
73
|
+
function syncVersionInFile(filePath, oldVersion, newVersion, label) {
|
|
74
|
+
if (oldVersion === newVersion) return false;
|
|
75
|
+
const text = readFileSync(filePath, 'utf-8');
|
|
76
|
+
if (!text.includes(oldVersion)) return false;
|
|
77
|
+
const updated = text.replaceAll(oldVersion, newVersion);
|
|
78
|
+
if (updated === text) return false;
|
|
79
|
+
if (!checkOnly) writeFileSync(filePath, updated);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
60
83
|
// ── Generate README.md defect index ──
|
|
61
84
|
|
|
62
85
|
function generateReadmeIndex() {
|
|
@@ -142,13 +165,21 @@ function updateNpmReadme() {
|
|
|
142
165
|
);
|
|
143
166
|
}
|
|
144
167
|
|
|
145
|
-
// ──
|
|
168
|
+
// ── Sync npm/config.json (version + defect counts) ──
|
|
146
169
|
|
|
147
170
|
function updateNpmConfig() {
|
|
148
171
|
const filePath = resolve(ROOT, 'npm', 'config.json');
|
|
149
172
|
const config = JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
150
173
|
|
|
151
174
|
let changed = false;
|
|
175
|
+
|
|
176
|
+
// Sync version.current from package.json
|
|
177
|
+
if (config.version?.current !== pkgVersion) {
|
|
178
|
+
config.version.current = pkgVersion;
|
|
179
|
+
changed = true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Sync defect counts from discovery
|
|
152
183
|
if (config.defects?.total !== stats.total) {
|
|
153
184
|
config.defects.total = stats.total;
|
|
154
185
|
changed = true;
|
|
@@ -168,41 +199,51 @@ function updateNpmConfig() {
|
|
|
168
199
|
|
|
169
200
|
let anyChanged = false;
|
|
170
201
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
'defect-index',
|
|
174
|
-
generateReadmeIndex()
|
|
175
|
-
);
|
|
176
|
-
if (readmeChanged) {
|
|
202
|
+
function report(changed, label) {
|
|
203
|
+
if (!changed) return;
|
|
177
204
|
anyChanged = true;
|
|
178
|
-
console.log(checkOnly ?
|
|
205
|
+
console.log(checkOnly ? `STALE: ${label}` : `Updated: ${label}`);
|
|
179
206
|
}
|
|
180
207
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
'defect-
|
|
184
|
-
|
|
208
|
+
// 1. Doc tables (marker-based sections)
|
|
209
|
+
report(
|
|
210
|
+
replaceMarkerSection(resolve(ROOT, 'README.md'), 'defect-index', generateReadmeIndex()),
|
|
211
|
+
'README.md (defect index)'
|
|
185
212
|
);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
213
|
+
report(
|
|
214
|
+
replaceMarkerSection(resolve(ROOT, 'CLAUDE.md'), 'defect-tables', generateClaudeTables()),
|
|
215
|
+
'CLAUDE.md (defect tables)'
|
|
216
|
+
);
|
|
217
|
+
report(updateNpmReadme(), 'npm/README.md (defect list)');
|
|
218
|
+
|
|
219
|
+
// 2. Config sync (version + counts)
|
|
220
|
+
report(updateNpmConfig(), 'npm/config.json (version/counts)');
|
|
221
|
+
|
|
222
|
+
// 3. Upstream baseline version in prose (sync from npm/config.json targets)
|
|
223
|
+
// Find any stale version strings and replace with current targets.
|
|
224
|
+
// We scan for the pattern v?X.Y.Z-alpha.N and replace if it doesn't match config.
|
|
225
|
+
const versionFiles = ['README.md', 'CLAUDE.md', 'npm/README.md', 'AGENTS.md'];
|
|
226
|
+
for (const file of versionFiles) {
|
|
227
|
+
const filePath = resolve(ROOT, file);
|
|
228
|
+
let text;
|
|
229
|
+
try { text = readFileSync(filePath, 'utf-8'); } catch { continue; }
|
|
230
|
+
|
|
231
|
+
let updated = text;
|
|
232
|
+
|
|
233
|
+
// Sync @claude-flow/cli version references
|
|
234
|
+
// Match patterns like **v3.1.0-alpha.NN** or `3.1.0-alpha.NN` or @3.1.0-alpha.NN
|
|
235
|
+
const cliRe = /(?<=[@`*v])3\.1\.0-alpha\.\d+/g;
|
|
236
|
+
updated = updated.replace(cliRe, cliTarget);
|
|
237
|
+
|
|
238
|
+
if (updated !== text) {
|
|
239
|
+
if (!checkOnly) writeFileSync(filePath, updated);
|
|
240
|
+
report(true, `${file} (upstream baseline)`);
|
|
241
|
+
}
|
|
201
242
|
}
|
|
202
243
|
|
|
203
244
|
if (!anyChanged) {
|
|
204
|
-
console.log('All
|
|
245
|
+
console.log('All files are up to date.');
|
|
205
246
|
} else if (checkOnly) {
|
|
206
|
-
console.log('\
|
|
247
|
+
console.log('\nFiles are out of date. Run: npm run preflight');
|
|
207
248
|
process.exit(1);
|
|
208
249
|
}
|