Skip to content

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

@davideast

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions