(commandPath: string[])
| 70 | } |
| 71 | |
| 72 | resolve(commandPath: string[]): { command: Command; extra: string[] } { |
| 73 | let node = this.root; |
| 74 | const matched: string[] = []; |
| 75 | |
| 76 | for (const part of commandPath) { |
| 77 | const child = node.children.get(part); |
| 78 | if (!child) break; |
| 79 | node = child; |
| 80 | matched.push(part); |
| 81 | } |
| 82 | |
| 83 | if (node.command) { |
| 84 | return { command: node.command, extra: commandPath.slice(matched.length) }; |
| 85 | } |
| 86 | |
| 87 | // Single child: auto-forward (e.g. `mmx quota` → `mmx quota show`) |
| 88 | if (matched.length > 0 && node.children.size === 1) { |
| 89 | const [, child] = node.children.entries().next().value as [string, CommandNode]; |
| 90 | if (child.command) { |
| 91 | return { command: child.command, extra: commandPath.slice(matched.length) }; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | // Alias-only group: auto-forward when every child points to the same command. |
| 96 | // Example: `mmx search "query"` should work even when both `search query` |
| 97 | // and `search web` are registered as aliases for the same implementation. |
| 98 | if (matched.length > 0 && node.children.size > 1) { |
| 99 | const children = Array.from(node.children.values()); |
| 100 | const commands = children.map((child) => child.command); |
| 101 | const first = commands[0]; |
| 102 | if (first && commands.every((command) => command === first)) { |
| 103 | return { command: first, extra: commandPath.slice(matched.length) }; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | // If we matched some path but no command, show help for that group |
| 108 | if (matched.length > 0 && node.children.size > 0) { |
| 109 | const subcommands = Array.from(node.children.entries()) |
| 110 | .map(([name, n]) => { |
| 111 | if (n.command) return ` ${matched.join(' ')} ${name} ${n.command.description}`; |
| 112 | const subs = Array.from(n.children.keys()).join(', '); |
| 113 | return ` ${matched.join(' ')} ${name} [${subs}]`; |
| 114 | }) |
| 115 | .join('\n'); |
| 116 | throw new CLIError( |
| 117 | `Unknown command: mmx ${commandPath.join(' ')}\n\nAvailable commands:\n${subcommands}`, |
| 118 | ExitCode.USAGE, |
| 119 | `mmx ${matched.join(' ')} --help`, |
| 120 | ); |
| 121 | } |
| 122 | |
| 123 | throw new CLIError( |
| 124 | `Unknown command: mmx ${commandPath.join(' ')}`, |
| 125 | ExitCode.USAGE, |
| 126 | 'mmx --help', |
| 127 | ); |
| 128 | } |
| 129 |
no outgoing calls