ReviewOS

home-lang/home

Route `home run` of .bun.sh/.sh files through the bun shell interpreter

#74
Closed glennmichael123 opened this 10 days ago ·
10 days ago

Tracks a bounded Bun parity gap surfaced by running the pinned suite (#66).

Problem

home run <file>.bun.sh routes shell scripts to the Home-language interpreter instead of the bun shell, so test/js/bun/shell/env.positionals.test.ts fails 2 pass / 4 fail.

src/main.zig:runCommand dispatches JS/TS files to the runtime and everything else (including .bun.sh / .sh) to the Home-language Lexer→Parser→Interpreter path (src/main.zig:2302-2359). For a .bun.sh fixture, this:

  1. Feeds the shebang line to the Home parser → error[EP0001]: Invalid character '#' in source code (packages/parser/src/parser.zig:8137), and
  2. Prints the Home-program banner Running: <file> / Success: Program completed (src/main.zig:2347,2359).

Both land on stderr, so the test's expect(stderr).toBeEmpty() fails.

Reproducer

cat > /tmp/p.bun.sh <<'SH'
#!/bin/sh
echo $0
echo $1
SH
./zig-out/bin/home run /tmp/p.bun.sh a b c 2>/tmp/err.txt
cat /tmp/err.txt   # currently: EP0001 shebang error + Running/Success banner; expected: empty

Failing tests: env.positionals.test.ts → $ argv: standalone, standalone: not enough args, standalone: only 10, standalone: non-ascii.

Acceptance

  • home run <file>.bun.sh (and .sh) executes the file through the bun shell interpreter (bun.shell), not the Home-language interpreter.
  • Shebang (#!...) on line 1 is skipped, not parsed.
  • Positional args are wired ($0 = script path, $1..$n = extra args), matching the fixture expectations.
  • No Running:/Success: banner and no EP0001 output; stderr carries only the script's own stderr.
  • env.positionals.test.ts: 6 pass / 0 fail through real Home execution.
  • No regression to .home/.hm/.js/.ts home run dispatch.
  • zig build clean, zig fmt --check clean, update #66 with the landed commit.

Note: needs a bun-shell file-run entry point in src/main.zig (none exists today — bun.shell is currently only reached via the $ template).

10 days ago

Implementation path (scouted)

The bun shell already has the exact file-run entry point Home needs — no new interpreter code required:

bun.shell.Interpreter.initAndRunFromFile(ctx, mini, path) (packages/runtime/src/runtime/shell/interpreter.zig:1034) reads the file, lexes/parses it through the bun shell parser (shebang-tolerant, same path bun uses), and runs it.

Bun's own .sh dispatch is the template to mirror (~/Code/bun/src/bun.js.zig:145-156):

var bundle = try bun.Transpiler.init(ctx.allocator, ctx.log, config, null);
try bundle.runEnvLoader(bundle.options.env.disable_default_env_files);
const mini = jsc.MiniEventLoop.initGlobal(bundle.env, null);
mini.top_level_dir = ctx.args.absolute_working_dir orelse "";
return bun.shell.Interpreter.initAndRunFromFile(ctx, mini, entry_path);

Wiring in src/main.zig:runCommand (before the Home-language fallback at ~2317):

  1. Add a .bun.sh / .sh extension check alongside fileExtIsJsLike.
  2. Reuse the process-global Command.Context (already built for other commands — see src/main.zig:1949,2089).
  3. Build the MiniEventLoop via the bun.js.zig pattern and call initAndRunFromFile.

Open unknowns to resolve during implementation

  • Positional args: initAndRunFromFile(ctx, mini, path) takes no extra_args — confirm how $1..$n reach the shell (likely ctx.passthrough / ctx.args; the home run script.bun.sh a b c case needs $1=a). Check ThisInterpreter.init's arg source.
  • Confirm bun.Transpiler / jsc.MiniEventLoop / bun.cli.Command.Context are importable from src/main.zig (the live boot cone).
  • Ensure clean exit-code propagation (ExitCode) without the Running:/Success: banner.
10 days ago

Landed in 650f62701a17f256a6c341f9017197cf467dc9e1 (feat(cli): run shell script files natively).

What changed:

  • .sh / .bun.sh files now route from home run into the ported Bun Shell file interpreter, with an absolute $0 and passthrough $1…$n.
  • The MiniEventLoop path now uses its own top-level directory, allocator, dotenv loader, and null-delimited environment map instead of dereferencing a JS VM.
  • The shell file reader is migrated to the Zig 0.17 std.Io API.
  • Removed the env.positionals.test.ts standalone spawn fixture; the four standalone cases now launch the installed Home binary.

Validation:

  • Exact native corpus: env.positionals.test.ts — 6 pass / 0 fail / 0 todo / 0 unsupported.
  • Full home_test: 1,051 pass / 1 intentional skip / 0 fail (1,052 total).
  • Direct .bun.sh checks: $0, missing args, $10, non-ASCII args, empty stderr.
  • Direct plain .sh: shebang accepted and exit 7 propagated as process exit 7.
  • .home, .js, and .ts home run smoke checks passed.
  • zig build --summary failures passed.
  • Scoped Pickier and zig fmt passed.

All acceptance criteria are satisfied.

Sign in to comment on this issue.