@sparkleideas/claude-flow-patch 3.1.0-alpha.44.patch.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +162 -0
- package/CLAUDE.md +458 -0
- package/README.md +306 -0
- package/bin/claude-flow-patch.mjs +148 -0
- package/check-patches.sh +176 -0
- package/lib/categories.json +15 -0
- package/lib/common.py +92 -0
- package/lib/discover.mjs +181 -0
- package/package.json +85 -0
- package/patch/010-CF-001-doctor-yaml/README.md +11 -0
- package/patch/010-CF-001-doctor-yaml/fix.py +20 -0
- package/patch/010-CF-001-doctor-yaml/sentinel +1 -0
- package/patch/020-CF-002-config-export-yaml/README.md +11 -0
- package/patch/020-CF-002-config-export-yaml/fix.py +130 -0
- package/patch/020-CF-002-config-export-yaml/sentinel +1 -0
- package/patch/030-DM-001-daemon-log-zero/README.md +12 -0
- package/patch/030-DM-001-daemon-log-zero/fix.py +37 -0
- package/patch/030-DM-001-daemon-log-zero/sentinel +1 -0
- package/patch/040-DM-002-cpu-load-threshold/README.md +11 -0
- package/patch/040-DM-002-cpu-load-threshold/fix.py +6 -0
- package/patch/040-DM-002-cpu-load-threshold/sentinel +1 -0
- package/patch/050-DM-003-macos-freemem/README.md +11 -0
- package/patch/050-DM-003-macos-freemem/fix.py +7 -0
- package/patch/050-DM-003-macos-freemem/sentinel +1 -0
- package/patch/060-DM-004-preload-worker-stub/README.md +11 -0
- package/patch/060-DM-004-preload-worker-stub/fix.py +34 -0
- package/patch/060-DM-004-preload-worker-stub/sentinel +1 -0
- package/patch/070-DM-005-consolidation-worker-stub/README.md +11 -0
- package/patch/070-DM-005-consolidation-worker-stub/fix.py +46 -0
- package/patch/070-DM-005-consolidation-worker-stub/sentinel +1 -0
- package/patch/080-EM-001-embedding-ignores-config/README.md +11 -0
- package/patch/080-EM-001-embedding-ignores-config/fix.py +111 -0
- package/patch/080-EM-001-embedding-ignores-config/sentinel +1 -0
- package/patch/090-EM-002-transformers-cache-eacces/README.md +11 -0
- package/patch/090-EM-002-transformers-cache-eacces/fix.sh +12 -0
- package/patch/090-EM-002-transformers-cache-eacces/sentinel +1 -0
- package/patch/100-GV-001-hnsw-ghost-vectors/README.md +11 -0
- package/patch/100-GV-001-hnsw-ghost-vectors/fix.py +34 -0
- package/patch/100-GV-001-hnsw-ghost-vectors/sentinel +1 -0
- package/patch/110-HK-001-post-edit-file-path/README.md +44 -0
- package/patch/110-HK-001-post-edit-file-path/fix.py +23 -0
- package/patch/110-HK-001-post-edit-file-path/sentinel +1 -0
- package/patch/120-HK-002-hooks-tools-stub/README.md +36 -0
- package/patch/120-HK-002-hooks-tools-stub/fix.py +155 -0
- package/patch/120-HK-002-hooks-tools-stub/sentinel +1 -0
- package/patch/130-HK-003-metrics-hardcoded/README.md +30 -0
- package/patch/130-HK-003-metrics-hardcoded/fix.py +82 -0
- package/patch/130-HK-003-metrics-hardcoded/sentinel +1 -0
- package/patch/140-HW-001-stdin-hang/README.md +11 -0
- package/patch/140-HW-001-stdin-hang/fix.py +6 -0
- package/patch/140-HW-001-stdin-hang/sentinel +1 -0
- package/patch/150-HW-002-failures-swallowed/README.md +11 -0
- package/patch/150-HW-002-failures-swallowed/fix.py +42 -0
- package/patch/150-HW-002-failures-swallowed/sentinel +1 -0
- package/patch/160-HW-003-aggressive-intervals/README.md +11 -0
- package/patch/160-HW-003-aggressive-intervals/fix.py +16 -0
- package/patch/160-HW-003-aggressive-intervals/sentinel +1 -0
- package/patch/170-IN-001-intelligence-stub/README.md +64 -0
- package/patch/170-IN-001-intelligence-stub/fix.py +70 -0
- package/patch/170-IN-001-intelligence-stub/sentinel +1 -0
- package/patch/180-MM-001-memory-persist-path/README.md +27 -0
- package/patch/180-MM-001-memory-persist-path/fix.py +54 -0
- package/patch/180-MM-001-memory-persist-path/sentinel +1 -0
- package/patch/190-NS-001-discovery-default-namespace/README.md +16 -0
- package/patch/190-NS-001-discovery-default-namespace/fix.py +68 -0
- package/patch/190-NS-001-discovery-default-namespace/sentinel +2 -0
- package/patch/200-NS-002-targeted-require-namespace/README.md +19 -0
- package/patch/200-NS-002-targeted-require-namespace/fix.py +158 -0
- package/patch/200-NS-002-targeted-require-namespace/sentinel +2 -0
- package/patch/210-NS-003-namespace-typo-pattern/README.md +15 -0
- package/patch/210-NS-003-namespace-typo-pattern/fix.py +23 -0
- package/patch/210-NS-003-namespace-typo-pattern/sentinel +1 -0
- package/patch/220-RS-001-better-sqlite3-node24/README.md +54 -0
- package/patch/220-RS-001-better-sqlite3-node24/fix.py +22 -0
- package/patch/220-RS-001-better-sqlite3-node24/rebuild.sh +31 -0
- package/patch/220-RS-001-better-sqlite3-node24/sentinel +2 -0
- package/patch/230-RV-001-force-learn-tick/README.md +31 -0
- package/patch/230-RV-001-force-learn-tick/fix.py +14 -0
- package/patch/230-RV-001-force-learn-tick/sentinel +2 -0
- package/patch/240-RV-002-trajectory-load/README.md +28 -0
- package/patch/240-RV-002-trajectory-load/fix.py +14 -0
- package/patch/240-RV-002-trajectory-load/sentinel +2 -0
- package/patch/250-RV-003-trajectory-stats-sync/README.md +31 -0
- package/patch/250-RV-003-trajectory-stats-sync/fix.py +18 -0
- package/patch/250-RV-003-trajectory-stats-sync/sentinel +2 -0
- package/patch/260-SG-001-init-settings/README.md +29 -0
- package/patch/260-SG-001-init-settings/fix.py +143 -0
- package/patch/260-SG-001-init-settings/sentinel +4 -0
- package/patch/270-SG-003-init-helpers-all-paths/README.md +60 -0
- package/patch/270-SG-003-init-helpers-all-paths/fix.py +164 -0
- package/patch/270-SG-003-init-helpers-all-paths/sentinel +3 -0
- package/patch/280-UI-001-intelligence-stats-crash/README.md +11 -0
- package/patch/280-UI-001-intelligence-stats-crash/fix.py +57 -0
- package/patch/280-UI-001-intelligence-stats-crash/sentinel +1 -0
- package/patch/290-UI-002-neural-status-not-loaded/README.md +11 -0
- package/patch/290-UI-002-neural-status-not-loaded/fix.py +19 -0
- package/patch/290-UI-002-neural-status-not-loaded/sentinel +1 -0
- package/patch/300-DM-006-log-rotation/README.md +11 -0
- package/patch/300-DM-006-log-rotation/fix.py +58 -0
- package/patch/300-DM-006-log-rotation/sentinel +1 -0
- package/patch/310-HW-004-runwithtimeout-orphan/README.md +11 -0
- package/patch/310-HW-004-runwithtimeout-orphan/fix.py +10 -0
- package/patch/310-HW-004-runwithtimeout-orphan/sentinel +1 -0
- package/patch-all.sh +203 -0
- package/repair-post-init.sh +245 -0
- package/scripts/update-docs.mjs +208 -0
- package/scripts/upstream-log.mjs +257 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# SG-003: Init missing helpers for --dual, --minimal, hooks, and upgrade paths
|
|
2
|
+
|
|
3
|
+
**Severity**: Critical
|
|
4
|
+
**GitHub**: [#1169](https://github.com/ruvnet/claude-flow/issues/1169)
|
|
5
|
+
|
|
6
|
+
## Root Cause
|
|
7
|
+
|
|
8
|
+
Multiple `init` code paths generate `settings.json` (which references `hook-handler.cjs`,
|
|
9
|
+
`auto-memory-hook.mjs`, `statusline.cjs`) without generating the helper files those hooks need.
|
|
10
|
+
|
|
11
|
+
| Path | Generates settings? | Generates helpers? | Result |
|
|
12
|
+
|------|--------------------|--------------------|--------|
|
|
13
|
+
| `init` (default) | YES | YES | OK |
|
|
14
|
+
| `init --dual` | NO (bypasses executeInit) | NO | Broken: no Claude infra despite CLAUDE.md |
|
|
15
|
+
| `init --codex` | NO (bypasses executeInit) | NO | OK (no Claude Code expected) |
|
|
16
|
+
| `init --minimal` | YES | NO (helpers: false) | Broken: dangling settings refs |
|
|
17
|
+
| `init hooks` | YES | NO (helpers: false) | Broken: dangling settings refs |
|
|
18
|
+
| `init upgrade` | Only with --settings | Partial (3 of 8) | Broken: missing router/session/memory |
|
|
19
|
+
| `init wizard` | YES | YES (default) | OK |
|
|
20
|
+
|
|
21
|
+
Additionally:
|
|
22
|
+
- `helpers-generator.js` generates a `hook-handler.cjs` that hardcodes `require('router.js')`
|
|
23
|
+
instead of `require('router.cjs')`, failing when `package.json` has `"type": "module"`.
|
|
24
|
+
- `executeUpgrade()` only upgrades 3 critical helpers but `hook-handler.cjs` needs 6.
|
|
25
|
+
- `executeUpgrade()` fallback also only generates 3 in `generatedCritical`.
|
|
26
|
+
|
|
27
|
+
## Fix
|
|
28
|
+
|
|
29
|
+
7 ops across 4 files:
|
|
30
|
+
|
|
31
|
+
1. **init.js** — After `--dual` codex init succeeds, call `executeInit()` with
|
|
32
|
+
all components so full Claude Code infrastructure is created.
|
|
33
|
+
2. **executor.js** — When `settings` is generated but `helpers` is not, also generate
|
|
34
|
+
the critical helpers that `settings.json` references (fixes `--minimal` and `init hooks`).
|
|
35
|
+
3. **executor.js** — Expand `executeUpgrade()` critical helpers list to include `router.cjs`,
|
|
36
|
+
`session.cjs`, `memory.cjs`.
|
|
37
|
+
4. **helpers-generator.js** — Fix generated `hook-handler.cjs` to `require('router.cjs')`
|
|
38
|
+
instead of `require('router.js')` (same for session and memory).
|
|
39
|
+
5. **hook-handler.cjs** (source template) — Fix source-shipped copy to use `.cjs` requires.
|
|
40
|
+
6. **executor.js** — Expand `executeUpgrade()` fallback `generatedCritical` to include
|
|
41
|
+
`router.cjs`, `session.cjs`, `memory.cjs` when source helpers aren't found.
|
|
42
|
+
7. **init.js** — Transition op: update `--dual` components from `skills: false` to `true`.
|
|
43
|
+
|
|
44
|
+
## Files Patched
|
|
45
|
+
|
|
46
|
+
- `commands/init.js`
|
|
47
|
+
- `init/executor.js`
|
|
48
|
+
- `init/helpers-generator.js`
|
|
49
|
+
- `<pkg-root>/.claude/helpers/hook-handler.cjs` (source template)
|
|
50
|
+
|
|
51
|
+
## Dependencies
|
|
52
|
+
|
|
53
|
+
Depends on IN-001 (170) — SG-003's `old_string` contains code introduced by IN-001.
|
|
54
|
+
|
|
55
|
+
## Ops
|
|
56
|
+
|
|
57
|
+
7 ops (11 patch calls) in fix.py
|
|
58
|
+
|
|
59
|
+
Note: .js copies of .cjs helpers are not needed. All require() paths use .cjs
|
|
60
|
+
exclusively after ops d-i. The former SG-002 compat copy approach was retired.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# SG-003: Init missing helpers for --dual, --minimal, hooks, and upgrade paths
|
|
2
|
+
# GitHub: #1169
|
|
3
|
+
#
|
|
4
|
+
# Root cause:
|
|
5
|
+
# 1. init --dual bypasses executeInit() entirely — no .claude/helpers/ created
|
|
6
|
+
# 2. init --minimal and init hooks set components.helpers=false but settings=true
|
|
7
|
+
# so settings.json references helpers that don't exist
|
|
8
|
+
# 3. executeUpgrade() only upgrades 3 of 8 helpers (missing router/session/memory)
|
|
9
|
+
# 4. helpers-generator.js generates hook-handler.cjs with require('router.js')
|
|
10
|
+
# instead of require('router.cjs'), failing with "type":"module"
|
|
11
|
+
#
|
|
12
|
+
# 5 ops: dual path (init.js), settings guard (executor.js),
|
|
13
|
+
# upgrade helpers (executor.js), generated requires (helpers-generator.js),
|
|
14
|
+
# source-shipped hook-handler.cjs requires (SRC_HOOK_HANDLER)
|
|
15
|
+
|
|
16
|
+
# Op 1: init --dual should also generate Claude Code infrastructure
|
|
17
|
+
# After codex init succeeds, call executeInit() for helpers/settings/statusline
|
|
18
|
+
patch("SG-003a: --dual also generates helpers + settings via executeInit",
|
|
19
|
+
INIT_CMD,
|
|
20
|
+
""" // If codex mode, use the Codex initializer
|
|
21
|
+
if (codexMode || dualMode) {
|
|
22
|
+
return initCodexAction(ctx, { codexMode, dualMode, force, minimal, full });
|
|
23
|
+
}""",
|
|
24
|
+
""" // If codex mode, use the Codex initializer
|
|
25
|
+
if (codexMode || dualMode) {
|
|
26
|
+
const codexResult = await initCodexAction(ctx, { codexMode, dualMode, force, minimal, full });
|
|
27
|
+
// SG-003: --dual must also create Claude Code infrastructure (.claude/helpers + settings)
|
|
28
|
+
if (dualMode) {
|
|
29
|
+
try {
|
|
30
|
+
await executeInit({
|
|
31
|
+
...DEFAULT_INIT_OPTIONS,
|
|
32
|
+
targetDir: cwd,
|
|
33
|
+
force,
|
|
34
|
+
components: {
|
|
35
|
+
settings: true,
|
|
36
|
+
helpers: true,
|
|
37
|
+
statusline: true,
|
|
38
|
+
skills: true,
|
|
39
|
+
commands: true,
|
|
40
|
+
agents: true,
|
|
41
|
+
mcp: true,
|
|
42
|
+
runtime: false,
|
|
43
|
+
claudeMd: false,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
} catch { /* non-fatal — codex init already succeeded */ }
|
|
47
|
+
}
|
|
48
|
+
return codexResult;
|
|
49
|
+
}""")
|
|
50
|
+
|
|
51
|
+
# Op 2: When settings is generated but helpers component is off, still generate
|
|
52
|
+
# the critical helpers that settings.json references
|
|
53
|
+
patch("SG-003b: generate critical helpers when settings references them",
|
|
54
|
+
EXECUTOR,
|
|
55
|
+
""" // Generate helpers
|
|
56
|
+
if (options.components.helpers) {
|
|
57
|
+
await writeHelpers(targetDir, options, result);
|
|
58
|
+
}""",
|
|
59
|
+
""" // Generate helpers
|
|
60
|
+
if (options.components.helpers) {
|
|
61
|
+
await writeHelpers(targetDir, options, result);
|
|
62
|
+
}
|
|
63
|
+
// SG-003: If settings will be generated but helpers were skipped,
|
|
64
|
+
// generate the critical helpers that settings.json hooks reference
|
|
65
|
+
else if (options.components.settings) {
|
|
66
|
+
const hDir = path.join(targetDir, '.claude', 'helpers');
|
|
67
|
+
fs.mkdirSync(hDir, { recursive: true });
|
|
68
|
+
const criticalForSettings = {
|
|
69
|
+
'hook-handler.cjs': generateHookHandler(),
|
|
70
|
+
'auto-memory-hook.mjs': generateAutoMemoryHook(),
|
|
71
|
+
};
|
|
72
|
+
for (const [name, content] of Object.entries(criticalForSettings)) {
|
|
73
|
+
const fp = path.join(hDir, name);
|
|
74
|
+
if (!fs.existsSync(fp)) {
|
|
75
|
+
fs.writeFileSync(fp, content, 'utf-8');
|
|
76
|
+
try { fs.chmodSync(fp, '755'); } catch {}
|
|
77
|
+
result.created.files.push(`.claude/helpers/${name}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}""")
|
|
81
|
+
|
|
82
|
+
# Op 3: Expand executeUpgrade() critical helpers to include router/session/memory
|
|
83
|
+
# and add compat-copy sweep after statusline
|
|
84
|
+
patch("SG-003c: upgrade generates all helpers + compat sweep",
|
|
85
|
+
EXECUTOR,
|
|
86
|
+
""" const criticalHelpers = ['auto-memory-hook.mjs', 'hook-handler.cjs', 'intelligence.cjs'];""",
|
|
87
|
+
""" const criticalHelpers = ['auto-memory-hook.mjs', 'hook-handler.cjs', 'intelligence.cjs', 'router.cjs', 'session.cjs', 'memory.cjs'];""")
|
|
88
|
+
|
|
89
|
+
# Op 4: Fix generated hook-handler.cjs to require .cjs instead of .js
|
|
90
|
+
# This is the fallback generator used when source helpers aren't found
|
|
91
|
+
patch_all("SG-003d: generated hook-handler requires .cjs not .js",
|
|
92
|
+
HELPERS_GEN,
|
|
93
|
+
"""safeRequire(path.join(helpersDir, 'router.js'))""",
|
|
94
|
+
"""safeRequire(path.join(helpersDir, 'router.cjs'))""")
|
|
95
|
+
|
|
96
|
+
patch_all("SG-003e: generated hook-handler requires session.cjs",
|
|
97
|
+
HELPERS_GEN,
|
|
98
|
+
"""safeRequire(path.join(helpersDir, 'session.js'))""",
|
|
99
|
+
"""safeRequire(path.join(helpersDir, 'session.cjs'))""")
|
|
100
|
+
|
|
101
|
+
patch_all("SG-003f: generated hook-handler requires memory.cjs",
|
|
102
|
+
HELPERS_GEN,
|
|
103
|
+
"""safeRequire(path.join(helpersDir, 'memory.js'))""",
|
|
104
|
+
"""safeRequire(path.join(helpersDir, 'memory.cjs'))""")
|
|
105
|
+
|
|
106
|
+
# Op 5: Fix the source-shipped hook-handler.cjs (copied by writeHelpers when source found)
|
|
107
|
+
# This file is at <pkg-root>/.claude/helpers/hook-handler.cjs and gets copied as-is
|
|
108
|
+
patch_all("SG-003g: source hook-handler requires router.cjs",
|
|
109
|
+
SRC_HOOK_HANDLER,
|
|
110
|
+
"""safeRequire(path.join(helpersDir, 'router.js'))""",
|
|
111
|
+
"""safeRequire(path.join(helpersDir, 'router.cjs'))""")
|
|
112
|
+
|
|
113
|
+
patch_all("SG-003h: source hook-handler requires session.cjs",
|
|
114
|
+
SRC_HOOK_HANDLER,
|
|
115
|
+
"""safeRequire(path.join(helpersDir, 'session.js'))""",
|
|
116
|
+
"""safeRequire(path.join(helpersDir, 'session.cjs'))""")
|
|
117
|
+
|
|
118
|
+
patch_all("SG-003i: source hook-handler requires memory.cjs",
|
|
119
|
+
SRC_HOOK_HANDLER,
|
|
120
|
+
"""safeRequire(path.join(helpersDir, 'memory.js'))""",
|
|
121
|
+
"""safeRequire(path.join(helpersDir, 'memory.cjs'))""")
|
|
122
|
+
|
|
123
|
+
# Op 6: Fix executeUpgrade() fallback — generatedCritical missing router/session/memory
|
|
124
|
+
# When source helpers aren't found, only 3 files were generated but hook-handler.cjs needs 6
|
|
125
|
+
patch("SG-003j: upgrade fallback generates router/session/memory",
|
|
126
|
+
EXECUTOR,
|
|
127
|
+
""" const generatedCritical = {
|
|
128
|
+
'hook-handler.cjs': generateHookHandler(),
|
|
129
|
+
'intelligence.cjs': intelligenceContent,
|
|
130
|
+
'auto-memory-hook.mjs': generateAutoMemoryHook(),
|
|
131
|
+
};""",
|
|
132
|
+
""" const generatedCritical = {
|
|
133
|
+
'hook-handler.cjs': generateHookHandler(),
|
|
134
|
+
'intelligence.cjs': intelligenceContent,
|
|
135
|
+
'auto-memory-hook.mjs': generateAutoMemoryHook(),
|
|
136
|
+
// SG-003: hook-handler.cjs requires these — generate fallback versions
|
|
137
|
+
'router.cjs': generateAgentRouter(),
|
|
138
|
+
'session.cjs': generateSessionManager(),
|
|
139
|
+
'memory.cjs': generateMemoryHelper(),
|
|
140
|
+
};""")
|
|
141
|
+
|
|
142
|
+
# Transition: update caches that already have old SG-003a (skills: false) to new (skills: true)
|
|
143
|
+
# On fresh cache SG-003a applies directly; this skips (new already present).
|
|
144
|
+
# On pre-patched cache SG-003a warns (upstream old_string gone); this catches the delta.
|
|
145
|
+
patch("SG-003l: --dual enables skills/commands/agents (transition)",
|
|
146
|
+
INIT_CMD,
|
|
147
|
+
""" skills: false,
|
|
148
|
+
commands: false,
|
|
149
|
+
agents: false,
|
|
150
|
+
mcp: true,
|
|
151
|
+
runtime: false,
|
|
152
|
+
claudeMd: false,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
} catch { /* non-fatal — codex init already succeeded */ }""",
|
|
156
|
+
""" skills: true,
|
|
157
|
+
commands: true,
|
|
158
|
+
agents: true,
|
|
159
|
+
mcp: true,
|
|
160
|
+
runtime: false,
|
|
161
|
+
claudeMd: false,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
} catch { /* non-fatal — codex init already succeeded */ }""")
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# UI-001: intelligence stats crashes on .toFixed()
|
|
2
|
+
**Severity**: Critical
|
|
3
|
+
**GitHub**: [#1145](https://github.com/ruvnet/claude-flow/issues/1145)
|
|
4
|
+
## Root Cause
|
|
5
|
+
`hooks intelligence stats` calls `.toFixed()` on potentially undefined properties (learningTimeMs, adaptationTimeMs, avgQuality, routingAccuracy, loadBalance, cacheHitRate, performance.*) without null checks. Crashes when the intelligence system returns incomplete data.
|
|
6
|
+
## Fix
|
|
7
|
+
Add null checks with 'N/A' fallback for all numeric display values. Wrap performance section in an `if (result.performance)` guard.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- commands/hooks.js
|
|
10
|
+
## Ops
|
|
11
|
+
7 ops in fix.py
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# UI-001: intelligence stats crashes on .toFixed() of undefined
|
|
2
|
+
# Absorbed from old patch-17. Applied via sed to npx cache.
|
|
3
|
+
|
|
4
|
+
# SONA component null checks
|
|
5
|
+
patch("17a: SONA learningTimeMs null check",
|
|
6
|
+
HOOKS_CMD,
|
|
7
|
+
"{ metric: 'Learning Time', value: `${result.components.sona.learningTimeMs.toFixed(3)}ms` }",
|
|
8
|
+
"{ metric: 'Learning Time', value: result.components.sona.learningTimeMs != null ? `${result.components.sona.learningTimeMs.toFixed(3)}ms` : 'N/A' }")
|
|
9
|
+
|
|
10
|
+
patch("17b: SONA adaptationTimeMs null check",
|
|
11
|
+
HOOKS_CMD,
|
|
12
|
+
"{ metric: 'Adaptation Time', value: `${result.components.sona.adaptationTimeMs.toFixed(3)}ms` }",
|
|
13
|
+
"{ metric: 'Adaptation Time', value: result.components.sona.adaptationTimeMs != null ? `${result.components.sona.adaptationTimeMs.toFixed(3)}ms` : 'N/A' }")
|
|
14
|
+
|
|
15
|
+
patch("17c: SONA avgQuality null check",
|
|
16
|
+
HOOKS_CMD,
|
|
17
|
+
"{ metric: 'Avg Quality', value: `${(result.components.sona.avgQuality * 100).toFixed(1)}%` }",
|
|
18
|
+
"{ metric: 'Avg Quality', value: result.components.sona.avgQuality != null ? `${(result.components.sona.avgQuality * 100).toFixed(1)}%` : 'N/A' }")
|
|
19
|
+
|
|
20
|
+
# MoE component null checks
|
|
21
|
+
patch("17d: MoE routingAccuracy null check",
|
|
22
|
+
HOOKS_CMD,
|
|
23
|
+
"{ metric: 'Routing Accuracy', value: `${(result.components.moe.routingAccuracy * 100).toFixed(1)}%` }",
|
|
24
|
+
"{ metric: 'Routing Accuracy', value: result.components.moe.routingAccuracy != null ? `${(result.components.moe.routingAccuracy * 100).toFixed(1)}%` : 'N/A' }")
|
|
25
|
+
|
|
26
|
+
patch("17e: MoE loadBalance null check",
|
|
27
|
+
HOOKS_CMD,
|
|
28
|
+
"{ metric: 'Load Balance', value: `${(result.components.moe.loadBalance * 100).toFixed(1)}%` }",
|
|
29
|
+
"{ metric: 'Load Balance', value: result.components.moe.loadBalance != null ? `${(result.components.moe.loadBalance * 100).toFixed(1)}%` : 'N/A' }")
|
|
30
|
+
|
|
31
|
+
# Embeddings null check
|
|
32
|
+
patch("17f: embeddings cacheHitRate null check",
|
|
33
|
+
HOOKS_CMD,
|
|
34
|
+
"{ metric: 'Cache Hit Rate', value: `${(result.components.embeddings.cacheHitRate * 100).toFixed(1)}%` }",
|
|
35
|
+
"{ metric: 'Cache Hit Rate', value: result.components.embeddings.cacheHitRate != null ? `${(result.components.embeddings.cacheHitRate * 100).toFixed(1)}%` : 'N/A' }")
|
|
36
|
+
|
|
37
|
+
# Performance section null guard
|
|
38
|
+
patch("17g: performance section null guard",
|
|
39
|
+
HOOKS_CMD,
|
|
40
|
+
""" output.printList([
|
|
41
|
+
`Flash Attention: ${output.success(result.performance.flashAttention)}`,
|
|
42
|
+
`Memory Reduction: ${output.success(result.performance.memoryReduction)}`,
|
|
43
|
+
`Search Improvement: ${output.success(result.performance.searchImprovement)}`,
|
|
44
|
+
`Token Reduction: ${output.success(result.performance.tokenReduction)}`,
|
|
45
|
+
`SWE-Bench Score: ${output.success(result.performance.sweBenchScore)}`
|
|
46
|
+
]);""",
|
|
47
|
+
""" if (result.performance) {
|
|
48
|
+
output.printList([
|
|
49
|
+
`Flash Attention: ${output.success(result.performance.flashAttention || 'N/A')}`,
|
|
50
|
+
`Memory Reduction: ${output.success(result.performance.memoryReduction || 'N/A')}`,
|
|
51
|
+
`Search Improvement: ${output.success(result.performance.searchImprovement || 'N/A')}`,
|
|
52
|
+
`Token Reduction: ${output.success(result.performance.tokenReduction || 'N/A')}`,
|
|
53
|
+
`SWE-Bench Score: ${output.success(result.performance.sweBenchScore || 'N/A')}`
|
|
54
|
+
]);
|
|
55
|
+
} else {
|
|
56
|
+
output.writeln(output.dim(' No performance data available'));
|
|
57
|
+
}""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "learningTimeMs != null" commands/hooks.js
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# UI-002: neural status shows "Not loaded"
|
|
2
|
+
**Severity**: Low (cosmetic)
|
|
3
|
+
**GitHub**: [#1146](https://github.com/ruvnet/claude-flow/issues/1146)
|
|
4
|
+
## Root Cause
|
|
5
|
+
`neural status` reads module-level flags (`initialized`, `sonaAvailable`, `hnswIndex`) without calling their init functions. RuVector WASM, SONA Engine, and HNSW Index always show "Not loaded" even when packages are installed and working.
|
|
6
|
+
## Fix
|
|
7
|
+
Add `initializeTraining()` and `getHNSWIndex()` calls before reading status. Update import to include `getHNSWIndex`.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- commands/neural.js
|
|
10
|
+
## Ops
|
|
11
|
+
2 ops in fix.py
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# UI-002: neural status shows "Not loaded" for installed components
|
|
2
|
+
# Absorbed from old patch-18. Applied manually to npx cache.
|
|
3
|
+
|
|
4
|
+
# Update import to include getHNSWIndex
|
|
5
|
+
patch("18a: neural.js import getHNSWIndex",
|
|
6
|
+
NEURAL,
|
|
7
|
+
"const { getHNSWStatus, loadEmbeddingModel } = await import('../memory/memory-initializer.js');",
|
|
8
|
+
"const { getHNSWIndex, getHNSWStatus, loadEmbeddingModel } = await import('../memory/memory-initializer.js');")
|
|
9
|
+
|
|
10
|
+
# Add initialization calls before status reads
|
|
11
|
+
patch("18b: neural.js init before status",
|
|
12
|
+
NEURAL,
|
|
13
|
+
" const ruvectorStats = ruvector.getTrainingStats();",
|
|
14
|
+
""" // Patch 18: Initialize RuVector WASM + SONA + HNSW so status reflects reality
|
|
15
|
+
if (!ruvector.getTrainingStats().initialized) {
|
|
16
|
+
await ruvector.initializeTraining({ useSona: true }).catch(() => {});
|
|
17
|
+
}
|
|
18
|
+
await getHNSWIndex().catch(() => null);
|
|
19
|
+
const ruvectorStats = ruvector.getTrainingStats();""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "getHNSWIndex" commands/neural.js
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# DM-006: No log rotation — headless execution logs grow unbounded
|
|
2
|
+
**Severity**: Medium
|
|
3
|
+
**GitHub**: [#1114](https://github.com/ruvnet/claude-flow/issues/1114)
|
|
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.
|
|
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.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- services/headless-worker-executor.js
|
|
10
|
+
## Ops
|
|
11
|
+
3 ops in fix.py
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# DM-006: No log rotation — headless execution logs grow unbounded
|
|
2
|
+
# GitHub: #1114
|
|
3
|
+
|
|
4
|
+
# A: Add unlinkSync and statSync to ESM import
|
|
5
|
+
patch("DM-006a: add unlinkSync/statSync to fs import",
|
|
6
|
+
HWE,
|
|
7
|
+
"import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync } from 'fs';",
|
|
8
|
+
"import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync, unlinkSync, statSync } from 'fs';")
|
|
9
|
+
|
|
10
|
+
# B: Call cleanupOldLogs() from ensureLogDir()
|
|
11
|
+
patch("DM-006b: call cleanup from ensureLogDir",
|
|
12
|
+
HWE,
|
|
13
|
+
""" ensureLogDir() {
|
|
14
|
+
try {
|
|
15
|
+
if (!existsSync(this.config.logDir)) {
|
|
16
|
+
mkdirSync(this.config.logDir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
this.emit('warning', { message: 'Failed to create log directory', error });
|
|
21
|
+
}
|
|
22
|
+
}""",
|
|
23
|
+
""" ensureLogDir() {
|
|
24
|
+
try {
|
|
25
|
+
if (!existsSync(this.config.logDir)) {
|
|
26
|
+
mkdirSync(this.config.logDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
this.cleanupOldLogs();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
this.emit('warning', { message: 'Failed to create log directory', error });
|
|
32
|
+
}
|
|
33
|
+
}""")
|
|
34
|
+
|
|
35
|
+
# C: Add cleanupOldLogs() method before logExecution()
|
|
36
|
+
patch("DM-006c: add cleanupOldLogs method",
|
|
37
|
+
HWE,
|
|
38
|
+
""" logExecution(executionId, type, content) {""",
|
|
39
|
+
""" cleanupOldLogs(maxAgeDays = 7, maxFiles = 500) {
|
|
40
|
+
try {
|
|
41
|
+
const files = readdirSync(this.config.logDir)
|
|
42
|
+
.filter(f => f.endsWith('.log'))
|
|
43
|
+
.map(f => {
|
|
44
|
+
try { return { name: f, mtime: statSync(join(this.config.logDir, f)).mtimeMs }; }
|
|
45
|
+
catch { return null; }
|
|
46
|
+
})
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
49
|
+
const cutoff = Date.now() - maxAgeDays * 86400000;
|
|
50
|
+
for (let i = 0; i < files.length; i++) {
|
|
51
|
+
if (files[i].mtime < cutoff || i >= maxFiles) {
|
|
52
|
+
try { unlinkSync(join(this.config.logDir, files[i].name)); } catch {}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch { /* ignore cleanup errors */ }
|
|
57
|
+
}
|
|
58
|
+
logExecution(executionId, type, content) {""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "cleanupOldLogs" services/headless-worker-executor.js
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# HW-004: runWithTimeout rejects but does not kill child process
|
|
2
|
+
**Severity**: Medium
|
|
3
|
+
**GitHub**: [#1117](https://github.com/ruvnet/claude-flow/issues/1117)
|
|
4
|
+
## Root Cause
|
|
5
|
+
`runWithTimeout()` in `worker-daemon.js` has `DEFAULT_WORKER_TIMEOUT_MS = 5 * 60 * 1000` (5 min), but the headless executor's per-worker timeouts range from 5-15 minutes. When the daemon timeout fires first, the promise rejects but the underlying `claude --print` child process keeps running as an orphan until the executor's own timeout fires minutes later.
|
|
6
|
+
## Fix
|
|
7
|
+
Raise `DEFAULT_WORKER_TIMEOUT_MS` from 5 minutes to 16 minutes so the daemon timeout never fires before the executor's own per-worker timeout (max 15 min for audit/refactor workers). The executor handles its own child process cleanup on timeout.
|
|
8
|
+
## Files Patched
|
|
9
|
+
- services/worker-daemon.js
|
|
10
|
+
## Ops
|
|
11
|
+
1 op in fix.py
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# HW-004: runWithTimeout rejects but does not kill child process
|
|
2
|
+
# GitHub: #1117
|
|
3
|
+
|
|
4
|
+
# A: Raise daemon worker timeout above max headless timeout (15 min)
|
|
5
|
+
patch("HW-004a: raise worker timeout to 16 min",
|
|
6
|
+
WD,
|
|
7
|
+
"""// Worker timeout (5 minutes max per worker)
|
|
8
|
+
const DEFAULT_WORKER_TIMEOUT_MS = 5 * 60 * 1000;""",
|
|
9
|
+
"""// Worker timeout — must exceed max headless timeout (15 min for audit/refactor)
|
|
10
|
+
const DEFAULT_WORKER_TIMEOUT_MS = 16 * 60 * 1000;""")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grep "16 \* 60 \* 1000" services/worker-daemon.js
|
package/patch-all.sh
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# patch-all.sh — Orchestrator for folder-per-defect patches
|
|
3
|
+
# Safe to run multiple times. Each fix.py is idempotent via patch()/patch_all().
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# bash patch-all.sh [--global] [--target <dir>]
|
|
7
|
+
#
|
|
8
|
+
# Options:
|
|
9
|
+
# --global Patch the npx cache (~/.npm/_npx/*)
|
|
10
|
+
# --target <dir> Patch node_modules inside <dir>
|
|
11
|
+
#
|
|
12
|
+
# If neither flag is given, --global is assumed.
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
# Parse arguments
|
|
17
|
+
DO_GLOBAL=0
|
|
18
|
+
TARGET_DIR=""
|
|
19
|
+
while [[ $# -gt 0 ]]; do
|
|
20
|
+
case $1 in
|
|
21
|
+
--global)
|
|
22
|
+
DO_GLOBAL=1
|
|
23
|
+
shift
|
|
24
|
+
;;
|
|
25
|
+
--target)
|
|
26
|
+
TARGET_DIR="${2:-}"
|
|
27
|
+
if [[ -z "$TARGET_DIR" ]]; then
|
|
28
|
+
echo "Error: --target requires a directory argument"
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
shift 2
|
|
32
|
+
;;
|
|
33
|
+
-h|--help)
|
|
34
|
+
echo "Usage: patch-all.sh [--global] [--target <dir>]"
|
|
35
|
+
echo ""
|
|
36
|
+
echo "Options:"
|
|
37
|
+
echo " --global Patch the npx cache (~/.npm/_npx/*)"
|
|
38
|
+
echo " --target <dir> Patch node_modules inside <dir>"
|
|
39
|
+
echo ""
|
|
40
|
+
echo "If neither flag is given, --global is assumed."
|
|
41
|
+
exit 0
|
|
42
|
+
;;
|
|
43
|
+
*)
|
|
44
|
+
echo "Unknown option: $1"
|
|
45
|
+
exit 1
|
|
46
|
+
;;
|
|
47
|
+
esac
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
# Default: --global when nothing specified
|
|
51
|
+
if [[ $DO_GLOBAL -eq 0 && -z "$TARGET_DIR" ]]; then
|
|
52
|
+
DO_GLOBAL=1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
56
|
+
|
|
57
|
+
# ── Find installations ──
|
|
58
|
+
|
|
59
|
+
# Global: npx cache
|
|
60
|
+
GLOBAL_CF_BASE=""
|
|
61
|
+
GLOBAL_CF_VERSION=""
|
|
62
|
+
GLOBAL_RV_CLI=""
|
|
63
|
+
|
|
64
|
+
if [[ $DO_GLOBAL -eq 1 ]]; then
|
|
65
|
+
GLOBAL_MEMORY=$(ls -t ~/.npm/_npx/*/node_modules/@claude-flow/cli/dist/src/memory/memory-initializer.js 2>/dev/null | head -1 || true)
|
|
66
|
+
if [ -n "$GLOBAL_MEMORY" ]; then
|
|
67
|
+
GLOBAL_CF_BASE=$(echo "$GLOBAL_MEMORY" | sed 's|/memory/memory-initializer.js||')
|
|
68
|
+
GLOBAL_CF_VERSION=$(grep -o '"version": "[^"]*"' "$GLOBAL_CF_BASE/../../package.json" 2>/dev/null | head -1 | cut -d'"' -f4 || echo "unknown")
|
|
69
|
+
fi
|
|
70
|
+
GLOBAL_RV_CLI=$(ls -t ~/.npm/_npx/*/node_modules/ruvector/bin/cli.js 2>/dev/null | head -1 || true)
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Target: node_modules in specified directory
|
|
74
|
+
TARGET_CF_BASE=""
|
|
75
|
+
TARGET_CF_VERSION=""
|
|
76
|
+
TARGET_RV_CLI=""
|
|
77
|
+
|
|
78
|
+
if [[ -n "$TARGET_DIR" ]]; then
|
|
79
|
+
if [[ ! -d "$TARGET_DIR" ]]; then
|
|
80
|
+
echo "Error: target directory does not exist: $TARGET_DIR"
|
|
81
|
+
exit 1
|
|
82
|
+
fi
|
|
83
|
+
TARGET_DIR="$(cd "$TARGET_DIR" && pwd)"
|
|
84
|
+
cf_path="$TARGET_DIR/node_modules/@claude-flow/cli/dist/src"
|
|
85
|
+
if [ -d "$cf_path" ]; then
|
|
86
|
+
TARGET_CF_BASE="$cf_path"
|
|
87
|
+
TARGET_CF_VERSION=$(grep -o '"version": "[^"]*"' "$TARGET_CF_BASE/../../package.json" 2>/dev/null | head -1 | cut -d'"' -f4 || echo "unknown")
|
|
88
|
+
fi
|
|
89
|
+
rv_path="$TARGET_DIR/node_modules/ruvector/bin/cli.js"
|
|
90
|
+
if [ -f "$rv_path" ]; then
|
|
91
|
+
TARGET_RV_CLI="$(cd "$(dirname "$rv_path")" && pwd)/cli.js"
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# ── Report what we found ──
|
|
96
|
+
|
|
97
|
+
TARGETS=()
|
|
98
|
+
if [[ $DO_GLOBAL -eq 1 ]]; then TARGETS+=(global); fi
|
|
99
|
+
if [[ -n "$TARGET_DIR" ]]; then TARGETS+=("$TARGET_DIR"); fi
|
|
100
|
+
echo "[PATCHES] Targets: ${TARGETS[*]}"
|
|
101
|
+
echo ""
|
|
102
|
+
|
|
103
|
+
if [[ $DO_GLOBAL -eq 1 ]]; then
|
|
104
|
+
if [ -n "$GLOBAL_CF_BASE" ]; then
|
|
105
|
+
echo " Global @claude-flow/cli: v$GLOBAL_CF_VERSION"
|
|
106
|
+
else
|
|
107
|
+
echo " Global @claude-flow/cli: not found"
|
|
108
|
+
fi
|
|
109
|
+
if [ -n "$GLOBAL_RV_CLI" ]; then
|
|
110
|
+
echo " Global ruvector: found"
|
|
111
|
+
else
|
|
112
|
+
echo " Global ruvector: not found"
|
|
113
|
+
fi
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if [[ -n "$TARGET_DIR" ]]; then
|
|
117
|
+
if [ -n "$TARGET_CF_BASE" ]; then
|
|
118
|
+
echo " Target @claude-flow/cli: v$TARGET_CF_VERSION at $TARGET_CF_BASE"
|
|
119
|
+
else
|
|
120
|
+
echo " Target @claude-flow/cli: not found in $TARGET_DIR"
|
|
121
|
+
fi
|
|
122
|
+
if [ -n "$TARGET_RV_CLI" ]; then
|
|
123
|
+
echo " Target ruvector: found at $TARGET_RV_CLI"
|
|
124
|
+
else
|
|
125
|
+
echo " Target ruvector: not found in $TARGET_DIR"
|
|
126
|
+
fi
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
echo ""
|
|
130
|
+
|
|
131
|
+
# ── Apply patches function ──
|
|
132
|
+
|
|
133
|
+
apply_patches() {
|
|
134
|
+
local base="$1"
|
|
135
|
+
local ruvector_cli="$2"
|
|
136
|
+
local label="$3"
|
|
137
|
+
|
|
138
|
+
if [ -z "$base" ] && [ -z "$ruvector_cli" ]; then
|
|
139
|
+
echo "[$label] No packages found, skipping"
|
|
140
|
+
return
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
if [ -n "$base" ]; then
|
|
144
|
+
echo "[$label] Patching @claude-flow/cli at: $base"
|
|
145
|
+
fi
|
|
146
|
+
if [ -n "$ruvector_cli" ]; then
|
|
147
|
+
echo "[$label] Patching ruvector at: $ruvector_cli"
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
export BASE="${base:-/dev/null}"
|
|
151
|
+
export RUVECTOR_CLI="$ruvector_cli"
|
|
152
|
+
|
|
153
|
+
# Dynamic discovery: concatenate common.py + all fix.py files sorted alphabetically.
|
|
154
|
+
# Alphabetical order preserves dependencies (e.g. NS-001 < NS-002 < NS-003).
|
|
155
|
+
#
|
|
156
|
+
# PATCH_INCLUDE / PATCH_EXCLUDE env vars filter by directory name regex.
|
|
157
|
+
python3 <(
|
|
158
|
+
cat "$SCRIPT_DIR/lib/common.py"
|
|
159
|
+
|
|
160
|
+
for fix in "$SCRIPT_DIR"/patch/*/fix.py; do
|
|
161
|
+
[ -f "$fix" ] || continue
|
|
162
|
+
dirname=$(basename "$(dirname "$fix")")
|
|
163
|
+
matchname="${dirname#[0-9][0-9][0-9]-}" # strip NNN- prefix for pattern matching
|
|
164
|
+
if [ -n "${PATCH_INCLUDE:-}" ] && ! echo "$matchname" | grep -qE "$PATCH_INCLUDE"; then
|
|
165
|
+
continue
|
|
166
|
+
fi
|
|
167
|
+
if [ -n "${PATCH_EXCLUDE:-}" ] && echo "$matchname" | grep -qE "$PATCH_EXCLUDE"; then
|
|
168
|
+
continue
|
|
169
|
+
fi
|
|
170
|
+
cat "$fix"
|
|
171
|
+
done
|
|
172
|
+
|
|
173
|
+
echo "print(f\"[$label] Done: {applied} applied, {skipped} already present\")"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Shell-based patches (e.g. EM-002: transformers cache permissions)
|
|
177
|
+
for fix in "$SCRIPT_DIR"/patch/*/fix.sh; do
|
|
178
|
+
[ -f "$fix" ] || continue
|
|
179
|
+
dirname=$(basename "$(dirname "$fix")")
|
|
180
|
+
matchname="${dirname#[0-9][0-9][0-9]-}" # strip NNN- prefix for pattern matching
|
|
181
|
+
if [ -n "${PATCH_INCLUDE:-}" ] && ! echo "$matchname" | grep -qE "$PATCH_INCLUDE"; then
|
|
182
|
+
continue
|
|
183
|
+
fi
|
|
184
|
+
if [ -n "${PATCH_EXCLUDE:-}" ] && echo "$matchname" | grep -qE "$PATCH_EXCLUDE"; then
|
|
185
|
+
continue
|
|
186
|
+
fi
|
|
187
|
+
bash "$fix" 2>/dev/null || true
|
|
188
|
+
done
|
|
189
|
+
|
|
190
|
+
echo ""
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# ── Apply based on flags ──
|
|
194
|
+
|
|
195
|
+
if [[ $DO_GLOBAL -eq 1 ]]; then
|
|
196
|
+
apply_patches "$GLOBAL_CF_BASE" "$GLOBAL_RV_CLI" "GLOBAL"
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
if [[ -n "$TARGET_DIR" ]]; then
|
|
200
|
+
apply_patches "$TARGET_CF_BASE" "$TARGET_RV_CLI" "TARGET"
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
echo "[PATCHES] Complete"
|