T-127: replace InProcessClient with socket loopback
test / unit + widget + golden + a11y (push) Failing after 2m16s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 29s

Fourth slice of T-99. The UI's DaemonClient now talks to its own
IpcServer through the same per-workspace Unix socket the C `clide`
client uses — one transport, one wire contract, no second path
through the dispatch tree.

Changes:
* lib/kernel/src/ipc/in_process.dart deleted. Nothing imports it.
* DaemonClient.socketPath becomes mutable + new `reconnectAt(path)`
  method swaps an active client onto a different socket without
  restart. Project switch in main.dart uses it — the dispatcher
  + IpcServer are rebuilt for the new workspace, and the client
  reconnects to the new path.
* main.dart's daemonClientFactory now builds a real DaemonClient
  pointed at workspaceSocketPath(workRoot); swapIpcServer kicks
  off server.start() then client.start() in sequence.
* lib/test_app.dart's pane.spawn smoke test uses dispatcher.dispatch
  directly instead of InProcessClient — same coverage, no dead-end
  import.
* DaemonClient client_test gets a reconnectAt round-trip test.

T-128 (delete IsolateClient + Backend + backend_entry.dart) unblocked.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-05-19 12:03:44 +02:00
co-authored by Claude
parent 88ed4bf391
commit 70c293b163
8 changed files with 130 additions and 48 deletions
+9 -4
View File
@@ -29,7 +29,6 @@ import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart' as pkg_ffi;
import 'kernel/kernel.dart';
import 'src/pty/ffi/libc.dart' as libc;
import 'kernel/src/ipc/in_process.dart';
import 'src/daemon/pane_commands.dart';
import 'src/ipc/envelope.dart';
import 'src/panes/event_sink.dart';
@@ -325,19 +324,25 @@ class _ClideTestAppState extends State<ClideTestApp> {
Future<void> _runTerminalTests(Toolchain tc, String workDir) async {
_say('--- terminal ---');
// Test PTY via InProcessClient — same path as the real app.
// Test PTY via the dispatcher directly — skip the socket
// round-trip for the smoke test since it adds setup without
// testing anything new for pane.spawn. The real app's path is
// covered by the IPC server + client tests under test/ipc/.
await _testAsync('pane.spawn via IPC', () async {
final dispatcher = DaemonDispatcher();
final bus = DaemonBus();
final eventSink = _TestEventSink(bus);
final paneRegistry = PaneRegistry(events: eventSink);
registerPaneCommands(dispatcher, paneRegistry);
final ipc = InProcessClient(log: Logger(), events: bus, dispatcher: dispatcher);
Future<IpcResponse> dispatch(String cmd, Map<String, Object?> args) {
return dispatcher.dispatch(IpcRequest(id: 'tm-${DateTime.now().microsecondsSinceEpoch}', cmd: cmd, args: args));
}
// Spawn a pane running /bin/echo.
// Use interactive shell — fast-exiting commands lose output on macOS
// because the slave closes before we can read the master.
final spawnResp = await ipc.request('pane.spawn', args: {
final spawnResp = await dispatch('pane.spawn', {
'argv': [tc.shell],
'kind': 'terminal',
});