feat(cli): support space-separated multi-word verbs

`ncl groups config get` now works alongside `ncl groups config-get`.
Parser joins all positionals with dashes; dispatcher falls back by
trimming the last segment as a target ID (`ncl groups get abc123`).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-05-09 12:04:45 +03:00
parent 4c83a8193b
commit 1efe28ccdc
3 changed files with 27 additions and 21 deletions
+3 -6
View File
@@ -165,12 +165,9 @@ function parseArgv(argv: string[]): {
process.exit(2);
}
const command = positional.length >= 2 ? `${positional[0]}-${positional[1]}` : positional[0];
// Third positional is the target ID
if (positional.length >= 3) {
args.id = positional[2];
}
// Join all positionals with dashes. The dispatcher trims the last
// segment as a target ID if the full name isn't a registered command.
const command = positional.join('-');
return { command, args, json };
}
+5 -14
View File
@@ -85,20 +85,11 @@ function parseArgv(argv: string[]): {
process.exit(2);
}
// Single word: `ncl help`
// Two words: `ncl groups list`, `ncl groups help`
// Three words: `ncl groups get abc123`
let command: string;
if (positional.length === 1) {
command = positional[0];
} else {
command = `${positional[0]}-${positional[1]}`;
}
// Third positional is the target ID
if (positional.length >= 3) {
args.id = positional[2];
}
// Join all positionals with dashes to form the command name.
// If the full name isn't a command, the dispatcher will try trimming
// the last segment and using it as the target ID (e.g. `groups get abc`
// → command "groups-get", id "abc").
const command = positional.join('-');
return { command, args, json };
}
+19 -1
View File
@@ -13,7 +13,25 @@ import type { CallerContext, ErrorCode, RequestFrame, ResponseFrame } from './fr
import { lookup } from './registry.js';
export async function dispatch(req: RequestFrame, ctx: CallerContext): Promise<ResponseFrame> {
const cmd = lookup(req.command);
let cmd = lookup(req.command);
// Fallback: if the full command isn't registered, trim the last
// dash-segment and treat it as the target ID. This lets clients join
// all positional args with dashes (e.g. `ncl groups get abc123`
// → command "groups-get-abc123" → trim → "groups-get" + id "abc123").
if (!cmd) {
const idx = req.command.lastIndexOf('-');
if (idx > 0) {
const shortened = req.command.slice(0, idx);
const tail = req.command.slice(idx + 1);
const fallback = lookup(shortened);
if (fallback) {
cmd = fallback;
req = { ...req, command: shortened, args: { ...req.args, id: req.args.id ?? tail } };
}
}
}
if (!cmd) {
return err(req.id, 'unknown-command', `no command "${req.command}"`);
}