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:
co-authored by
Claude Opus 4.6
parent
8edcc78bfe
commit
73e80a55a6
@@ -2,6 +2,8 @@ import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import '../../src/pty/env.dart';
|
||||
|
||||
class ToolCheck extends ChangeNotifier {
|
||||
bool ptycOk = false;
|
||||
bool pqlOk = false;
|
||||
@@ -18,24 +20,31 @@ class ToolCheck extends ChangeNotifier {
|
||||
if (!gitOk) 'git not found',
|
||||
];
|
||||
|
||||
/// Workspace root, set by the app at boot. Falls back to cwd.
|
||||
static String? workspaceRoot;
|
||||
|
||||
Future<void> check() async {
|
||||
final cwd = Directory.current.path;
|
||||
ptycOk = File('$cwd/native/linux-x64/ptyc').existsSync() ||
|
||||
File('$cwd/ptyc/bin/ptyc').existsSync() ||
|
||||
await _which('ptyc');
|
||||
pqlOk = await _which('pql');
|
||||
tmuxOk = await _which('tmux');
|
||||
gitOk = await _which('git');
|
||||
final root = workspaceRoot ?? Directory.current.path;
|
||||
ptycOk = File('$root/native/linux-x64/ptyc').existsSync() ||
|
||||
File('$root/native/macos-arm64/ptyc').existsSync() ||
|
||||
File('$root/native/macos-x64/ptyc').existsSync() ||
|
||||
File('$root/ptyc/bin/ptyc').existsSync() ||
|
||||
_existsOnPath('ptyc');
|
||||
pqlOk = _existsOnPath('pql');
|
||||
tmuxOk = _existsOnPath('tmux');
|
||||
gitOk = _existsOnPath('git');
|
||||
checked = true;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
static Future<bool> _which(String name) async {
|
||||
try {
|
||||
final r = await Process.run('which', [name]);
|
||||
return r.exitCode == 0;
|
||||
} catch (_) {
|
||||
return false;
|
||||
/// Check if [name] exists as an executable in any PATH directory.
|
||||
/// Uses direct file-existence checks — works inside a macOS sandbox
|
||||
/// without needing to exec `which`.
|
||||
static bool _existsOnPath(String name) {
|
||||
for (final dir in expandedPath.split(':')) {
|
||||
if (dir.isEmpty) continue;
|
||||
if (File('$dir/$name').existsSync()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user