@claude-flow/cli 3.61.0 → 3.62.0
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/.claude/helpers/helpers.manifest.json +2 -2
- package/catalog-manifest.json +3 -3
- package/dist/src/mcp-tools/rure-tools.js +59 -0
- package/dist/src/rure/cuda-cubin.d.ts +7 -0
- package/dist/src/rure/cuda-cubin.js +17 -2
- package/dist/src/rure/cuda-occupancy.d.ts +59 -0
- package/dist/src/rure/cuda-occupancy.js +69 -0
- package/dist/src/rure/cuda-plan.d.ts +84 -0
- package/dist/src/rure/cuda-plan.js +197 -0
- package/dist/src/services/headless-worker-executor.js +56 -19
- package/dist/src/services/worker-daemon.d.ts +1 -0
- package/dist/src/services/worker-daemon.js +11 -2
- package/package.json +1 -1
- package/plugins/ruflo-console/dist/tui.mjs +154 -154
|
@@ -584,7 +584,12 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
584
584
|
return false;
|
|
585
585
|
}
|
|
586
586
|
clearTimeout(entry.timeout);
|
|
587
|
-
|
|
587
|
+
if (entry.abort) {
|
|
588
|
+
entry.abort();
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
this.killEntryTree(entry.process, 'SIGTERM');
|
|
592
|
+
}
|
|
588
593
|
this.processPool.delete(executionId);
|
|
589
594
|
this.emit('cancelled', { executionId });
|
|
590
595
|
// Process next in queue
|
|
@@ -600,15 +605,21 @@ export class HeadlessWorkerExecutor extends EventEmitter {
|
|
|
600
605
|
const entries = Array.from(this.processPool.entries());
|
|
601
606
|
for (const [executionId, entry] of entries) {
|
|
602
607
|
clearTimeout(entry.timeout);
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
608
|
+
if (entry.abort) {
|
|
609
|
+
// Settles the promise and owns the SIGTERM -> SIGKILL escalation (#4463).
|
|
610
|
+
entry.abort();
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
this.killEntryTree(entry.process, 'SIGTERM');
|
|
614
|
+
// SIGKILL fallback after 5s to prevent orphan processes (#1395 Bug 6)
|
|
615
|
+
setTimeout(() => {
|
|
616
|
+
try {
|
|
617
|
+
if (entry.process.exitCode === null && entry.process.signalCode === null)
|
|
618
|
+
this.killEntryTree(entry.process, 'SIGKILL');
|
|
619
|
+
}
|
|
620
|
+
catch { /* already dead */ }
|
|
621
|
+
}, 5000).unref();
|
|
622
|
+
}
|
|
612
623
|
this.emit('cancelled', { executionId });
|
|
613
624
|
cancelled++;
|
|
614
625
|
}
|
|
@@ -1075,16 +1086,31 @@ Analyze the above codebase context and provide your response following the forma
|
|
|
1075
1086
|
}
|
|
1076
1087
|
catch { /* already dead */ }
|
|
1077
1088
|
};
|
|
1089
|
+
// #4463 — `child.killed` only means a signal was delivered, not that the
|
|
1090
|
+
// child exited, so escalation keys off the exit state instead.
|
|
1091
|
+
const hasExited = () => child.exitCode !== null || child.signalCode !== null;
|
|
1092
|
+
let escalationHandle;
|
|
1093
|
+
let deadlineHandle;
|
|
1094
|
+
const terminate = () => {
|
|
1095
|
+
if (escalationHandle)
|
|
1096
|
+
return; // already signalled; never repeat SIGTERM
|
|
1097
|
+
killTree('SIGTERM');
|
|
1098
|
+
// Give it a moment to terminate gracefully, then force it.
|
|
1099
|
+
escalationHandle = setTimeout(() => {
|
|
1100
|
+
if (!hasExited())
|
|
1101
|
+
killTree('SIGKILL');
|
|
1102
|
+
}, 5000);
|
|
1103
|
+
};
|
|
1104
|
+
const stopTimers = () => {
|
|
1105
|
+
clearTimeout(escalationHandle);
|
|
1106
|
+
clearTimeout(deadlineHandle);
|
|
1107
|
+
};
|
|
1108
|
+
child.once('exit', () => clearTimeout(escalationHandle));
|
|
1109
|
+
child.once('close', stopTimers);
|
|
1078
1110
|
// Setup timeout
|
|
1079
1111
|
const timeoutHandle = setTimeout(() => {
|
|
1080
1112
|
if (this.processPool.has(options.executionId)) {
|
|
1081
|
-
|
|
1082
|
-
// Give it a moment to terminate gracefully
|
|
1083
|
-
setTimeout(() => {
|
|
1084
|
-
if (!child.killed) {
|
|
1085
|
-
killTree('SIGKILL');
|
|
1086
|
-
}
|
|
1087
|
-
}, 5000);
|
|
1113
|
+
terminate();
|
|
1088
1114
|
}
|
|
1089
1115
|
}, options.timeoutMs);
|
|
1090
1116
|
// Track in process pool
|
|
@@ -1101,8 +1127,17 @@ Analyze the above codebase context and provide your response following the forma
|
|
|
1101
1127
|
let resolved = false;
|
|
1102
1128
|
const cleanup = () => {
|
|
1103
1129
|
clearTimeout(timeoutHandle);
|
|
1130
|
+
clearTimeout(deadlineHandle);
|
|
1104
1131
|
this.processPool.delete(options.executionId);
|
|
1105
1132
|
};
|
|
1133
|
+
poolEntry.abort = () => {
|
|
1134
|
+
if (resolved)
|
|
1135
|
+
return;
|
|
1136
|
+
resolved = true;
|
|
1137
|
+
terminate();
|
|
1138
|
+
cleanup();
|
|
1139
|
+
resolve({ success: false, output: stdout || stderr, error: 'Execution cancelled' });
|
|
1140
|
+
};
|
|
1106
1141
|
child.stdout?.on('data', (data) => {
|
|
1107
1142
|
const chunk = data.toString();
|
|
1108
1143
|
stdout += chunk;
|
|
@@ -1152,13 +1187,15 @@ Analyze the above codebase context and provide your response following the forma
|
|
|
1152
1187
|
});
|
|
1153
1188
|
});
|
|
1154
1189
|
// Handle timeout
|
|
1155
|
-
setTimeout(() => {
|
|
1190
|
+
deadlineHandle = setTimeout(() => {
|
|
1156
1191
|
if (resolved)
|
|
1157
1192
|
return;
|
|
1158
1193
|
if (!this.processPool.has(options.executionId))
|
|
1159
1194
|
return;
|
|
1160
1195
|
resolved = true;
|
|
1161
|
-
|
|
1196
|
+
// Normally a no-op: the timeout handler above already signalled the
|
|
1197
|
+
// tree and owns the SIGKILL escalation (no duplicate SIGTERM).
|
|
1198
|
+
terminate();
|
|
1162
1199
|
cleanup();
|
|
1163
1200
|
resolve({
|
|
1164
1201
|
success: false,
|
|
@@ -90,6 +90,7 @@ export declare class WorkerDaemon extends EventEmitter {
|
|
|
90
90
|
private headlessInitPromise;
|
|
91
91
|
private originalConfig?;
|
|
92
92
|
private fileConfigResourceThresholds?;
|
|
93
|
+
private fileConfigScalars?;
|
|
93
94
|
private gitIdentity;
|
|
94
95
|
private lastSupervisorRenewalMs;
|
|
95
96
|
constructor(projectRoot: string, config?: Partial<DaemonConfig>);
|
|
@@ -143,6 +143,8 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
143
143
|
// originalConfig — so a config.json override kept losing to whatever
|
|
144
144
|
// .claude-flow/daemon-state.json had persisted from a previous run.
|
|
145
145
|
fileConfigResourceThresholds;
|
|
146
|
+
// #4462 — the same record for maxConcurrent / workerTimeoutMs.
|
|
147
|
+
fileConfigScalars;
|
|
146
148
|
// #2661 root-fix — resolved once (git identity doesn't change at runtime)
|
|
147
149
|
// and reused for lease heartbeats + supervisor election, both gated on
|
|
148
150
|
// aiWorkersEnabled since they only matter for the recurring AI schedule.
|
|
@@ -161,6 +163,7 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
161
163
|
maxCpuLoad: fileConfig.maxCpuLoad,
|
|
162
164
|
minFreeMemoryPercent: fileConfig.minFreeMemoryPercent,
|
|
163
165
|
};
|
|
166
|
+
this.fileConfigScalars = { maxConcurrent: fileConfig.maxConcurrent, workerTimeoutMs: fileConfig.workerTimeoutMs };
|
|
164
167
|
// CPU-proportional smart default instead of hardcoded 2.0
|
|
165
168
|
const cpuCount = WorkerDaemon.getEffectiveCpuCount();
|
|
166
169
|
let smartMaxCpuLoad = Math.max(cpuCount * 0.8, 2.0); // Floor of 2.0 for single-CPU machines
|
|
@@ -691,10 +694,16 @@ export class WorkerDaemon extends EventEmitter {
|
|
|
691
694
|
this.config.resourceThresholds.minFreeMemoryPercent = rt.minFreeMemoryPercent;
|
|
692
695
|
}
|
|
693
696
|
}
|
|
694
|
-
|
|
697
|
+
// #4462 — same rule for the two scalar fields: constructor arg or
|
|
698
|
+
// config.json beats saved state, which only fills in what neither set.
|
|
699
|
+
const maxConcurrentExplicit = this.originalConfig?.maxConcurrent !== undefined
|
|
700
|
+
|| this.fileConfigScalars?.maxConcurrent !== undefined;
|
|
701
|
+
const workerTimeoutExplicit = this.originalConfig?.workerTimeoutMs !== undefined
|
|
702
|
+
|| this.fileConfigScalars?.workerTimeoutMs !== undefined;
|
|
703
|
+
if (!maxConcurrentExplicit && typeof saved.config?.maxConcurrent === 'number' && saved.config.maxConcurrent > 0) {
|
|
695
704
|
this.config.maxConcurrent = saved.config.maxConcurrent;
|
|
696
705
|
}
|
|
697
|
-
if (typeof saved.config?.workerTimeoutMs === 'number' && saved.config.workerTimeoutMs > 0) {
|
|
706
|
+
if (!workerTimeoutExplicit && typeof saved.config?.workerTimeoutMs === 'number' && saved.config.workerTimeoutMs > 0) {
|
|
698
707
|
this.config.workerTimeoutMs = saved.config.workerTimeoutMs;
|
|
699
708
|
}
|
|
700
709
|
// Restore worker runtime states (runCount, successCount, etc.)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.62.0",
|
|
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",
|