Skip to content

Runtime Support

dreamcli runs on Node.js, Bun, and Deno without code changes. A thin RuntimeAdapter interface abstracts the platform-specific edges.

Supported Runtimes

RuntimeStatusPackage
Node.js >= 22.22.2Supported@kjanat/dreamcli (npm)
Bun >= 1.3Supported@kjanat/dreamcli (npm)
Deno >= 2.6.0Supported@kjanat/dreamcli (JSR)

These minimums are the tested support floor, declared in the package engines field. As a dependency, your package manager enforces them at install time; DreamCLI does not hard-fail the host CLI at runtime when the version is lower.

How It Works

The core framework never imports platform-specific APIs directly. Instead, a RuntimeAdapter provides:

  • argv — command-line arguments
  • env — environment variables
  • cwd — current working directory
  • stdin — line reader for interactive prompts
  • readStdin — full piped stdin reader for .stdin() arguments
  • exit — process exit
  • isTTY — terminal detection
  • stdinIsTTY — interactive stdin detection
  • getTerminalSize — current stdout columns and rows when available
  • onTerminalResize — terminal resize subscription when supported
  • readFile / stat / homedir / configDir — filesystem access

Runtime detection is automatic — dreamcli picks the right adapter at startup.

Terminal Width

When cli().run() renders help, DreamCLI uses the runtime adapter's terminal width if stdout is a TTY and no explicit help width is configured. Direct formatHelp() calls and cli().execute() keep the deterministic 80-column fallback.

Node and Bun use process.stdout.getWindowSize() when available, falling back to process.stdout.columns / rows. Deno uses Deno.consoleSize(). Resize subscriptions use stdout resize on Node/Bun and SIGWINCH on Deno Unix platforms.

Set a fixed width with .help({ width }) or runtime help: { width } when tests or generated output need stable wrapping.

Explicit Adapter

ts
import {
  createAdapter,
  createNodeAdapter,
} from '@kjanat/dreamcli/runtime';

const adapter = createAdapter(); // auto-detect
const nodeAdapter = createNodeAdapter(); // explicit

Deno Permissions

On Deno, the adapter handles permission-safe access to the Deno namespace. If permissions are missing, features degrade gracefully with clear error messages.

bash
deno run --allow-read --allow-env mycli.ts deploy

Testing Runtime Seams

For command behavior tests, runCommand() is process-free and injects runtime state directly:

ts
import { runCommand } from '@kjanat/dreamcli/testkit';

const result = await runCommand(regionCmd, [], {
  env: { MY_REGION: 'test' },
});

When you need adapter-level control (argv, filesystem reads, exit behavior), use createTestAdapter() with cli().run({ adapter }).

What's Next?

Released under the MIT License.