moflo 4.7.2 → 4.7.3

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.
@@ -333,8 +333,9 @@ function getSecurityStatus() {
333
333
  function getSwarmStatus() {
334
334
  const activityData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'swarm-activity.json'));
335
335
  if (activityData?.swarm) {
336
+ const count = activityData.swarm.agent_count || 0;
336
337
  return {
337
- activeAgents: activityData.swarm.agent_count || 0,
338
+ activeAgents: Math.min(count, CONFIG.maxAgents),
338
339
  maxAgents: CONFIG.maxAgents,
339
340
  coordinationActive: activityData.swarm.coordination_active || activityData.swarm.active || false,
340
341
  };
@@ -342,10 +343,12 @@ function getSwarmStatus() {
342
343
 
343
344
  const progressData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'v3-progress.json'));
344
345
  if (progressData?.swarm) {
346
+ const count = progressData.swarm.activeAgents || progressData.swarm.agent_count || 0;
347
+ const max = progressData.swarm.totalAgents || CONFIG.maxAgents;
345
348
  return {
346
- activeAgents: progressData.swarm.activeAgents || progressData.swarm.agent_count || 0,
347
- maxAgents: progressData.swarm.totalAgents || CONFIG.maxAgents,
348
- coordinationActive: progressData.swarm.active || (progressData.swarm.activeAgents > 0),
349
+ activeAgents: Math.min(count, max),
350
+ maxAgents: max,
351
+ coordinationActive: progressData.swarm.active || (count > 0),
349
352
  };
350
353
  }
351
354
 
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * MoFlo Project Setup
4
4
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moflo",
3
- "version": "4.7.2",
3
+ "version": "4.7.3",
4
4
  "description": "MoFlo — AI agent orchestration for Claude Code. Forked from ruflo/claude-flow with patches applied to source, plus feature-level orchestration.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -61,6 +61,7 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@ruvector/learning-wasm": "^0.1.29",
64
+ "js-yaml": "^4.1.1",
64
65
  "semver": "^7.6.0",
65
66
  "sql.js": "^1.12.0",
66
67
  "zod": "^3.22.4"
@@ -239,7 +239,7 @@ const listCommand = {
239
239
  }));
240
240
  output.printTable({
241
241
  columns: [
242
- { key: 'id', header: 'ID', width: 20 },
242
+ { key: 'id', header: 'ID', width: 35 },
243
243
  { key: 'type', header: 'Type', width: 15 },
244
244
  { key: 'status', header: 'Status', width: 12, format: formatStatus },
245
245
  { key: 'created', header: 'Created', width: 12 },
@@ -546,7 +546,7 @@ const poolCommand = {
546
546
  output.writeln(output.bold('Pool Agents'));
547
547
  output.printTable({
548
548
  columns: [
549
- { key: 'id', header: 'ID', width: 20 },
549
+ { key: 'id', header: 'ID', width: 35 },
550
550
  { key: 'type', header: 'Type', width: 15 },
551
551
  { key: 'status', header: 'Status', width: 12, format: formatStatus }
552
552
  ],
@@ -370,9 +370,9 @@ const initCommand = {
370
370
  const config = {
371
371
  topology: topology || 'hierarchical-mesh',
372
372
  consensus: consensus || 'byzantine',
373
- maxAgents: ctx.flags.maxAgents || 15,
373
+ maxAgents: (ctx.flags.maxAgents ?? ctx.flags['max-agents']) || 15,
374
374
  persist: ctx.flags.persist,
375
- memoryBackend: ctx.flags.memoryBackend || 'hybrid'
375
+ memoryBackend: (ctx.flags.memoryBackend ?? ctx.flags['memory-backend']) || 'hybrid'
376
376
  };
377
377
  output.writeln();
378
378
  output.writeln(output.bold('Initializing Hive Mind'));
@@ -1095,9 +1095,9 @@ const shutdownCommand = {
1095
1095
  spinner.succeed('Hive mind shutdown complete');
1096
1096
  output.writeln();
1097
1097
  output.printList([
1098
- `Agents terminated: ${result.agentsTerminated}`,
1098
+ `Agents terminated: ${result.agentsTerminated ?? 0}`,
1099
1099
  `State saved: ${result.stateSaved ? 'Yes' : 'No'}`,
1100
- `Shutdown time: ${result.shutdownTime}`
1100
+ `Shutdown time: ${result.shutdownTime ?? 'N/A'}`
1101
1101
  ]);
1102
1102
  return { success: true, data: result };
1103
1103
  }
@@ -178,28 +178,15 @@ const initAction = async (ctx) => {
178
178
  output.printWarning(`MoFlo setup: ${e instanceof Error ? e.message : String(e)}`);
179
179
  }
180
180
  // ── End MoFlo Setup ────────────────────────────────────────────────
181
- // Check if already initialized
181
+ // Check if already initialized — allow re-running to update/merge
182
182
  const initialized = isInitialized(cwd);
183
183
  const hasExisting = initialized.claude || initialized.claudeFlow;
184
184
  if (hasExisting && !force) {
185
- output.printWarning('MoFlo appears to be already initialized');
185
+ output.printInfo('MoFlo is already initialized updating configuration');
186
186
  if (initialized.claude)
187
187
  output.printInfo(' Found: .claude/settings.json');
188
188
  if (initialized.claudeFlow)
189
189
  output.printInfo(' Found: .claude-flow/config.yaml');
190
- output.printInfo('Use --force to reinitialize');
191
- if (ctx.interactive) {
192
- const proceed = await confirm({
193
- message: 'Do you want to reinitialize? This will overwrite existing configuration.',
194
- default: false,
195
- });
196
- if (!proceed) {
197
- return { success: true, message: 'Initialization cancelled' };
198
- }
199
- }
200
- else {
201
- return { success: false, exitCode: 1, message: 'Already initialized' };
202
- }
203
190
  }
204
191
  output.writeln();
205
192
  output.writeln(output.bold('Initializing MoFlo V4'));
@@ -519,7 +519,8 @@ const stopCommand = {
519
519
  const swarmId = ctx.args[0];
520
520
  const force = ctx.flags.force;
521
521
  if (!swarmId) {
522
- output.printError('Swarm ID is required');
522
+ output.printError('Swarm ID is required. Usage: moflo swarm stop <swarm-id>');
523
+ output.printInfo('Run "moflo swarm status" to find the active swarm ID');
523
524
  return { success: false, exitCode: 1 };
524
525
  }
525
526
  if (ctx.interactive && !force) {
@@ -567,7 +568,8 @@ const scaleCommand = {
567
568
  const targetAgents = ctx.flags.agents;
568
569
  const agentType = ctx.flags.type;
569
570
  if (!swarmId) {
570
- output.printError('Swarm ID is required');
571
+ output.printError('Swarm ID is required. Usage: moflo swarm scale <swarm-id>');
572
+ output.printInfo('Run "moflo swarm status" to find the active swarm ID');
571
573
  return { success: false, exitCode: 1 };
572
574
  }
573
575
  if (!targetAgents) {
@@ -4,7 +4,16 @@
4
4
  */
5
5
  import * as fs from 'fs';
6
6
  import * as path from 'path';
7
- import yaml from 'js-yaml';
7
+ let yaml;
8
+ try {
9
+ yaml = await import('js-yaml');
10
+ if (yaml.default)
11
+ yaml = yaml.default;
12
+ }
13
+ catch {
14
+ // js-yaml not installed — YAML config files will fall back to JSON parsing
15
+ yaml = null;
16
+ }
8
17
  // ============================================================================
9
18
  // Defaults
10
19
  // ============================================================================
@@ -181,9 +190,17 @@ export function loadMofloConfig(projectRoot) {
181
190
  }
182
191
  try {
183
192
  const content = fs.readFileSync(configFile.path, 'utf-8');
184
- const raw = configFile.format === 'json'
185
- ? JSON.parse(content)
186
- : yaml.load(content);
193
+ let raw;
194
+ if (configFile.format === 'json') {
195
+ raw = JSON.parse(content);
196
+ }
197
+ else if (yaml) {
198
+ raw = yaml.load(content);
199
+ }
200
+ else {
201
+ // js-yaml not available — cannot parse YAML config
202
+ throw new Error('js-yaml is required to parse moflo.yaml. Install it: npm install js-yaml');
203
+ }
187
204
  if (!raw || typeof raw !== 'object') {
188
205
  return { ...DEFAULT_CONFIG, project: { name: path.basename(root) } };
189
206
  }
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import * as fs from 'fs';
13
13
  import * as path from 'path';
14
+ import { fileURLToPath } from 'url';
14
15
  // ============================================================================
15
16
  // Init
16
17
  // ============================================================================
@@ -429,17 +430,29 @@ function generateSkill(root, force) {
429
430
  }
430
431
  // Copy static SKILL.md from moflo package instead of generating it
431
432
  let skillContent = '';
433
+ // Resolve this file's directory in ESM-safe way
434
+ let thisDir;
435
+ try {
436
+ thisDir = path.dirname(fileURLToPath(import.meta.url));
437
+ }
438
+ catch {
439
+ // Fallback for CJS or environments where import.meta.url is unavailable
440
+ thisDir = typeof __dirname !== 'undefined' ? __dirname : '';
441
+ }
432
442
  const staticSkillCandidates = [
433
- // Installed via npm
443
+ // Installed via npm (most common)
434
444
  path.join(root, 'node_modules', 'moflo', '.claude', 'skills', 'flo', 'SKILL.md'),
435
- // Running from moflo repo itself
436
- path.join(path.dirname(path.dirname(path.dirname(path.dirname(path.dirname(__dirname))))), '.claude', 'skills', 'flo', 'SKILL.md'),
445
+ // Running from moflo repo itself (dev)
446
+ ...(thisDir ? [path.join(thisDir, '..', '..', '..', '..', '.claude', 'skills', 'flo', 'SKILL.md')] : []),
437
447
  ];
438
448
  for (const candidate of staticSkillCandidates) {
439
- if (fs.existsSync(candidate)) {
440
- skillContent = fs.readFileSync(candidate, 'utf-8');
441
- break;
449
+ try {
450
+ if (fs.existsSync(candidate)) {
451
+ skillContent = fs.readFileSync(candidate, 'utf-8');
452
+ break;
453
+ }
442
454
  }
455
+ catch { /* skip inaccessible paths */ }
443
456
  }
444
457
  if (!skillContent) {
445
458
  return { name: '.claude/skills/flo/', status: 'error', detail: 'Could not find SKILL.md in moflo package' };
@@ -567,12 +580,24 @@ function syncScripts(root, force) {
567
580
  fs.mkdirSync(scriptsDir, { recursive: true });
568
581
  }
569
582
  // Find moflo bin/ directory
583
+ let syncThisDir;
584
+ try {
585
+ syncThisDir = path.dirname(fileURLToPath(import.meta.url));
586
+ }
587
+ catch {
588
+ syncThisDir = typeof __dirname !== 'undefined' ? __dirname : '';
589
+ }
570
590
  const candidates = [
571
591
  path.join(root, 'node_modules', 'moflo', 'bin'),
572
592
  // When running from moflo repo itself
573
- path.join(path.dirname(path.dirname(path.dirname(path.dirname(path.dirname(__dirname))))), 'bin'),
593
+ ...(syncThisDir ? [path.join(syncThisDir, '..', '..', '..', '..', 'bin')] : []),
574
594
  ];
575
- const binDir = candidates.find(d => fs.existsSync(d));
595
+ const binDir = candidates.find(d => { try {
596
+ return fs.existsSync(d);
597
+ }
598
+ catch {
599
+ return false;
600
+ } });
576
601
  if (!binDir) {
577
602
  return { name: '.claude/scripts/', status: 'skipped', detail: 'moflo bin/ not found' };
578
603
  }
@@ -608,8 +633,11 @@ function updateGitignore(root) {
608
633
  const gitignorePath = path.join(root, '.gitignore');
609
634
  const entries = ['.claude-orc/', '.swarm/', '.moflo/'];
610
635
  if (!fs.existsSync(gitignorePath)) {
611
- fs.writeFileSync(gitignorePath, entries.join('\n') + '\n', 'utf-8');
612
- return { name: '.gitignore', status: 'created', detail: entries.join(', ') };
636
+ // Create .gitignore with common defaults + MoFlo entries
637
+ const defaultEntries = ['node_modules/', 'dist/', '.env', '.env.*', ''];
638
+ const content = '# Dependencies\n' + defaultEntries.join('\n') + '\n# MoFlo state\n' + entries.join('\n') + '\n';
639
+ fs.writeFileSync(gitignorePath, content, 'utf-8');
640
+ return { name: '.gitignore', status: 'created', detail: 'Created with node_modules, .env, and MoFlo entries' };
613
641
  }
614
642
  const existing = fs.readFileSync(gitignorePath, 'utf-8');
615
643
  const toAdd = entries.filter(e => !existing.includes(e));
@@ -289,8 +289,9 @@ function getSecurityStatus() {
289
289
  function getSwarmStatus() {
290
290
  const activityData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'swarm-activity.json'));
291
291
  if (activityData && activityData.swarm) {
292
+ const count = activityData.swarm.agent_count || 0;
292
293
  return {
293
- activeAgents: activityData.swarm.agent_count || 0,
294
+ activeAgents: Math.min(count, CONFIG.maxAgents),
294
295
  maxAgents: CONFIG.maxAgents,
295
296
  coordinationActive: activityData.swarm.coordination_active || activityData.swarm.active || false,
296
297
  };
@@ -298,10 +299,12 @@ function getSwarmStatus() {
298
299
 
299
300
  const progressData = readJSON(path.join(CWD, '.claude-flow', 'metrics', 'v3-progress.json'));
300
301
  if (progressData && progressData.swarm) {
302
+ const count = progressData.swarm.activeAgents || progressData.swarm.agent_count || 0;
303
+ const max = progressData.swarm.totalAgents || CONFIG.maxAgents;
301
304
  return {
302
- activeAgents: progressData.swarm.activeAgents || progressData.swarm.agent_count || 0,
303
- maxAgents: progressData.swarm.totalAgents || CONFIG.maxAgents,
304
- coordinationActive: progressData.swarm.active || (progressData.swarm.activeAgents > 0),
305
+ activeAgents: Math.min(count, max),
306
+ maxAgents: max,
307
+ coordinationActive: progressData.swarm.active || (count > 0),
305
308
  };
306
309
  }
307
310
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moflo/cli",
3
- "version": "4.7.2",
3
+ "version": "4.7.3",
4
4
  "type": "module",
5
5
  "description": "MoFlo CLI — AI agent orchestration with specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",
@@ -1,5 +0,0 @@
1
- {
2
- "tasksCreated": false,
3
- "taskCount": 0,
4
- "memorySearched": true
5
- }