resolve bare command names via PATH before execve
test / unit + widget + golden + a11y (push) Failing after 28s
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

execve doesn't search PATH — bare names like 'tmux' or 'claude' fail
silently. Resolve via the environment's PATH in Dart before passing
to the child. This matches ptyc's old execvp behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeroen Schweitzer
2026-04-30 22:42:24 +02:00
co-authored by Claude Opus 4.6
parent 5aa0eb46e4
commit 6d180a876a
2 changed files with 15 additions and 2 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
{
"exported_at": "2026-04-30T18:30:16Z",
"exported_at": "2026-04-30T20:42:24Z",
"decisions": [
{
"id": "D-1",
+14 -1
View File
@@ -11,7 +11,7 @@ library;
import 'dart:async';
import 'dart:ffi' as ffi;
import 'dart:io' show Platform;
import 'dart:io' show File, Platform;
import 'dart:isolate';
import 'dart:typed_data';
@@ -120,6 +120,19 @@ class NativePty {
String? workingDirectory,
Map<String, String> environment = const {},
}) {
// Resolve bare command names via PATH (execve doesn't search PATH).
if (!executable.contains('/')) {
final path = environment['PATH'] ?? Platform.environment['PATH'] ?? '';
for (final dir in path.split(':')) {
if (dir.isEmpty) continue;
final candidate = '$dir/$executable';
if (File(candidate).existsSync()) {
executable = candidate;
break;
}
}
}
// Force-resolve FFI functions that run in the child process.
// Top-level finals are lazy; touching them here ensures the FFI
// trampolines are compiled before fork() clones the process.