`flutter build web --wasm` had been broken since the tree-sitter/PTY dart:ffi pivot. Per D-100 (resolving Q-50: keep the web "happy accident" alive), every native binding now sits behind a `dart.library.ffi` conditional import with a graceful web stub. Desktop builds are unchanged — no fidelity loss; the web target degrades (no terminal, native git, or syntax highlighting). Discriminator is `dart.library.ffi`, not `dart.library.io` — dart2wasm provides dart:io, so FFI is the only blocker. Fences: - PTY: pty_session → pty_backend_io / pty_backend_web (stub throws). - tree-sitter: pure types → syntax_result.dart; tree_sitter_service is now a facade over _ffi/_stub; tree_sitter_boot_io/stub fences TreeSitterLib.init(). - watchdog: watchdog_windows_stub (all -1 sampler). - claude ABI probe: native_abi_io/stub (was `dart:ffi show Abi`). - testmode fd-check: fd_check_io/stub. Also dart2js-safe: the 64-bit FNV literals in session_naming.dart + paths.dart (the dual JS fallback rejected them) — split into 32-bit halves, dropped a no-op 64-bit mask. Desktop/wasm hash values unchanged. CI: added a `web-wasm` job (flutter build web --wasm) so the fence can't rot. Two FFI-constructing tree-sitter tests import _ffi.dart directly (the analyzer resolves the conditional facade to the stub branch). Verified: `flutter build web --wasm` → built; `flutter analyze` clean; `make test` green. Full Playwright e2e harness wiring is the tracked follow-on. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
2.0 KiB
Dart
64 lines
2.0 KiB
Dart
/// Platform-neutral PTY session contract + factory.
|
|
///
|
|
/// The pane registry (and anything else that spawns PTY children)
|
|
/// programs against [PtySession]; [startPtySession] picks the
|
|
/// platform backend — `posix_openpt` + `posix_spawn` on Linux/macOS
|
|
/// ([NativePty]), ConPTY on Windows ([WindowsPty]). Both backends
|
|
/// share the same lifecycle: spawn → byte stream out → write/resize
|
|
/// in → EOF on child exit → close() reaps.
|
|
library;
|
|
|
|
import 'dart:typed_data';
|
|
|
|
// Web fence (T-438, D-100): the FFI-backed backends are reachable only when
|
|
// `dart.library.ffi` is available; the web build gets a throwing stub, so
|
|
// `dart:ffi` never enters the wasm compile graph.
|
|
import 'pty_backend_web.dart' if (dart.library.ffi) 'pty_backend_io.dart';
|
|
import 'pty_log.dart';
|
|
|
|
abstract interface class PtySession {
|
|
/// OS process id of the spawned child.
|
|
int get pid;
|
|
|
|
/// Byte stream of data produced by the child.
|
|
Stream<Uint8List> get output;
|
|
|
|
bool get isClosed;
|
|
|
|
/// Write bytes to the child's stdin. Returns the bytes written.
|
|
int write(List<int> bytes);
|
|
|
|
/// Resize the terminal.
|
|
void resize({required int cols, required int rows});
|
|
|
|
/// Signal the child. [signal] is a POSIX signal number; backends
|
|
/// without signals (Windows) treat any value as terminate. Null
|
|
/// means the backend's default hang-up behaviour.
|
|
bool kill([int? signal]);
|
|
|
|
/// Kill the child and release resources.
|
|
Future<void> close();
|
|
}
|
|
|
|
/// Spawn a child under a PTY using the platform backend.
|
|
///
|
|
/// [environment] must be the complete environment — it goes straight
|
|
/// to the child. Merge `Platform.environment` before calling.
|
|
PtySession startPtySession({
|
|
required String executable,
|
|
List<String> arguments = const [],
|
|
required int columns,
|
|
required int rows,
|
|
String? workingDirectory,
|
|
Map<String, String> environment = const {},
|
|
PtyLog log = PtyLog.none,
|
|
}) => startPtyBackend(
|
|
executable: executable,
|
|
arguments: arguments,
|
|
columns: columns,
|
|
rows: rows,
|
|
workingDirectory: workingDirectory,
|
|
environment: environment,
|
|
log: log,
|
|
);
|