add Toolchain, GitClient, native directory picker

Toolchain centralizes binary resolution — replaces five ad-hoc
mechanisms (expandedPath, _resolveGit, _resolve, _resolvePtyc,
_existsOnPath). Resolves via Future.delayed after runApp to avoid
blocking the merged UI/platform thread on macOS.

GitClient wraps all git operations with a typed API. Every subprocess
call goes through _run() using toolchain.git + toolchain.gitEnv.
Replaces free functions in operations.dart.

Native directory picker: NSOpenPanel on macOS (method channel in
AppDelegate), GtkFileChooserDialog on Linux. Falls back to text-input
dialog on web or MissingPluginException. Shows "No git repo found"
dialog when the selected directory is not a git repository.

PqlClient and pane commands updated to use Toolchain. ToolCheck
replaced by Toolchain.missing/allOk. All IPC handlers now catch
GitException to prevent unhandled exceptions on the merged thread.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeroen Schweitzer
2026-04-25 13:18:39 +02:00
co-authored by Claude Opus 4.6
parent 8edcc78bfe
commit 73e80a55a6
22 changed files with 734 additions and 147 deletions
+7 -3
View File
@@ -5,6 +5,7 @@ import 'package:clide/kernel/src/events/bus.dart';
import 'package:clide/kernel/src/events/types.dart';
import 'package:clide/kernel/src/log.dart';
import 'package:clide/kernel/src/settings.dart';
import 'package:clide/kernel/src/toolchain.dart';
import 'package:flutter/foundation.dart';
class RecentProject {
@@ -47,13 +48,16 @@ class ProjectManager extends ChangeNotifier {
required Logger log,
required DaemonBus events,
required SettingsStore settings,
required Toolchain toolchain,
}) : _log = log,
_events = events,
_settings = settings;
_settings = settings,
_toolchain = toolchain;
final Logger _log;
final DaemonBus _events;
final SettingsStore _settings;
final Toolchain _toolchain;
Directory? _current;
Directory? get current => _current;
@@ -116,7 +120,7 @@ class ProjectManager extends ChangeNotifier {
Future<String?> resolveWorkspace(String path) async {
try {
final r = await Process.run('git', ['rev-parse', '--show-toplevel'], workingDirectory: path, runInShell: false);
final r = await Process.run(_toolchain.git, ['rev-parse', '--show-toplevel'], workingDirectory: path, environment: _toolchain.gitEnv);
if (r.exitCode != 0) return null;
final out = (r.stdout as String).trim();
return out.isEmpty ? null : out;
@@ -128,7 +132,7 @@ class ProjectManager extends ChangeNotifier {
Future<String?> _currentBranch(String root) async {
try {
final r = await Process.run('git', ['rev-parse', '--abbrev-ref', 'HEAD'], workingDirectory: root, runInShell: false);
final r = await Process.run(_toolchain.git, ['rev-parse', '--abbrev-ref', 'HEAD'], workingDirectory: root, environment: _toolchain.gitEnv);
if (r.exitCode != 0) return null;
final out = (r.stdout as String).trim();
return out.isEmpty ? null : out;