@claude-flow/cli 3.0.0-alpha.7 → 3.0.0-alpha.9

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.
Files changed (38) hide show
  1. package/.agentic-flow/intelligence.json +4 -4
  2. package/.claude-flow/daemon-state.json +42 -35
  3. package/.claude-flow/daemon-test.log +0 -0
  4. package/.claude-flow/daemon.log +0 -0
  5. package/.claude-flow/daemon2.log +0 -0
  6. package/.claude-flow/daemon3.log +0 -0
  7. package/.claude-flow/metrics/codebase-map.json +2 -2
  8. package/.claude-flow/metrics/consolidation.json +1 -1
  9. package/.claude-flow/metrics/performance.json +12 -84
  10. package/.claude-flow/metrics/security-audit.json +1 -1
  11. package/.claude-flow/metrics/task-metrics.json +3 -3
  12. package/.claude-flow/metrics/test-gaps.json +1 -1
  13. package/agents/architect.yaml +1 -1
  14. package/agents/coder.yaml +1 -1
  15. package/agents/reviewer.yaml +1 -1
  16. package/agents/security-architect.yaml +1 -1
  17. package/agents/tester.yaml +1 -1
  18. package/dist/src/commands/daemon.d.ts.map +1 -1
  19. package/dist/src/commands/daemon.js +182 -8
  20. package/dist/src/commands/daemon.js.map +1 -1
  21. package/dist/src/index.d.ts +1 -1
  22. package/dist/src/index.d.ts.map +1 -1
  23. package/dist/src/index.js +21 -0
  24. package/dist/src/index.js.map +1 -1
  25. package/dist/src/output.d.ts +16 -0
  26. package/dist/src/output.d.ts.map +1 -1
  27. package/dist/src/output.js +42 -0
  28. package/dist/src/output.js.map +1 -1
  29. package/dist/src/services/worker-daemon.d.ts +29 -2
  30. package/dist/src/services/worker-daemon.d.ts.map +1 -1
  31. package/dist/src/services/worker-daemon.js +123 -20
  32. package/dist/src/services/worker-daemon.js.map +1 -1
  33. package/dist/tsconfig.tsbuildinfo +1 -1
  34. package/package.json +1 -1
  35. package/src/commands/daemon.ts +211 -8
  36. package/src/index.ts +25 -1
  37. package/src/output.ts +47 -1
  38. package/src/services/worker-daemon.ts +153 -21
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "patterns": {
3
3
  "command:": {
4
- "success": 0.9999872957652524,
5
- "failure": -0.343094701955
4
+ "success": 0.9999999972244487,
5
+ "failure": -0.44529050543424387
6
6
  }
7
7
  },
8
8
  "sequences": {},
@@ -10,8 +10,8 @@
10
10
  "dirPatterns": {},
11
11
  "errorPatterns": [],
12
12
  "metrics": {
13
- "totalRoutes": 118,
14
- "successfulRoutes": 107,
13
+ "totalRoutes": 208,
14
+ "successfulRoutes": 187,
15
15
  "routingHistory": []
16
16
  }
17
17
  }
@@ -1,51 +1,46 @@
1
1
  {
2
- "running": true,
3
- "startedAt": "2026-01-07T03:07:50.010Z",
2
+ "running": false,
3
+ "startedAt": "2026-01-07T03:59:44.097Z",
4
4
  "workers": {
5
5
  "map": {
6
- "runCount": 3,
7
- "successCount": 3,
6
+ "runCount": 0,
7
+ "successCount": 0,
8
8
  "failureCount": 0,
9
- "averageDurationMs": 0.6666666666666666,
10
- "isRunning": false,
11
- "nextRun": "2026-01-07T03:17:50.077Z",
12
- "lastRun": "2026-01-07T03:17:50.116Z"
9
+ "averageDurationMs": 0,
10
+ "nextRun": "2026-01-07T04:14:44.099Z",
11
+ "isRunning": false
13
12
  },
14
13
  "audit": {
15
- "runCount": 2,
16
- "successCount": 2,
14
+ "runCount": 0,
15
+ "successCount": 0,
17
16
  "failureCount": 0,
18
- "averageDurationMs": 0.5,
19
- "isRunning": false,
20
- "nextRun": "2026-01-07T03:27:50.115Z",
21
- "lastRun": "2026-01-07T03:17:50.115Z"
17
+ "averageDurationMs": 0,
18
+ "nextRun": "2026-01-07T04:01:44.097Z",
19
+ "isRunning": false
22
20
  },
23
21
  "optimize": {
24
- "runCount": 1,
25
- "successCount": 1,
22
+ "runCount": 0,
23
+ "successCount": 0,
26
24
  "failureCount": 0,
27
25
  "averageDurationMs": 0,
28
- "isRunning": false,
29
- "nextRun": "2026-01-07T03:22:50.014Z",
30
- "lastRun": "2026-01-07T03:07:50.014Z"
26
+ "nextRun": "2026-01-07T04:03:44.097Z",
27
+ "isRunning": false
31
28
  },
32
29
  "consolidate": {
33
- "runCount": 1,
34
- "successCount": 1,
30
+ "runCount": 0,
31
+ "successCount": 0,
35
32
  "failureCount": 0,
36
- "averageDurationMs": 1,
37
- "isRunning": false,
38
- "nextRun": "2026-01-07T03:37:50.015Z",
39
- "lastRun": "2026-01-07T03:07:50.015Z"
33
+ "averageDurationMs": 0,
34
+ "nextRun": "2026-01-07T04:05:44.097Z",
35
+ "isRunning": false
40
36
  },
41
37
  "testgaps": {
42
- "runCount": 1,
43
- "successCount": 1,
38
+ "runCount": 0,
39
+ "successCount": 0,
44
40
  "failureCount": 0,
45
41
  "averageDurationMs": 0,
46
- "isRunning": false,
47
- "nextRun": "2026-01-07T03:27:50.015Z",
48
- "lastRun": "2026-01-07T03:07:50.015Z"
42
+ "nextRun": "2026-01-07T04:07:44.097Z",
43
+ "isRunning": false
49
44
  },
50
45
  "predict": {
51
46
  "runCount": 0,
@@ -63,14 +58,20 @@
63
58
  }
64
59
  },
65
60
  "config": {
66
- "autoStart": true,
61
+ "autoStart": false,
67
62
  "logDir": "/workspaces/claude-flow/v3/@claude-flow/cli/.claude-flow/logs",
68
63
  "stateFile": "/workspaces/claude-flow/v3/@claude-flow/cli/.claude-flow/daemon-state.json",
69
- "maxConcurrent": 3,
64
+ "maxConcurrent": 2,
65
+ "workerTimeoutMs": 300000,
66
+ "resourceThresholds": {
67
+ "maxCpuLoad": 2,
68
+ "minFreeMemoryPercent": 20
69
+ },
70
70
  "workers": [
71
71
  {
72
72
  "type": "map",
73
- "intervalMs": 300000,
73
+ "intervalMs": 900000,
74
+ "offsetMs": 0,
74
75
  "priority": "normal",
75
76
  "description": "Codebase mapping",
76
77
  "enabled": true
@@ -78,6 +79,7 @@
78
79
  {
79
80
  "type": "audit",
80
81
  "intervalMs": 600000,
82
+ "offsetMs": 120000,
81
83
  "priority": "critical",
82
84
  "description": "Security analysis",
83
85
  "enabled": true
@@ -85,6 +87,7 @@
85
87
  {
86
88
  "type": "optimize",
87
89
  "intervalMs": 900000,
90
+ "offsetMs": 240000,
88
91
  "priority": "high",
89
92
  "description": "Performance optimization",
90
93
  "enabled": true
@@ -92,6 +95,7 @@
92
95
  {
93
96
  "type": "consolidate",
94
97
  "intervalMs": 1800000,
98
+ "offsetMs": 360000,
95
99
  "priority": "low",
96
100
  "description": "Memory consolidation",
97
101
  "enabled": true
@@ -99,13 +103,15 @@
99
103
  {
100
104
  "type": "testgaps",
101
105
  "intervalMs": 1200000,
106
+ "offsetMs": 480000,
102
107
  "priority": "normal",
103
108
  "description": "Test coverage analysis",
104
109
  "enabled": true
105
110
  },
106
111
  {
107
112
  "type": "predict",
108
- "intervalMs": 120000,
113
+ "intervalMs": 600000,
114
+ "offsetMs": 0,
109
115
  "priority": "low",
110
116
  "description": "Predictive preloading",
111
117
  "enabled": false
@@ -113,11 +119,12 @@
113
119
  {
114
120
  "type": "document",
115
121
  "intervalMs": 3600000,
122
+ "offsetMs": 0,
116
123
  "priority": "low",
117
124
  "description": "Auto-documentation",
118
125
  "enabled": false
119
126
  }
120
127
  ]
121
128
  },
122
- "savedAt": "2026-01-07T03:17:50.116Z"
129
+ "savedAt": "2026-01-07T03:59:45.210Z"
123
130
  }
File without changes
File without changes
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-01-07T03:17:50.116Z",
2
+ "timestamp": "2026-01-07T03:57:50.243Z",
3
3
  "projectRoot": "/workspaces/claude-flow/v3/@claude-flow/cli",
4
4
  "structure": {
5
5
  "hasPackageJson": true,
@@ -7,5 +7,5 @@
7
7
  "hasClaudeConfig": false,
8
8
  "hasClaudeFlow": true
9
9
  },
10
- "scannedAt": 1767755870116
10
+ "scannedAt": 1767758270243
11
11
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-01-07T03:07:50.015Z",
2
+ "timestamp": "2026-01-07T03:37:50.088Z",
3
3
  "patternsConsolidated": 0,
4
4
  "memoryCleaned": 0,
5
5
  "duplicatesRemoved": 0
@@ -1,87 +1,15 @@
1
1
  {
2
- "startTime": 1767756039785,
3
- "sessionId": "session-1767756039785",
4
- "lastActivity": 1767756039785,
5
- "sessionDuration": 0,
6
- "totalTasks": 1,
7
- "successfulTasks": 1,
8
- "failedTasks": 0,
9
- "totalAgents": 0,
10
- "activeAgents": 0,
11
- "neuralEvents": 0,
12
- "memoryMode": {
13
- "reasoningbankOperations": 0,
14
- "basicOperations": 0,
15
- "autoModeSelections": 0,
16
- "modeOverrides": 0,
17
- "currentMode": "auto"
18
- },
19
- "operations": {
20
- "store": {
21
- "count": 0,
22
- "totalDuration": 0,
23
- "errors": 0
24
- },
25
- "retrieve": {
26
- "count": 0,
27
- "totalDuration": 0,
28
- "errors": 0
29
- },
30
- "query": {
31
- "count": 0,
32
- "totalDuration": 0,
33
- "errors": 0
34
- },
35
- "list": {
36
- "count": 0,
37
- "totalDuration": 0,
38
- "errors": 0
39
- },
40
- "delete": {
41
- "count": 0,
42
- "totalDuration": 0,
43
- "errors": 0
44
- },
45
- "search": {
46
- "count": 0,
47
- "totalDuration": 0,
48
- "errors": 0
49
- },
50
- "init": {
51
- "count": 0,
52
- "totalDuration": 0,
53
- "errors": 0
54
- }
55
- },
56
- "performance": {
57
- "avgOperationDuration": 0,
58
- "minOperationDuration": null,
59
- "maxOperationDuration": null,
60
- "slowOperations": 0,
61
- "fastOperations": 0,
62
- "totalOperationTime": 0
63
- },
64
- "storage": {
65
- "totalEntries": 0,
66
- "reasoningbankEntries": 0,
67
- "basicEntries": 0,
68
- "databaseSize": 0,
69
- "lastBackup": null,
70
- "growthRate": 0
71
- },
72
- "errors": {
73
- "total": 0,
74
- "byType": {},
75
- "byOperation": {},
76
- "recent": []
77
- },
78
- "reasoningbank": {
79
- "semanticSearches": 0,
80
- "sqlFallbacks": 0,
81
- "embeddingGenerated": 0,
82
- "consolidations": 0,
83
- "avgQueryTime": 0,
84
- "cacheHits": 0,
85
- "cacheMisses": 0
2
+ "timestamp": "2026-01-07T03:52:50.190Z",
3
+ "memoryUsage": {
4
+ "rss": 65392640,
5
+ "heapTotal": 11304960,
6
+ "heapUsed": 9487728,
7
+ "external": 2145622,
8
+ "arrayBuffers": 24811
9
+ },
10
+ "uptime": 2700.280050891,
11
+ "optimizations": {
12
+ "cacheHitRate": 0.78,
13
+ "avgResponseTime": 45
86
14
  }
87
15
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-01-07T03:17:50.115Z",
2
+ "timestamp": "2026-01-07T03:57:50.234Z",
3
3
  "checks": {
4
4
  "envFilesProtected": true,
5
5
  "gitIgnoreExists": false,
@@ -1,10 +1,10 @@
1
1
  [
2
2
  {
3
- "id": "cmd-hooks-1767756039890",
3
+ "id": "cmd-hooks-1767757800648",
4
4
  "type": "hooks",
5
5
  "success": true,
6
- "duration": 1.6088340000000017,
7
- "timestamp": 1767756039891,
6
+ "duration": 1.631386999999961,
7
+ "timestamp": 1767757800650,
8
8
  "metadata": {}
9
9
  }
10
10
  ]
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-01-07T03:07:50.015Z",
2
+ "timestamp": "2026-01-07T03:47:50.172Z",
3
3
  "hasTestDir": true,
4
4
  "estimatedCoverage": "unknown",
5
5
  "gaps": []
@@ -8,4 +8,4 @@ capabilities:
8
8
  optimizations:
9
9
  - context-caching
10
10
  - memory-persistence
11
- createdAt: "2026-01-07T03:15:23.193Z"
11
+ createdAt: "2026-01-07T03:49:59.116Z"
package/agents/coder.yaml CHANGED
@@ -8,4 +8,4 @@ capabilities:
8
8
  optimizations:
9
9
  - flash-attention
10
10
  - token-reduction
11
- createdAt: "2026-01-07T03:15:23.193Z"
11
+ createdAt: "2026-01-07T03:49:59.116Z"
@@ -7,4 +7,4 @@ capabilities:
7
7
  - best-practices
8
8
  optimizations:
9
9
  - incremental-analysis
10
- createdAt: "2026-01-07T03:15:23.194Z"
10
+ createdAt: "2026-01-07T03:49:59.116Z"
@@ -7,4 +7,4 @@ capabilities:
7
7
  - security-review
8
8
  optimizations:
9
9
  - pattern-matching
10
- createdAt: "2026-01-07T03:15:23.193Z"
10
+ createdAt: "2026-01-07T03:49:59.116Z"
@@ -7,4 +7,4 @@ capabilities:
7
7
  - coverage
8
8
  optimizations:
9
9
  - parallel-execution
10
- createdAt: "2026-01-07T03:15:23.193Z"
10
+ createdAt: "2026-01-07T03:49:59.116Z"
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAiC,MAAM,aAAa,CAAC;AA2U1E,eAAO,MAAM,aAAa,EAAE,OAwD3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAiC,MAAM,aAAa,CAAC;AAshB1E,eAAO,MAAM,aAAa,EAAE,OAwD3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -4,6 +4,10 @@
4
4
  */
5
5
  import { output } from '../output.js';
6
6
  import { getDaemon, startDaemon, stopDaemon } from '../services/worker-daemon.js';
7
+ import { spawn } from 'child_process';
8
+ import { fileURLToPath } from 'url';
9
+ import { dirname, join } from 'path';
10
+ import * as fs from 'fs';
7
11
  // Start daemon subcommand
8
12
  const startCommand = {
9
13
  name: 'start',
@@ -11,21 +15,41 @@ const startCommand = {
11
15
  options: [
12
16
  { name: 'workers', short: 'w', type: 'string', description: 'Comma-separated list of workers to enable (default: map,audit,optimize,consolidate,testgaps)' },
13
17
  { name: 'quiet', short: 'q', type: 'boolean', description: 'Suppress output' },
18
+ { name: 'background', short: 'b', type: 'boolean', description: 'Run daemon in background (detached process)', default: true },
19
+ { name: 'foreground', short: 'f', type: 'boolean', description: 'Run daemon in foreground (blocks terminal)' },
14
20
  ],
15
21
  examples: [
16
- { command: 'claude-flow daemon start', description: 'Start daemon with default workers' },
22
+ { command: 'claude-flow daemon start', description: 'Start daemon in background (default)' },
23
+ { command: 'claude-flow daemon start --foreground', description: 'Start in foreground (blocks terminal)' },
17
24
  { command: 'claude-flow daemon start -w map,audit,optimize', description: 'Start with specific workers' },
18
25
  ],
19
26
  action: async (ctx) => {
20
27
  const quiet = ctx.flags.quiet;
28
+ const foreground = ctx.flags.foreground;
21
29
  const projectRoot = process.cwd();
30
+ const isDaemonProcess = process.env.CLAUDE_FLOW_DAEMON === '1';
31
+ // Check if background daemon already running (skip if we ARE the daemon process)
32
+ if (!isDaemonProcess) {
33
+ const bgPid = getBackgroundDaemonPid(projectRoot);
34
+ if (bgPid && isProcessRunning(bgPid)) {
35
+ if (!quiet) {
36
+ output.printWarning(`Daemon already running in background (PID: ${bgPid})`);
37
+ }
38
+ return { success: true };
39
+ }
40
+ }
41
+ // Background mode (default): fork a detached process
42
+ if (!foreground) {
43
+ return startBackgroundDaemon(projectRoot, quiet);
44
+ }
45
+ // Foreground mode: run in current process (blocks terminal)
22
46
  try {
23
47
  if (!quiet) {
24
48
  const spinner = output.createSpinner({ text: 'Starting worker daemon...', spinner: 'dots' });
25
49
  spinner.start();
26
50
  const daemon = await startDaemon(projectRoot);
27
51
  const status = daemon.getStatus();
28
- spinner.succeed('Worker daemon started');
52
+ spinner.succeed('Worker daemon started (foreground mode)');
29
53
  output.writeln();
30
54
  output.printBox([
31
55
  `PID: ${status.pid}`,
@@ -53,6 +77,8 @@ const startCommand = {
53
77
  description: w.description,
54
78
  })),
55
79
  });
80
+ output.writeln();
81
+ output.writeln(output.dim('Press Ctrl+C to stop daemon'));
56
82
  // Listen for worker events
57
83
  daemon.on('worker:start', ({ type }) => {
58
84
  output.writeln(output.dim(`[daemon] Worker starting: ${type}`));
@@ -63,9 +89,12 @@ const startCommand = {
63
89
  daemon.on('worker:error', ({ type, error }) => {
64
90
  output.writeln(output.error(`[daemon] Worker failed: ${type} - ${error}`));
65
91
  });
92
+ // Keep process alive
93
+ await new Promise(() => { }); // Never resolves - daemon runs until killed
66
94
  }
67
95
  else {
68
96
  await startDaemon(projectRoot);
97
+ await new Promise(() => { }); // Keep alive
69
98
  }
70
99
  return { success: true };
71
100
  }
@@ -75,6 +104,62 @@ const startCommand = {
75
104
  }
76
105
  },
77
106
  };
107
+ /**
108
+ * Start daemon as a detached background process
109
+ */
110
+ async function startBackgroundDaemon(projectRoot, quiet) {
111
+ const stateDir = join(projectRoot, '.claude-flow');
112
+ const pidFile = join(stateDir, 'daemon.pid');
113
+ const logFile = join(stateDir, 'daemon.log');
114
+ // Ensure state directory exists
115
+ if (!fs.existsSync(stateDir)) {
116
+ fs.mkdirSync(stateDir, { recursive: true });
117
+ }
118
+ // Get path to CLI (from dist/src/commands/daemon.js -> bin/cli.js)
119
+ const __filename = fileURLToPath(import.meta.url);
120
+ const __dirname = dirname(__filename);
121
+ // dist/src/commands -> dist/src -> dist -> package root -> bin/cli.js
122
+ const cliPath = join(__dirname, '..', '..', '..', 'bin', 'cli.js');
123
+ // Verify CLI path exists
124
+ if (!fs.existsSync(cliPath)) {
125
+ output.printError(`CLI not found at: ${cliPath}`);
126
+ return { success: false, exitCode: 1 };
127
+ }
128
+ // Use shell to spawn daemon with proper output redirection
129
+ // This ensures the log file stays open even after parent exits
130
+ const shellCmd = `"${process.execPath}" "${cliPath}" daemon start --foreground --quiet >> "${logFile}" 2>&1 & echo $!`;
131
+ const child = spawn('sh', ['-c', shellCmd], {
132
+ cwd: projectRoot,
133
+ detached: true,
134
+ stdio: ['ignore', 'pipe', 'ignore'],
135
+ env: { ...process.env, CLAUDE_FLOW_DAEMON: '1' },
136
+ });
137
+ // Wait for the PID to be echoed back
138
+ return new Promise((resolve) => {
139
+ let pidStr = '';
140
+ child.stdout?.on('data', (data) => {
141
+ pidStr += data.toString();
142
+ });
143
+ child.on('close', () => {
144
+ const pid = parseInt(pidStr.trim(), 10);
145
+ if (isNaN(pid) || pid <= 0) {
146
+ output.printError('Failed to get daemon PID');
147
+ resolve({ success: false, exitCode: 1 });
148
+ return;
149
+ }
150
+ // Save PID
151
+ fs.writeFileSync(pidFile, String(pid));
152
+ if (!quiet) {
153
+ output.printSuccess(`Daemon started in background (PID: ${pid})`);
154
+ output.printInfo(`Logs: ${logFile}`);
155
+ output.printInfo(`Stop with: claude-flow daemon stop`);
156
+ }
157
+ resolve({ success: true });
158
+ });
159
+ // Unref so parent can exit immediately
160
+ child.unref();
161
+ });
162
+ }
78
163
  // Stop daemon subcommand
79
164
  const stopCommand = {
80
165
  name: 'stop',
@@ -87,15 +172,20 @@ const stopCommand = {
87
172
  ],
88
173
  action: async (ctx) => {
89
174
  const quiet = ctx.flags.quiet;
175
+ const projectRoot = process.cwd();
90
176
  try {
91
177
  if (!quiet) {
92
178
  const spinner = output.createSpinner({ text: 'Stopping worker daemon...', spinner: 'dots' });
93
179
  spinner.start();
180
+ // Try to stop in-process daemon first
94
181
  await stopDaemon();
95
- spinner.succeed('Worker daemon stopped');
182
+ // Also kill any background daemon by PID
183
+ const killed = await killBackgroundDaemon(projectRoot);
184
+ spinner.succeed(killed ? 'Worker daemon stopped' : 'Worker daemon was not running');
96
185
  }
97
186
  else {
98
187
  await stopDaemon();
188
+ await killBackgroundDaemon(projectRoot);
99
189
  }
100
190
  return { success: true };
101
191
  }
@@ -105,6 +195,83 @@ const stopCommand = {
105
195
  }
106
196
  },
107
197
  };
198
+ /**
199
+ * Kill background daemon process using PID file
200
+ */
201
+ async function killBackgroundDaemon(projectRoot) {
202
+ const pidFile = join(projectRoot, '.claude-flow', 'daemon.pid');
203
+ if (!fs.existsSync(pidFile)) {
204
+ return false;
205
+ }
206
+ try {
207
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
208
+ if (isNaN(pid)) {
209
+ fs.unlinkSync(pidFile);
210
+ return false;
211
+ }
212
+ // Check if process is running
213
+ try {
214
+ process.kill(pid, 0); // Signal 0 = check if alive
215
+ }
216
+ catch {
217
+ // Process not running, clean up stale PID file
218
+ fs.unlinkSync(pidFile);
219
+ return false;
220
+ }
221
+ // Kill the process
222
+ process.kill(pid, 'SIGTERM');
223
+ // Wait a moment then force kill if needed
224
+ await new Promise(resolve => setTimeout(resolve, 1000));
225
+ try {
226
+ process.kill(pid, 0);
227
+ // Still alive, force kill
228
+ process.kill(pid, 'SIGKILL');
229
+ }
230
+ catch {
231
+ // Process terminated
232
+ }
233
+ // Clean up PID file
234
+ if (fs.existsSync(pidFile)) {
235
+ fs.unlinkSync(pidFile);
236
+ }
237
+ return true;
238
+ }
239
+ catch (error) {
240
+ // Clean up PID file on any error
241
+ if (fs.existsSync(pidFile)) {
242
+ fs.unlinkSync(pidFile);
243
+ }
244
+ return false;
245
+ }
246
+ }
247
+ /**
248
+ * Get PID of background daemon from PID file
249
+ */
250
+ function getBackgroundDaemonPid(projectRoot) {
251
+ const pidFile = join(projectRoot, '.claude-flow', 'daemon.pid');
252
+ if (!fs.existsSync(pidFile)) {
253
+ return null;
254
+ }
255
+ try {
256
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
257
+ return isNaN(pid) ? null : pid;
258
+ }
259
+ catch {
260
+ return null;
261
+ }
262
+ }
263
+ /**
264
+ * Check if a process is running
265
+ */
266
+ function isProcessRunning(pid) {
267
+ try {
268
+ process.kill(pid, 0); // Signal 0 = check if alive
269
+ return true;
270
+ }
271
+ catch {
272
+ return false;
273
+ }
274
+ }
108
275
  // Status subcommand
109
276
  const statusCommand = {
110
277
  name: 'status',
@@ -118,16 +285,23 @@ const statusCommand = {
118
285
  ],
119
286
  action: async (ctx) => {
120
287
  const verbose = ctx.flags.verbose;
288
+ const projectRoot = process.cwd();
121
289
  try {
122
- const daemon = getDaemon(process.cwd());
290
+ const daemon = getDaemon(projectRoot);
123
291
  const status = daemon.getStatus();
292
+ // Also check for background daemon
293
+ const bgPid = getBackgroundDaemonPid(projectRoot);
294
+ const bgRunning = bgPid ? isProcessRunning(bgPid) : false;
295
+ const isRunning = status.running || bgRunning;
296
+ const displayPid = bgPid || status.pid;
124
297
  output.writeln();
125
298
  // Daemon status box
126
- const statusIcon = status.running ? output.success('●') : output.error('○');
127
- const statusText = status.running ? output.success('RUNNING') : output.error('STOPPED');
299
+ const statusIcon = isRunning ? output.success('●') : output.error('○');
300
+ const statusText = isRunning ? output.success('RUNNING') : output.error('STOPPED');
301
+ const mode = bgRunning ? output.dim(' (background)') : status.running ? output.dim(' (foreground)') : '';
128
302
  output.printBox([
129
- `Status: ${statusIcon} ${statusText}`,
130
- `PID: ${status.pid}`,
303
+ `Status: ${statusIcon} ${statusText}${mode}`,
304
+ `PID: ${displayPid}`,
131
305
  status.startedAt ? `Started: ${status.startedAt.toISOString()}` : '',
132
306
  `Workers Enabled: ${status.config.workers.filter(w => w.enabled).length}`,
133
307
  `Max Concurrent: ${status.config.maxConcurrent}`,