claude-flow 3.7.0-alpha.80 → 3.7.0-alpha.81
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/package.json +1 -1
- package/v3/@claude-flow/cli/dist/src/services/headless-worker-executor.d.ts +14 -1
- package/v3/@claude-flow/cli/dist/src/services/headless-worker-executor.js +28 -7
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +12 -0
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.js +68 -14
- package/v3/@claude-flow/cli/package.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.7.0-alpha.
|
|
3
|
+
"version": "3.7.0-alpha.81",
|
|
4
4
|
"description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -208,7 +208,20 @@ export declare class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
208
208
|
private claudeCodeVersion;
|
|
209
209
|
constructor(projectRoot: string, options?: HeadlessExecutorConfig);
|
|
210
210
|
/**
|
|
211
|
-
* Check if Claude Code CLI is available
|
|
211
|
+
* Check if Claude Code CLI is available.
|
|
212
|
+
*
|
|
213
|
+
* #2110 fix — three issues addressed:
|
|
214
|
+
* 1. Cache only `true`, never `false`. A transient failure (WSL2 cold
|
|
215
|
+
* start, AV scanner, slow shell init) used to set
|
|
216
|
+
* `claudeCodeAvailable = false` for the rest of the daemon
|
|
217
|
+
* lifetime, so the daemon kept running local stubs even after the
|
|
218
|
+
* user fixed `claude auth login`. Now: false results re-probe on
|
|
219
|
+
* the next call.
|
|
220
|
+
* 2. Log the actual error from the catch block instead of silently
|
|
221
|
+
* swallowing it. Operators couldn't distinguish timeout / ENOENT /
|
|
222
|
+
* auth-failure / exit-code without this.
|
|
223
|
+
* 3. Honour `CLAUDE_CODE_AVAILABILITY_TIMEOUT_MS` for WSL2 / slow
|
|
224
|
+
* systems where `claude --version` can take >5s on first invoke.
|
|
212
225
|
*/
|
|
213
226
|
isAvailable(): Promise<boolean>;
|
|
214
227
|
/**
|
|
@@ -387,17 +387,33 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
387
387
|
// Public API
|
|
388
388
|
// ============================================
|
|
389
389
|
/**
|
|
390
|
-
* Check if Claude Code CLI is available
|
|
390
|
+
* Check if Claude Code CLI is available.
|
|
391
|
+
*
|
|
392
|
+
* #2110 fix — three issues addressed:
|
|
393
|
+
* 1. Cache only `true`, never `false`. A transient failure (WSL2 cold
|
|
394
|
+
* start, AV scanner, slow shell init) used to set
|
|
395
|
+
* `claudeCodeAvailable = false` for the rest of the daemon
|
|
396
|
+
* lifetime, so the daemon kept running local stubs even after the
|
|
397
|
+
* user fixed `claude auth login`. Now: false results re-probe on
|
|
398
|
+
* the next call.
|
|
399
|
+
* 2. Log the actual error from the catch block instead of silently
|
|
400
|
+
* swallowing it. Operators couldn't distinguish timeout / ENOENT /
|
|
401
|
+
* auth-failure / exit-code without this.
|
|
402
|
+
* 3. Honour `CLAUDE_CODE_AVAILABILITY_TIMEOUT_MS` for WSL2 / slow
|
|
403
|
+
* systems where `claude --version` can take >5s on first invoke.
|
|
391
404
|
*/
|
|
392
405
|
async isAvailable() {
|
|
393
|
-
|
|
394
|
-
|
|
406
|
+
// Only the `true` result is cached — `false` is re-probed every call
|
|
407
|
+
// so a transient failure doesn't poison the rest of the daemon's life.
|
|
408
|
+
if (this.claudeCodeAvailable === true) {
|
|
409
|
+
return true;
|
|
395
410
|
}
|
|
411
|
+
const timeoutMs = Number.parseInt(process.env.CLAUDE_CODE_AVAILABILITY_TIMEOUT_MS || '', 10) || 5000;
|
|
396
412
|
try {
|
|
397
413
|
const output = execSync('claude --version', {
|
|
398
414
|
encoding: 'utf-8',
|
|
399
415
|
stdio: 'pipe',
|
|
400
|
-
timeout:
|
|
416
|
+
timeout: timeoutMs,
|
|
401
417
|
windowsHide: true, // Prevent phantom console windows on Windows
|
|
402
418
|
});
|
|
403
419
|
this.claudeCodeAvailable = true;
|
|
@@ -405,9 +421,14 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
405
421
|
this.emit('status', { available: true, version: this.claudeCodeVersion });
|
|
406
422
|
return true;
|
|
407
423
|
}
|
|
408
|
-
catch {
|
|
409
|
-
|
|
410
|
-
|
|
424
|
+
catch (err) {
|
|
425
|
+
// Don't cache false — let the next call retry. Surface the actual
|
|
426
|
+
// error via emit so operators can diagnose timeout / ENOENT / auth.
|
|
427
|
+
this.claudeCodeAvailable = null;
|
|
428
|
+
const reason = err instanceof Error
|
|
429
|
+
? `${err.name}: ${err.message}`.slice(0, 200)
|
|
430
|
+
: String(err).slice(0, 200);
|
|
431
|
+
this.emit('status', { available: false, reason });
|
|
411
432
|
return false;
|
|
412
433
|
}
|
|
413
434
|
}
|
|
@@ -94,6 +94,18 @@ export declare class WorkerDaemon extends EventEmitter {
|
|
|
94
94
|
* cgroup v2 / v1 quota files first so the maxCpuLoad threshold stays
|
|
95
95
|
* meaningful under resource-limited containers.
|
|
96
96
|
*/
|
|
97
|
+
/**
|
|
98
|
+
* #2110 — detect WSL2 / WSL1 so the CPU-load gate can use a sane
|
|
99
|
+
* default. `/proc/loadavg` on WSL maps in Windows-side process counts
|
|
100
|
+
* and routinely reports values 100-1000x larger than real Linux load.
|
|
101
|
+
*
|
|
102
|
+
* Detection order:
|
|
103
|
+
* 1. `WSL_DISTRO_NAME` env var (set by Microsoft's WSL launcher)
|
|
104
|
+
* 2. `WSL_INTEROP` env var (set by recent WSL2)
|
|
105
|
+
* 3. `/proc/sys/kernel/osrelease` contains "microsoft" or "WSL"
|
|
106
|
+
* (kernel build marker; survives env stripping)
|
|
107
|
+
*/
|
|
108
|
+
static isWslEnvironment(): boolean;
|
|
97
109
|
static getEffectiveCpuCount(): number;
|
|
98
110
|
/**
|
|
99
111
|
* Read daemon-specific config from .claude-flow/config.{json,yaml,yml}.
|
|
@@ -57,7 +57,18 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
57
57
|
const fileConfig = this.readDaemonConfigFromFile(claudeFlowDir);
|
|
58
58
|
// CPU-proportional smart default instead of hardcoded 2.0
|
|
59
59
|
const cpuCount = WorkerDaemon.getEffectiveCpuCount();
|
|
60
|
-
|
|
60
|
+
let smartMaxCpuLoad = Math.max(cpuCount * 0.8, 2.0); // Floor of 2.0 for single-CPU machines
|
|
61
|
+
// #2110 — WSL2 reports `/proc/loadavg` values that include Windows-side
|
|
62
|
+
// process counts mapped into the Linux kernel. Real load on a 4-CPU
|
|
63
|
+
// WSL2 host can be 200-400 even when the Linux side is idle. The
|
|
64
|
+
// default gate of `cpuCount * 0.8` always trips, deferring every
|
|
65
|
+
// worker as "CPU load too high" while the daemon reports healthy.
|
|
66
|
+
// Bump the floor to 1000 when WSL is detected so the gate is
|
|
67
|
+
// effectively disabled (real load on Linux side rarely exceeds 100
|
|
68
|
+
// even under heavy contention).
|
|
69
|
+
if (WorkerDaemon.isWslEnvironment()) {
|
|
70
|
+
smartMaxCpuLoad = Math.max(smartMaxCpuLoad, 1000);
|
|
71
|
+
}
|
|
61
72
|
// Platform-aware default: macOS os.freemem() excludes reclaimable file cache,
|
|
62
73
|
// so reported "free" is much lower than actually available memory.
|
|
63
74
|
// Linux reports available memory (including reclaimable cache) more accurately.
|
|
@@ -155,6 +166,28 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
155
166
|
* cgroup v2 / v1 quota files first so the maxCpuLoad threshold stays
|
|
156
167
|
* meaningful under resource-limited containers.
|
|
157
168
|
*/
|
|
169
|
+
/**
|
|
170
|
+
* #2110 — detect WSL2 / WSL1 so the CPU-load gate can use a sane
|
|
171
|
+
* default. `/proc/loadavg` on WSL maps in Windows-side process counts
|
|
172
|
+
* and routinely reports values 100-1000x larger than real Linux load.
|
|
173
|
+
*
|
|
174
|
+
* Detection order:
|
|
175
|
+
* 1. `WSL_DISTRO_NAME` env var (set by Microsoft's WSL launcher)
|
|
176
|
+
* 2. `WSL_INTEROP` env var (set by recent WSL2)
|
|
177
|
+
* 3. `/proc/sys/kernel/osrelease` contains "microsoft" or "WSL"
|
|
178
|
+
* (kernel build marker; survives env stripping)
|
|
179
|
+
*/
|
|
180
|
+
static isWslEnvironment() {
|
|
181
|
+
if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP)
|
|
182
|
+
return true;
|
|
183
|
+
try {
|
|
184
|
+
const osrelease = readFileSync('/proc/sys/kernel/osrelease', 'utf8').toLowerCase();
|
|
185
|
+
if (osrelease.includes('microsoft') || osrelease.includes('wsl'))
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
catch { /* not on Linux or /proc inaccessible */ }
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
158
191
|
static getEffectiveCpuCount() {
|
|
159
192
|
// 1. Try cgroup v2: /sys/fs/cgroup/cpu.max
|
|
160
193
|
try {
|
|
@@ -909,21 +942,42 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
909
942
|
try {
|
|
910
943
|
this.log('info', `Running ${workerConfig.type} in headless mode (Claude Code AI)`);
|
|
911
944
|
const result = await this.headlessExecutor.execute(workerConfig.type);
|
|
912
|
-
// #
|
|
913
|
-
//
|
|
914
|
-
//
|
|
915
|
-
// never
|
|
916
|
-
//
|
|
917
|
-
|
|
918
|
-
|
|
945
|
+
// #2110 — `HeadlessWorkerExecutor.execute()` returns
|
|
946
|
+
// `createErrorResult(...)` with `success: false` when
|
|
947
|
+
// `isAvailable()` is false, instead of throwing. The previous
|
|
948
|
+
// try/catch never fired in that path, and the result was
|
|
949
|
+
// persisted as mode:"headless" despite being a stub. Downstream
|
|
950
|
+
// dashboards / `memory stats` couldn't distinguish a real AI
|
|
951
|
+
// run from a fallback. Treat falsy success the same as throw.
|
|
952
|
+
const ok = result?.success === true;
|
|
953
|
+
if (!ok) {
|
|
954
|
+
const reason = result?.error ||
|
|
955
|
+
result?.note ||
|
|
956
|
+
'headless executor reported success=false';
|
|
957
|
+
this.log('warn', `Headless ${workerConfig.type} returned success=false (${String(reason).slice(0, 200)}); falling back to local mode`);
|
|
958
|
+
this.emit('headless:fallback', {
|
|
959
|
+
type: workerConfig.type,
|
|
960
|
+
error: String(reason).slice(0, 500),
|
|
961
|
+
});
|
|
962
|
+
// Fall through to local switch.
|
|
919
963
|
}
|
|
920
|
-
|
|
921
|
-
|
|
964
|
+
else {
|
|
965
|
+
// #1793: persist the headless result to the same metrics files the
|
|
966
|
+
// local workers write to. Without this, AI-mode runs produced rich
|
|
967
|
+
// parsedOutput that lived only in `.claude-flow/logs/headless/*` and
|
|
968
|
+
// never reached `.claude-flow/metrics/<name>.json` — `memory stats`
|
|
969
|
+
// and downstream consumers saw nothing despite successful runs.
|
|
970
|
+
try {
|
|
971
|
+
this.persistHeadlessResult(workerConfig.type, result);
|
|
972
|
+
}
|
|
973
|
+
catch (persistError) {
|
|
974
|
+
this.log('warn', `Failed to persist headless result for ${workerConfig.type}: ${persistError.message}`);
|
|
975
|
+
}
|
|
976
|
+
return {
|
|
977
|
+
mode: 'headless',
|
|
978
|
+
...result,
|
|
979
|
+
};
|
|
922
980
|
}
|
|
923
|
-
return {
|
|
924
|
-
mode: 'headless',
|
|
925
|
-
...result,
|
|
926
|
-
};
|
|
927
981
|
}
|
|
928
982
|
catch (error) {
|
|
929
983
|
this.log('warn', `Headless execution failed for ${workerConfig.type}, falling back to local mode`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.7.0-alpha.
|
|
3
|
+
"version": "3.7.0-alpha.81",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|