#!/usr/bin/env -S bun --no-env-file --config=/dev/null /** * gstack-ship-budget — the /ship token budget and fresh-context handoff * (docs/ship-budget.md). An admission cap: no step or dispatch starts unless * used + open reservations + unknown + its projection + the tail and stop * reserve fit under the cap. --mode observe (ship/DRIVER.md) only records: * note at each program's end, and the cap is one hard stop. Every --reading * takes --credits beside it. * * start --record [--token-cap ] [--mode admit|observe] [--meter capy|claude|estimate] [--reading ] [--credits ] * [--prior-reading ] [--session |--nonce ] [--reserve ] [--delegate auto|never] [--calibration ] [--ledger ] * note --run|--record --step [--label ] --reading [--credits ] [--dispatched-at [--dispatched-credits ] --readers ] * check --run |--record --step --next [,...]> [--reading ] [--credits ] [--prior-reading ] * [--returned [,...]] [--runtime-lines ] [--dispatched-at --readers ] * settle --run|--record --reservation [--unknown] [--reading ] [--credits ] [--dispatched-at --readers ] * release --run|--record --reservation * handoff --run|--record --from --to --base origin/ [--reviewed-tree ] [--trail --trail-run ] * [--sub-cap ] [--reading ] [--child-session ] * launch --in (Claude Code: background headless child with explicit permissions) * verify-handoff --in [--reading ] [--session ] * return --run --to [--changed ] [--status complete|refused|incomplete] [--reading ] * reconcile --run|--record (--return |--handoff ) [--reading ] * resume --record |--run [--reading ] [--meter ] [--session ] [--token-cap --approved-by --words ] * [--rebuild-from-record] * close --run|--record [--reading ] [--approved-by --words ] * calls --events [--since ] [--until ] (the host's transcript items: one CALLS: line, lib/ship-calls.ts) * * Exit: 0 continue/delegate · 3 stop (the next step does not start) · 2 usage * or validation (stderr). Logic: lib/ship-budget.ts, lib/ship-budget-cli.ts, * lib/ship-handoff.ts. */ import { BudgetError } from '../lib/ship-budget'; import { cmdCalls, cmdCheck, cmdClose, cmdNote, cmdResume, cmdSettle, cmdStart, type Outcome } from '../lib/ship-budget-cli'; import { cmdHandoff, cmdLaunch, cmdReconcile, cmdReturn, cmdVerifyHandoff } from '../lib/ship-handoff'; const [command, ...rest] = process.argv.slice(2); const ctx = { env: process.env, cwd: process.cwd() }; const commands: Record Outcome> = { start: () => cmdStart(rest, ctx), note: () => cmdNote(rest, ctx), check: () => cmdCheck(rest, ctx), settle: () => cmdSettle(rest, ctx), release: () => cmdSettle(rest, ctx, true), handoff: () => cmdHandoff(rest, ctx), launch: () => cmdLaunch(rest, ctx), 'verify-handoff': () => cmdVerifyHandoff(rest, ctx), return: () => cmdReturn(rest, ctx), reconcile: () => cmdReconcile(rest, ctx), resume: () => cmdResume(rest, ctx), close: () => cmdClose(rest, ctx), calls: () => cmdCalls(rest), }; if (!command || command === '--help' || command === '-h' || !commands[command]) { const lines = (await Bun.file(import.meta.path).text()).split('\n'); const text = lines.slice(2, lines.indexOf(' */')).map(l => l.replace(/^ \* ?/, '')).join('\n'); (command && command !== '--help' && command !== '-h' ? console.error : console.log)(text); process.exit(command && command !== '--help' && command !== '-h' ? 2 : 0); } try { const out = commands[command]!(); if (out.stdout.length) console.log(out.stdout.join('\n')); process.exit(out.exit); } catch (e) { if (!(e instanceof BudgetError)) throw e; if (e.exit === 3) console.log(e.message); else console.error(e.message); process.exit(e.exit); }