feat(cli): clide instances / instance verbs for instance discovery (T-247)
Closes the observability half of T-247: a way to find and identify running clides. `clide instances` scans the runtime socket dir, probes each live *.sock, and prints its identity (version/pid/workspace/socketPath) as jsonl; dead sockets are skipped. `clide instance` reports the one you're connected to. Combined with CLIDE_SOCK honoring (this same ticket), you can now list instances and pin the CLI to a chosen one. Server: a new `instance` dispatcher command (registered in buildDispatcher with the live workspace/pid/socket) returns the identity map; added to the argv translator's umbrella set so a bare `instance` token routes to it. Client: a POSIX dir-scan in clide.c (Windows stub until it ships). Tests: e2e `instances` lists the live test server with its identity; a cc-free unit test covers the `instance` command shape. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import 'package:clide/kernel/src/events/types.dart';
|
||||
import 'package:clide/kernel/src/log.dart';
|
||||
import 'package:clide/src/cli/argv_dispatch.dart';
|
||||
import 'package:clide/src/daemon/dispatcher.dart';
|
||||
import 'package:clide/src/daemon/instance_command.dart';
|
||||
import 'package:clide/src/ipc/envelope.dart';
|
||||
import 'package:clide/src/ipc/server.dart';
|
||||
import 'package:test/test.dart';
|
||||
@@ -58,6 +59,10 @@ void main() {
|
||||
events: streamingBus,
|
||||
);
|
||||
await server.start();
|
||||
// The `instance` command isn't a dispatcher builtin (main.dart registers it
|
||||
// with the live workspace/pid); register it here so `clide instances` has
|
||||
// identity to read back (T-247).
|
||||
registerInstanceCommand(dispatcher, version: '9.9.9-test', pid: 4242, workspace: workspaceRoot.path, socketPath: server.socketPath);
|
||||
});
|
||||
|
||||
tearDownAll(() async {
|
||||
@@ -203,5 +208,25 @@ void main() {
|
||||
expect(r.stderr.toString(), contains('cannot connect'));
|
||||
expect(r.stdout.toString().trim(), isEmpty, reason: 'must not return data from a different instance');
|
||||
});
|
||||
|
||||
test('instances lists live instances with their identity (T-247)', () async {
|
||||
if (!hasCC) {
|
||||
markTestSkipped('cc not available');
|
||||
return;
|
||||
}
|
||||
final r = await Process.run(binaryPath, ['instances'], workingDirectory: workspaceRoot.path, environment: const {'CLIDE_SOCK': ''});
|
||||
expect(r.exitCode, 0, reason: 'stderr: ${r.stderr}');
|
||||
// This test server is one live instance; its socket path must appear.
|
||||
// Other live clides on the machine may also be listed — assert ours is
|
||||
// present and carries the full identity payload, not an exact count.
|
||||
final lines = const LineSplitter().convert(r.stdout.toString());
|
||||
final mine = lines.where((l) => l.contains(server.socketPath)).toList();
|
||||
expect(mine, hasLength(1), reason: 'expected exactly one line for our socket, got: $lines');
|
||||
final obj = jsonDecode(mine.single) as Map<String, Object?>;
|
||||
expect(obj['workspace'], workspaceRoot.path);
|
||||
expect(obj['version'], '9.9.9-test');
|
||||
expect(obj['pid'], 4242);
|
||||
expect(obj['socketPath'], server.socketPath);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/// Tests for the `instance` command verb (T-247) — this clide's identity
|
||||
/// (version / pid / workspace / socket path), the per-instance metadata the
|
||||
/// `clide instances` CLI verb aggregates. Covers the dispatch mechanics
|
||||
/// independent of the C client.
|
||||
library;
|
||||
|
||||
import 'package:clide/clide.dart';
|
||||
import 'package:clide/src/daemon/instance_command.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('instance resolves and returns version/pid/workspace/socketPath', () async {
|
||||
final d = DaemonDispatcher();
|
||||
registerInstanceCommand(d, version: '1.2.3', pid: 4242, workspace: '/repo', socketPath: '/run/user/1000/clide/abc.sock');
|
||||
final r = await d.dispatch(IpcRequest(id: '1', cmd: 'instance', args: const {}));
|
||||
expect(r.ok, isTrue);
|
||||
expect(r.data, {'version': '1.2.3', 'pid': 4242, 'workspace': '/repo', 'socketPath': '/run/user/1000/clide/abc.sock'});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user