repl

js/commands/repl.ts

fino:commands/repl — reusable fino repl command task.

Implements the interactive REPL behind both fino repl and bare fino. The parent realm owns the terminal — reading stdin, editing the current line, and printing results — while each complete snippet is evaluated in an embedded child realm created with Realm({ repl: true }). The child routes code through the inspector bridge (internal:repl/handler) over the realm's MessagePort, so snippets run in a normal runtime context with top-level await and redeclarable bindings, and the CLI shell itself stays out of scope.

When both stdin and stdout are TTYs the loop switches the terminal to raw mode for the duration of the session, enabling cursor movement, Home/End, Backspace/Delete editing, and up/down navigation through in-memory input history. Without a TTY it degrades to plain line reading, which makes the REPL scriptable: pipe source into stdin and read results from stdout. Multi-line input uses a bracket/quote balance heuristic — while the accumulated buffer looks incomplete the prompt changes to ... and lines keep accumulating. .exit, Ctrl-C, Ctrl-D on an empty line, or stdin EOF end the session.

The default export is the repl Task. The root Fino CLI mounts it as a subcommand and also delegates to it when fino is invoked with no script.

import { Task } from 'fino:task';
import replCommand from 'fino:commands/repl';

// Run the REPL loop directly; resolves when the session ends.
await replCommand.run({});

// Or mount it as a subcommand of a larger CLI.
const cli = new Task({
  name: 'mycli',
  description: 'My tool',
  outputMode: 'text',
  run: async () => 'usage: mycli repl',
  children: [replCommand],
});
await cli.parse(['repl']);

Constants

const command

The repl subcommand task consumed by the root Fino CLI.

A Task named repl with text output mode and no positional arguments or command-specific options; it delegates directly to the private REPL loop. Errors from child realm setup, stdin, or stdout propagate to the caller — evaluation errors inside the session do not, since the loop prints them and continues.

Invoke it programmatically with run({}), or parse an argv slice the way the CLI dispatcher does. Either form resolves once the session ends.

import repl from 'fino:commands/repl';

await repl.parse([]);   // as the CLI would invoke it
await repl.run({});     // direct invocation, same session