From 289d064639c14a70553359495fa4bb1e9bd5111d Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Thu, 23 Apr 2026 00:51:33 +0200 Subject: [PATCH] =?UTF-8?q?wire=20in-process=20dispatcher=20=E2=80=94=20no?= =?UTF-8?q?=20daemon=20socket=20needed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InProcessClient dispatches IPC requests directly to handlers in the same process, bypassing the unix socket entirely. All subsystem registries (pane, files, editor, git, pql) are created in the Flutter app's boot sequence and registered on a DaemonDispatcher. Events bridge to the kernel EventBus via _BusEventSink. The app no longer needs `clide --daemon` running. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/kernel/src/ipc/in_process.dart | 32 ++++++++++++++++++++ lib/main.dart | 48 ++++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 lib/kernel/src/ipc/in_process.dart diff --git a/lib/kernel/src/ipc/in_process.dart b/lib/kernel/src/ipc/in_process.dart new file mode 100644 index 00000000..3c1d0c30 --- /dev/null +++ b/lib/kernel/src/ipc/in_process.dart @@ -0,0 +1,32 @@ +import 'package:clide/clide.dart'; +import 'package:clide/kernel/src/ipc/client.dart'; +import 'package:clide/kernel/src/events/bus.dart'; +import 'package:clide/kernel/src/log.dart'; +import 'package:clide/src/daemon/dispatcher.dart'; + +class InProcessClient extends DaemonClient { + InProcessClient({ + required Logger log, + required EventBus events, + required this.dispatcher, + }) : super(socketPath: '', log: log, events: events); + + final DaemonDispatcher dispatcher; + int _nextReqId = 0; + + @override + bool get isConnected => true; + + @override + Future start() async {} + + @override + Future stop() async {} + + @override + Future request(String cmd, {Map args = const {}}) { + final id = '${_nextReqId++}'; + final req = IpcRequest(id: id, cmd: cmd, args: args); + return dispatcher.dispatch(req); + } +} diff --git a/lib/main.dart b/lib/main.dart index 4a44f8c8..833274c0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -25,7 +25,19 @@ import 'package:clide/builtin/welcome/welcome.dart'; import 'dart:io' show Directory, Platform; import 'package:clide/kernel/kernel.dart'; +import 'package:clide/kernel/src/ipc/in_process.dart'; import 'package:clide/kernel/src/syntax/tree_sitter_ffi.dart'; +import 'package:clide/src/daemon/dispatcher.dart'; +import 'package:clide/src/daemon/editor_commands.dart'; +import 'package:clide/src/daemon/files_commands.dart'; +import 'package:clide/src/daemon/git_commands.dart'; +import 'package:clide/src/daemon/pane_commands.dart'; +import 'package:clide/src/daemon/pql_commands.dart'; +import 'package:clide/src/editor/registry.dart' show EditorRegistry; +import 'package:clide/src/panes/registry.dart'; +import 'package:clide/src/ipc/envelope.dart'; +import 'package:clide/src/panes/event_sink.dart'; +import 'package:clide/src/pql/client.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart' show rootBundle; import 'package:flutter/widgets.dart'; @@ -45,11 +57,22 @@ Future main() async { bundledThemes: themes, i18nLoader: AssetCatalogLoader(bundle: rootBundle), preloadNamespaces: _tier0Namespaces, - // The local unix-socket daemon is desktop-only. On web the - // connection indicator stays `disconnected` — that's the honest - // state: the Flutter-web build can't reach a local socket. - autoStartDaemonClient: !kIsWeb, - socketPath: kIsWeb ? '/clide-web-no-socket' : null, + autoStartDaemonClient: false, + daemonClientFactory: kIsWeb ? null : (log, events) { + final dispatcher = DaemonDispatcher(); + final eventSink = _BusEventSink(events); + final filesService = FilesService.atCwd(events: eventSink); + final workRoot = filesService.root; + final paneRegistry = PaneRegistry(events: eventSink); + registerPaneCommands(dispatcher, paneRegistry); + registerFilesCommands(dispatcher, filesService); + final editorRegistry = EditorRegistry(events: eventSink, workspaceRoot: workRoot); + registerEditorCommands(dispatcher, editorRegistry); + registerGitCommands(dispatcher, workRoot, eventSink); + final pql = PqlClient(workDir: workRoot); + registerPqlCommands(dispatcher, pql); + return InProcessClient(log: log, events: events, dispatcher: dispatcher); + }, ); // Register every built-in. Tier 0 activates only the four that do @@ -128,6 +151,21 @@ Future> _loadBundledThemes() async { /// Every Tier-0 extension that ships an i18n catalog. Extensions /// registered but not active (the 17 stubs) don't preload — their /// catalogs load lazily on activate in later tiers. +class _BusEventSink implements DaemonEventSink { + _BusEventSink(this._bus); + final EventBus _bus; + + @override + void emit(IpcEvent event) { + _bus.emit(DaemonEvent( + subsystem: event.subsystem, + kind: event.kind, + data: event.data, + ts: DateTime.now(), + )); + } +} + const List _tier0Namespaces = [ 'builtin.default-layout', 'builtin.welcome',