claude-flow 3.5.5 → 3.5.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow",
3
- "version": "3.5.5",
3
+ "version": "3.5.6",
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",
@@ -67,6 +67,10 @@ const startCommand = {
67
67
  process.on('exit', cleanup);
68
68
  process.on('SIGINT', () => { cleanup(); process.exit(0); });
69
69
  process.on('SIGTERM', () => { cleanup(); process.exit(0); });
70
+ // Ignore SIGHUP on macOS/Linux — prevents daemon death when terminal closes (#1283)
71
+ if (process.platform !== 'win32') {
72
+ process.on('SIGHUP', () => { });
73
+ }
70
74
  if (!quiet) {
71
75
  const spinner = output.createSpinner({ text: 'Starting worker daemon...', spinner: 'dots' });
72
76
  spinner.start();
@@ -179,32 +183,44 @@ async function startBackgroundDaemon(projectRoot, quiet) {
179
183
  output.printError(`CLI not found at: ${cliPath}`);
180
184
  return { success: false, exitCode: 1 };
181
185
  }
186
+ // Platform-aware spawn flags
187
+ const isWin = process.platform === 'win32';
188
+ const spawnOpts = {
189
+ cwd: resolvedRoot,
190
+ detached: !isWin, // detached is POSIX-only; Windows uses windowsHide
191
+ stdio: ['ignore', fs.openSync(logFile, 'a'), fs.openSync(logFile, 'a')],
192
+ env: {
193
+ ...process.env,
194
+ CLAUDE_FLOW_DAEMON: '1',
195
+ // Prevent macOS SIGHUP kill when terminal closes
196
+ ...(process.platform === 'darwin' ? { NOHUP: '1' } : {}),
197
+ },
198
+ ...(isWin ? { shell: true, windowsHide: true } : {}),
199
+ };
182
200
  // Use spawn with explicit arguments instead of shell string interpolation
183
201
  // This prevents command injection via paths
184
202
  const child = spawn(process.execPath, [
185
203
  cliPath,
186
204
  'daemon', 'start', '--foreground', '--quiet'
187
- ], {
188
- cwd: resolvedRoot,
189
- detached: true,
190
- stdio: ['ignore', fs.openSync(logFile, 'a'), fs.openSync(logFile, 'a')],
191
- env: { ...process.env, CLAUDE_FLOW_DAEMON: '1' },
192
- });
205
+ ], spawnOpts);
193
206
  // Get PID from spawned process directly (no shell echo needed)
194
207
  const pid = child.pid;
195
208
  if (!pid || pid <= 0) {
196
209
  output.printError('Failed to get daemon PID');
197
210
  return { success: false, exitCode: 1 };
198
211
  }
199
- // Save PID
212
+ // Unref BEFORE writing PID file — prevents race where parent exits
213
+ // but child hasn't fully detached yet (fixes macOS daemon death #1283)
214
+ child.unref();
215
+ // Small delay to let the child process fully detach on macOS
216
+ await new Promise(resolve => setTimeout(resolve, 100));
217
+ // Save PID only after child is detached
200
218
  fs.writeFileSync(pidFile, String(pid));
201
219
  if (!quiet) {
202
220
  output.printSuccess(`Daemon started in background (PID: ${pid})`);
203
221
  output.printInfo(`Logs: ${logFile}`);
204
222
  output.printInfo(`Stop with: claude-flow daemon stop`);
205
223
  }
206
- // Unref so parent can exit immediately
207
- child.unref();
208
224
  return { success: true };
209
225
  }
210
226
  // Stop daemon subcommand
@@ -355,7 +371,7 @@ const statusCommand = {
355
371
  status.startedAt ? `Started: ${status.startedAt.toISOString()}` : '',
356
372
  `Workers Enabled: ${status.config.workers.filter(w => w.enabled).length}`,
357
373
  `Max Concurrent: ${status.config.maxConcurrent}`,
358
- ].filter(Boolean).join('\n'), 'Worker Daemon');
374
+ ].filter(Boolean).join('\n'), 'RuFlo Daemon');
359
375
  output.writeln();
360
376
  output.writeln(output.bold('Worker Status'));
361
377
  const workerData = status.config.workers.map(w => {
@@ -426,7 +442,7 @@ const statusCommand = {
426
442
  `Status: ${output.error('○')} ${output.error('NOT INITIALIZED')}`,
427
443
  '',
428
444
  'Run "claude-flow daemon start" to start the daemon',
429
- ].join('\n'), 'Worker Daemon');
445
+ ].join('\n'), 'RuFlo Daemon');
430
446
  return { success: true };
431
447
  }
432
448
  },
@@ -551,7 +567,7 @@ export const daemonCommand = {
551
567
  ],
552
568
  action: async () => {
553
569
  output.writeln();
554
- output.writeln(output.bold('Worker Daemon - Background Task Management'));
570
+ output.writeln(output.bold('RuFlo Daemon - Background Task Management'));
555
571
  output.writeln();
556
572
  output.writeln('Node.js-based background worker system that auto-runs like shell daemons.');
557
573
  output.writeln('Manages 12 specialized workers for continuous optimization and monitoring.');
@@ -215,7 +215,7 @@ function generateHooksConfig(config) {
215
215
  const hooks = {};
216
216
  // Node.js scripts handle errors internally via try/catch.
217
217
  // No shell-level error suppression needed (2>/dev/null || true breaks Windows).
218
- // PreToolUse — validate commands before execution
218
+ // PreToolUse — validate commands and edits before execution
219
219
  if (config.preToolUse) {
220
220
  hooks.PreToolUse = [
221
221
  {
@@ -228,9 +228,19 @@ function generateHooksConfig(config) {
228
228
  },
229
229
  ],
230
230
  },
231
+ {
232
+ matcher: 'Write|Edit|MultiEdit',
233
+ hooks: [
234
+ {
235
+ type: 'command',
236
+ command: hookHandlerCmd('pre-edit'),
237
+ timeout: config.timeout,
238
+ },
239
+ ],
240
+ },
231
241
  ];
232
242
  }
233
- // PostToolUse — record edits for session metrics / learning
243
+ // PostToolUse — record edits and commands for session metrics / learning
234
244
  if (config.postToolUse) {
235
245
  hooks.PostToolUse = [
236
246
  {
@@ -243,6 +253,16 @@ function generateHooksConfig(config) {
243
253
  },
244
254
  ],
245
255
  },
256
+ {
257
+ matcher: 'Bash',
258
+ hooks: [
259
+ {
260
+ type: 'command',
261
+ command: hookHandlerCmd('post-bash'),
262
+ timeout: config.timeout,
263
+ },
264
+ ],
265
+ },
246
266
  ];
247
267
  }
248
268
  // UserPromptSubmit — intelligent task routing
@@ -351,6 +371,32 @@ function generateHooksConfig(config) {
351
371
  ],
352
372
  },
353
373
  ];
374
+ // SubagentEnd — track agent completion for metrics
375
+ hooks.SubagentEnd = [
376
+ {
377
+ hooks: [
378
+ {
379
+ type: 'command',
380
+ command: hookHandlerCmd('post-task'),
381
+ timeout: 5000,
382
+ },
383
+ ],
384
+ },
385
+ ];
386
+ // Notification — capture Claude Code notifications for logging
387
+ if (config.notification) {
388
+ hooks.Notification = [
389
+ {
390
+ hooks: [
391
+ {
392
+ type: 'command',
393
+ command: hookHandlerCmd('notify'),
394
+ timeout: 3000,
395
+ },
396
+ ],
397
+ },
398
+ ];
399
+ }
354
400
  // NOTE: TeammateIdle and TaskCompleted are NOT valid Claude Code hook events.
355
401
  // Their configuration lives in claudeFlow.agentTeams.hooks instead (see generateSettings).
356
402
  return hooks;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.5.5",
3
+ "version": "3.5.6",
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",