@sparkleideas/claude-flow-patch 3.1.0-alpha.44.patch.4 → 3.1.0-alpha.44.patch.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @sparkleideas/claude-flow-patch
2
2
 
3
- > Runtime patches for `@claude-flow/cli` v3.1.0-alpha.40, `ruvector`, and `ruv-swarm` v1.0.20
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
 
@@ -95,7 +95,7 @@ Use `$skill-name` syntax to invoke:
95
95
 
96
96
  [optional body]
97
97
 
98
- Co-Authored-By: claude-flow <ruv@ruv.net>
98
+ Sparkling Ideas <henrik@sparklingideas.co.uk>
99
99
  ```
100
100
 
101
101
  Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`
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
- update-docs.mjs # Regenerates doc tables from discovery (npm run update-docs)
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
@@ -135,7 +136,7 @@ Save the returned GitHub issue number for the defect README.md.
135
136
  | DM | Daemon & Workers | 6 |
136
137
  | EM | Embeddings & HNSW | 2 |
137
138
  | GV | Ghost Vectors | 1 |
138
- | HK | Hooks | 3 |
139
+ | HK | Hooks | 4 |
139
140
  | HW | Headless Worker | 4 |
140
141
  | IN | Intelligence | 1 |
141
142
  | MM | Memory Management | 1 |
@@ -145,7 +146,7 @@ Save the returned GitHub issue number for the defect README.md.
145
146
  | SG | Settings Generator | 2 |
146
147
  | UI | Display & Cosmetic | 2 |
147
148
 
148
- ## All 31 Defects
149
+ ## All 32 Defects
149
150
 
150
151
  | ID | GitHub Issue | Severity |
151
152
  |----|-------------|----------|
@@ -162,9 +163,10 @@ Save the returned GitHub issue number for the defect README.md.
162
163
  | HK-001 | [#1155 post-edit hook records file_path as "unknown"](https://github.com/ruvnet/claude-flow/issues/1155) | Medium |
163
164
  | HK-002 | [#1058 MCP hook handlers are stubs that don't persist data](https://github.com/ruvnet/claude-flow/issues/1058) | High |
164
165
  | HK-003 | [#1158 hooks_metrics MCP handler returns hardcoded fake data](https://github.com/ruvnet/claude-flow/issues/1158) | High |
166
+ | HK-004 | [#1175 hooks_session-start ignores daemon.autoStart from settings.json](https://github.com/ruvnet/claude-flow/issues/1175) | High |
165
167
  | HW-001 | [#1111 Headless workers hang — stdin pipe never closed](https://github.com/ruvnet/claude-flow/issues/1111) | Critical |
166
168
  | 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 |
169
+ | HW-003 | [#1113 Worker scheduling intervals too aggressive + settings ignored](https://github.com/ruvnet/claude-flow/issues/1113) | High |
168
170
  | IN-001 | [#1154 intelligence.cjs is a stub that doesn't actually learn](https://github.com/ruvnet/claude-flow/issues/1154) | Critical |
169
171
  | MM-001 | [#1152 Remove dead persistPath config option](https://github.com/ruvnet/claude-flow/issues/1152) | Low |
170
172
  | NS-001 | [#1123 Discovery ops default to wrong namespace](https://github.com/ruvnet/claude-flow/issues/1123) | Critical |
@@ -178,7 +180,7 @@ Save the returned GitHub issue number for the defect README.md.
178
180
  | SG-003 | [#1169 Init missing helpers for --dual, --minimal, hooks, and upgrade paths](https://github.com/ruvnet/claude-flow/issues/1169) | Critical |
179
181
  | UI-001 | [#1145 intelligence stats crashes on .toFixed()](https://github.com/ruvnet/claude-flow/issues/1145) | Critical |
180
182
  | UI-002 | [#1146 neural status shows "Not loaded"](https://github.com/ruvnet/claude-flow/issues/1146) | Low |
181
- | DM-006 | [#1114 No log rotation — headless execution logs grow unbounded](https://github.com/ruvnet/claude-flow/issues/1114) | Medium |
183
+ | DM-006 | [#1114 No log rotation — logs grow unbounded](https://github.com/ruvnet/claude-flow/issues/1114) | Medium |
182
184
  | HW-004 | [#1117 runWithTimeout rejects but does not kill child process](https://github.com/ruvnet/claude-flow/issues/1117) | Medium |
183
185
  <!-- GENERATED:defect-tables:end -->
184
186
 
@@ -313,7 +315,7 @@ To target a new file, add a variable to `lib/common.py` following the existing p
313
315
 
314
316
  ```bash
315
317
  # Regenerate all documentation from dynamic discovery
316
- npm run update-docs
318
+ npm run preflight
317
319
 
318
320
  # Apply -- should show "Applied: ..."
319
321
  bash patch-all.sh --global
@@ -339,7 +341,7 @@ npm test
339
341
  - [ ] `patch/{PREFIX}-{NNN}-{slug}/sentinel` created with verification directives
340
342
  - [ ] Path variable added to `lib/common.py` (if targeting a new file)
341
343
  - [ ] If new category prefix: add one line to `lib/categories.json`
342
- - [ ] `npm run update-docs` regenerates all doc tables
344
+ - [ ] `npm run preflight` regenerates all doc tables
343
345
  - [ ] `bash patch-all.sh` applies successfully
344
346
  - [ ] `bash patch-all.sh` is idempotent (0 applied on re-run)
345
347
  - [ ] `bash check-patches.sh` shows OK
@@ -355,7 +357,7 @@ Before removing any defect:
355
357
  1. Confirm the bug is genuinely fixed upstream or the patch is truly unreachable.
356
358
  2. Do NOT remove a defect just because a local workaround exists -- the MCP-level patch may still be needed.
357
359
  3. If removing, retire the defect ID permanently. Never reassign a deleted ID to a different GitHub issue.
358
- 4. Run `npm run update-docs` to regenerate all documentation.
360
+ 4. Run `npm run preflight` to regenerate all documentation.
359
361
 
360
362
  ---
361
363
 
@@ -450,6 +452,31 @@ Two dependency chains exist:
450
452
 
451
453
  All other patches are independent.
452
454
 
455
+ ## Preflight & Pre-Commit Hook
456
+
457
+ 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.
458
+
459
+ **Setup** (one-time, already done for this clone):
460
+ ```bash
461
+ git config core.hooksPath hooks
462
+ ```
463
+
464
+ **Before staging**, run:
465
+ ```bash
466
+ npm run preflight # Syncs doc tables, defect counts, version strings, config
467
+ npm test # Runs all tests
468
+ ```
469
+
470
+ Then `git add -u` to stage the regenerated files.
471
+
472
+ **What `preflight` syncs**:
473
+ - Defect tables in README.md, CLAUDE.md, npm/README.md (from `patch/*/README.md`)
474
+ - Defect counts in `npm/config.json` (from discovery)
475
+ - `npm/config.json` version.current (from `package.json`)
476
+ - Upstream baseline version in prose (from `npm/config.json` targets)
477
+
478
+ Manual edits to generated sections (`<!-- GENERATED:*:begin/end -->`) will be overwritten.
479
+
453
480
  ## Key Design Decisions
454
481
 
455
482
  - **Idempotent**: `patch()` checks if `new` string is already present before replacing.
package/README.md CHANGED
@@ -1,42 +1,71 @@
1
1
  # @sparkleideas/claude-flow-patch
2
2
 
3
- ## Contents
4
-
5
- - [Quick Start](#quick-start)
6
- - [CLI Commands](#cli-commands)
7
- - [How It Works](#how-it-works)
8
- - [Sentinel Files](#sentinel-files)
9
- - [Target Packages](#target-packages)
10
- - [Dependency Order](#dependency-order)
11
- - [Key Design Decisions](#key-design-decisions)
12
- - [Repository Structure](#repository-structure)
13
- - [Defect Index](#defect-index)
14
- - [Init-Script Patches](#init-script-patches)
15
- - [Compatibility](#compatibility)
16
- - [Links](#links)
17
-
18
- ---
19
-
20
- Community patches for [`@claude-flow/cli`](https://www.npmjs.com/package/@claude-flow/cli) **v3.1.0-alpha.41**, [`ruvector`](https://www.npmjs.com/package/ruvector), and [`ruv-swarm`](https://www.npmjs.com/package/ruv-swarm) **v1.0.20**.
21
-
22
- These patches fix 29 defects across 13 categories. They are applied at runtime via idempotent Python scripts that perform targeted string replacements on the npx-cached source files.
23
-
24
- <a id="quick-start"></a>
3
+ Patch toolkit for `@claude-flow/cli` runtime and init-script defects.
4
+
5
+ This package applies verified, idempotent patches to your local CLI source in the npm cache or local `node_modules`, then verifies sentinels and can repair projects initialized before patching.
6
+
7
+ ## What This Solves
8
+
9
+ `claude-flow init` can generate incomplete or broken project helpers when upstream defects are present. This toolkit addresses known defects in:
10
+
11
+ - `@claude-flow/cli`
12
+ - `ruvector`
13
+ - `ruv-swarm`
14
+
15
+ <!-- GENERATED:npm-defects:begin -->
16
+ 32 tracked defects across 13 categories.
17
+
18
+ | Defect | Description | GitHub Issue |
19
+ |--------|-------------|-------------|
20
+ | [CF-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/010-CF-001-doctor-yaml) | Doctor ignores YAML config files | [#1141](https://github.com/ruvnet/claude-flow/issues/1141) |
21
+ | [CF-002](https://github.com/sparkling/claude-flow-patch/tree/master/patch/020-CF-002-config-export-yaml) | Config export shows hardcoded defaults | [#1142](https://github.com/ruvnet/claude-flow/issues/1142) |
22
+ | [DM-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/030-DM-001-daemon-log-zero) | daemon.log always 0 bytes | [#1116](https://github.com/ruvnet/claude-flow/issues/1116) |
23
+ | [DM-002](https://github.com/sparkling/claude-flow-patch/tree/master/patch/040-DM-002-cpu-load-threshold) | maxCpuLoad=2.0 blocks all workers on multi-core | [#1138](https://github.com/ruvnet/claude-flow/issues/1138) |
24
+ | [DM-003](https://github.com/sparkling/claude-flow-patch/tree/master/patch/050-DM-003-macos-freemem) | macOS freemem() always ~0% — workers blocked | [#1077](https://github.com/ruvnet/claude-flow/issues/1077) |
25
+ | [DM-004](https://github.com/sparkling/claude-flow-patch/tree/master/patch/060-DM-004-preload-worker-stub) | Preload worker stub + missing from defaults | [#1139](https://github.com/ruvnet/claude-flow/issues/1139) |
26
+ | [DM-005](https://github.com/sparkling/claude-flow-patch/tree/master/patch/070-DM-005-consolidation-worker-stub) | Consolidation worker stub (no decay/rebuild) | [#1140](https://github.com/ruvnet/claude-flow/issues/1140) |
27
+ | [DM-006](https://github.com/sparkling/claude-flow-patch/tree/master/patch/300-DM-006-log-rotation) | No log rotation — logs grow unbounded | [#1114](https://github.com/ruvnet/claude-flow/issues/1114) |
28
+ | [EM-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/080-EM-001-embedding-ignores-config) | Embedding system ignores project config (model + HNSW dims) | [#1143](https://github.com/ruvnet/claude-flow/issues/1143) |
29
+ | [EM-002](https://github.com/sparkling/claude-flow-patch/tree/master/patch/090-EM-002-transformers-cache-eacces) | @xenova/transformers cache EACCES | [#1144](https://github.com/ruvnet/claude-flow/issues/1144) |
30
+ | [GV-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/100-GV-001-hnsw-ghost-vectors) | HNSW ghost vectors persist after memory delete | [#1122](https://github.com/ruvnet/claude-flow/issues/1122) |
31
+ | [HK-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/110-HK-001-post-edit-file-path) | post-edit hook records file_path as "unknown" | [#1155](https://github.com/ruvnet/claude-flow/issues/1155) |
32
+ | [HK-002](https://github.com/sparkling/claude-flow-patch/tree/master/patch/120-HK-002-hooks-tools-stub) | MCP hook handlers are stubs that don't persist data | [#1058](https://github.com/ruvnet/claude-flow/issues/1058) |
33
+ | [HK-003](https://github.com/sparkling/claude-flow-patch/tree/master/patch/130-HK-003-metrics-hardcoded) | hooks_metrics MCP handler returns hardcoded fake data | [#1158](https://github.com/ruvnet/claude-flow/issues/1158) |
34
+ | [HK-004](https://github.com/sparkling/claude-flow-patch/tree/master/patch/135-HK-004-respect-daemon-autostart) | hooks_session-start ignores daemon.autoStart from settings.json | [#1175](https://github.com/ruvnet/claude-flow/issues/1175) |
35
+ | [HW-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/140-HW-001-stdin-hang) | Headless workers hang — stdin pipe never closed | [#1111](https://github.com/ruvnet/claude-flow/issues/1111) |
36
+ | [HW-002](https://github.com/sparkling/claude-flow-patch/tree/master/patch/150-HW-002-failures-swallowed) | Headless failures silently swallowed as success | [#1112](https://github.com/ruvnet/claude-flow/issues/1112) |
37
+ | [HW-003](https://github.com/sparkling/claude-flow-patch/tree/master/patch/160-HW-003-aggressive-intervals) | Worker scheduling intervals too aggressive + settings ignored | [#1113](https://github.com/ruvnet/claude-flow/issues/1113) |
38
+ | [HW-004](https://github.com/sparkling/claude-flow-patch/tree/master/patch/310-HW-004-runwithtimeout-orphan) | runWithTimeout rejects but does not kill child process | [#1117](https://github.com/ruvnet/claude-flow/issues/1117) |
39
+ | [IN-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/170-IN-001-intelligence-stub) | intelligence.cjs is a stub that doesn't actually learn | [#1154](https://github.com/ruvnet/claude-flow/issues/1154) |
40
+ | [MM-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/180-MM-001-memory-persist-path) | Remove dead persistPath config option | [#1152](https://github.com/ruvnet/claude-flow/issues/1152) |
41
+ | [NS-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/190-NS-001-discovery-default-namespace) | Discovery ops default to wrong namespace | [#1123](https://github.com/ruvnet/claude-flow/issues/1123) |
42
+ | [NS-002](https://github.com/sparkling/claude-flow-patch/tree/master/patch/200-NS-002-targeted-require-namespace) | Store/delete/retrieve fall back to 'default' + accept 'all' | [#581](https://github.com/ruvnet/claude-flow/issues/581) |
43
+ | [NS-003](https://github.com/sparkling/claude-flow-patch/tree/master/patch/210-NS-003-namespace-typo-pattern) | Namespace typo 'pattern' vs 'patterns' | [#1136](https://github.com/ruvnet/claude-flow/issues/1136) |
44
+ | [RS-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/220-RS-001-better-sqlite3-node24) | ruv-swarm MCP fails on Node 24 — better-sqlite3 missing native bindings | [ruv-FANN#185](https://github.com/ruvnet/ruv-FANN/issues/185) |
45
+ | [RV-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/230-RV-001-force-learn-tick) | force-learn command calls intel.tick() which doesn't exist | [#1156](https://github.com/ruvnet/claude-flow/issues/1156) |
46
+ | [RV-002](https://github.com/sparkling/claude-flow-patch/tree/master/patch/240-RV-002-trajectory-load) | activeTrajectories not loaded from saved file | [#1157](https://github.com/ruvnet/claude-flow/issues/1157) |
47
+ | [RV-003](https://github.com/sparkling/claude-flow-patch/tree/master/patch/250-RV-003-trajectory-stats-sync) | trajectory-end does not update stats counters | [ruv-FANN#186](https://github.com/ruvnet/ruv-FANN/issues/186) |
48
+ | [SG-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/260-SG-001-init-settings) | Init generates invalid settings | [#1150](https://github.com/ruvnet/claude-flow/issues/1150) |
49
+ | [SG-003](https://github.com/sparkling/claude-flow-patch/tree/master/patch/270-SG-003-init-helpers-all-paths) | Init missing helpers for --dual, --minimal, hooks, and upgrade paths | [#1169](https://github.com/ruvnet/claude-flow/issues/1169) |
50
+ | [UI-001](https://github.com/sparkling/claude-flow-patch/tree/master/patch/280-UI-001-intelligence-stats-crash) | intelligence stats crashes on .toFixed() | [#1145](https://github.com/ruvnet/claude-flow/issues/1145) |
51
+ | [UI-002](https://github.com/sparkling/claude-flow-patch/tree/master/patch/290-UI-002-neural-status-not-loaded) | neural status shows "Not loaded" | [#1146](https://github.com/ruvnet/claude-flow/issues/1146) |
52
+ <!-- GENERATED:npm-defects:end -->
25
53
 
26
54
  ## Quick Start
27
55
 
28
- **Patch before init.** Several patches fix the init/generator scripts. If you run `claude-flow init` before patching, the generated `.claude/helpers/` files will be stubs with no learning, no PageRank, and no-op feedback. Always patch first:
56
+ Patch first, then initialize projects.
29
57
 
30
58
  ```bash
31
- # 1. Patch first -- fixes the init generators
59
+ # 1) apply patches (global npx cache)
32
60
  npx --yes @sparkleideas/claude-flow-patch --global
33
61
 
34
- # 2. Then init (or re-init if already initialized)
35
- npx @claude-flow/cli@latest init # fresh project
36
- npx @claude-flow/cli@latest init upgrade # existing project
37
-
38
- # 3. Verify
62
+ # 2) verify sentinels
39
63
  npx --yes @sparkleideas/claude-flow-patch check
64
+
65
+ # 3) now initialize or upgrade project
66
+ npx @claude-flow/cli@latest init
67
+ # or
68
+ npx @claude-flow/cli@latest init upgrade
40
69
  ```
41
70
 
42
71
  If you already initialized before patching:
@@ -45,19 +74,6 @@ If you already initialized before patching:
45
74
  npx --yes @sparkleideas/claude-flow-patch repair --target /path/to/project
46
75
  ```
47
76
 
48
- ### Target Options
49
-
50
- ```bash
51
- npx --yes @sparkleideas/claude-flow-patch # global npx cache (default)
52
- npx --yes @sparkleideas/claude-flow-patch --global # explicit global
53
- npx --yes @sparkleideas/claude-flow-patch --target ~/my-project # project's node_modules
54
- npx --yes @sparkleideas/claude-flow-patch --global --target ~/my-project # both
55
- ```
56
-
57
- `npx @claude-flow/cli` uses local `node_modules` if present, otherwise the global npx cache. Use `--target` to patch a project's local install.
58
-
59
- <a id="cli-commands"></a>
60
-
61
77
  ## CLI Commands
62
78
 
63
79
  | Command | Purpose |
@@ -67,281 +83,46 @@ npx --yes @sparkleideas/claude-flow-patch --global --target ~/my-project # bot
67
83
  | `claude-flow-patch check` | Verify patch sentinels and auto-detect drift |
68
84
  | `claude-flow-patch repair --target <dir> [--source auto\|local\|global] [--dry-run]` | Rehydrate `.claude/helpers` in projects initialized before patching |
69
85
 
70
- <a id="how-it-works"></a>
71
-
72
- ## How It Works
73
-
74
- 1. `patch-all.sh` locates the `@claude-flow/cli` dist files in the npm/npx cache
75
- 2. Globs `patch/*/fix.py` (numeric prefixes on directories ensure correct execution order)
76
- 3. Concatenates `lib/common.py` with each `fix.py` and runs as a single Python process
77
- 4. Each patch is idempotent: skips if already applied, warns if source changed
78
-
79
- The `check-patches.sh` sentinel runs on session start to detect npx cache wipes and auto-reapply. It reads `sentinel` files from each patch directory — no hardcoded patch list.
80
-
81
- <a id="sentinel-files"></a>
82
-
83
- ### Sentinel Files
84
-
85
- Each patch directory contains a `sentinel` file that declares how to verify the patch is applied:
86
-
87
- ```
88
- grep "pattern to find" relative/path/to/file.js
89
- absent "pattern that should NOT exist" relative/path.js
90
- none
91
- package: ruvector
92
- ```
93
-
94
- | Directive | Meaning |
95
- |-----------|---------|
96
- | `grep "..." file` | Pass if pattern is found in file (standard check) |
97
- | `absent "..." file` | Pass if pattern is **not** found (removal check) |
98
- | `none` | No sentinel — skip verification |
99
- | `package: X` | Target package (default: `@claude-flow/cli`). Skipped if package not installed |
100
-
101
- `check-patches.sh` and `lib/discover.mjs` both read these files dynamically. Adding a new patch requires no edits to any script — just create the `sentinel` file in the new patch directory.
102
-
103
- <a id="target-packages"></a>
104
-
105
- ### Target Packages
106
-
107
- | Package | Version | Location | Env var |
108
- |---------|---------|----------|---------|
109
- | `@claude-flow/cli` | `3.1.0-alpha.41` | `~/.npm/_npx/*/node_modules/@claude-flow/cli/dist/src/` | `BASE` |
110
- | `ruvector` | (bundled) | `~/.npm/_npx/*/node_modules/ruvector/bin/cli.js` | `RUVECTOR_CLI` |
111
- | `ruv-swarm` | `1.0.20` | `~/.npm/_npx/*/node_modules/ruv-swarm/` | (found via glob) |
112
-
113
- `BASE` is set by `patch-all.sh`. All path variables in `lib/common.py` derive from it.
114
- `RUVECTOR_CLI` is set by `patch-all.sh` to the ruvector CLI entry point.
115
- RS-001 locates its own target via `find`.
116
-
117
- <a id="dependency-order"></a>
118
-
119
- ### Dependency Order
120
-
121
- Execution order is controlled by 3-digit numeric prefixes on directory names (e.g. `010-CF-001-*`,
122
- `170-IN-001-*`). `patch-all.sh` globs `patch/*/fix.py`, which sorts lexicographically — numeric
123
- prefixes guarantee correct order.
124
-
125
- Two dependency chains exist:
126
-
127
- | Chain | Directories | Reason |
128
- |-------|-------------|--------|
129
- | IN-001 -> SG-003 | `170-IN-001-*` before `270-SG-003-*` | SG-003's patch targets code introduced by IN-001 |
130
- | NS-001 -> NS-002 -> NS-003 | `190-NS-001-*` before `200-NS-002-*` before `210-NS-003-*` | Sequential namespace fixes |
131
-
132
- All other patches are independent.
133
-
134
- <a id="key-design-decisions"></a>
135
-
136
- ### Key Design Decisions
137
-
138
- - **Zero-maintenance discovery**: `patch-all.sh`, `check-patches.sh`, and doc generation all discover patches dynamically — no hardcoded lists.
139
- - **Idempotent**: `patch()` checks if `new` string is already present before replacing.
140
- - **Non-destructive**: patches only modify the npx cache, never the npm registry package.
141
- - **Platform-aware**: DM-003 is macOS-only (auto-skipped on Linux).
142
- - **Sentinel-guarded**: `check-patches.sh` reads `sentinel` files from each patch directory to detect cache wipes and auto-reapply.
143
-
144
- <a id="repository-structure"></a>
145
-
146
- ### Repository Structure
147
-
148
- ```
149
- claude-flow-patch/
150
- README.md # This file
151
- CLAUDE.md # Claude Code instructions (defect workflow, policies)
152
- AGENTS.md # Codex agent configuration
153
- patch-all.sh # Apply all patches (globs patch/*/fix.py dynamically)
154
- check-patches.sh # Sentinel: reads patch/*/sentinel files dynamically
155
- repair-post-init.sh # Post-init helper repair
156
- lib/
157
- common.py # Shared patch()/patch_all() helpers + path variables
158
- discover.mjs # Dynamic patch discovery — single source of truth
159
- categories.json # Prefix-to-label mapping (e.g. HW → Headless Worker)
160
- scripts/
161
- update-docs.mjs # Regenerate doc tables from discover() output
162
- patch/
163
- {NNN}-{PREFIX}-{NNN}-{slug}/ # NNN = 3-digit execution order
164
- README.md # Defect report: title, severity, root cause, fix
165
- fix.py # Idempotent patch script
166
- fix.sh # Shell-based patch script (EM-002 only)
167
- sentinel # Verification directives for check-patches.sh
168
- (29 defect directories total)
169
- ```
170
-
171
- <a id="defect-index"></a>
172
-
173
- ## Defect Index
174
-
175
- <!-- GENERATED:defect-index:begin -->
176
- 31 defects across 13 categories.
177
-
178
- ### CF -- Config & Doctor
179
-
180
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
181
- |----|-------------|----------|--------------|
182
- | [CF&#8209;001](patch/010-CF-001-doctor-yaml/) | Doctor ignores YAML config files | Low | [#1141](https://github.com/ruvnet/claude-flow/issues/1141) |
183
- | [CF&#8209;002](patch/020-CF-002-config-export-yaml/) | Config export shows hardcoded defaults | Medium | [#1142](https://github.com/ruvnet/claude-flow/issues/1142) |
86
+ ## Target Behavior
184
87
 
185
- ### DM -- Daemon & Workers
186
-
187
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
188
- |----|-------------|----------|--------------|
189
- | [DM&#8209;001](patch/030-DM-001-daemon-log-zero/) | daemon.log always 0 bytes | Medium | [#1116](https://github.com/ruvnet/claude-flow/issues/1116) |
190
- | [DM&#8209;002](patch/040-DM-002-cpu-load-threshold/) | maxCpuLoad=2.0 blocks all workers on multi-core | Critical | [#1138](https://github.com/ruvnet/claude-flow/issues/1138) |
191
- | [DM&#8209;003](patch/050-DM-003-macos-freemem/) | macOS freemem() always ~0% — workers blocked | Critical | [#1077](https://github.com/ruvnet/claude-flow/issues/1077) |
192
- | [DM&#8209;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
- | [DM&#8209;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&#8209;006](patch/300-DM-006-log-rotation/) | No log rotation — headless execution logs grow unbounded | Medium | [#1114](https://github.com/ruvnet/claude-flow/issues/1114) |
195
-
196
- ### EM -- Embeddings & HNSW
197
-
198
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
199
- |----|-------------|----------|--------------|
200
- | [EM&#8209;001](patch/080-EM-001-embedding-ignores-config/) | Embedding system ignores project config (model + HNSW dims) | High | [#1143](https://github.com/ruvnet/claude-flow/issues/1143) |
201
- | [EM&#8209;002](patch/090-EM-002-transformers-cache-eacces/) | @xenova/transformers cache EACCES | Medium | [#1144](https://github.com/ruvnet/claude-flow/issues/1144) |
202
-
203
- ### GV -- Ghost Vectors
204
-
205
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
206
- |----|-------------|----------|--------------|
207
- | [GV&#8209;001](patch/100-GV-001-hnsw-ghost-vectors/) | HNSW ghost vectors persist after memory delete | Medium | [#1122](https://github.com/ruvnet/claude-flow/issues/1122) |
208
-
209
- ### HK -- Hooks
210
-
211
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
212
- |----|-------------|----------|--------------|
213
- | [HK&#8209;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
- | [HK&#8209;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
- | [HK&#8209;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
-
217
- ### HW -- Headless Worker
218
-
219
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
220
- |----|-------------|----------|--------------|
221
- | [HW&#8209;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
- | [HW&#8209;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&#8209;003](patch/160-HW-003-aggressive-intervals/) | Worker scheduling intervals too aggressive | High | [#1113](https://github.com/ruvnet/claude-flow/issues/1113) |
224
- | [HW&#8209;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
-
226
- ### IN -- Intelligence
227
-
228
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
229
- |----|-------------|----------|--------------|
230
- | [IN&#8209;001](patch/170-IN-001-intelligence-stub/) | intelligence.cjs is a stub that doesn't actually learn | Critical | [#1154](https://github.com/ruvnet/claude-flow/issues/1154) |
231
-
232
- ### MM -- Memory Management
233
-
234
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
235
- |----|-------------|----------|--------------|
236
- | [MM&#8209;001](patch/180-MM-001-memory-persist-path/) | Remove dead persistPath config option | Low | [#1152](https://github.com/ruvnet/claude-flow/issues/1152) |
237
-
238
- ### NS -- Memory Namespace
239
-
240
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
241
- |----|-------------|----------|--------------|
242
- | [NS&#8209;001](patch/190-NS-001-discovery-default-namespace/) | Discovery ops default to wrong namespace | Critical | [#1123](https://github.com/ruvnet/claude-flow/issues/1123) |
243
- | [NS&#8209;002](patch/200-NS-002-targeted-require-namespace/) | Store/delete/retrieve fall back to 'default' + accept 'all' | Critical | [#581](https://github.com/ruvnet/claude-flow/issues/581) |
244
- | [NS&#8209;003](patch/210-NS-003-namespace-typo-pattern/) | Namespace typo 'pattern' vs 'patterns' | Medium | [#1136](https://github.com/ruvnet/claude-flow/issues/1136) |
245
-
246
- ### RS -- ruv-swarm
247
-
248
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
249
- |----|-------------|----------|--------------|
250
- | [RS&#8209;001](patch/220-RS-001-better-sqlite3-node24/) | ruv-swarm MCP fails on Node 24 — better-sqlite3 missing native bindings | Critical | [ruv-FANN#185](https://github.com/ruvnet/ruv-FANN/issues/185) |
251
-
252
- ### RV -- RuVector Intelligence
253
-
254
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
255
- |----|-------------|----------|--------------|
256
- | [RV&#8209;001](patch/230-RV-001-force-learn-tick/) | force-learn command calls intel.tick() which doesn't exist | Medium | [#1156](https://github.com/ruvnet/claude-flow/issues/1156) |
257
- | [RV&#8209;002](patch/240-RV-002-trajectory-load/) | activeTrajectories not loaded from saved file | High | [#1157](https://github.com/ruvnet/claude-flow/issues/1157) |
258
- | [RV&#8209;003](patch/250-RV-003-trajectory-stats-sync/) | trajectory-end does not update stats counters | Medium | [ruv-FANN#186](https://github.com/ruvnet/ruv-FANN/issues/186) |
259
-
260
- ### SG -- Settings Generator
261
-
262
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
263
- |----|-------------|----------|--------------|
264
- | [SG&#8209;001](patch/260-SG-001-init-settings/) | Init generates invalid settings | High | [#1150](https://github.com/ruvnet/claude-flow/issues/1150) |
265
- | [SG&#8209;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) |
266
-
267
- ### UI -- Display & Cosmetic
268
-
269
- | ID | Description <img width="500" height="1" /> | Severity | GitHub&nbsp;Issue |
270
- |----|-------------|----------|--------------|
271
- | [UI&#8209;001](patch/280-UI-001-intelligence-stats-crash/) | intelligence stats crashes on .toFixed() | Critical | [#1145](https://github.com/ruvnet/claude-flow/issues/1145) |
272
- | [UI&#8209;002](patch/290-UI-002-neural-status-not-loaded/) | neural status shows "Not loaded" | Low | [#1146](https://github.com/ruvnet/claude-flow/issues/1146) |
273
- <!-- GENERATED:defect-index:end -->
274
-
275
- <a id="init-script-patches"></a>
276
-
277
- ## Init-Script Patches (Local Project Action Required)
278
-
279
- Five patches target the **init/generator scripts** (`executor.js`, `settings-generator.js`, `helpers-generator.js`). These fix the code that *generates* your `.claude/` project files -- but applying patches does **not** update files already generated in your project. You must take one additional step.
280
-
281
- ### Affected Defects
282
-
283
- | ID | Generator patched | Local file affected | Problem if not refreshed |
284
- |----|-------------------|---------------------|--------------------------|
285
- | IN-001 | `init/executor.js` | `.claude/helpers/intelligence.cjs` | 197-line stub: no PageRank, no graph, `feedback()` is a no-op, no learning |
286
- | HK-001 | `init/helpers-generator.js` | `.claude/helpers/hook-handler.cjs` | Reads env vars instead of stdin JSON; post-edit logs `file: "unknown"` |
287
- | SG-001 | `init/settings-generator.js` | `.claude/settings.json` | May contain invalid hook events, broad permissions, relative paths |
288
- | SG-002 | `init/executor.js` | `.claude/helpers/*.js` / `*.cjs` | Missing .js/.cjs compat copies; `hook-handler.cjs` require() calls fail silently |
289
- | MM-001 | `init/executor.js` | `.claude-flow/config.yaml` | Misleading `persistPath` setting that nothing reads |
290
-
291
- ### How to Fix
292
-
293
- **Option A: Run `repair`** (recommended)
294
-
295
- ```bash
296
- npx --yes @sparkleideas/claude-flow-patch --global
297
- npx --yes @sparkleideas/claude-flow-patch repair --target .
298
- npx --yes @sparkleideas/claude-flow-patch apply SG-002 # apply a single patch
299
- ```
300
-
301
- This copies patched helper files into your project and creates any missing .js/.cjs compat copies.
88
+ | Flag | Patched location |
89
+ |---|---|
90
+ | (none) | Global npx cache (default) |
91
+ | `--global` | `~/.npm/_npx/*/node_modules/...` |
92
+ | `--target <dir>` | `<dir>/node_modules/...` |
93
+ | `--global --target <dir>` | Both locations |
302
94
 
303
- **Option B: Copy full helpers from the package manually**
95
+ Use `--target` when your project has a local `@claude-flow/cli` install.
304
96
 
305
- ```bash
306
- npx --yes @sparkleideas/claude-flow-patch --global
307
- SRC=$(find ~/.npm/_npx -path '*/@claude-flow/cli/.claude/helpers' -type d 2>/dev/null | head -1)
308
- for f in intelligence.cjs hook-handler.cjs session.js learning-service.mjs metrics-db.mjs statusline.cjs; do
309
- [ -f "$SRC/$f" ] && cp "$SRC/$f" .claude/helpers/ && echo "Copied: $f"
310
- done
311
- ```
97
+ ## Why `repair` Exists
312
98
 
313
- **Option C: Re-run init upgrade** (regenerates from patched scripts)
99
+ Some fixes patch generator code (`init/executor.js`, `init/settings-generator.js`, `init/helpers-generator.js`). Those fixes affect future generated files only.
314
100
 
315
- ```bash
316
- npx --yes @sparkleideas/claude-flow-patch --global
317
- npx @claude-flow/cli@latest init upgrade --force
318
- ```
319
-
320
- Caution: Option C may overwrite other customizations in `.claude/`.
101
+ If your repo was initialized before patching, existing `.claude/helpers/*` can remain stale. `repair` copies patched helper files into the target repo and creates .js/.cjs compatibility copies where needed.
321
102
 
322
- ### Why This Happens
103
+ ## How Patching Works
323
104
 
324
- These patches fix the **generator functions** inside the npm package (e.g., `generateIntelligenceStub()` in `executor.js`). When the generator runs via `claude-flow init`, it produces the project files in `.claude/helpers/`. If your project was initialized *before* patches were applied, the stubs are already on disk. Patches only modify the npm package source -- they do not touch files already generated in your project.
105
+ 1. Locate CLI/package targets.
106
+ 2. Concatenate shared helpers (`lib/common.py`) with each defect `fix.py`.
107
+ 3. Apply string-based replacements with idempotency guards.
108
+ 4. Validate with sentinel checks.
325
109
 
326
- Additionally, `init upgrade` only force-overwrites 3 "critical" helpers (`auto-memory-hook.mjs`, `hook-handler.cjs`, `intelligence.cjs`). The other 30+ helper files (shell scripts for daemon management, health monitoring, security scanning, swarm hooks, etc.) are only copied on fresh `init`, not on upgrade. If these are missing, use Option A above.
110
+ Design guarantees:
327
111
 
328
- <a id="compatibility"></a>
112
+ - **Idempotent**: safe to re-run
113
+ - **Non-destructive**: modifies local cache/install only
114
+ - **Ordered**: dependent patches applied in sequence (e.g. NS-001 -> NS-002 -> NS-003)
115
+ - **Platform-aware**: macOS-specific patches auto-skip on Linux
329
116
 
330
117
  ## Compatibility
331
118
 
332
- - Tested against `@claude-flow/cli@3.1.0-alpha.41` and `ruv-swarm@1.0.20`
333
- - Requires Python 3.6+ and Bash
334
- - Works on Linux and macOS (DM-003 is macOS-only, auto-skipped on Linux)
335
-
336
- <a id="links"></a>
119
+ - Tested with `@claude-flow/cli@3.1.0-alpha.41`
120
+ - Tested with `ruv-swarm@1.0.20`
121
+ - Requires Bash + Python 3.6+
122
+ - Linux and macOS supported
337
123
 
338
124
  ## Links
339
125
 
340
126
  - Homepage: https://sparklingideas.co.uk/claude-flow/patch
341
- - Package: https://www.npmjs.com/package/@sparkleideas/claude-flow-patch
342
127
  - GitHub: https://github.com/sparkling/claude-flow-patch
343
128
  - Issues: https://github.com/sparkling/claude-flow-patch/issues
344
-
345
- ## License
346
-
347
- MIT
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. Restarting daemon..."
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 with patched code."
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/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@sparkleideas/claude-flow-patch",
3
- "version": "3.1.0-alpha.44.patch.4",
3
+ "version": "3.1.0-alpha.44.patch.6",
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
@@ -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
- 3 ops in fix.py
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 +1,3 @@
1
- grep "30 * 60 * 1000" services/worker-daemon.js
1
+ grep "intervalMs: 30" services/worker-daemon.js
2
+ grep "parseInterval" services/worker-daemon.js
3
+ grep "daemon?.schedules" services/worker-daemon.js
@@ -10,15 +10,12 @@
10
10
  # 2 ops: upgrade path (line ~398) + writeHelpers path (line ~943)
11
11
 
12
12
  # Op 1: Upgrade path — when findSourceHelpersDir() returns null
13
+ # old/new strings stop BEFORE generatedCritical to avoid overlap with SG-003j
13
14
  patch("IN-001a: upgrade fallback reads real intelligence.cjs",
14
15
  EXECUTOR,
15
16
  """ else {
16
17
  // Source not found (npx with broken paths) — use generated fallbacks
17
- const generatedCritical = {
18
- 'hook-handler.cjs': generateHookHandler(),
19
- 'intelligence.cjs': generateIntelligenceStub(),
20
- 'auto-memory-hook.mjs': generateAutoMemoryHook(),
21
- };""",
18
+ const generatedCritical = {""",
22
19
  """ else {
23
20
  // Source not found (npx with broken paths) — use generated fallbacks
24
21
  // IN-001: Try reading real intelligence.cjs from package before using stub
@@ -29,11 +26,7 @@ patch("IN-001a: upgrade fallback reads real intelligence.cjs",
29
26
  intelligenceContent = fs.readFileSync(realPath, 'utf-8');
30
27
  }
31
28
  } catch { /* use stub */ }
32
- const generatedCritical = {
33
- 'hook-handler.cjs': generateHookHandler(),
34
- 'intelligence.cjs': intelligenceContent,
35
- 'auto-memory-hook.mjs': generateAutoMemoryHook(),
36
- };""")
29
+ const generatedCritical = {""")
37
30
 
38
31
  # Op 2: writeHelpers path — fresh init when source dir not found
39
32
  patch("IN-001b: writeHelpers fallback reads real intelligence.cjs",
@@ -122,11 +122,12 @@ patch_all("SG-003i: source hook-handler requires memory.cjs",
122
122
 
123
123
  # Op 6: Fix executeUpgrade() fallback — generatedCritical missing router/session/memory
124
124
  # When source helpers aren't found, only 3 files were generated but hook-handler.cjs needs 6
125
+ # Also replaces generateIntelligenceStub() → intelligenceContent (set by IN-001a above)
125
126
  patch("SG-003j: upgrade fallback generates router/session/memory",
126
127
  EXECUTOR,
127
128
  """ const generatedCritical = {
128
129
  'hook-handler.cjs': generateHookHandler(),
129
- 'intelligence.cjs': intelligenceContent,
130
+ 'intelligence.cjs': generateIntelligenceStub(),
130
131
  'auto-memory-hook.mjs': generateAutoMemoryHook(),
131
132
  };""",
132
133
  """ const generatedCritical = {
@@ -1,11 +1,12 @@
1
- # DM-006: No log rotation — headless execution logs grow unbounded
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
- 3 ops in fix.py
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 */ }""")
@@ -1 +1,2 @@
1
1
  grep "cleanupOldLogs" services/headless-worker-executor.js
2
+ grep "Rotate main daemon.log" commands/daemon.js
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
- // scripts/update-docs.mjs — Regenerate documentation from dynamic patch discovery.
3
- // Updates: README.md, CLAUDE.md, npm/README.md, npm/config.json
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/update-docs.mjs [--check]
6
- // --check Exit 1 if docs are out of date (for CI), don't write.
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
- // ── Update npm/config.json counts ──
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
- const readmeChanged = replaceMarkerSection(
172
- resolve(ROOT, 'README.md'),
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 ? 'STALE: README.md' : 'Updated: README.md');
205
+ console.log(checkOnly ? `STALE: ${label}` : `Updated: ${label}`);
179
206
  }
180
207
 
181
- const claudeChanged = replaceMarkerSection(
182
- resolve(ROOT, 'CLAUDE.md'),
183
- 'defect-tables',
184
- generateClaudeTables()
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
- if (claudeChanged) {
187
- anyChanged = true;
188
- console.log(checkOnly ? 'STALE: CLAUDE.md' : 'Updated: CLAUDE.md');
189
- }
190
-
191
- const npmReadmeChanged = updateNpmReadme();
192
- if (npmReadmeChanged) {
193
- anyChanged = true;
194
- console.log(checkOnly ? 'STALE: npm/README.md' : 'Updated: npm/README.md');
195
- }
196
-
197
- const npmConfigChanged = updateNpmConfig();
198
- if (npmConfigChanged) {
199
- anyChanged = true;
200
- console.log(checkOnly ? 'STALE: npm/config.json' : 'Updated: npm/config.json');
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 docs are up to date.');
245
+ console.log('All files are up to date.');
205
246
  } else if (checkOnly) {
206
- console.log('\nDocs are out of date. Run: npm run update-docs');
247
+ console.log('\nFiles are out of date. Run: npm run preflight');
207
248
  process.exit(1);
208
249
  }