start method

  1. @override
Future<ShellSession> start(
  1. ShellRequest request
)
override

Starts a session for request, returning a live ShellSession.

May throw if the command is invalid or the node is at capacity; the node runtime translates failures into a node.session.rejected message.

Implementation

@override
Future<ShellSession> start(ShellRequest request) async {
  final spec = request.pty;
  if (spec == null || !_scriptUsable) {
    return fallback.start(request);
  }

  if (allowCommand != null && !allowCommand!(request)) {
    throw ProcessException(
      request.command ?? defaultShell,
      request.args,
      'Command not permitted by node policy',
    );
  }

  Directory? ttyDir;
  try {
    final script = _scriptPath();
    if (script == null) throw StateError('script(1) not found');
    // A unique per-session temp file the wrapper records its controlling-tty
    // path into (via `tty`), so [ScriptPtyShellSession.resize] can target the
    // child PTS with `stty` — `script` over pipes leaves the node no pty fd.
    ttyDir = Directory.systemTemp.createTempSync('omnyshell-pts-');
    final ttyFile = '${ttyDir.path}/tty';
    final (executable, args) = _scriptInvocation(request, spec, ttyFile);
    final process = await Process.start(
      script,
      args,
      workingDirectory: request.cwd ?? workingDirectory,
      environment: {
        ...baseEnvironment,
        ..._environment(spec),
        ...request.env,
      },
      includeParentEnvironment: true,
    );
    return ScriptPtyShellSession(process, ttyFile: ttyFile, ttyDir: ttyDir);
  } on Object catch (e) {
    // Disable the `script` path for the rest of the process and fall back so
    // the session still works (with env-var geometry) instead of being
    // rejected.
    try {
      ttyDir?.deleteSync(recursive: true);
    } on Object {
      // Best-effort cleanup of the unused temp dir.
    }
    _scriptUsable = false;
    onWarning?.call(
      'script PTY backend unavailable, using pipe fallback: $e',
    );
    return fallback.start(request);
  }
}