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.
247 lines (245 loc) • 8.5 kB
JavaScript
import {
neverFiredDigestLines,
renderEpisodeReport
} from "./bin-awvz75fn.js";
import {
loadHeavy
} from "./bin-6676fry4.js";
import {
renderOffer
} from "./bin-x2cbtyjz.js";
import {
parseArgs,
required
} from "./bin-1gc4zavq.js";
import {
CliError,
EXIT
} from "./bin-t9ggwnv5.js";
import"./bin-xx1qrxe3.js";
import"./bin-t58k60v9.js";
import"./bin-p5jfg5b0.js";
import {
canonicalPlansText
} from "./bin-29be75ss.js";
import {
exports_fill
} from "./bin-n77kea5n.js";
import"./bin-mn7wcxhv.js";
import"./bin-8pchjxn2.js";
import"./bin-am3351y2.js";
import"./bin-73jr945c.js";
import"./bin-df1tn094.js";
import"./bin-3ft0k1jq.js";
import {
exports_lang
} from "./bin-2ywrx58g.js";
import {
__require
} from "./bin-wckvcay0.js";
// src/cli/commands/grade.ts
import { mkdirSync, readFileSync } from "node:fs";
import { dirname } from "node:path";
var FILL_MODELS = new Set(["strict-cross-v1", "maker-fair-v1"]);
var DEFAULT_DB = "data/kestrel.db";
var HOURS_PER_YEAR = 365 * 24;
function usageErr(message) {
return new CliError({ code: "USAGE", exit: EXIT.USAGE, message });
}
var DAY_HANDSHAKE_CODES = new Set(["NO_AUTHOR", "HANDSHAKE_ABANDONED"]);
async function dayHandshakeTyped(run) {
try {
return await run();
} catch (err) {
if (err instanceof Error && err.name === "DayHandshakeError") {
const code = err.code;
if (typeof code === "string" && DAY_HANDSHAKE_CODES.has(code)) {
const hint = err.hint;
throw new CliError({
code,
exit: EXIT.HANDSHAKE,
message: err.message,
...typeof hint === "string" ? { hint } : {}
});
}
}
throw err;
}
}
function loadDocuments(plansPath) {
const text = readFileSync(plansPath, "utf8");
return plansPath.endsWith(".md") ? exports_lang.parseMarkdown(text) : [exports_lang.parse(text)];
}
function parseGradeFlags(flags) {
const fillModel = required(flags, "fill");
if (!FILL_MODELS.has(fillModel)) {
throw usageErr(`unknown fill model ${JSON.stringify(fillModel)} — one of strict-cross-v1 | maker-fair-v1`);
}
const rUsdRaw = required(flags, "r-usd");
const rUsd = Number(rUsdRaw);
if (!Number.isFinite(rUsd) || rUsd <= 0) {
throw usageErr(`--r-usd must be a positive number, got ${JSON.stringify(rUsdRaw)}`);
}
let fairTauYears;
const tauRaw = flags.get("tau-hours");
if (tauRaw !== undefined) {
const tauHours = Number(tauRaw);
if (!Number.isFinite(tauHours) || tauHours <= 0) {
throw usageErr(`--tau-hours must be a positive number, got ${JSON.stringify(tauRaw)}`);
}
const tauYears = tauHours / HOURS_PER_YEAR;
fairTauYears = () => tauYears;
}
let makerFairParams;
const hazardPath = flags.get("hazard-params");
if (hazardPath !== undefined) {
if (fillModel !== "maker-fair-v1")
throw usageErr("--hazard-params applies only to --fill maker-fair-v1");
const raw = JSON.parse(readFileSync(hazardPath, "utf8"));
makerFairParams = exports_fill.loadEpisodeSigmoidParams(raw);
}
return {
fillModel,
rUsd,
...fairTauYears !== undefined ? { fairTauYears } : {},
...makerFairParams !== undefined ? { makerFairParams } : {},
...flags.get("out") !== undefined ? { out: flags.get("out") } : {}
};
}
function settleDigest(report) {
const traces = report.plans;
const reached = (state) => traces.filter((p) => p.lifecycle.some((s) => s.state === state)).length;
const armed = reached("armed");
const fired = reached("fired");
const expired = traces.filter((p) => p.final_state === "expired").length;
const placed = report.orders.length;
const filled = report.orders.filter((o) => o.filled).length;
return `settle=${report.session.settle_ts}` + ` pnl=${report.totals.realized_floor_usd}` + ` expected=${report.totals.expected_usd}` + ` events=${report.session.bus_events}` + ` plans_armed=${armed} plans_fired=${fired} plans_expired=${expired}` + ` orders_placed=${placed} orders_filled=${filled}`;
}
function writeReport(report, ctx) {
if (ctx.mode === "text") {
const lines = [settleDigest(report), ...neverFiredDigestLines(report)];
process.stdout.write(lines.join(`
`) + `
`);
return;
}
if (ctx.mode === "human") {
renderEpisodeReport(report, ctx);
return;
}
process.stdout.write(JSON.stringify(report, null, 2) + `
`);
}
async function recordGraded(flags, report, opts) {
const registry = await loadHeavy(() => import("./heavy-v95qw596.js"));
const dbPath = flags.get("db") ?? DEFAULT_DB;
mkdirSync(dirname(dbPath), { recursive: true });
const db = registry.openRegistry(dbPath);
try {
const { runId } = registry.record(db, report, {
plansText: opts.plansText,
now: report.session.settle_ts,
rUsd: opts.rUsd,
calibrated: opts.calibrated,
...opts.reportPath !== undefined ? { reportPath: opts.reportPath } : {}
});
process.stderr.write(`session: recorded run ${runId.slice(0, 12)} into ${dbPath}
`);
} finally {
db.close();
}
}
async function runCommand(argv, ctx, backend) {
const { flags, bools } = parseArgs(argv, new Set(["no-record"]), new Set(["bus", "plans", "fill", "r-usd", "tau-hours", "hazard-params", "out", "db"]));
const busPath = required(flags, "bus");
const plansPath = required(flags, "plans");
const { fillModel, rUsd, fairTauYears, makerFairParams, out } = parseGradeFlags(flags);
const documents = loadDocuments(plansPath);
const sessionArgs = {
busPath,
documents,
fillModel,
rUsd,
...fairTauYears !== undefined ? { fairTauYears } : {},
...makerFairParams !== undefined ? { makerFairParams } : {},
...out !== undefined ? { out } : {}
};
const g = await backend.openSession("sim", sessionArgs);
if (g.gated) {
renderOffer(g.payment, ctx);
return EXIT.PAYMENT_REQUIRED;
}
const { report } = g.value;
writeReport(report, ctx);
if (!bools.has("no-record")) {
await recordGraded(flags, report, {
plansText: canonicalPlansText(documents),
rUsd,
calibrated: makerFairParams !== undefined,
...out !== undefined ? { reportPath: out } : {}
});
}
return 0;
}
async function dayCommand(argv, ctx, backend) {
const { flags, bools } = parseArgs(argv, new Set(["no-record", "structural", "no-author", "await-author"]), new Set(["bus", "dir", "fill", "r-usd", "tau-hours", "hazard-params", "wakes", "max-wait", "out", "db"]));
const busPath = required(flags, "bus");
const dir = required(flags, "dir");
const { fillModel, rUsd, fairTauYears, makerFairParams, out } = parseGradeFlags(flags);
let wakes = [];
const wakesRaw = flags.get("wakes");
if (wakesRaw !== undefined) {
const day = await loadHeavy(() => import("./heavy-v95qw596.js"));
wakes = day.parseWakeTimes(wakesRaw);
}
let maxWaitSec;
const maxWaitRaw = flags.get("max-wait");
if (maxWaitRaw !== undefined) {
maxWaitSec = Number(maxWaitRaw);
if (!Number.isFinite(maxWaitSec) || maxWaitSec <= 0) {
throw usageErr(`--max-wait must be a positive number of seconds, got ${JSON.stringify(maxWaitRaw)}`);
}
}
if (bools.has("await-author") && bools.has("no-author")) {
throw usageErr("--await-author and --no-author are contradictory: declare at most one (default: refuse promptly on a missing document).");
}
const dayArgs = {
dir,
documents: [],
busPath,
wakes,
structural: bools.has("structural"),
fillModel,
rUsd,
...fairTauYears !== undefined ? { fairTauYears } : {},
...makerFairParams !== undefined ? { makerFairParams } : {},
...maxWaitSec !== undefined ? { maxWaitSec } : {},
...bools.has("await-author") ? { awaitAuthor: true } : {},
...bools.has("no-author") ? { noAuthor: true } : {},
...out !== undefined ? { out } : {}
};
const g = await dayHandshakeTyped(() => backend.openDaySession("sim", dayArgs));
if (g.gated) {
renderOffer(g.payment, ctx);
return EXIT.PAYMENT_REQUIRED;
}
const { report, plansText, wakes: delivered } = g.value;
writeReport(report, ctx);
const revised = delivered.filter((w) => w.revised).length;
process.stderr.write(`day: ${delivered.length} wake(s), ${revised} revision(s) — settle ${report.session.settle_ts}
`);
if (!bools.has("no-record")) {
await recordGraded(flags, report, {
plansText,
rUsd,
calibrated: makerFairParams !== undefined,
...out !== undefined ? { reportPath: out } : {}
});
}
return 0;
}
export {
runCommand,
dayCommand
};