@claude-flow/cli 3.0.0-alpha.13 → 3.0.0-alpha.15
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/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +75 -2
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -4
- package/.agentic-flow/intelligence.json +0 -17
- package/.claude-flow/agents/store.json +0 -16
- package/.claude-flow/daemon-state.json +0 -123
- package/.claude-flow/daemon-test.log +0 -0
- package/.claude-flow/daemon.log +0 -0
- package/.claude-flow/daemon2.log +0 -0
- package/.claude-flow/daemon3.log +0 -0
- package/.claude-flow/hive-mind/state.json +0 -51
- package/.claude-flow/metrics/agent-metrics.json +0 -1
- package/.claude-flow/metrics/codebase-map.json +0 -11
- package/.claude-flow/metrics/consolidation.json +0 -6
- package/.claude-flow/metrics/performance.json +0 -87
- package/.claude-flow/metrics/security-audit.json +0 -10
- package/.claude-flow/metrics/task-metrics.json +0 -10
- package/.claude-flow/metrics/test-gaps.json +0 -6
- package/__tests__/README.md +0 -140
- package/__tests__/TEST_SUMMARY.md +0 -144
- package/__tests__/cli.test.ts +0 -558
- package/__tests__/commands.test.ts +0 -726
- package/__tests__/config-adapter.test.ts +0 -362
- package/__tests__/config-loading.test.ts +0 -106
- package/__tests__/coverage/.tmp/coverage-0.json +0 -1
- package/__tests__/coverage/.tmp/coverage-1.json +0 -1
- package/__tests__/coverage/.tmp/coverage-2.json +0 -1
- package/__tests__/coverage/.tmp/coverage-3.json +0 -1
- package/__tests__/coverage/.tmp/coverage-4.json +0 -1
- package/__tests__/coverage/.tmp/coverage-5.json +0 -1
- package/__tests__/mcp-client.test.ts +0 -480
- package/__tests__/p1-commands.test.ts +0 -1064
- package/agents/architect.yaml +0 -11
- package/agents/coder.yaml +0 -11
- package/agents/reviewer.yaml +0 -10
- package/agents/security-architect.yaml +0 -10
- package/agents/tester.yaml +0 -10
- package/docs/CONFIG_LOADING.md +0 -236
- package/docs/IMPLEMENTATION_COMPLETE.md +0 -421
- package/docs/MCP_CLIENT_GUIDE.md +0 -620
- package/docs/REFACTORING_SUMMARY.md +0 -247
- package/scripts/publish.sh +0 -46
- package/src/commands/agent.ts +0 -955
- package/src/commands/claims.ts +0 -317
- package/src/commands/completions.ts +0 -558
- package/src/commands/config.ts +0 -452
- package/src/commands/daemon.ts +0 -621
- package/src/commands/deployment.ts +0 -323
- package/src/commands/doctor.ts +0 -382
- package/src/commands/embeddings.ts +0 -686
- package/src/commands/hive-mind.ts +0 -928
- package/src/commands/hooks.ts +0 -2603
- package/src/commands/index.ts +0 -154
- package/src/commands/init.ts +0 -597
- package/src/commands/mcp.ts +0 -753
- package/src/commands/memory.ts +0 -1161
- package/src/commands/migrate.ts +0 -447
- package/src/commands/neural.ts +0 -253
- package/src/commands/performance.ts +0 -292
- package/src/commands/plugins.ts +0 -316
- package/src/commands/process.ts +0 -695
- package/src/commands/providers.ts +0 -259
- package/src/commands/security.ts +0 -288
- package/src/commands/session.ts +0 -891
- package/src/commands/start.ts +0 -457
- package/src/commands/status.ts +0 -736
- package/src/commands/swarm.ts +0 -648
- package/src/commands/task.ts +0 -792
- package/src/commands/workflow.ts +0 -742
- package/src/config-adapter.ts +0 -210
- package/src/index.ts +0 -443
- package/src/infrastructure/in-memory-repositories.ts +0 -310
- package/src/init/claudemd-generator.ts +0 -631
- package/src/init/executor.ts +0 -762
- package/src/init/helpers-generator.ts +0 -628
- package/src/init/index.ts +0 -60
- package/src/init/mcp-generator.ts +0 -83
- package/src/init/settings-generator.ts +0 -284
- package/src/init/statusline-generator.ts +0 -211
- package/src/init/types.ts +0 -447
- package/src/mcp-client.ts +0 -241
- package/src/mcp-server.ts +0 -577
- package/src/mcp-tools/agent-tools.ts +0 -466
- package/src/mcp-tools/config-tools.ts +0 -370
- package/src/mcp-tools/hive-mind-tools.ts +0 -521
- package/src/mcp-tools/hooks-tools.ts +0 -1888
- package/src/mcp-tools/index.ts +0 -16
- package/src/mcp-tools/memory-tools.ts +0 -270
- package/src/mcp-tools/session-tools.ts +0 -359
- package/src/mcp-tools/swarm-tools.ts +0 -105
- package/src/mcp-tools/task-tools.ts +0 -347
- package/src/mcp-tools/types.ts +0 -33
- package/src/mcp-tools/workflow-tools.ts +0 -573
- package/src/output.ts +0 -639
- package/src/parser.ts +0 -417
- package/src/prompt.ts +0 -619
- package/src/services/index.ts +0 -15
- package/src/services/worker-daemon.ts +0 -726
- package/src/suggest.ts +0 -245
- package/src/types.ts +0 -287
- package/tmp.json +0 -0
- package/tsconfig.json +0 -16
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -13
package/src/commands/daemon.ts
DELETED
|
@@ -1,621 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* V3 CLI Daemon Command
|
|
3
|
-
* Manages background worker daemon (Node.js-based, similar to shell helpers)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Command, CommandContext, CommandResult } from '../types.js';
|
|
7
|
-
import { output } from '../output.js';
|
|
8
|
-
import { WorkerDaemon, getDaemon, startDaemon, stopDaemon, type WorkerType } from '../services/worker-daemon.js';
|
|
9
|
-
import { spawn } from 'child_process';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
11
|
-
import { dirname, join } from 'path';
|
|
12
|
-
import * as fs from 'fs';
|
|
13
|
-
|
|
14
|
-
// Start daemon subcommand
|
|
15
|
-
const startCommand: Command = {
|
|
16
|
-
name: 'start',
|
|
17
|
-
description: 'Start the worker daemon with all enabled background workers',
|
|
18
|
-
options: [
|
|
19
|
-
{ name: 'workers', short: 'w', type: 'string', description: 'Comma-separated list of workers to enable (default: map,audit,optimize,consolidate,testgaps)' },
|
|
20
|
-
{ name: 'quiet', short: 'q', type: 'boolean', description: 'Suppress output' },
|
|
21
|
-
{ name: 'background', short: 'b', type: 'boolean', description: 'Run daemon in background (detached process)', default: true },
|
|
22
|
-
{ name: 'foreground', short: 'f', type: 'boolean', description: 'Run daemon in foreground (blocks terminal)' },
|
|
23
|
-
],
|
|
24
|
-
examples: [
|
|
25
|
-
{ command: 'claude-flow daemon start', description: 'Start daemon in background (default)' },
|
|
26
|
-
{ command: 'claude-flow daemon start --foreground', description: 'Start in foreground (blocks terminal)' },
|
|
27
|
-
{ command: 'claude-flow daemon start -w map,audit,optimize', description: 'Start with specific workers' },
|
|
28
|
-
],
|
|
29
|
-
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
30
|
-
const quiet = ctx.flags.quiet as boolean;
|
|
31
|
-
const foreground = ctx.flags.foreground as boolean;
|
|
32
|
-
const projectRoot = process.cwd();
|
|
33
|
-
const isDaemonProcess = process.env.CLAUDE_FLOW_DAEMON === '1';
|
|
34
|
-
|
|
35
|
-
// Check if background daemon already running (skip if we ARE the daemon process)
|
|
36
|
-
if (!isDaemonProcess) {
|
|
37
|
-
const bgPid = getBackgroundDaemonPid(projectRoot);
|
|
38
|
-
if (bgPid && isProcessRunning(bgPid)) {
|
|
39
|
-
if (!quiet) {
|
|
40
|
-
output.printWarning(`Daemon already running in background (PID: ${bgPid})`);
|
|
41
|
-
}
|
|
42
|
-
return { success: true };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Background mode (default): fork a detached process
|
|
47
|
-
if (!foreground) {
|
|
48
|
-
return startBackgroundDaemon(projectRoot, quiet);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Foreground mode: run in current process (blocks terminal)
|
|
52
|
-
try {
|
|
53
|
-
const stateDir = join(projectRoot, '.claude-flow');
|
|
54
|
-
const pidFile = join(stateDir, 'daemon.pid');
|
|
55
|
-
|
|
56
|
-
// Ensure state directory exists
|
|
57
|
-
if (!fs.existsSync(stateDir)) {
|
|
58
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Write PID file for foreground mode
|
|
62
|
-
fs.writeFileSync(pidFile, String(process.pid));
|
|
63
|
-
|
|
64
|
-
// Clean up PID file on exit
|
|
65
|
-
const cleanup = () => {
|
|
66
|
-
try {
|
|
67
|
-
if (fs.existsSync(pidFile)) {
|
|
68
|
-
fs.unlinkSync(pidFile);
|
|
69
|
-
}
|
|
70
|
-
} catch { /* ignore */ }
|
|
71
|
-
};
|
|
72
|
-
process.on('exit', cleanup);
|
|
73
|
-
process.on('SIGINT', () => { cleanup(); process.exit(0); });
|
|
74
|
-
process.on('SIGTERM', () => { cleanup(); process.exit(0); });
|
|
75
|
-
|
|
76
|
-
if (!quiet) {
|
|
77
|
-
const spinner = output.createSpinner({ text: 'Starting worker daemon...', spinner: 'dots' });
|
|
78
|
-
spinner.start();
|
|
79
|
-
|
|
80
|
-
const daemon = await startDaemon(projectRoot);
|
|
81
|
-
const status = daemon.getStatus();
|
|
82
|
-
|
|
83
|
-
spinner.succeed('Worker daemon started (foreground mode)');
|
|
84
|
-
|
|
85
|
-
output.writeln();
|
|
86
|
-
output.printBox(
|
|
87
|
-
[
|
|
88
|
-
`PID: ${status.pid}`,
|
|
89
|
-
`Started: ${status.startedAt?.toISOString()}`,
|
|
90
|
-
`Workers: ${status.config.workers.filter(w => w.enabled).length} enabled`,
|
|
91
|
-
`Max Concurrent: ${status.config.maxConcurrent}`,
|
|
92
|
-
].join('\n'),
|
|
93
|
-
'Daemon Status'
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
output.writeln();
|
|
97
|
-
output.writeln(output.bold('Scheduled Workers'));
|
|
98
|
-
output.printTable({
|
|
99
|
-
columns: [
|
|
100
|
-
{ key: 'type', header: 'Worker', width: 15 },
|
|
101
|
-
{ key: 'interval', header: 'Interval', width: 12 },
|
|
102
|
-
{ key: 'priority', header: 'Priority', width: 10 },
|
|
103
|
-
{ key: 'description', header: 'Description', width: 30 },
|
|
104
|
-
],
|
|
105
|
-
data: status.config.workers
|
|
106
|
-
.filter(w => w.enabled)
|
|
107
|
-
.map(w => ({
|
|
108
|
-
type: output.highlight(w.type),
|
|
109
|
-
interval: `${Math.round(w.intervalMs / 60000)}min`,
|
|
110
|
-
priority: w.priority === 'critical' ? output.error(w.priority) :
|
|
111
|
-
w.priority === 'high' ? output.warning(w.priority) :
|
|
112
|
-
output.dim(w.priority),
|
|
113
|
-
description: w.description,
|
|
114
|
-
})),
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
output.writeln();
|
|
118
|
-
output.writeln(output.dim('Press Ctrl+C to stop daemon'));
|
|
119
|
-
|
|
120
|
-
// Listen for worker events
|
|
121
|
-
daemon.on('worker:start', ({ type }: { type: string }) => {
|
|
122
|
-
output.writeln(output.dim(`[daemon] Worker starting: ${type}`));
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
daemon.on('worker:complete', ({ type, durationMs }: { type: string; durationMs: number }) => {
|
|
126
|
-
output.writeln(output.success(`[daemon] Worker completed: ${type} (${durationMs}ms)`));
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
daemon.on('worker:error', ({ type, error }: { type: string; error: string }) => {
|
|
130
|
-
output.writeln(output.error(`[daemon] Worker failed: ${type} - ${error}`));
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Keep process alive
|
|
134
|
-
await new Promise(() => {}); // Never resolves - daemon runs until killed
|
|
135
|
-
} else {
|
|
136
|
-
await startDaemon(projectRoot);
|
|
137
|
-
await new Promise(() => {}); // Keep alive
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return { success: true };
|
|
141
|
-
} catch (error) {
|
|
142
|
-
output.printError(`Failed to start daemon: ${error instanceof Error ? error.message : String(error)}`);
|
|
143
|
-
return { success: false, exitCode: 1 };
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Start daemon as a detached background process
|
|
150
|
-
*/
|
|
151
|
-
async function startBackgroundDaemon(projectRoot: string, quiet: boolean): Promise<CommandResult> {
|
|
152
|
-
const stateDir = join(projectRoot, '.claude-flow');
|
|
153
|
-
const pidFile = join(stateDir, 'daemon.pid');
|
|
154
|
-
const logFile = join(stateDir, 'daemon.log');
|
|
155
|
-
|
|
156
|
-
// Ensure state directory exists
|
|
157
|
-
if (!fs.existsSync(stateDir)) {
|
|
158
|
-
fs.mkdirSync(stateDir, { recursive: true });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Get path to CLI (from dist/src/commands/daemon.js -> bin/cli.js)
|
|
162
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
163
|
-
const __dirname = dirname(__filename);
|
|
164
|
-
// dist/src/commands -> dist/src -> dist -> package root -> bin/cli.js
|
|
165
|
-
const cliPath = join(__dirname, '..', '..', '..', 'bin', 'cli.js');
|
|
166
|
-
|
|
167
|
-
// Verify CLI path exists
|
|
168
|
-
if (!fs.existsSync(cliPath)) {
|
|
169
|
-
output.printError(`CLI not found at: ${cliPath}`);
|
|
170
|
-
return { success: false, exitCode: 1 };
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Use shell to spawn daemon with proper output redirection
|
|
174
|
-
// This ensures the log file stays open even after parent exits
|
|
175
|
-
const shellCmd = `"${process.execPath}" "${cliPath}" daemon start --foreground --quiet >> "${logFile}" 2>&1 & echo $!`;
|
|
176
|
-
|
|
177
|
-
const child = spawn('sh', ['-c', shellCmd], {
|
|
178
|
-
cwd: projectRoot,
|
|
179
|
-
detached: true,
|
|
180
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
181
|
-
env: { ...process.env, CLAUDE_FLOW_DAEMON: '1' },
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// Wait for the PID to be echoed back
|
|
185
|
-
return new Promise((resolve) => {
|
|
186
|
-
let pidStr = '';
|
|
187
|
-
child.stdout?.on('data', (data: Buffer) => {
|
|
188
|
-
pidStr += data.toString();
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
child.on('close', () => {
|
|
192
|
-
const pid = parseInt(pidStr.trim(), 10);
|
|
193
|
-
|
|
194
|
-
if (isNaN(pid) || pid <= 0) {
|
|
195
|
-
output.printError('Failed to get daemon PID');
|
|
196
|
-
resolve({ success: false, exitCode: 1 });
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Save PID
|
|
201
|
-
fs.writeFileSync(pidFile, String(pid));
|
|
202
|
-
|
|
203
|
-
if (!quiet) {
|
|
204
|
-
output.printSuccess(`Daemon started in background (PID: ${pid})`);
|
|
205
|
-
output.printInfo(`Logs: ${logFile}`);
|
|
206
|
-
output.printInfo(`Stop with: claude-flow daemon stop`);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
resolve({ success: true });
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// Unref so parent can exit immediately
|
|
213
|
-
child.unref();
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Stop daemon subcommand
|
|
218
|
-
const stopCommand: Command = {
|
|
219
|
-
name: 'stop',
|
|
220
|
-
description: 'Stop the worker daemon and all background workers',
|
|
221
|
-
options: [
|
|
222
|
-
{ name: 'quiet', short: 'q', type: 'boolean', description: 'Suppress output' },
|
|
223
|
-
],
|
|
224
|
-
examples: [
|
|
225
|
-
{ command: 'claude-flow daemon stop', description: 'Stop the daemon' },
|
|
226
|
-
],
|
|
227
|
-
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
228
|
-
const quiet = ctx.flags.quiet as boolean;
|
|
229
|
-
const projectRoot = process.cwd();
|
|
230
|
-
|
|
231
|
-
try {
|
|
232
|
-
if (!quiet) {
|
|
233
|
-
const spinner = output.createSpinner({ text: 'Stopping worker daemon...', spinner: 'dots' });
|
|
234
|
-
spinner.start();
|
|
235
|
-
|
|
236
|
-
// Try to stop in-process daemon first
|
|
237
|
-
await stopDaemon();
|
|
238
|
-
|
|
239
|
-
// Also kill any background daemon by PID
|
|
240
|
-
const killed = await killBackgroundDaemon(projectRoot);
|
|
241
|
-
|
|
242
|
-
spinner.succeed(killed ? 'Worker daemon stopped' : 'Worker daemon was not running');
|
|
243
|
-
} else {
|
|
244
|
-
await stopDaemon();
|
|
245
|
-
await killBackgroundDaemon(projectRoot);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return { success: true };
|
|
249
|
-
} catch (error) {
|
|
250
|
-
output.printError(`Failed to stop daemon: ${error instanceof Error ? error.message : String(error)}`);
|
|
251
|
-
return { success: false, exitCode: 1 };
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Kill background daemon process using PID file
|
|
258
|
-
*/
|
|
259
|
-
async function killBackgroundDaemon(projectRoot: string): Promise<boolean> {
|
|
260
|
-
const pidFile = join(projectRoot, '.claude-flow', 'daemon.pid');
|
|
261
|
-
|
|
262
|
-
if (!fs.existsSync(pidFile)) {
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
try {
|
|
267
|
-
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
268
|
-
|
|
269
|
-
if (isNaN(pid)) {
|
|
270
|
-
fs.unlinkSync(pidFile);
|
|
271
|
-
return false;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Check if process is running
|
|
275
|
-
try {
|
|
276
|
-
process.kill(pid, 0); // Signal 0 = check if alive
|
|
277
|
-
} catch {
|
|
278
|
-
// Process not running, clean up stale PID file
|
|
279
|
-
fs.unlinkSync(pidFile);
|
|
280
|
-
return false;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Kill the process
|
|
284
|
-
process.kill(pid, 'SIGTERM');
|
|
285
|
-
|
|
286
|
-
// Wait a moment then force kill if needed
|
|
287
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
288
|
-
|
|
289
|
-
try {
|
|
290
|
-
process.kill(pid, 0);
|
|
291
|
-
// Still alive, force kill
|
|
292
|
-
process.kill(pid, 'SIGKILL');
|
|
293
|
-
} catch {
|
|
294
|
-
// Process terminated
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Clean up PID file
|
|
298
|
-
if (fs.existsSync(pidFile)) {
|
|
299
|
-
fs.unlinkSync(pidFile);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return true;
|
|
303
|
-
} catch (error) {
|
|
304
|
-
// Clean up PID file on any error
|
|
305
|
-
if (fs.existsSync(pidFile)) {
|
|
306
|
-
fs.unlinkSync(pidFile);
|
|
307
|
-
}
|
|
308
|
-
return false;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Get PID of background daemon from PID file
|
|
314
|
-
*/
|
|
315
|
-
function getBackgroundDaemonPid(projectRoot: string): number | null {
|
|
316
|
-
const pidFile = join(projectRoot, '.claude-flow', 'daemon.pid');
|
|
317
|
-
|
|
318
|
-
if (!fs.existsSync(pidFile)) {
|
|
319
|
-
return null;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
try {
|
|
323
|
-
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
324
|
-
return isNaN(pid) ? null : pid;
|
|
325
|
-
} catch {
|
|
326
|
-
return null;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Check if a process is running
|
|
332
|
-
*/
|
|
333
|
-
function isProcessRunning(pid: number): boolean {
|
|
334
|
-
try {
|
|
335
|
-
process.kill(pid, 0); // Signal 0 = check if alive
|
|
336
|
-
return true;
|
|
337
|
-
} catch {
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Status subcommand
|
|
343
|
-
const statusCommand: Command = {
|
|
344
|
-
name: 'status',
|
|
345
|
-
description: 'Show daemon and worker status',
|
|
346
|
-
options: [
|
|
347
|
-
{ name: 'verbose', short: 'v', type: 'boolean', description: 'Show detailed worker statistics' },
|
|
348
|
-
],
|
|
349
|
-
examples: [
|
|
350
|
-
{ command: 'claude-flow daemon status', description: 'Show daemon status' },
|
|
351
|
-
{ command: 'claude-flow daemon status -v', description: 'Show detailed status' },
|
|
352
|
-
],
|
|
353
|
-
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
354
|
-
const verbose = ctx.flags.verbose as boolean;
|
|
355
|
-
const projectRoot = process.cwd();
|
|
356
|
-
|
|
357
|
-
try {
|
|
358
|
-
const daemon = getDaemon(projectRoot);
|
|
359
|
-
const status = daemon.getStatus();
|
|
360
|
-
|
|
361
|
-
// Also check for background daemon
|
|
362
|
-
const bgPid = getBackgroundDaemonPid(projectRoot);
|
|
363
|
-
const bgRunning = bgPid ? isProcessRunning(bgPid) : false;
|
|
364
|
-
|
|
365
|
-
const isRunning = status.running || bgRunning;
|
|
366
|
-
const displayPid = bgPid || status.pid;
|
|
367
|
-
|
|
368
|
-
output.writeln();
|
|
369
|
-
|
|
370
|
-
// Daemon status box
|
|
371
|
-
const statusIcon = isRunning ? output.success('●') : output.error('○');
|
|
372
|
-
const statusText = isRunning ? output.success('RUNNING') : output.error('STOPPED');
|
|
373
|
-
const mode = bgRunning ? output.dim(' (background)') : status.running ? output.dim(' (foreground)') : '';
|
|
374
|
-
|
|
375
|
-
output.printBox(
|
|
376
|
-
[
|
|
377
|
-
`Status: ${statusIcon} ${statusText}${mode}`,
|
|
378
|
-
`PID: ${displayPid}`,
|
|
379
|
-
status.startedAt ? `Started: ${status.startedAt.toISOString()}` : '',
|
|
380
|
-
`Workers Enabled: ${status.config.workers.filter(w => w.enabled).length}`,
|
|
381
|
-
`Max Concurrent: ${status.config.maxConcurrent}`,
|
|
382
|
-
].filter(Boolean).join('\n'),
|
|
383
|
-
'Worker Daemon'
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
output.writeln();
|
|
387
|
-
output.writeln(output.bold('Worker Status'));
|
|
388
|
-
|
|
389
|
-
const workerData = status.config.workers.map(w => {
|
|
390
|
-
const state = status.workers.get(w.type);
|
|
391
|
-
return {
|
|
392
|
-
type: w.enabled ? output.highlight(w.type) : output.dim(w.type),
|
|
393
|
-
enabled: w.enabled ? output.success('✓') : output.dim('○'),
|
|
394
|
-
status: state?.isRunning ? output.warning('running') :
|
|
395
|
-
w.enabled ? output.success('idle') : output.dim('disabled'),
|
|
396
|
-
runs: state?.runCount ?? 0,
|
|
397
|
-
success: state ? `${Math.round((state.successCount / Math.max(state.runCount, 1)) * 100)}%` : '-',
|
|
398
|
-
lastRun: state?.lastRun ? formatTimeAgo(state.lastRun) : output.dim('never'),
|
|
399
|
-
nextRun: state?.nextRun && w.enabled ? formatTimeUntil(state.nextRun) : output.dim('-'),
|
|
400
|
-
};
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
output.printTable({
|
|
404
|
-
columns: [
|
|
405
|
-
{ key: 'type', header: 'Worker', width: 12 },
|
|
406
|
-
{ key: 'enabled', header: 'On', width: 4 },
|
|
407
|
-
{ key: 'status', header: 'Status', width: 10 },
|
|
408
|
-
{ key: 'runs', header: 'Runs', width: 6 },
|
|
409
|
-
{ key: 'success', header: 'Success', width: 8 },
|
|
410
|
-
{ key: 'lastRun', header: 'Last Run', width: 12 },
|
|
411
|
-
{ key: 'nextRun', header: 'Next Run', width: 12 },
|
|
412
|
-
],
|
|
413
|
-
data: workerData,
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
if (verbose) {
|
|
417
|
-
output.writeln();
|
|
418
|
-
output.writeln(output.bold('Worker Configuration'));
|
|
419
|
-
output.printTable({
|
|
420
|
-
columns: [
|
|
421
|
-
{ key: 'type', header: 'Worker', width: 12 },
|
|
422
|
-
{ key: 'interval', header: 'Interval', width: 10 },
|
|
423
|
-
{ key: 'priority', header: 'Priority', width: 10 },
|
|
424
|
-
{ key: 'avgDuration', header: 'Avg Duration', width: 12 },
|
|
425
|
-
{ key: 'description', header: 'Description', width: 30 },
|
|
426
|
-
],
|
|
427
|
-
data: status.config.workers.map(w => {
|
|
428
|
-
const state = status.workers.get(w.type);
|
|
429
|
-
return {
|
|
430
|
-
type: w.type,
|
|
431
|
-
interval: `${Math.round(w.intervalMs / 60000)}min`,
|
|
432
|
-
priority: w.priority,
|
|
433
|
-
avgDuration: state?.averageDurationMs ? `${Math.round(state.averageDurationMs)}ms` : '-',
|
|
434
|
-
description: w.description,
|
|
435
|
-
};
|
|
436
|
-
}),
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
return { success: true, data: status };
|
|
441
|
-
} catch (error) {
|
|
442
|
-
// Daemon not initialized
|
|
443
|
-
output.writeln();
|
|
444
|
-
output.printBox(
|
|
445
|
-
[
|
|
446
|
-
`Status: ${output.error('○')} ${output.error('NOT INITIALIZED')}`,
|
|
447
|
-
'',
|
|
448
|
-
'Run "claude-flow daemon start" to start the daemon',
|
|
449
|
-
].join('\n'),
|
|
450
|
-
'Worker Daemon'
|
|
451
|
-
);
|
|
452
|
-
|
|
453
|
-
return { success: true };
|
|
454
|
-
}
|
|
455
|
-
},
|
|
456
|
-
};
|
|
457
|
-
|
|
458
|
-
// Trigger subcommand - manually run a worker
|
|
459
|
-
const triggerCommand: Command = {
|
|
460
|
-
name: 'trigger',
|
|
461
|
-
description: 'Manually trigger a specific worker',
|
|
462
|
-
options: [
|
|
463
|
-
{ name: 'worker', short: 'w', type: 'string', description: 'Worker type to trigger', required: true },
|
|
464
|
-
],
|
|
465
|
-
examples: [
|
|
466
|
-
{ command: 'claude-flow daemon trigger -w map', description: 'Trigger the map worker' },
|
|
467
|
-
{ command: 'claude-flow daemon trigger -w audit', description: 'Trigger security audit' },
|
|
468
|
-
],
|
|
469
|
-
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
470
|
-
const workerType = ctx.flags.worker as WorkerType;
|
|
471
|
-
|
|
472
|
-
if (!workerType) {
|
|
473
|
-
output.printError('Worker type is required. Use --worker or -w flag.');
|
|
474
|
-
output.writeln();
|
|
475
|
-
output.writeln('Available workers: map, audit, optimize, consolidate, testgaps, predict, document, ultralearn, refactor, benchmark, deepdive, preload');
|
|
476
|
-
return { success: false, exitCode: 1 };
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
try {
|
|
480
|
-
const daemon = getDaemon(process.cwd());
|
|
481
|
-
|
|
482
|
-
const spinner = output.createSpinner({ text: `Running ${workerType} worker...`, spinner: 'dots' });
|
|
483
|
-
spinner.start();
|
|
484
|
-
|
|
485
|
-
const result = await daemon.triggerWorker(workerType);
|
|
486
|
-
|
|
487
|
-
if (result.success) {
|
|
488
|
-
spinner.succeed(`Worker ${workerType} completed in ${result.durationMs}ms`);
|
|
489
|
-
|
|
490
|
-
if (result.output) {
|
|
491
|
-
output.writeln();
|
|
492
|
-
output.writeln(output.bold('Output'));
|
|
493
|
-
output.printJson(result.output);
|
|
494
|
-
}
|
|
495
|
-
} else {
|
|
496
|
-
spinner.fail(`Worker ${workerType} failed: ${result.error}`);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
return { success: result.success, data: result };
|
|
500
|
-
} catch (error) {
|
|
501
|
-
output.printError(`Failed to trigger worker: ${error instanceof Error ? error.message : String(error)}`);
|
|
502
|
-
return { success: false, exitCode: 1 };
|
|
503
|
-
}
|
|
504
|
-
},
|
|
505
|
-
};
|
|
506
|
-
|
|
507
|
-
// Enable/disable worker subcommand
|
|
508
|
-
const enableCommand: Command = {
|
|
509
|
-
name: 'enable',
|
|
510
|
-
description: 'Enable or disable a specific worker',
|
|
511
|
-
options: [
|
|
512
|
-
{ name: 'worker', short: 'w', type: 'string', description: 'Worker type', required: true },
|
|
513
|
-
{ name: 'disable', short: 'd', type: 'boolean', description: 'Disable instead of enable' },
|
|
514
|
-
],
|
|
515
|
-
examples: [
|
|
516
|
-
{ command: 'claude-flow daemon enable -w predict', description: 'Enable predict worker' },
|
|
517
|
-
{ command: 'claude-flow daemon enable -w document --disable', description: 'Disable document worker' },
|
|
518
|
-
],
|
|
519
|
-
action: async (ctx: CommandContext): Promise<CommandResult> => {
|
|
520
|
-
const workerType = ctx.flags.worker as WorkerType;
|
|
521
|
-
const disable = ctx.flags.disable as boolean;
|
|
522
|
-
|
|
523
|
-
if (!workerType) {
|
|
524
|
-
output.printError('Worker type is required. Use --worker or -w flag.');
|
|
525
|
-
return { success: false, exitCode: 1 };
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
try {
|
|
529
|
-
const daemon = getDaemon(process.cwd());
|
|
530
|
-
daemon.setWorkerEnabled(workerType, !disable);
|
|
531
|
-
|
|
532
|
-
output.printSuccess(`Worker ${workerType} ${disable ? 'disabled' : 'enabled'}`);
|
|
533
|
-
|
|
534
|
-
return { success: true };
|
|
535
|
-
} catch (error) {
|
|
536
|
-
output.printError(`Failed to ${disable ? 'disable' : 'enable'} worker: ${error instanceof Error ? error.message : String(error)}`);
|
|
537
|
-
return { success: false, exitCode: 1 };
|
|
538
|
-
}
|
|
539
|
-
},
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
// Helper functions for time formatting
|
|
543
|
-
function formatTimeAgo(date: Date): string {
|
|
544
|
-
const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
|
|
545
|
-
|
|
546
|
-
if (seconds < 60) return `${seconds}s ago`;
|
|
547
|
-
if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
|
|
548
|
-
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
|
|
549
|
-
return `${Math.floor(seconds / 86400)}d ago`;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
function formatTimeUntil(date: Date): string {
|
|
553
|
-
const seconds = Math.floor((date.getTime() - Date.now()) / 1000);
|
|
554
|
-
|
|
555
|
-
if (seconds < 0) return 'now';
|
|
556
|
-
if (seconds < 60) return `in ${seconds}s`;
|
|
557
|
-
if (seconds < 3600) return `in ${Math.floor(seconds / 60)}m`;
|
|
558
|
-
if (seconds < 86400) return `in ${Math.floor(seconds / 3600)}h`;
|
|
559
|
-
return `in ${Math.floor(seconds / 86400)}d`;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// Main daemon command
|
|
563
|
-
export const daemonCommand: Command = {
|
|
564
|
-
name: 'daemon',
|
|
565
|
-
description: 'Manage background worker daemon (Node.js-based, auto-runs like shell helpers)',
|
|
566
|
-
subcommands: [
|
|
567
|
-
startCommand,
|
|
568
|
-
stopCommand,
|
|
569
|
-
statusCommand,
|
|
570
|
-
triggerCommand,
|
|
571
|
-
enableCommand,
|
|
572
|
-
],
|
|
573
|
-
options: [],
|
|
574
|
-
examples: [
|
|
575
|
-
{ command: 'claude-flow daemon start', description: 'Start the daemon' },
|
|
576
|
-
{ command: 'claude-flow daemon status', description: 'Check daemon status' },
|
|
577
|
-
{ command: 'claude-flow daemon stop', description: 'Stop the daemon' },
|
|
578
|
-
{ command: 'claude-flow daemon trigger -w audit', description: 'Run security audit' },
|
|
579
|
-
],
|
|
580
|
-
action: async (): Promise<CommandResult> => {
|
|
581
|
-
output.writeln();
|
|
582
|
-
output.writeln(output.bold('Worker Daemon - Background Task Management'));
|
|
583
|
-
output.writeln();
|
|
584
|
-
output.writeln('Node.js-based background worker system that auto-runs like shell daemons.');
|
|
585
|
-
output.writeln('Manages 12 specialized workers for continuous optimization and monitoring.');
|
|
586
|
-
output.writeln();
|
|
587
|
-
|
|
588
|
-
output.writeln(output.bold('Available Workers'));
|
|
589
|
-
output.printList([
|
|
590
|
-
`${output.highlight('map')} - Codebase mapping (5 min interval)`,
|
|
591
|
-
`${output.highlight('audit')} - Security analysis (10 min interval)`,
|
|
592
|
-
`${output.highlight('optimize')} - Performance optimization (15 min interval)`,
|
|
593
|
-
`${output.highlight('consolidate')} - Memory consolidation (30 min interval)`,
|
|
594
|
-
`${output.highlight('testgaps')} - Test coverage analysis (20 min interval)`,
|
|
595
|
-
`${output.highlight('predict')} - Predictive preloading (2 min, disabled by default)`,
|
|
596
|
-
`${output.highlight('document')} - Auto-documentation (60 min, disabled by default)`,
|
|
597
|
-
`${output.highlight('ultralearn')} - Deep knowledge acquisition (manual trigger)`,
|
|
598
|
-
`${output.highlight('refactor')} - Code refactoring suggestions (manual trigger)`,
|
|
599
|
-
`${output.highlight('benchmark')} - Performance benchmarking (manual trigger)`,
|
|
600
|
-
`${output.highlight('deepdive')} - Deep code analysis (manual trigger)`,
|
|
601
|
-
`${output.highlight('preload')} - Resource preloading (manual trigger)`,
|
|
602
|
-
]);
|
|
603
|
-
|
|
604
|
-
output.writeln();
|
|
605
|
-
output.writeln(output.bold('Subcommands'));
|
|
606
|
-
output.printList([
|
|
607
|
-
`${output.highlight('start')} - Start the daemon`,
|
|
608
|
-
`${output.highlight('stop')} - Stop the daemon`,
|
|
609
|
-
`${output.highlight('status')} - Show daemon status`,
|
|
610
|
-
`${output.highlight('trigger')} - Manually run a worker`,
|
|
611
|
-
`${output.highlight('enable')} - Enable/disable a worker`,
|
|
612
|
-
]);
|
|
613
|
-
|
|
614
|
-
output.writeln();
|
|
615
|
-
output.writeln('Run "claude-flow daemon <subcommand> --help" for details');
|
|
616
|
-
|
|
617
|
-
return { success: true };
|
|
618
|
-
},
|
|
619
|
-
};
|
|
620
|
-
|
|
621
|
-
export default daemonCommand;
|