claude-flow 3.5.79 → 3.5.80

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.79",
3
+ "version": "3.5.80",
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",
@@ -83,6 +83,13 @@ export declare function getCommandAsync(name: string): Promise<Command | undefin
83
83
  * Check if command exists (sync check for core commands)
84
84
  */
85
85
  export declare function hasCommand(name: string): boolean;
86
+ /**
87
+ * Get the names of all lazy-loadable commands (the commandLoaders keys).
88
+ * Used by the CLI constructor to register these names with the parser so
89
+ * the two-pass argument walker can recognize them as commands before their
90
+ * modules have been imported. Fix for #1596.
91
+ */
92
+ export declare function getLazyCommandNames(): string[];
86
93
  /**
87
94
  * Get all command names (including aliases and lazy-loadable)
88
95
  */
@@ -280,6 +280,15 @@ export async function getCommandAsync(name) {
280
280
  export function hasCommand(name) {
281
281
  return loadedCommands.has(name) || commandRegistry.has(name) || name in commandLoaders;
282
282
  }
283
+ /**
284
+ * Get the names of all lazy-loadable commands (the commandLoaders keys).
285
+ * Used by the CLI constructor to register these names with the parser so
286
+ * the two-pass argument walker can recognize them as commands before their
287
+ * modules have been imported. Fix for #1596.
288
+ */
289
+ export function getLazyCommandNames() {
290
+ return Object.keys(commandLoaders);
291
+ }
283
292
  /**
284
293
  * Get all command names (including aliases and lazy-loadable)
285
294
  */
@@ -231,12 +231,8 @@ const initAction = async (ctx) => {
231
231
  }
232
232
  output.printBox(summary.join('\n'), 'Summary');
233
233
  output.writeln();
234
- // Show what was created (honest about skip-claude — #1597)
235
- if (skipClaude) {
236
- output.printBox('Skipped (--skip-claude): no files written under .claude/ or ~/.claude/', 'Claude Code Integration');
237
- output.writeln();
238
- }
239
- else if (options.components.claudeMd || options.components.settings || options.components.skills || options.components.commands || options.components.agents) {
234
+ // Show what was created
235
+ if (options.components.claudeMd || options.components.settings || options.components.skills || options.components.commands || options.components.agents) {
240
236
  output.printBox([
241
237
  options.components.claudeMd ? `CLAUDE.md: Swarm guidance & configuration` : '',
242
238
  options.components.settings ? `Settings: .claude/settings.json` : '',
@@ -913,7 +909,7 @@ export const initCommand = {
913
909
  },
914
910
  {
915
911
  name: 'skip-claude',
916
- description: 'Skip all .claude/ writes including global ~/.claude/CLAUDE.md (runtime only)',
912
+ description: 'Skip .claude/ directory creation (runtime only)',
917
913
  type: 'boolean',
918
914
  default: false,
919
915
  },
@@ -9,7 +9,7 @@ import { fileURLToPath } from 'url';
9
9
  import { dirname, join } from 'path';
10
10
  import { commandParser } from './parser.js';
11
11
  import { output } from './output.js';
12
- import { commands, getCommandsByCategory, getCommand, getCommandAsync, getCommandNames, hasCommand } from './commands/index.js';
12
+ import { commands, getCommandsByCategory, getCommand, getCommandAsync, getCommandNames, getLazyCommandNames, hasCommand } from './commands/index.js';
13
13
  import { suggestCommand } from './suggest.js';
14
14
  import { runStartupUpdateCheck } from './update/index.js';
15
15
  // Read version from package.json at runtime
@@ -44,10 +44,16 @@ export class CLI {
44
44
  this.parser = commandParser;
45
45
  this.output = output;
46
46
  this.interactive = options.interactive ?? process.stdin.isTTY ?? false;
47
- // Register all commands
47
+ // Register all core (synchronously loaded) commands with full definitions
48
48
  for (const cmd of commands) {
49
49
  this.parser.registerCommand(cmd);
50
50
  }
51
+ // Register lazy command names so the parser can recognize them during
52
+ // argument resolution without importing their modules. Fix for #1596:
53
+ // prevents `daemon start` from being mis-routed to the `start` command.
54
+ for (const name of getLazyCommandNames()) {
55
+ this.parser.registerLazyCommandName(name);
56
+ }
51
57
  }
52
58
  /**
53
59
  * Run the CLI with given arguments
@@ -1663,11 +1663,6 @@ async function writeClaudeMd(targetDir, options, result) {
1663
1663
  result.created.files.push('CLAUDE.md');
1664
1664
  }
1665
1665
  // Also write/append global ~/.claude/CLAUDE.md so ruflo tools are used automatically (#1497)
1666
- // Guarded to never overwrite user content and to respect opt-out env var (#1597).
1667
- // Opt out entirely with CLAUDE_FLOW_SKIP_GLOBAL_CLAUDE_MD=1.
1668
- if (process.env.CLAUDE_FLOW_SKIP_GLOBAL_CLAUDE_MD === '1') {
1669
- return;
1670
- }
1671
1666
  const homeDir = process.env.HOME || process.env.USERPROFILE || '';
1672
1667
  if (homeDir) {
1673
1668
  const globalClaudeDir = path.join(homeDir, '.claude');
@@ -1687,13 +1682,8 @@ async function writeClaudeMd(targetDir, options, result) {
1687
1682
  if (fs.existsSync(globalClaudeMd)) {
1688
1683
  const existing = fs.readFileSync(globalClaudeMd, 'utf-8');
1689
1684
  if (!existing.includes('Ruflo Integration')) {
1690
- // Always back up existing user content before any modification (#1597).
1691
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
1692
- const backupPath = `${globalClaudeMd}.backup-${timestamp}`;
1693
- fs.copyFileSync(globalClaudeMd, backupPath);
1694
1685
  fs.appendFileSync(globalClaudeMd, rufloBlock);
1695
1686
  result.created.files.push('~/.claude/CLAUDE.md (appended ruflo block)');
1696
- result.created.files.push(`~/.claude/CLAUDE.md.backup-${timestamp} (backup of pre-existing content)`);
1697
1687
  }
1698
1688
  }
1699
1689
  else {
@@ -18,28 +18,11 @@ export interface MCPToolResult {
18
18
  isError?: boolean;
19
19
  }
20
20
  /**
21
- * Returns the effective project working directory for storage path resolution.
22
- *
23
- * Resolution order (#1577):
24
- * 1. CLAUDE_FLOW_PROJECT_DIR — explicit ruflo project override
25
- * 2. CLAUDE_FLOW_CWD — legacy ruflo override set by install script
26
- * 3. CLAUDE_PROJECT_DIR — Claude Code's native project dir env var
27
- * 4. INIT_CWD — npm's original invocation dir
28
- * 5. process.cwd() — if it is not a system directory
29
- * 6. os.homedir() — safe fallback
30
- *
31
- * System directories (e.g. C:\Windows\System32 on Windows, where MCP servers
32
- * spawned by AI agents commonly inherit cwd) are rejected at every step.
33
- *
34
- * Only use this for storage path resolution. When the actual runtime working
35
- * directory matters (e.g. child process cwd, user-facing status), call
36
- * process.cwd() directly.
21
+ * Returns the effective project working directory.
22
+ * Prefers CLAUDE_FLOW_CWD (set by the install script for global/MCP installs
23
+ * where process.cwd() may resolve to '/') over the real process.cwd().
37
24
  */
38
25
  export declare function getProjectCwd(): string;
39
- /**
40
- * Reset cached value. Intended for tests only.
41
- */
42
- export declare function __resetProjectCwdCache(): void;
43
26
  export interface MCPTool {
44
27
  name: string;
45
28
  description: string;
@@ -3,73 +3,12 @@
3
3
  *
4
4
  * Local type definitions to avoid external imports outside package boundary.
5
5
  */
6
- import { homedir } from 'node:os';
7
- // System directories that must not be used for project storage (#1577).
8
- // On Windows, MCP servers spawned by AI agents often inherit System32 as cwd
9
- // — writing there fails with EPERM.
10
- const SYSTEM_DIR_PREFIXES = [
11
- 'c:\\windows',
12
- 'c:/windows',
13
- '/windows/system32',
14
- ];
15
- function isSystemDir(dir) {
16
- if (!dir)
17
- return true;
18
- const lower = dir.toLowerCase().replace(/\\/g, '/');
19
- return SYSTEM_DIR_PREFIXES.some((p) => lower.startsWith(p.replace(/\\/g, '/')));
20
- }
21
- let _cachedProjectCwd;
22
6
  /**
23
- * Returns the effective project working directory for storage path resolution.
24
- *
25
- * Resolution order (#1577):
26
- * 1. CLAUDE_FLOW_PROJECT_DIR — explicit ruflo project override
27
- * 2. CLAUDE_FLOW_CWD — legacy ruflo override set by install script
28
- * 3. CLAUDE_PROJECT_DIR — Claude Code's native project dir env var
29
- * 4. INIT_CWD — npm's original invocation dir
30
- * 5. process.cwd() — if it is not a system directory
31
- * 6. os.homedir() — safe fallback
32
- *
33
- * System directories (e.g. C:\Windows\System32 on Windows, where MCP servers
34
- * spawned by AI agents commonly inherit cwd) are rejected at every step.
35
- *
36
- * Only use this for storage path resolution. When the actual runtime working
37
- * directory matters (e.g. child process cwd, user-facing status), call
38
- * process.cwd() directly.
7
+ * Returns the effective project working directory.
8
+ * Prefers CLAUDE_FLOW_CWD (set by the install script for global/MCP installs
9
+ * where process.cwd() may resolve to '/') over the real process.cwd().
39
10
  */
40
11
  export function getProjectCwd() {
41
- if (_cachedProjectCwd !== undefined)
42
- return _cachedProjectCwd;
43
- const envKeys = [
44
- 'CLAUDE_FLOW_PROJECT_DIR',
45
- 'CLAUDE_FLOW_CWD',
46
- 'CLAUDE_PROJECT_DIR',
47
- 'INIT_CWD',
48
- ];
49
- for (const key of envKeys) {
50
- const val = process.env[key];
51
- if (val && !isSystemDir(val)) {
52
- _cachedProjectCwd = val;
53
- return _cachedProjectCwd;
54
- }
55
- }
56
- try {
57
- const cwd = process.cwd();
58
- if (!isSystemDir(cwd)) {
59
- _cachedProjectCwd = cwd;
60
- return _cachedProjectCwd;
61
- }
62
- }
63
- catch {
64
- // process.cwd() can throw ENOENT if the cwd was deleted — fall through.
65
- }
66
- _cachedProjectCwd = homedir();
67
- return _cachedProjectCwd;
68
- }
69
- /**
70
- * Reset cached value. Intended for tests only.
71
- */
72
- export function __resetProjectCwdCache() {
73
- _cachedProjectCwd = undefined;
12
+ return process.env.CLAUDE_FLOW_CWD || process.cwd();
74
13
  }
75
14
  //# sourceMappingURL=types.js.map
@@ -113,18 +113,25 @@ export async function validateAgentSpawn(input) {
113
113
  if (!r.valid)
114
114
  errors.push(r.error);
115
115
  }
116
- // Try enhanced Zod validation if available
116
+ // Try enhanced Zod validation if available.
117
+ // Fix for #1567: @claude-flow/security's SpawnAgentSchema expects `type` and
118
+ // `id` (not `agentType`/`name`), so the previous call always failed with
119
+ // "type: Required". Also swallow `invalid_enum_value` errors because the
120
+ // schema enumerates only 15 built-in agent types — we support custom types
121
+ // (the inline validator already checked the identifier is safe).
117
122
  const sec = await getSecurityModule();
118
123
  if (sec?.SpawnAgentSchema) {
119
124
  try {
120
125
  sec.SpawnAgentSchema.parse({
121
- agentType: input.agentType,
122
- name: input.agentId,
126
+ type: input.agentType,
127
+ id: input.agentId,
123
128
  });
124
129
  }
125
130
  catch (zodErr) {
126
131
  if (zodErr.issues) {
127
132
  for (const issue of zodErr.issues) {
133
+ if (issue.code === 'invalid_enum_value')
134
+ continue;
128
135
  errors.push(`${issue.path.join('.')}: ${issue.message}`);
129
136
  }
130
137
  }
@@ -21,10 +21,19 @@ export interface ParserOptions {
21
21
  export declare class CommandParser {
22
22
  private options;
23
23
  private commands;
24
+ private lazyCommandNames;
24
25
  private globalOptions;
25
26
  constructor(options?: ParserOptions);
26
27
  private initializeGlobalOptions;
27
28
  registerCommand(command: Command): void;
29
+ /**
30
+ * Register a lazy-loaded command's name so Pass 1/Pass 2 can recognize it as
31
+ * a command position even though its full definition hasn't been loaded yet.
32
+ * Fix for #1596: without this, lazy commands like `daemon start` were
33
+ * mis-routed because Pass 1 walked past `daemon` and greedy-matched `start`.
34
+ */
35
+ registerLazyCommandName(name: string): void;
36
+ private isKnownCommandName;
28
37
  getCommand(name: string): Command | undefined;
29
38
  getAllCommands(): Command[];
30
39
  parse(args: string[]): ParseResult;
@@ -5,6 +5,7 @@
5
5
  export class CommandParser {
6
6
  options;
7
7
  commands = new Map();
8
+ lazyCommandNames = new Set();
8
9
  globalOptions = [];
9
10
  constructor(options = {}) {
10
11
  this.options = {
@@ -83,6 +84,18 @@ export class CommandParser {
83
84
  }
84
85
  }
85
86
  }
87
+ /**
88
+ * Register a lazy-loaded command's name so Pass 1/Pass 2 can recognize it as
89
+ * a command position even though its full definition hasn't been loaded yet.
90
+ * Fix for #1596: without this, lazy commands like `daemon start` were
91
+ * mis-routed because Pass 1 walked past `daemon` and greedy-matched `start`.
92
+ */
93
+ registerLazyCommandName(name) {
94
+ this.lazyCommandNames.add(name);
95
+ }
96
+ isKnownCommandName(name) {
97
+ return this.commands.has(name) || this.lazyCommandNames.has(name);
98
+ }
86
99
  getCommand(name) {
87
100
  return this.commands.get(name);
88
101
  }
@@ -103,16 +116,33 @@ export class CommandParser {
103
116
  positional: [],
104
117
  raw: [...args]
105
118
  };
106
- // Pass 1: Identify command and subcommand (skip flags)
119
+ // Pass 1: Identify command and subcommand (skip flags).
120
+ // Fix for #1596: the first non-flag positional is ALWAYS the command slot.
121
+ // If it's a known command (sync or lazy) we resolve it; otherwise we stop
122
+ // searching — we MUST NOT walk past it and greedy-match a later arg as the
123
+ // command, because that's what caused `daemon start` to resolve as `start`
124
+ // with `daemon` left as a positional.
107
125
  let resolvedCmd;
108
126
  let resolvedSub;
127
+ let sawFirstPositional = false;
109
128
  for (const arg of args) {
110
129
  if (arg.startsWith('-'))
111
130
  continue;
112
- if (!resolvedCmd && this.commands.has(arg)) {
113
- resolvedCmd = this.commands.get(arg);
131
+ if (!sawFirstPositional) {
132
+ sawFirstPositional = true;
133
+ if (this.commands.has(arg)) {
134
+ resolvedCmd = this.commands.get(arg);
135
+ continue;
136
+ }
137
+ // Lazy command: we know its name but not its subcommands. Stop the
138
+ // walk here — we'll rely on Pass 2 to push it onto commandPath.
139
+ if (this.lazyCommandNames.has(arg)) {
140
+ break;
141
+ }
142
+ // Unknown first positional — not a command. Stop walking.
143
+ break;
114
144
  }
115
- else if (resolvedCmd && !resolvedSub && resolvedCmd.subcommands) {
145
+ if (resolvedCmd && !resolvedSub && resolvedCmd.subcommands) {
116
146
  resolvedSub = resolvedCmd.subcommands.find(sc => sc.name === arg || sc.aliases?.includes(arg));
117
147
  }
118
148
  }
@@ -138,11 +168,15 @@ export class CommandParser {
138
168
  i = parseResult.nextIndex;
139
169
  continue;
140
170
  }
141
- // Handle positional arguments
142
- if (result.command.length === 0 && this.commands.has(arg)) {
171
+ // Handle positional arguments.
172
+ // Fix for #1596: treat lazy command names as commands here too so that
173
+ // downstream dispatch sees `commandPath = ['daemon', 'start']` instead of
174
+ // `commandPath = ['start'], positional = ['daemon']`.
175
+ if (result.command.length === 0 && this.isKnownCommandName(arg)) {
143
176
  // This is a command
144
177
  result.command.push(arg);
145
- // Check for subcommand (level 1)
178
+ // Check for subcommand (level 1) — only possible for sync commands
179
+ // whose subcommand definitions are already loaded.
146
180
  const cmd = this.commands.get(arg);
147
181
  if (cmd?.subcommands && i + 1 < args.length) {
148
182
  const nextArg = args[i + 1];
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.5.79",
3
+ "version": "3.5.80",
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",
@@ -115,7 +115,8 @@
115
115
  "@ruvector/rvagent-wasm": "^0.1.0",
116
116
  "@ruvector/diskann": "^0.1.0",
117
117
  "@ruvector/sona": "^0.1.5",
118
- "agentdb": "^3.0.0-alpha.11"
118
+ "agentdb": "^3.0.0-alpha.11",
119
+ "agentic-flow": "^3.0.0-alpha.1"
119
120
  },
120
121
  "publishConfig": {
121
122
  "access": "public",