UNPKG

kestrel.markets

Version:

A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.

46 lines (42 loc) 2.56 kB
/** * # cli/commands/_heavy — the lazy-load boundary (Kestrel CLI v1 §4) * * `loadHeavy` is the ONE gate every HEAVY handler passes through. It fails closed on a bun-less host * (exit 4, `RUNTIME_UNAVAILABLE`) — never a raw resolution stack, never a half-degraded verb. HEAVY * handlers call it at the point of use, so the bundled `dist/cli.js` only reaches for * `bun:sqlite`/`Bun.CryptoHasher`/chdb when a HEAVY command is actually invoked; LIGHT commands never * reach here and stay node-runnable with no bun/chdb. * * The guard is STRUCTURAL, not incidental (kestrel-mkn review B1). It used to rely purely on the * dynamic `import()` FAULTING on a `bun:*` specifier — which silently fails to fire for any heavy verb * whose module graph happens to load fine under node and only touches Bun through a LAZY global. That * was exactly the `agent` verb: its `{op:catalog}` ran to completion under bun-less node, and * `{op:openSession}` died with a raw `ReferenceError: Bun is not defined` on the protocol channel (exit * 1) instead of the loud exit-4 refusal every other heavy verb raises. So the runtime is now checked * BEFORE the import: no Bun ⇒ no heavy verb, whatever its import graph happens to look like. */ import { CliError, EXIT } from "../errors.ts"; function runtimeUnavailable(needsChdb: boolean): CliError { return new CliError({ code: "RUNTIME_UNAVAILABLE", exit: EXIT.RUNTIME_UNAVAILABLE, message: "this command requires the Bun runtime" + (needsChdb ? " and the native chdb dependency" : ""), hint: "no usable Bun runtime found — reinstall with optional dependencies enabled (the package bundles `bun`), set KESTREL_BUN=/path/to/bun, or install Bun (https://bun.sh)", }); } /** * Load a heavy module, or fail closed. Refuses UP FRONT under a bun-less runtime (the published bin * re-execs heavy verbs onto a bun, so reaching this on node means no bun exists anywhere), and maps any * remaining load failure — a missing native chdb, say — onto the same loud exit-4 error. */ export async function loadHeavy<T>(imp: () => Promise<T>): Promise<T> { // Fail closed BEFORE the import: a heavy verb must never half-run under node and surface its // Bun-shaped fault as some unrelated domain error (a bogus `corrupt-content-root`, a raw TypeError). if (process.versions.bun === undefined) throw runtimeUnavailable(false); try { return await imp(); } catch (e) { const s = String(e instanceof Error ? e.message : e); throw runtimeUnavailable(/chdb/i.test(s)); } }