claude-flow 3.5.78 → 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.78",
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
  */
@@ -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
@@ -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.78",
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",