Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
# Runner (spawn-engine child entry)
## Purpose
`runner.ts` is the child-process entry point invoked by `SpawnEngine`. The parent process spawns it via `node:child_process.spawn`, writes a JSON `RunnerInput` envelope to its stdin (closing the pipe to signal end-of-input), and reads a JSON `RunnerOutput` envelope from its stdout. The runner runs inside a fresh OS process with a sanitised environment — that process boundary is the security guarantee, not anything the runner itself does.
The runner exports `runRunner(input)` as a pure function so the parent can also test the evaluation pipeline without spawning a child. The `main()` entry point reads stdin, parses JSON, calls `runRunner`, and writes stdout — exposed for tests that want to drive the full I/O surface.
## Features
- Pure `runRunner(input): RunnerOutput` for in-process testing.
- `readStdinAll()` async stdin slurper.
- `main()` orchestrator.
- Auto-invokes `main()` when the file is launched directly (matched by
filename ending in `runner.{js,ts,cjs,mjs}`).
- `stringify(value)` JSON-safe fallback used by the captured console.
## Usage: Basic
The runner is normally invoked by `SpawnEngine`; consumers do not call it
directly. To test in isolation:
```ts
import { runRunner } from "@suaveplan/sandbox/runner";
const out = runRunner({
code: "1 + 1",
context: {},
modules: [],
maxOutputSize: 1024,
});
console.log(out.result); // 2
```
## Usage: Advanced
Drive the full stdin/stdout pipeline against the runner file by spawning a
real child:
```ts
import { spawn } from "node:child_process";
const child = spawn(process.execPath, ["./dist/spawn-engine/runner.js"], {
stdio: ["pipe", "pipe", "pipe"],
});
child.stdin.write(JSON.stringify({ code: "1 + 1", context: {}, modules: [], maxOutputSize: 1024 }));
child.stdin.end();
```
## API Reference
- `RunnerInput` — `{ code, context, modules, maxOutputSize }`.
- `RunnerOutput` — `{ success, result, error, logs, memoryUsed }`.
- `runRunner(input: RunnerInput): RunnerOutput`.
- `readStdinAll(): Promise<string>`.
- `main(): Promise<void>`.
- `stringify(value: unknown): string`.
## Implementation Notes
The runner builds a function scope via
`Reflect.construct(Function, [...keys, source])` — this is the controlled
boundary the runner owns; the parent is the one that decides whether to
spawn it. Strict mode is enforced via the prologue. The
auto-invoke guard checks `process.argv[1]` against a filename regex so
re-importing the runner from a test never triggers the main loop.