process_lualike

Pub Version Pub Version License

Bridges remote process execution into the LuaLike scripting runtime. Enables os.execute() over SSH, Docker, or any custom backend — so Lua scripts can run commands on remote machines without changing a single line of Lua code.

Install

dependencies:
  lualike: ^0.4.0
  process_lualike: ^0.1.2

Then run:

dart pub get

Quick start

import 'package:lualike/lualike.dart';
import 'package:process_lualike/process_lualike.dart';
import 'package:dartssh2/dartssh2.dart';

Future<void> main() async {
  final lua = LuaLike();

  final client = await connect(
    SSHClient(
      await SSHSocket.connect('example.com', 22),
      keys: [SSHKeyPair.fromPrivateKey(privateKey)],
    ),
  );

  await useProcessBackend(SshProcessBackend(client));

  lua.expose('greet', (List<Object?> args) {
    return Value('Hello, ${args.first ?? 'world'}!');
  });

  final result = await lua.execute('''
    local ok, _, code = os.execute("whoami")
    return greet("remote command ran")
  ''');

  print((result as Value).unwrap());
}

Usage

Wiring into lualike

Call useProcessBackend(backend) once during setup. It routes os.execute() and process.exec() through the backend instead of local dart:io.

await useProcessBackend(backend);

SSH backend (remote execution)

import 'package:process_lualike/process_lualike.dart';
import 'package:dartssh2/dartssh2.dart';

final client = await connect(SSHClient(socket, keys: [keyPair]));
final backend = SshProcessBackend(client);

await useProcessBackend(backend);

All Lua os.execute() calls now run inside the SSH session. Stdout, stderr, and exit codes are captured and returned to Lua just like local execution.

Custom backend

Implement the ProcessBackend interface to route execution through Docker, Kubernetes, RPC, or any other transport:

class MyBackend implements ProcessBackend {
  @override
  bool get isShellAvailable => true;

  @override
  ProcessRunResult runSync(String command) {
    // Remote execution logic...
  }

  @override
  Future<ProcessRunResult> run(String command) async {
    return runSync(command);
  }

  @override
  Future<int> runStreaming(
    String command, {
    void Function(List<int> chunk)? onStdout,
    void Function(List<int> chunk)? onStderr,
    void Function()? onDone,
  }) async {
    final result = runSync(command);
    onStdout?.call(result.stdout.codeUnits);
    onStderr?.call(result.stderr.codeUnits);
    onDone?.call();
    return result.exitCode;
  }
}

await useProcessBackend(MyBackend());

Live streaming output

runStreaming delivers stdout/stderr chunks as they arrive — useful for long-running commands or interactive sessions:

await backend.runStreaming(
  'tail -f /var/log/syslog',
  onStdout: (chunk) => print(utf8.decode(chunk)),
  onStderr: (chunk) => print('ERR: ${utf8.decode(chunk)}'),
);

Resetting to local processes

Pass null to restore the default dart:io process execution:

await useProcessBackend(null);

Libraries

process_lualike
Bridges remote process execution into the lualike scripting runtime.