Skip to content

Latest commit

 

History

History
157 lines (133 loc) · 14.8 KB

File metadata and controls

157 lines (133 loc) · 14.8 KB

CLI and environment reference

oam --help and oam <command> --help are authoritative. This page is the overview, plus the environment variables, which --help does not list.

Commands

Command What it does
oam run <file> Run a JS/TS file. TypeScript is type-checked concurrently — execution never waits on the checker.
oam test Run *.test.* / *.spec.* / *_test.*, each file in a fresh isolate. Import oam:test. Does not block on types.
oam repl Interactive typed REPL. Also the default with no subcommand.
oam check Type-check a file or project with tsgo (TypeScript 7 native).
oam daemon Inspect or stop the per-project type-check daemon.
oam mcp Serve oam's introspection to coding agents over MCP (stdio). E.g. claude mcp add oam -- oam mcp.
oam serve <file> oam run with PORT/HOST set from --port/--host.
oam install Install from the lockfile (the npm ci equivalent).
oam install --precompile oam install, plus transpile the TypeScript shipped inside installed packages into node_modules/.oam/precompile/ so the first run pays no transpile cost. Walks every package in the lockfile — a warm (already-installed) tree is populated or refreshed too, and entries invalidate automatically when a package's source, oam's transpiler, or the effective JSX settings change.
oam trust Manage the trust list for package lifecycle scripts.
oam compile <file> Embed a pre-bundled JS file into a standalone executable. Bundle it yourself first (esbuild/rollup); this does not bundle.
oam self-update Update in place. Verifies the release's signed RELEASE-MANIFEST against the release keys built into oam (before v0.18.0: a pinned SHA256SUMS digest), then the binary against it. Refuses a downgrade unless --version names the tag.
oam cache info / oam cache clean Inspect or delete the V8 bytecode cache (see OAM_CODE_CACHE below).

Global: --json emits machine-readable ODIF JSONL on stderr instead of pretty-printed errors — the form agents should consume. The envelope is documented at https://oamjs.org/docs/odif, and every code it can carry at https://oamjs.org/docs/errors.

Every check -- oam check, and the concurrent one behind oam run and oam test -- also sees oam's own declarations for the oam: modules (oam:mcp, oam:test, oam:ai, oam:permissions) and the oam global. Nothing to install and no tsconfig.json edit: for a project they arrive through a generated config that extends yours, so your compilerOptions, include, paths, types and references still decide what is checked and how. That config is written under node_modules/.oam/ts-decls/ at your project's nearest node_modules (the directory oam's --precompile output already lives in, gitignored there), because TypeScript resolves a types entry from the root config's directory and that has to be where your own @types are. It goes under oam's own cache dir only when there is no node_modules at or above the project, or that directory cannot be written; a project that names a package in types is then checked against its own tsconfig alone, with TS2307 on oam: imports, and OAM_DEBUG=1 says so. ${configDir} in any config of the extends chain is honoured: the generated config restates each key it affects with your project's own directory substituted, so the program checked is the one tsgo -p tsconfig.json builds; OAM_DEBUG=1 lists the keys restated. Node's own globals are a separate question -- process, Buffer and friends still want @types/node in the project, because those are Node's types to publish, not oam's. A project that carries its own ambient declare const oam (hand-written, or copied from oam's demo before 0.14) should drop it -- two declarations of one global are a redeclaration error.

Node compatibility flags

oam accepts the Node flags it implements, so existing invocations keep working. Notable ones:

Flag Notes
--permission Denies everything, then grants back with the --allow-* flags below.
--allow-fs-read=<paths> / --allow-fs-write=<paths> * for everything, otherwise a comma-separated allow-list. Both take the list with =; neither has a bare form.
--allow-net[=<hosts>] / --allow-env[=<names>] Bare grants everything; the = form takes a comma-separated allow-list. A net entry without a port (example.com) grants the host on every port; one with a port (example.com:443) grants that port alone, for raw sockets and HTTP clients alike (https://example.com/ is port 443).
--allow-child-process Spawning and process.execve, which replaces the image.
--allow-worker Starting a worker_threads Worker or an oam.fork() isolate. Does not imply --allow-child-process — a child isolate inherits the parent's permissions, so it cannot spawn unless the parent could.
--allow-addons Loading native addons. Enforced at require() of a .node file: without the grant the load throws ERR_ACCESS_DENIED carrying permission: 'Addon', and OAM_ENABLE_NATIVE_ADDONS=1 does not override it -- an environment variable cannot widen a permission the caller withheld. The two switches are independent and both must pass: this flag is the sandbox grant, the variable is the alpha opt-in. Requires a binary built with the napi cargo feature (the default); a build without it rejects the flag at startup rather than granting a permission it cannot honour.
--experimental-vm-modules Enables vm.SourceTextModule.
--expose-internals Resolves internal/* from the builtin registry.
--expose-gc, --no-warnings, --no-deprecation, --pending-deprecation As in Node.
--tls-min-v1.0, --tls-min-v1.1, --tls-min-v1.2, --tls-min-v1.3, --tls-max-v1.2, --tls-max-v1.3 As in Node: the initial tls.DEFAULT_MIN_VERSION / DEFAULT_MAX_VERSION, so the default version range of every TLS connection and server (NODE_OPTIONS takes them too, several resolve in Node's precedence, and --tls-min-v1.3 with --tls-max-v1.2 is refused at startup with exit 9, as Node refuses it). A floor below TLS 1.2 is accepted and raised to 1.2, which is what Node negotiates too -- see docs/node-divergences.md, entry 34.
--env-file=<path>, --env-file-if-exists=<path> As in Node.
--v8-pool-size=<n> As in Node: the number of V8 platform worker threads (concurrent GC and background compilation). Default 4, capped at one per core but one; 0 (or anything below 1) sizes it from the core count. Also read from NODE_OPTIONS, reflected in process.execArgv (so a fork() child inherits it), and wins over OAM_V8_POOL_SIZE.
-e / --eval, -p / --print, -pe As in Node, including the bundled form.

Debugging

oam run and oam serve take the V8 Inspector flags, and so do executables built by oam compile. oam test, oam check and oam repl do not, and reject them rather than ignoring them.

Flag Notes
--inspect[=[host:]port] Attach the V8 Inspector (Chrome DevTools Protocol) and run immediately. Default 127.0.0.1:9229; a bare port binds loopback.
--inspect-brk[=[host:]port] As --inspect, but execute nothing until a debugger attaches, then break on the first statement. Wins if both are given.

One debugger at a time: a second concurrent client is refused with 503, and reconnecting after the first disconnects is supported. CDP has no authentication, so a non-loopback bind hands the process to the network.

A TypeScript entry is transpiled before V8 compiles it and oam attaches no source map for the debugger, so the Sources panel shows generated JavaScript with reflowed line numbers. Printed stack traces are mapped back to the .ts line; the debugger is not. Full story: https://oamjs.org/docs/inspector.

Environment variables

Runtime

Variable Effect
OAM_ENABLE_NATIVE_ADDONS=1 Enable N-API addon loading. Off by default and alpha: an addon compiled against node.exe can deadlock the OS loader inside oam, before any oam code runs, so the default is a clean throw that lets a package's JS fallback take over. This is the runtime switch; there is also a compile-time one — the napi cargo feature (on by default). A binary built --no-default-features has no N-API layer and no exported napi_* ABI at all, so require() of a .node throws OAM-NATIVE0002 and this variable does nothing.
OAM_MAX_HEAP_MB Cap the V8 heap, in megabytes. Set this to match a container memory limit. Unset or empty, the cap is 75% of the container (cgroup) memory limit when there is one, else 4096. There is always a cap: 0, a negative or a non-numeric value is not "unlimited" -- it prints one warning on stderr and keeps the default. Reaching the cap exits 134 with an error[OAM-RT-OOM] line naming the cap and where it came from.
OAM_V8_POOL_SIZE The V8 worker-thread count when --v8-pool-size is not given; same values, except that a value that is not a whole integer prints one warning and keeps the default (the flag, as in Node, reads it as 0). Default 4 (one per core but one on a smaller machine). Earlier releases started one per core but one in every process, which on a many-core box running many oam processes added up to hundreds of mostly idle threads; set 0 to get that back for a single large program that wants every core for GC.
OAM_PRIORITY Lower this process's scheduling priority at startup: normal, below_normal, idle (alias low), or a number from 0 to 19 on Node's os.setPriority scale. Applied before any thread starts, and inherited by child processes (the variable itself is in their environment too, so every oam in a fork tree applies it). Lowering only: a process already started at that priority or lower (start /low, nice, an idle oam parent) is left where it is, so normal changes nothing unless the process started above normal; an unrecognized value prints one warning and is ignored. Meant for background work -- test suites, sidecars, hooks -- that should yield to interactive processes.
OAM_ECOQOS=1 Also true or on. Windows: opt the process into EcoQoS (execution-speed power throttling), so the scheduler favours efficiency cores and lower clocks for it. No effect elsewhere.
OAM_MAX_BODY_BYTES Aggregate cap on queued HTTP request-body bytes across all in-flight requests (default 512MB). Past it, excess uploads are shed rather than buffered. Per-request backpressure is the first line of defence; this bounds the total once concurrency is high.
OAM_CODE_CACHE V8 bytecode cache across runs. On by default; 0, off, false or no turns it off entirely -- no consume, no produce, no write. Blobs live under <cache dir>/bytecode, content-addressed by source text + V8 build, so a stale blob is a miss, never a wrong hit. Housekeeping is automatic: at most once a day a run sweeps the directory on a background thread, deleting orphaned .tmp files older than 10 minutes and blobs not written in 30 days. oam cache info prints the directory, entry count and total size; oam cache clean deletes it (safe at any time -- the next run recompiles and repopulates).
OAM_TRANSPILE_CACHE Transpile output cache across runs (TypeScript/TSX -> JS). On by default; 0, off, false or no turns it off entirely -- no read, no write. Entries live under <cache dir>/transpile, content-addressed by source text + transpile settings, so a stale entry is a miss, never a wrong hit. Every filesystem failure is a silent miss: the fallback (transpile again) is always correct.
OAM_CACHE_DIR Where oam keeps its caches (bytecode, transpile output, type-check daemon state). Default: %LOCALAPPDATA%\oam on Windows, $XDG_CACHE_HOME/oam or ~/.cache/oam elsewhere; when none of those resolve (a scrubbed environment), the system temp dir -- never the working directory.
OAM_IO_URING Opt into the Linux io_uring FS path. Off by default — it benchmarked as not a win.
OAM_EXPERIMENTAL_VM_MODULES / OAM_EXPOSE_INTERNALS Env equivalents of the flags above; set by the CLI, readable by the loader.

Type checking

Variable Effect
OAM_TSGO Path to the tsgo binary. Without it, oam prefers the project's node_modules/.bin/tsgo (nearest, walking up), then PATH.
OAM_TSGO_TIMEOUT_MS Wall-clock bound on one tsgo run (default 300000). A run past it is killed — whole process tree — and reported as OAM-TS0006.
OAM_CHECK_WAIT_MS How long warn-mode oam run waits for the concurrent checker after the program exits (default 10000).
OAM_DAEMON_IDLE_MS How long the type-check daemon stays warm before exiting.
OAM_DEBUG 1 prints why a check fell back from the daemon to one-shot (normally swallowed by the never-worse-than-one-shot contract).

Install and update

Variable Effect
OAM_VERSION Pin the version the installer fetches (e.g. v0.8.0).
OAM_INSTALL_DIR Install target. Default ~/.oam/bin, or %LOCALAPPDATA%\oam\bin.
OAM_INSTALL_BASE Asset base URL, for a mirror or CDN. Default is GitHub Releases. Requires OAM_VERSION.
OAM_INSECURE_SKIP_SIGNATURE 1 lets the installer put a v0.18.0+ release on a host with no usable ssh-keygen, without checking its signature. A bad signature still fails.
OAM_SELF_UPDATE_URL Fetch the release files oam self-update installs from this base instead of GitHub Releases (needs --version). They must still carry a valid signature. When unset, oam self-update reads OAM_INSTALL_BASE the same way.
OAM_GH_API GitHub API base, for GitHub Enterprise.
GH_TOKEN / GITHUB_TOKEN Needed while the repo is private — unauthenticated asset URLs 404. In a pipeline put it on sh, not on curl: curl -fsSL … | GH_TOKEN=… sh.
OAM_IGNORE_SCRIPTS Skip package lifecycle scripts during install.

Diagnostics

Variable Effect
OAM_NAPI_TRACE Trace N-API calls.
OAM_CRASH_SELFTEST Force a crash path, for testing the fatal reporter.
OAM_DEP_VERSIONS / OAM_GIT_SHA Build-time provenance, surfaced in process.versions.
OAM_CLUSTER_WORKER Set by oam in cluster workers; not something you set yourself.

Related