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.
201 lines (199 loc) • 6.99 kB
JavaScript
import {
parseArgs
} from "./bin-1gc4zavq.js";
import {
CliError,
EXIT
} from "./bin-t9ggwnv5.js";
import {
defaultCredentialsPath,
defaultKeypairPath,
loadCredential,
loadKeypair,
saveCredential
} from "./bin-q0g6xvsw.js";
import"./bin-wckvcay0.js";
// src/cli/commands/self.ts
function notRegistered(credPath) {
return new CliError({
code: "NOT_FOUND",
exit: EXIT.NOT_FOUND,
message: `no stored credential at ${credPath} — this CLI is anonymous (no registered identity)`,
hint: "run `kestrel register` to self-register and mint a durable capability (proof-before-account: `sim`/`prove` still work anonymously)"
});
}
var EXPIRING_SOON_MS = 5 * 60 * 1000;
function expiryStatus(expiry, nowMs) {
const at = Date.parse(expiry);
if (Number.isNaN(at))
return { state: "unknown", remaining_ms: null, label: "unknown (unparseable expiry)" };
const remaining = at - nowMs;
if (remaining <= 0)
return { state: "expired", remaining_ms: remaining, label: `EXPIRED ${fmtDuration(-remaining)} ago — run \`kestrel refresh\`` };
if (remaining <= EXPIRING_SOON_MS)
return { state: "expiring", remaining_ms: remaining, label: `expiring in ${fmtDuration(remaining)} — run \`kestrel refresh\`` };
return { state: "valid", remaining_ms: remaining, label: `valid, expires in ${fmtDuration(remaining)}` };
}
function fmtDuration(ms) {
const totalSec = Math.floor(ms / 1000);
const h = Math.floor(totalSec / 3600);
const m = Math.floor(totalSec % 3600 / 60);
const s = totalSec % 60;
if (h > 0)
return `${h}h${String(m).padStart(2, "0")}m`;
return `${m}m${String(s).padStart(2, "0")}s`;
}
function whoamiCommand(argv, ctx, deps = {}) {
parseArgs(argv, new Set, new Set);
const env = deps.env ?? process.env;
const credPath = deps.credentialsPath ?? defaultCredentialsPath(env);
const cred = loadCredential(credPath);
if (cred === undefined)
throw notRegistered(credPath);
const keyPath = deps.keypairPath ?? defaultKeypairPath(env);
const keypair = loadKeypair(keyPath);
const nowMs = (deps.now ?? Date.now)();
const status = expiryStatus(cred.expiry, nowMs);
if (ctx.mode === "json") {
process.stdout.write(JSON.stringify({
schema: "kestrel.whoami/v1",
agent_id: cred.agent_id,
subject: cred.subject ?? null,
api: cred.api,
token_type: cred.token_type,
scopes: cred.scopes,
expiry: cred.expiry,
expiry_status: status.state,
expiry_remaining_ms: status.remaining_ms,
keypair_enrolled: keypair !== undefined,
credential_path: credPath,
...keypair !== undefined ? { keyfile_path: keyPath } : {},
...cred.claimed !== undefined ? { claimed_unverified: cred.claimed } : {}
}) + `
`);
return 0;
}
if (ctx.mode === "text") {
const lines = [
`agent_id ${cred.agent_id}`,
`subject ${cred.subject ?? ""}`,
`api ${cred.api}`,
`token_type ${cred.token_type}`,
`scopes ${cred.scopes.join(",")}`,
`expiry ${cred.expiry}`,
`expiry_status ${status.state}`,
`keypair_enrolled ${keypair !== undefined}`,
`credential_path ${credPath}`
];
process.stdout.write(lines.join(`
`) + `
`);
return 0;
}
const out = [
`agent_id ${cred.agent_id}`,
`subject ${cred.subject ?? "(none)"}`,
`api ${cred.api}`,
`token_type ${cred.token_type}`,
`scopes ${cred.scopes.join(", ")}`,
`expiry ${cred.expiry} (${status.label})`,
`keypair ${keypair !== undefined ? `enrolled — ${keyPath}` : "not enrolled"}`,
`credential ${credPath}`
];
if (cred.claimed !== undefined)
out.push(`claimed ${cred.claimed.name ?? "(no name)"} <${cred.claimed.email ?? "no-email"}> (UNVERIFIED)`);
process.stdout.write(out.join(`
`) + `
`);
return 0;
}
async function problemDetail(res, fallback) {
try {
const b = await res.json();
return b.detail ?? b.title ?? fallback;
} catch {
return fallback;
}
}
async function refreshCommand(argv, ctx, _globals, deps = {}) {
parseArgs(argv, new Set, new Set);
const env = deps.env ?? process.env;
const credPath = deps.credentialsPath ?? defaultCredentialsPath(env);
const cred = loadCredential(credPath);
if (cred === undefined)
throw notRegistered(credPath);
const fetchImpl = deps.fetch ?? globalThis.fetch;
if (fetchImpl === undefined)
throw new CliError({
code: "RUNTIME_UNAVAILABLE",
exit: EXIT.RUNTIME_UNAVAILABLE,
message: "global fetch unavailable — need node ≥18 or bun to refresh"
});
const base = cred.api.replace(/\/+$/, "");
const res = await fetchImpl(`${base}/capabilities/refresh`, {
method: "POST",
headers: { "content-type": "application/json", accept: "application/json", authorization: `Bearer ${cred.capability}` },
body: JSON.stringify({})
});
if (!res.ok) {
const detail = await problemDetail(res, `capability refresh failed (HTTP ${res.status})`);
throw new CliError({
code: `HTTP_${res.status}`,
exit: res.status >= 500 ? EXIT.RUNTIME_UNAVAILABLE : EXIT.GENERIC,
message: `capability refresh failed (HTTP ${res.status}): ${detail}`,
...res.status === 401 || res.status === 403 ? { hint: "the current capability may already be past its refresh window — run `kestrel register` to mint a fresh durable capability" } : {}
});
}
const body = await res.json();
if (typeof body.capability !== "string" || body.capability.length === 0)
throw new CliError({
code: "HTTP_502",
exit: EXIT.RUNTIME_UNAVAILABLE,
message: "capability refresh returned no usable capability token"
});
const next = {
...cred,
capability: body.capability,
...body.token_type !== undefined ? { token_type: body.token_type } : {},
...body.subject !== undefined ? { subject: body.subject } : {},
...body.scopes !== undefined ? { scopes: body.scopes } : {},
...body.expiry !== undefined ? { expiry: body.expiry } : {}
};
saveCredential(next, credPath);
emitRefreshResult(ctx, next, credPath);
return 0;
}
function emitRefreshResult(ctx, cred, credPath) {
if (ctx.mode === "json") {
process.stdout.write(JSON.stringify({
schema: "kestrel.refresh/v1",
agent_id: cred.agent_id,
subject: cred.subject ?? null,
api: cred.api,
token_type: cred.token_type,
scopes: cred.scopes,
expiry: cred.expiry,
credential_path: credPath
}) + `
`);
return;
}
if (ctx.mode === "text") {
process.stdout.write(`refreshed agent_id=${cred.agent_id} scopes=${cred.scopes.join(",")} expiry=${cred.expiry} credential=${credPath}
`);
return;
}
process.stdout.write(`refreshed ${cred.agent_id}
`);
process.stdout.write(` scopes: ${cred.scopes.join(", ")}
`);
process.stdout.write(` expiry: ${cred.expiry}
`);
process.stdout.write(` credential: ${credPath}
`);
}
export {
whoamiCommand,
refreshCommand,
expiryStatus
};