make CLI argv args reach typed command handlers (T-232)

Parameterized subsystem commands were unreachable from the CLI: the
argv translator emits {positional, flags} but the handlers read named
top-level keys (args['path'], args['id'], ...), and nothing mapped
between them -- so 'clide editor open <path>' returned 'path is
required'. The fix needed no new mechanism: D-74's CommandSchema.normalize
already folds the argv shape into named args by a declared positional
ordering; these commands just never registered a schema.

Adopts it for the navigation/drive surface -- editor.open/activate/read/
save/close, files.read/ls, pane.close/focus/resize/write -- with
non-required positional schemas, so the only effect is positional->named
mapping plus numeric coercion of line/cols/rows. Handlers unchanged;
missing-arg errors unchanged. Edit-mutation verbs, pane.spawn, and git
arg verbs are deferred (noted on the ticket).

Takes effect on app restart (the dispatcher is built once at boot).

Closes T-232 (under T-208 'Give Claude hands').

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 15:47:34 +02:00
co-authored by Claude Opus 4.8
parent 4e5d7b1347
commit a08f75ae1c
9 changed files with 103 additions and 11 deletions
+8 -2
View File
@@ -9,11 +9,17 @@ import '../files/listing.dart';
import '../files/path_safety.dart';
import '../files/pql_config.dart';
import '../files/watcher.dart';
import '../ipc/command_schema.dart';
import '../ipc/envelope.dart';
import '../ipc/schema_v1.dart';
import '../panes/event_sink.dart';
import 'dispatcher.dart';
/// Positional schema binding `clide files <verb> <path>` to args['path']
/// (T-232, via D-74 normalize). Non-required — the handlers keep their own
/// path checks — so the only effect is the positional→named mapping.
const _pathArg = CommandSchema(positional: ['path'], args: {'path': ArgSpec()});
/// Cap on `files.read` response size. UI doesn't render multi-MB
/// blobs usefully and a single uncapped call can OOM. Range/stream
/// reads will land as a separate command (T-104 follow-up).
@@ -112,7 +118,7 @@ void registerFilesCommands(DaemonDispatcher d, FilesService files) {
}
final content = file.readAsStringSync();
return IpcResponse.ok(id: req.id, data: {'path': path, 'content': content});
});
}, schema: _pathArg);
d.register('files.ls', (req) async {
final dir = (req.args['path'] as String?) ?? '';
@@ -135,7 +141,7 @@ void registerFilesCommands(DaemonDispatcher d, FilesService files) {
'entries': [for (final e in entries) e.toJson()],
},
);
});
}, schema: _pathArg);
d.register('files.walk', (req) async {
final result = await walkFiles(root: files.root, ignore: files.ignore);