Skip to content

node shim ignores flags (-e, --test, etc.) — treats them as the script path #18

Description

@davideast

Summary

The node command shim in almostnode appears to take its first positional argument as the script filename, regardless of whether it's a flag. Common flags fail with Cannot find module '/work/<flag>':

node -e "console.log('hello')"
# → Error: Cannot find module '/work/-e'

node --test fib.test.ts
# → Error: Cannot find module '/work/--test'

Both are everyday Node usage:

  • node -e "<code>" is the canonical "run a one-liner" pattern, used constantly by humans and by LLM agents for quick debugging ("let me check what's in this var")
  • node --test <file> runs node:test, the built-in test runner shipped since Node 18

Treating these as script paths means the moment an agent or developer reaches for them, they hit a confusing error and have to invent a workaround (write a tempfile, then node tempfile.js).

Repro

import { createContainer } from "almostnode";
const c = createContainer();
console.log(await c.run('node -e "console.log(1+1)"'));
// { stdout: '', stderr: "Error: Cannot find module '/work/-e'\n", exitCode: 1 }

Why this matters

  • node -e is what training data teaches LLMs to use for inline checks. Agents reach for it before reaching for "write a file first."
  • node --test is what the official Node docs prescribe for the built-in test runner. Anyone following modern Node tutorials hits this immediately.
  • Other useful flags in the same boat: node -p "<expr>" (eval + print), node -r <module> (require before main), node --input-type=module -e "<code>".

Suggested fix

In the node custom command (src/shims/child_process.ts), parse argv before treating arg[0] as the script path:

// pseudocode for the node command handler
const args = parseArgs(rawArgs); // handle -e, -p, --test, -r, etc.

if (args.eval) {
  // -e / --eval "<code>" → execute the string directly
  return runtime.execute(args.eval, '__eval__.js');
}
if (args.print) {
  // -p / --print "<expr>" → execute as expression, print result
  const result = runtime.execute(`module.exports = (${args.print});`, '__print__.js');
  return { stdout: String(result.exports) + '\\n', stderr: '', exitCode: 0 };
}
if (args.test) {
  // --test [file...] → wrap node:test runner around the listed files
  // (implementation could either: a) execute each file in sequence and let
  // node:test's auto-run kick in, or b) explicitly call test.run from the
  // node:test shim)
  ...
}
// fallback: arg[0] is the script path
return runtime.runFile(args._[0]);

-e and -p are the high-leverage ones (zero new behaviour needed — they just delegate to runtime.execute). --test is bigger work because it needs the test runner.

Environment

  • almostnode 0.2.14

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions