@binaryandthread/cli 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin.ts","../src/client-config.ts","../src/version.ts","../src/eggs.ts","../src/is-main.ts","../src/update-notice.ts","../src/keychain.ts","../src/commands/browse.ts","../src/commands/region.ts","../src/commands/completion.ts","../src/commands/search.ts","../src/commands/cart.ts","../src/commands/checkout.ts","../src/commands/order.ts","../src/jwt.ts","../src/commands/token.ts","../src/commands/log-graph.ts","../src/commands/log.ts","../src/commands/status.ts","../src/commands/unstage.ts","../src/commands/whoami.ts","../src/commands/drops.ts","../src/commands/connect.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/drop.ts","../src/commands/init.ts","../src/commands/buy.ts","../src/commands/config.ts","../src/commands/doctor.ts","../src/commands/report.ts","../src/commands/blame.ts"],"sourcesContent":["// bt — the Binary & Thread terminal store entrypoint + command router.\n//\n// PRIMARY invocation is `npx @binaryandthread/cli` (SECURITY G14) — a bare `bt` may collide\n// with an existing binary on PATH, so the help text says so. Cards never touch the terminal;\n// this is a dumb client over the Store API (all safety lives in the backend).\n//\n// Task 2 wires: --version (codename egg deferred to Wave-3 polish), --help, --no-color/--json,\n// and the C1 teapot egg (`bt brew coffee`). Task 3 wires browse/search/view/stage/cart.\n\nimport { spawn } from \"node:child_process\"\nimport { Command } from \"commander\"\nimport { StoreClient } from \"@binaryandthread/store-client\"\nimport { forgetConfig, loadConfig, saveConfig, type BtConfig } from \"./config\"\nimport { resolveClientConfig, makeLogger } from \"./client-config\"\nimport { VERSION } from \"./version\"\nimport { versionLine } from \"./voice\"\nimport {\n teapot,\n sudo,\n vim,\n panic,\n deploy,\n shipIt,\n rmWardrobe,\n force,\n gitClone,\n gitStash,\n gitPush,\n gitPull,\n gitReflog,\n fortune,\n manPage,\n FORTUNES,\n} from \"./eggs\"\nimport { formatFatal } from \"./errors\"\nimport { isMainModule } from \"./is-main\"\nimport { maybeNotifyUpdate } from \"./update-notice\"\nimport { getToken, setToken, deleteToken } from \"./keychain\"\nimport { makePrompts } from \"./prompts\"\nimport { registerBrowse } from \"./commands/browse\"\nimport { registerRegion } from \"./commands/region\"\nimport { registerCompletion } from \"./commands/completion\"\nimport { registerSearch } from \"./commands/search\"\nimport { registerView } from \"./commands/view\"\nimport { registerStage } from \"./commands/stage\"\nimport { registerCart } from \"./commands/cart\"\nimport { registerCheckout } from \"./commands/checkout\"\nimport { registerOrder } from \"./commands/order\"\nimport { registerLog } from \"./commands/log\"\nimport { registerStatus } from \"./commands/status\"\nimport { registerUnstage } from \"./commands/unstage\"\nimport { registerWhoami } from \"./commands/whoami\"\nimport { registerDrops } from \"./commands/drops\"\nimport { registerConnect } from \"./commands/connect\"\nimport { registerLogin } from \"./commands/login\"\nimport { registerLogout } from \"./commands/logout\"\nimport { registerDrop, type DropExecPort } from \"./commands/drop\"\nimport { registerInit } from \"./commands/init\"\nimport { registerBuy } from \"./commands/buy\"\nimport { registerConfig } from \"./commands/config\"\nimport { registerToken, resolveBridgeToken } from \"./commands/token\"\nimport { registerDoctor } from \"./commands/doctor\"\nimport { registerReport } from \"./commands/report\"\nimport { registerBlame } from \"./commands/blame\"\n\nexport interface GlobalOpts {\n json: boolean\n color: boolean\n}\n\n/**\n * Build a StoreClient from env + baked-in prod defaults. The publishable key is PUBLIC by design\n * (T6) and ships baked in so `npx @binaryandthread/cli` Just Works with zero setup (d2); any env\n * var overrides it for local dev / staging (see resolveClientConfig).\n */\nexport function makeClient(): StoreClient {\n const { baseUrl, publishableKey } = resolveClientConfig()\n // The customer-scoped JWT: env BT_TOKEN (CI/non-interactive) wins, else the OS keychain (d18).\n // Guest (no token) by default. The token is NEVER read from the plaintext config (G15).\n const jwt = resolveBridgeToken(process.env, getToken()) ?? undefined\n // Quiet by default; --debug/--verbose enables redacted request tracing to stderr (d15).\n const debug = process.argv.includes(\"--debug\") || process.argv.includes(\"--verbose\")\n return new StoreClient({\n baseUrl,\n publishableKey,\n jwt,\n logger: makeLogger(debug),\n })\n}\n\nexport function buildProgram(): Command {\n const program = new Command()\n\n program\n .name(\"bt\")\n .description(\n \"the binary & thread terminal store. techno-minimalist clothing & lifestyle, bought with the ceremony of a deploy.\\n\" +\n \"primary invocation: npx @binaryandthread/cli (a bare `bt` may collide with another binary)\"\n )\n .version(versionLine(VERSION), \"-v, --version\", \"print the version\")\n .option(\"--json\", \"machine-readable output\", false)\n .option(\"--no-color\", \"disable ANSI colour + inline images (also honours NO_COLOR)\")\n .option(\"--debug, --verbose\", \"trace requests to stderr (redacted) — for bug reports (d15)\")\n // Ship-to country for THIS invocation, overriding the saved region (bt config set region / bt\n // region). Scriptable + parity with the MCP per-call region. Overlaid onto config by\n // effectiveConfig below, so every region-aware command honours it with no per-command wiring.\n .option(\"--region <cc>\", \"ship-to country for this command (ISO-2, overrides your saved region)\")\n // On a typo of a REAL command, suggest the closest one (\"did you mean bt browse?\") instead of a\n // bare \"unknown command\". Git-verb typos (clone/stash/push/reflog) are caught as eggs below.\n .showSuggestionAfterError()\n\n // First-run banner — surfaced where a newcomer looks (bare `bt` / `bt --help`). Not printed in\n // --json (help text never is). Points at `bt init` for the happy path (d3).\n program.addHelpText(\"beforeAll\", \"\\n bt — the binary & thread terminal store. new here? → bt init\\n\")\n\n // C1 teapot egg — `bt brew` → 418. Evergreen Core (governed copy). The 418 lives in the\n // MESSAGE, not the exit code: an egg must never set a non-zero exit (it would poison a script\n // that happens to run it) — d11.\n program\n .command(\"brew\")\n .argument(\"[what]\", \"what to brew\")\n .description(\"we make clothing, not coffee.\")\n .action(() => {\n process.stdout.write(teapot() + \"\\n\")\n })\n\n // The governed egg family (VOICE §3.1). Each prints a deadpan line and EXITS 0 — an egg must\n // never change behaviour or poison a script's exit code (d11). registerEggs keeps bin.ts lean.\n registerEggs(program)\n\n // `bt forget` — the GDPR erasure path (G15): wipe the keychain token AND the local PII config.\n program\n .command(\"forget\")\n .description(\"wipe your local session + config (keychain token, cart, email, defaults).\")\n .action(() => {\n deleteToken() // keychain JWT + the 0600 fallback (G15)\n forgetConfig() // ~/.config/bt PII (email/cart_id)\n const json = Boolean((program.opts() as { json?: boolean }).json)\n if (json) process.stdout.write(JSON.stringify({ wiped: true }) + \"\\n\")\n else process.stdout.write(\"✓ local session + config wiped. (your wardrobe on the server is untouched.)\\n\")\n })\n\n // Task-3 read + cart commands (browse/search/view/stage/cart) are registered here.\n registerCommands(program)\n\n return program\n}\n\n/**\n * The drop exec port: run a backend `medusa exec` drop script via npm. Uses spawn with an ARGUMENT\n * ARRAY (no shell string interpolation) so a drop_id/slug can never inject a shell command. The env\n * is passed through the child's env, not the command line.\n */\nconst dropExec: DropExecPort = {\n run(script, env) {\n return new Promise<number>((resolve) => {\n const cwd = process.env.BT_BACKEND_DIR || process.cwd()\n const child = spawn(\"npm\", [\"run\", script], {\n cwd,\n env: { ...process.env, ...env },\n stdio: \"inherit\",\n })\n child.on(\"close\", (code) => resolve(code ?? 1))\n child.on(\"error\", () => resolve(1))\n })\n },\n}\n\n/** The Task-3 read + cart commands; each is a thin function over StoreClient. */\nfunction registerCommands(program: Command): void {\n const persist = (patch: Partial<BtConfig>) => {\n saveConfig(patch)\n }\n // Effective config = the saved config with the global `--region <cc>` overlaid for THIS run. Every\n // region-aware command reads config.region, so passing this wrapper (instead of the raw loader)\n // makes the flag work everywhere with zero per-command wiring. `bt config get/set` deliberately\n // uses the RAW persisted config (it manages the saved value, not the per-invocation override).\n const effectiveConfig = (): BtConfig => {\n const saved = loadConfig()\n const flag = (program.opts() as { region?: string }).region\n return flag ? { ...saved, region: flag.trim().toLowerCase() } : saved\n }\n registerInit(program)\n registerBrowse(program, makeClient, effectiveConfig)\n registerSearch(program, makeClient, effectiveConfig)\n registerView(program, makeClient, effectiveConfig)\n registerStage(program, makeClient, effectiveConfig)\n registerBuy(program, makeClient, effectiveConfig)\n registerConfig(program)\n registerRegion(program, makeClient, effectiveConfig, persist)\n registerCompletion(program)\n registerToken(program)\n registerDoctor(program)\n registerReport(program, makeClient)\n registerBlame(program, makeClient, effectiveConfig)\n registerCart(program, makeClient, effectiveConfig)\n registerCheckout(program, makeClient, effectiveConfig)\n // Task-3 tracking + management commands.\n registerOrder(program, makeClient, effectiveConfig)\n registerLog(program, makeClient, effectiveConfig)\n registerStatus(program, makeClient, effectiveConfig)\n registerWhoami(program, makeClient, effectiveConfig)\n registerDrops(program, makeClient, effectiveConfig)\n registerConnect(program)\n registerUnstage(program, makeClient, effectiveConfig)\n // Wave-5 auth + operator commands.\n const prompts = makePrompts()\n registerLogin(\n program,\n makeClient,\n effectiveConfig,\n prompts,\n { setToken: (jwt: string) => setToken(jwt) },\n persist\n )\n registerLogout(program, { deleteToken: () => deleteToken() })\n registerDrop(program, dropExec)\n}\n\n/**\n * The governed easter-egg family (VOICE §3.1). HARD invariant: every egg prints a line and exits 0\n * — never a non-zero exit (it would poison a script that runs it — d11), never a behaviour change.\n * Most are hidden from `--help` (eggs are \"if you know, you know\"); `fortune` is visible because\n * it's a genuine, harmless utility. Unknown options are allowed where a command mimics a real one\n * (`rm -rf`, `deploy --prod`) so commander doesn't reject the joke.\n */\nfunction registerEggs(program: Command): void {\n const print = (s: string): void => {\n process.stdout.write(s + \"\\n\")\n }\n\n // C2 ★ — sudo. `bt sudo <anything>`.\n program.command(\"sudo\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(sudo()))\n // C7 ★ — vim.\n program.command(\"vim\", { hidden: true }).action(() => print(vim()))\n // C17 — panic.\n program.command(\"panic\", { hidden: true }).action(() => print(panic()))\n // C16 — deploy (did-you-mean → commit).\n program.command(\"deploy\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(deploy()))\n // C18 ★ — ship it.\n program.command(\"ship\", { hidden: true }).argument(\"[what]\").action(() => print(shipIt()))\n // C12 — rm -rf ~/wardrobe (defused warmly; never destructive).\n program.command(\"rm\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(rmWardrobe()))\n // --force flavour, as a hidden verb.\n program.command(\"force\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(force()))\n\n // git verbs that aren't ours — deadpan did-you-mean redirects (hidden; allow args so\n // `bt push origin main` / `bt clone <url>` don't error before the joke lands).\n program.command(\"clone\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitClone()))\n program.command(\"stash\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitStash()))\n program.command(\"push\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitPush()))\n program.command(\"pull\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitPull()))\n program.command(\"reflog\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitReflog()))\n\n // C5 / delight #6 — blame is now a real, data-backed provenance command (see registerCommands →\n // registerBlame): it shows a design's actual lore + sources, falling back to the generic\n // provenance line. Kept out of registerEggs because it fetches.\n\n // C10 — fortune (visible: a real, harmless utility). Rotates through real dev aphorisms; the seed\n // rotates per invocation so successive runs differ, but each line is deterministic given a seed.\n program\n .command(\"fortune\")\n .description(\"a coding fortune. real aphorisms only.\")\n .action(() => {\n // Date is available in the real Node runtime (only workflow scripts forbid it); rotate by it.\n const seed = Math.floor(Date.now() / 1000) % FORTUNES.length\n print(fortune(seed))\n })\n\n // C3 ★ — man bt. `bt man` prints the real man page (the system `man bt` reads the bundled roff).\n program\n .command(\"man\", { hidden: true })\n .description(\"the bt man page (also installed for the system man(1)).\")\n .action(() => print(manPage(VERSION).join(\"\\n\")))\n}\n\n// Only auto-run when invoked as the binary (not when imported by tests). This compares the\n// invoked path against this module's own URL with symlinks resolved on both sides — so the npm\n// bin shim (a symlink named `bt`/`btn`, NOT `bin.js`) still counts as \"main\". See ./is-main for\n// why a `argv[1].endsWith(\"bin.js\")` check silently no-ops every real `npx` install.\nif (isMainModule(process.argv[1], import.meta.url)) {\n buildProgram()\n .parseAsync(process.argv)\n .catch((e) => {\n // Distinct exit codes + a JSON error envelope so CI/agents can branch on the failure (d10).\n const json = process.argv.includes(\"--json\")\n const { out, err, code } = formatFatal(e, json)\n if (out) process.stdout.write(out + \"\\n\")\n if (err) process.stderr.write(err + \"\\n\")\n process.exitCode = code\n })\n .finally(() => {\n // A gentle \"you're behind\" nudge AFTER the command, to STDERR only, human-terminal only.\n // Never touches stdout / --json / CI (see isUpdateCheckSuppressed); never blocks or throws.\n maybeNotifyUpdate({\n current: VERSION,\n env: process.env,\n argv: process.argv,\n stderrIsTTY: Boolean(process.stderr.isTTY),\n write: (s) => process.stderr.write(s),\n })\n })\n}\n","// Resolve the StoreClient transport config (base URL + publishable key) from the environment,\n// falling back to the baked-in PUBLIC production defaults so `npx @binaryandthread/cli` works\n// with zero setup (d2 / P4.5-7b). Env ALWAYS wins — set BT_API_URL / BT_PUBLISHABLE_KEY (or the\n// MEDUSA_* equivalents) to point at local dev or staging. An empty-string env value is ignored.\n\nimport { BT_DEFAULT_STORE_URL, BT_DEFAULT_PUBLISHABLE_KEY, redact } from \"@binaryandthread/store-client\"\nimport type { ClientLogger } from \"@binaryandthread/store-client\"\n\nexport interface ResolvedClientConfig {\n baseUrl: string\n publishableKey: string\n}\n\nexport function resolveClientConfig(env: NodeJS.ProcessEnv = process.env): ResolvedClientConfig {\n const baseUrl = env.BT_API_URL || env.MEDUSA_BACKEND_URL || BT_DEFAULT_STORE_URL\n const publishableKey =\n env.BT_PUBLISHABLE_KEY || env.MEDUSA_PUBLISHABLE_KEY || BT_DEFAULT_PUBLISHABLE_KEY\n return { baseUrl, publishableKey }\n}\n\n/**\n * The StoreClient logger. QUIET by default (the client's internal store.request.* events are noise\n * to a normal user — the friendly fatal handler covers real failures); --debug/--verbose turns on\n * redacted request tracing to stderr (d15). Everything passes through redact() (G10).\n */\nexport function makeLogger(debug: boolean, write: (s: string) => void = (s) => process.stderr.write(s)): ClientLogger {\n if (!debug) {\n const noop = (): void => {}\n return { info: noop, warn: noop, error: noop }\n }\n return {\n info: (...a) => write(\"· \" + JSON.stringify(redact(a)) + \"\\n\"),\n warn: (...a) => write(\"⚠ \" + JSON.stringify(redact(a)) + \"\\n\"),\n error: (...a) => write(\"✗ \" + JSON.stringify(redact(a)) + \"\\n\"),\n }\n}\n","// The single source of truth for the CLI version string.\n//\n// Mirrored into cli/package.json's \"version\" field; version.test.ts asserts the two never drift.\n// We don't import package.json directly (JSON imports complicate the ESM dist build), so this\n// literal is the canonical value the binary reports (bt --version) and bt doctor's snapshot.\nexport const VERSION = \"0.2.0\"\n","// The governed CLI easter-egg catalog (VOICE §3.1 + the five-gate governance §3.5).\n//\n// EVERY egg here is: opt-in (off the happy/critical path), deadpan, leans on a REAL dev reference\n// (RFC / exit code / git verb / a genuine holy war / a real dev aphorism), and — the hard rule —\n// NEVER changes behaviour or sets a non-zero exit code (an egg that poisoned a script's exit would\n// be a bug, not a joke; d11). These are pure string functions; bin.ts wires them to commands that\n// print the line and exit 0.\n//\n// Brand voice (memory brand-voice-no-pod-no-tshirt — the HARD rule, postdates VOICE.md): NEVER\n// \"t-shirt\"/\"tee\"/\"print\"/Gelato in any copy. Products are \"clothing\"/\"pieces\"/\"fits\"/\"the wardrobe\".\n\nimport { GLYPH } from \"./voice\"\n\n/** C1 ★ — the canonical teapot. Evergreen Core. Cites the RFC, delivered straight. (brew coffee → 418) */\nexport function teapot(): string {\n return `${GLYPH.fail} 418 i'm a teapot. we make clothing, not coffee. (RFC 2324)`\n}\n\n/** C2 ★ — sudo. One line, no follow-up. */\nexport function sudo(): string {\n return \"nice try. you don't have root on fashion.\"\n}\n\n/** C7 ★ — the eternal vim-exit gag, one line. */\nexport function vim(): string {\n return \"to exit, commit a piece. (:q won't save you here.)\"\n}\n\n/** C17 — bt panic. A genuinely kind response to a desperate command. */\nexport function panic(): string {\n return \"don't. nothing's on fire. your orders are safe. take a walk; the wardrobe will still be here.\"\n}\n\n/** C16 — bt deploy. A helpful did-you-mean that's also a joke about working too much. */\nexport function deploy(): string {\n return (\n `${GLYPH.fail} command not found: deploy. you mean \\`bt commit\\`?\\n` +\n \" we ship clothing, not services. did you fat-finger your day job?\"\n )\n}\n\n/** C18 ★ — bt ship it. Redirects to the real verb; no meme, just the did-you-mean. */\nexport function shipIt(): string {\n return `that's commit's job. ${GLYPH.arrow} bt commit`\n}\n\n/** C12 — bt rm -rf ~/wardrobe. Defuses a scary-looking command warmly; never destructive. */\nexport function rmWardrobe(): string {\n return (\n `${GLYPH.warn} this would delete your entire order history. it won't, obviously —\\n` +\n \" we don't have rm on your memories. (and you can't unship a delivered piece.)\"\n )\n}\n\n/** --force flavour. Deadpan: a commit to your wardrobe is already that decisive. */\nexport function force(): string {\n return (\n \"--force-pushing to prod, are we. there's no --force here —\\n\" +\n \" a commit to your wardrobe is already that decisive.\"\n )\n}\n\n// git verbs that aren't ours — deadpan did-you-mean redirects. Each leans on the real git verb,\n// points at the right bt command, and (like every egg) prints one line and exits 0. Turns the\n// off-brand \"unknown command\" surface into an on-brand one for muscle-memory git typos.\n\n/** `bt clone` — you can't clone a one-of-one motif. */\nexport function gitClone(): string {\n return \"no clone for a fit — each one's committed by hand. browse the originals → bt browse\"\n}\n\n/** `bt stash` — that's unstage; nothing is lost. */\nexport function gitStash(): string {\n return \"that's bt unstage here. your cart holds; nothing's lost.\"\n}\n\n/** `bt push` — the only push that ships is a commit. */\nexport function gitPush(): string {\n return \"no remote for your wardrobe. the only push that ships → bt commit\"\n}\n\n/** `bt pull` — the freshest designs arrive by drop, not by fetch. */\nexport function gitPull(): string {\n return \"nothing to pull — the freshest designs land as drops → bt drops\"\n}\n\n/** `bt reflog` — your history is bt log; nothing is ever truly lost. */\nexport function gitReflog(): string {\n return \"nothing's ever truly lost here. your history → bt log\"\n}\n\n/**\n * C10 — fortune. A rotating pool of REAL dev aphorisms (gate 1: never invented). Attributed where\n * the attribution is well-established. `fortune(seed)` is deterministic for tests + reproducible\n * screenshots; bin.ts passes a rotating seed.\n */\nexport const FORTUNES: ReadonlyArray<string> = [\n '// \"there are only two hard things in computer science: cache invalidation and naming things.\" — phil karlton',\n '// \"premature optimization is the root of all evil.\" — donald knuth',\n '// \"weeks of programming can save you hours of planning.\"',\n '// \"make it work, make it right, make it fast.\" — kent beck',\n '// \"talk is cheap. show me the code.\" — linus torvalds',\n '// \"given enough eyeballs, all bugs are shallow.\" — linus\\'s law',\n '// \"always code as if the person maintaining it is a violent psychopath who knows where you live.\" — john woods',\n '// \"it works on my machine.\"',\n]\n\nexport function fortune(seed = 0): string {\n const n = Number.isFinite(seed) ? Math.abs(Math.floor(seed)) : 0\n // modulo over a non-empty const pool always hits a real index (the ! is safe by construction).\n return FORTUNES[n % FORTUNES.length]!\n}\n\n/**\n * C5 / brand-delight #6 — bt blame. Provenance/lore, deadpan. We do NOT invent designer names\n * (gate 1: no invented references) — per-design author attribution needs a real crew/lore dataset\n * (noted as a follow-up). What we CAN state truthfully: every motif is a deliberate collision of a\n * style and an idea, curated by hand. With a slug, we name it; without, we credit the process.\n */\nexport function blame(slug?: string): string {\n const subject = slug ? slug.trim() : \"\"\n if (subject) {\n return (\n `blame ${subject}\\n` +\n \" motif a style × an idea, collided on purpose — then curated by hand, not shipped raw.\\n\" +\n \" crew the people at Binary & Thread. (per-designer credit is coming — bt drops to watch.)\"\n )\n }\n return (\n \"blame — who's responsible for all this?\\n\" +\n \" every piece here is a style collided with an idea, curated by hand at Binary & Thread.\\n\" +\n \" nothing auto-shipped. someone looked at each one. that's the whole point.\"\n )\n}\n\n/**\n * man bt — a real, correctly-structured man page (VOICE C3). The jokes live in the footer sections\n * devs actually read (BUGS / AUTHORS / SEE ALSO); the page itself is genuinely useful. Returned as\n * plain man-styled text for `bt man`; a roff `man/bt.1` ships alongside for the system `man bt`.\n */\nexport function manPage(version: string): string[] {\n return [\n \"BT(1) Binary & Thread BT(1)\",\n \"\",\n \"NAME\",\n \" bt — the Binary & Thread terminal store\",\n \"\",\n \"SYNOPSIS\",\n \" bt <command> [options]\",\n \" npx @binaryandthread/cli <command> [options]\",\n \"\",\n \"DESCRIPTION\",\n \" Binary & Thread is a techno-minimalist clothing & lifestyle\",\n \" company. bt is its terminal store: you browse, stage, and commit\",\n \" pieces with the ceremony of a deploy. Payment opens in your\",\n \" browser — cards never touch the terminal.\",\n \"\",\n \"COMMANDS\",\n \" init first-run welcome + the happy path\",\n \" browse list what's in stock\",\n \" view render one piece (image or ASCII) + specs\",\n \" stage reserve stock (like git add)\",\n \" commit turn your staged items into an order\",\n \" buy stage + commit in one\",\n \" log your order history as a git log (--graph, --oneline)\",\n \" order track one order through its lifecycle\",\n \" whoami your contribution profile + standing\",\n \" drops what's on next, before it hits the web\",\n \" login passwordless magic-link sign-in\",\n \" report file a bug report (you become a contributor)\",\n \"\",\n \"ENVIRONMENT\",\n \" NO_COLOR disable ANSI colour + inline images\",\n \" BT_TOKEN a customer JWT for non-interactive sessions\",\n \" BT_STORE_URL override the store base URL (defaults baked in)\",\n \"\",\n \"EXIT STATUS\",\n \" 0 success 1 general error\",\n \" 75 EX_TEMPFAIL — a transient failure; nothing was charged, retry\",\n \"\",\n \"BUGS\",\n \" none known. if you find one, you're now a contributor.\",\n \" file it: bt report (or bugs@binaryandthread.com)\",\n \"\",\n \"AUTHORS\",\n \" The crew at Binary & Thread, and every contributor who committed\",\n \" a fit. earned, not bought.\",\n \"\",\n \"SEE ALSO\",\n \" git(1), curl(1), a mirror. go build something.\",\n \"\",\n `Binary & Thread bt ${version} BT(1)`,\n ]\n}\n","// Is THIS module the program entry (a real invocation) — or is it being imported as a library\n// (by the test runner, or by another module)? The bin only auto-runs when the former is true.\n//\n// WHY NOT `process.argv[1].endsWith(\"bin.js\")`: npm installs the package's `bin` field as a shim\n// whose basename is the COMMAND name (`bt`/`btn`, or an `npx` cache path) — a symlink to\n// dist/bin.js — so `process.argv[1]` NEVER ends in \"bin.js\" for a real install. A filename check\n// therefore returns false for EVERY `npx @binaryandthread/cli …` invocation → the CLI loads,\n// concludes it's a library, and exits 0 in silence. (Reported by Simon Hagert, 2026-07-07.)\n//\n// The robust check: compare the invoked path (argv[1]) against this module's own URL, resolving\n// symlinks on BOTH sides so the npm shim (symlink → dist/bin.js) collapses onto the real file.\n// Resolving both sides also makes it correct regardless of Node's `--preserve-symlinks-main`.\n\nimport { realpathSync } from \"node:fs\"\nimport { fileURLToPath } from \"node:url\"\n\nexport function isMainModule(\n argv1: string | undefined,\n moduleUrl: string,\n realpath: (p: string) => string = realpathSync,\n): boolean {\n if (typeof argv1 !== \"string\" || argv1.length === 0) return false\n try {\n const invoked = realpath(argv1)\n const self = realpath(fileURLToPath(moduleUrl))\n return invoked === self\n } catch {\n // A non-existent path, a non-file URL, etc. — safest default is \"not the entry\" (stay quiet\n // as a library) rather than risk auto-running where we shouldn't.\n return false\n }\n}\n","// A gentle \"you're behind\" nudge — the update-notifier pattern. On a real terminal run, print ONE\n// dim line to STDERR if a newer bt is published, and refresh the check-cache in the background at\n// most once a day. HARD rules: never touch stdout (would corrupt --json / a pipe), never block the\n// command (the notice comes from cache; the registry fetch is fire-and-forget), never throw.\n\nimport * as fs from \"node:fs\"\nimport * as path from \"node:path\"\nimport { configDir } from \"./config\"\n\nconst CACHE_FILE = \"update-check.json\"\nconst CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000 // at most once a day\nconst REGISTRY_LATEST = \"https://registry.npmjs.org/@binaryandthread/cli/latest\"\nconst FETCH_TIMEOUT_MS = 2_000\n\nexport interface UpdateCache {\n lastCheck: number\n latest: string\n}\n\nfunction parseSemver(v: string): [number, number, number] | null {\n const m = /^(\\d+)\\.(\\d+)\\.(\\d+)/.exec((v ?? \"\").trim())\n return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null\n}\n\n/** Numeric major.minor.patch \"greater than\" (pre-release/build ignored; false on malformed). */\nexport function semverGt(a: string, b: string): boolean {\n const pa = parseSemver(a)\n const pb = parseSemver(b)\n if (!pa || !pb) return false\n for (let i = 0; i < 3; i++) {\n if (pa[i]! > pb[i]!) return true\n if (pa[i]! < pb[i]!) return false\n }\n return false\n}\n\n/** The dim, on-voice nudge when `latest` is newer than `current`, else null. */\nexport function updateNoticeLine(current: string, latest: string | null | undefined): string | null {\n if (!latest || !semverGt(latest, current)) return null\n return `⚙ a newer bt is out (${latest}). update → npm i -g @binaryandthread/cli@latest`\n}\n\n/** A nudge is for a human at a terminal — never on non-TTY, --json, CI, or an explicit opt-out. */\nexport function isUpdateCheckSuppressed(\n env: NodeJS.ProcessEnv,\n argv: string[],\n stderrIsTTY: boolean\n): boolean {\n if (!stderrIsTTY) return true\n if (argv.includes(\"--json\")) return true\n if (env.CI || env.BT_NO_UPDATE_NOTIFIER || env.NO_UPDATE_NOTIFIER) return true\n return false\n}\n\nexport interface NotifyDeps {\n current: string\n env: NodeJS.ProcessEnv\n argv: string[]\n stderrIsTTY: boolean\n write: (s: string) => void\n now?: number\n readCache?: () => UpdateCache | null\n refresh?: (now: number) => void\n}\n\n/**\n * Print the notice from the LAST-known latest (cache → instant, never blocks), then refresh the\n * cache in the background at most once a day (fire-and-forget). All I/O is injectable for tests.\n */\nexport function maybeNotifyUpdate(deps: NotifyDeps): void {\n if (isUpdateCheckSuppressed(deps.env, deps.argv, deps.stderrIsTTY)) return\n const now = deps.now ?? Date.now()\n const read = deps.readCache ?? readUpdateCache\n const refresh = deps.refresh ?? ((n: number) => void fetchLatestIntoCache(n))\n\n const cache = read()\n const line = updateNoticeLine(deps.current, cache?.latest)\n if (line) deps.write(line + \"\\n\")\n\n if (!cache || now - cache.lastCheck > CHECK_INTERVAL_MS) {\n refresh(now)\n }\n}\n\n// ---- best-effort cache I/O (never throws) ----\nfunction cachePath(): string {\n return path.join(configDir(), CACHE_FILE)\n}\n\nexport function readUpdateCache(): UpdateCache | null {\n try {\n const j = JSON.parse(fs.readFileSync(cachePath(), \"utf8\"))\n if (j && typeof j.latest === \"string\" && typeof j.lastCheck === \"number\") {\n return { latest: j.latest, lastCheck: j.lastCheck }\n }\n } catch {\n /* no/one bad cache — treat as absent */\n }\n return null\n}\n\nfunction writeUpdateCache(c: UpdateCache): void {\n try {\n fs.mkdirSync(configDir(), { recursive: true })\n const tmp = cachePath() + \".tmp\"\n fs.writeFileSync(tmp, JSON.stringify(c), \"utf8\")\n fs.renameSync(tmp, cachePath())\n } catch {\n /* best-effort */\n }\n}\n\nasync function fetchLatestIntoCache(now: number): Promise<void> {\n try {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS)\n try {\n const res = await fetch(REGISTRY_LATEST, { signal: ctrl.signal })\n if (!res.ok) return\n const data = (await res.json()) as { version?: unknown }\n if (typeof data.version === \"string\") {\n writeUpdateCache({ lastCheck: now, latest: data.version })\n }\n } finally {\n clearTimeout(timer)\n }\n } catch {\n /* offline / registry down / aborted — silently skip; try again next day */\n }\n}\n","// keychain.ts — OS-keychain token storage via @napi-rs/keyring (SECURITY G7/G8).\n//\n// The customer-scoped JWT lives in the OS keychain (macOS Keychain / Windows Credential Manager /\n// libsecret on Linux) — NEVER in the plaintext ~/.config/bt config (that's the leak G15 forbids).\n// We use @napi-rs/keyring, the MAINTAINED keychain lib (G7) — never the archived/unmaintained\n// alternative the threat model calls out.\n//\n// FALLBACK (SECURITY §4): if the OS keychain is unavailable (a headless CI box, an unusual Linux with\n// no secret service), we fall back to a 0600 file in ~/.config/bt — documented, owner-read-only, and\n// clearly second-best. The token is short-lived (the backend JWT TTL is minutes), so even the fallback\n// has a bounded exposure window. The keychain path is always tried FIRST.\n//\n// Service/account namespacing: service = \"binaryandthread/bt\", account = \"jwt\". One token per machine\n// user. deleteToken is used by `bt logout` + `bt forget`.\n\nimport * as fs from \"node:fs\"\nimport * as os from \"node:os\"\nimport * as path from \"node:path\"\n\n/** The keychain service + account names (namespaced to the project). */\nexport const KEYCHAIN_SERVICE = \"binaryandthread/bt\"\nexport const KEYCHAIN_ACCOUNT = \"jwt\"\n\n/** The 0600 fallback token path (only used when the OS keychain is unavailable). */\nfunction fallbackTokenPath(): string {\n const xdg = process.env.XDG_CONFIG_HOME\n const base = xdg && xdg.trim() ? xdg : path.join(os.homedir(), \".config\")\n return path.join(base, \"bt\", \"token\")\n}\n\n/** The keyring Entry interface we depend on (a structural subset of @napi-rs/keyring's Entry). */\nexport interface KeyringEntry {\n getPassword(): string | null\n setPassword(password: string): void\n deletePassword(): boolean\n}\n\nexport interface KeychainDeps {\n /** Build a keyring Entry for (service, account). Injected for tests; defaults to @napi-rs/keyring. */\n makeEntry?: (service: string, account: string) => KeyringEntry | null\n}\n\n/** Lazily load @napi-rs/keyring and build an Entry; returns null if the native lib can't load. */\nfunction defaultMakeEntry(service: string, account: string): KeyringEntry | null {\n try {\n // Lazy require so a missing native binary degrades to the file fallback rather than crashing import.\n const { Entry } = require(\"@napi-rs/keyring\") as {\n Entry: new (service: string, account: string) => KeyringEntry\n }\n return new Entry(service, account)\n } catch {\n return null\n }\n}\n\n/** Store the JWT in the OS keychain (preferred) or the 0600 fallback file. */\nexport function setToken(jwt: string, deps: KeychainDeps = {}): void {\n const make = deps.makeEntry ?? defaultMakeEntry\n const entry = make(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT)\n if (entry) {\n try {\n entry.setPassword(jwt)\n // Belt-and-suspenders: if a stale fallback file exists, remove it (the keychain is now truth).\n try {\n fs.rmSync(fallbackTokenPath(), { force: true })\n } catch {\n /* ignore */\n }\n return\n } catch {\n // Fall through to the file fallback.\n }\n }\n // Fallback: a 0600 file (owner-read-only). Documented second-best (SECURITY §4).\n const target = fallbackTokenPath()\n fs.mkdirSync(path.dirname(target), { recursive: true })\n const tmp = target + \".tmp\"\n fs.writeFileSync(tmp, jwt, { encoding: \"utf8\", mode: 0o600 })\n fs.renameSync(tmp, target)\n}\n\n/** Read the JWT from the OS keychain (preferred) or the 0600 fallback. null if none. */\nexport function getToken(deps: KeychainDeps = {}): string | null {\n const make = deps.makeEntry ?? defaultMakeEntry\n const entry = make(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT)\n if (entry) {\n try {\n const pw = entry.getPassword()\n if (pw) {\n return pw\n }\n } catch {\n // Fall through to the file fallback.\n }\n }\n try {\n const raw = fs.readFileSync(fallbackTokenPath(), \"utf8\").trim()\n return raw || null\n } catch {\n return null\n }\n}\n\n/** Delete the JWT from BOTH the keychain and the fallback file (bt logout / bt forget — G15). */\nexport function deleteToken(deps: KeychainDeps = {}): void {\n const make = deps.makeEntry ?? defaultMakeEntry\n const entry = make(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT)\n if (entry) {\n try {\n entry.deletePassword()\n } catch {\n /* ignore — still wipe the fallback below */\n }\n }\n try {\n fs.rmSync(fallbackTokenPath(), { force: true })\n } catch {\n /* ignore */\n }\n}\n","// bt browse — list in-stock products for the resolved region (VOICE §2.1).\n//\n// Region is RESOLVED (config.region or region #1 from the API) — never a hardcoded SEK/SE\n// literal (F-A2 / INV-11). --branch=next also pulls drops via listDrops. The cached list is\n// advisory only; the cart re-validates price/availability at stage (F-A4).\n//\n// A1: the product TITLE is the primary name (matches checkout/web), with the handle shown\n// secondarily/dimmed (still needed for bt view/bt stage).\n// A3: a compact colour marker per product (⬜⬛ white/black), DERIVED from the variants.\n// B1/B2: a header treatment + cyan price accent; degrades cleanly under --json / NO_COLOR.\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { productColours } from \"@binaryandthread/store-client\"\nimport {\n fmtPrice,\n firstPrice,\n stageMarker,\n displayName,\n brandOf,\n regionLine,\n printResult,\n resolveOutput,\n type HandlerResult,\n type Branded,\n} from \"./shared\"\nimport { header, cyan, dim, colourMarker, type BrandStyle } from \"../brand\"\nimport type { StoreClient, ProductLike, DropRow, BtConfigLike } from \"./types-bridge\"\n\nexport interface BrowseArgs extends Branded {\n branch?: string\n json?: boolean\n}\n\n/** Truncate to width with a trailing ellipsis (never mid-ANSI — callers pass raw text). */\nfunction truncate(s: string, w: number): string {\n if (s.length <= w) return s\n if (w <= 1) return s.slice(0, Math.max(0, w))\n return s.slice(0, w - 1) + \"…\"\n}\n\n/**\n * Lay out the in-stock rows as an aligned table that ADAPTS to the terminal (#3/E1) — measure the\n * real content + `stdout.columns`, right-align the price like a ledger, keep the SLUG full (it's the\n * copy-target for `bt stage <slug>`, #6), and truncate the descriptive TITLE when space is tight.\n * When the width is unknown (piped/non-TTY) nothing is constrained — `--json` is the tool there.\n */\nfunction layoutRows(rows: Array<{ p: ProductLike; stage: string }>, style: BrandStyle): string[] {\n const cells = rows.map(({ p, stage }, i) => {\n const { amount, currency } = firstPrice(p)\n const { title, handle } = displayName(p)\n return {\n ref: `[${i + 1}]`,\n title,\n price: fmtPrice(amount, currency),\n handle,\n stage,\n colours: colourMarker(productColours(p)),\n }\n })\n const refW = Math.max(...cells.map((c) => c.ref.length))\n const priceW = Math.max(...cells.map((c) => c.price.length))\n const handleW = Math.max(...cells.map((c) => c.handle.length))\n const maxTitle = Math.max(...cells.map((c) => c.title.length))\n const GAP = 2\n const STAGE_W = 12 // \"● in stock\" + slack — the stage marker is the last, un-padded column\n const term = process.stdout.columns ?? 0\n // Title is the only elastic column (slug stays full for copy-paste). Fit it to the terminal when\n // known; otherwise let it be its natural width.\n let titleW = maxTitle\n if (term > 0) {\n const fixed = refW + GAP + priceW + GAP + handleW + GAP + STAGE_W\n titleW = Math.max(12, Math.min(maxTitle, term - fixed))\n }\n const out: string[] = []\n for (const c of cells) {\n const row = [\n dim(style, c.ref.padEnd(refW)),\n truncate(c.title, titleW).padEnd(titleW),\n cyan(style, c.price.padStart(priceW)), // right-align money — reads like a ledger\n dim(style, c.handle.padEnd(handleW)),\n stageMarker(c.stage),\n ]\n .join(\" \")\n .trimEnd()\n out.push(c.colours ? `${row}\\n ${dim(style, c.colours)}` : row)\n }\n return out\n}\n\nexport async function runBrowse(\n client: StoreClient,\n config: BtConfigLike,\n args: BrowseArgs\n): Promise<HandlerResult> {\n const style = brandOf(args)\n // Region resolved WITH provenance, NEVER hardcoded — so we can show which region/currency these\n // prices are in (T3.2). config.region is a country code (derived), region #1 otherwise.\n const rr = await client.resolveRegionResult(config.region)\n const region = rr.region\n const products = await client.listProducts({ region })\n\n const rows: Array<{ p: ProductLike; stage: string }> = products.map((p) => ({\n p,\n stage: (p.metadata?.[\"channel_stage\"] as string) ?? \"main\",\n }))\n\n let drops: DropRow[] = []\n if (args.branch === \"next\") {\n drops = await client.listDrops()\n }\n\n const lines: string[] = []\n if (rows.length === 0 && drops.length === 0) {\n // empty state — a dry true line (VOICE §1.4).\n lines.push(empty(\"nothing in stock on this branch yet. main is the latest.\"))\n lines.push(\" peek at next → bt browse --branch=next\")\n } else {\n lines.push(header(style, \"bt browse — in stock\"))\n lines.push(regionLine(rr, style)) // one dim provenance line: region · currency (T3.2)\n lines.push(...layoutRows(rows, style))\n for (const d of drops) {\n const dt = (d.title ?? d.handle ?? d.id).toString()\n lines.push(\n [\n dt.padEnd(22),\n cyan(style, fmtPrice(d.price, region.currency_code).padEnd(11)),\n dim(style, (d.handle ?? d.id).padEnd(34)),\n stageMarker(d.channel_stage),\n ].join(\" \").trimEnd()\n )\n }\n if (drops.length > 0) {\n lines.push(\" on next, before the web → bt drops\")\n }\n // A5 — one subtle VAT-label line (not per-row: it's a table). Only when the region prices\n // tax-inclusive (SE/EU); a tax-exclusive market (US) shows no VAT claim. Parity with bt view/cart/MCP.\n const taxIncl = rows.length > 0 ? firstPrice(rows[0]!.p).taxInclusive : null\n if (taxIncl === true) {\n lines.push(dim(style, \" prices incl. VAT\"))\n }\n lines.push(\" view one → bt view <n|slug> · stage one → bt stage <n|slug> --size L\")\n }\n\n return {\n lines,\n json: args.json\n ? products.map((p) => ({\n id: p.id,\n handle: p.handle,\n title: p.title,\n price: firstPrice(p).amount,\n currency: firstPrice(p).currency,\n colours: productColours(p),\n channel_stage: (p.metadata?.[\"channel_stage\"] as string) ?? \"main\",\n }))\n : undefined,\n }\n}\n\nexport function registerBrowse(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"browse\")\n .alias(\"ls\")\n .description(\"list what's in stock on a branch.\")\n .option(\"--branch <branch>\", \"main (live) or next (terminal-only drops)\")\n .option(\"--pick\", \"opt into the arrow-key picker (default is the numbered table — use bt stage <n>)\")\n .option(\"--plain\", \"force the static table (the default; kept for back-compat)\")\n .action(async (opts: { branch?: string; pick?: boolean; plain?: boolean }) => {\n const { json, brand } = resolveOutput(program)\n // The numbered table is the DEFAULT now — typed slugs / quick-pick numbers are the on-brand,\n // scriptable, screenshot-able path (the arrow-key maze contradicted the deploy conceit). The\n // picker is opt-in via --pick, and only when we truly have an interactive stdin+stdout.\n if (opts.pick && !json && brand.color && process.stdout.isTTY && process.stdin.isTTY) {\n const { runInteractiveBrowse } = await import(\"../interactive\")\n const handled = await runInteractiveBrowse(makeClient(), loadConfig(), { branch: opts.branch, brand })\n if (handled) return\n // picker unavailable / aborted-to-static → fall through to the static table.\n }\n const res = await runBrowse(makeClient(), loadConfig(), { branch: opts.branch, json, brand })\n printResult(res, json)\n })\n}\n","// bt region — see (or set) your ship-to country + currency. The onboarding surface for the money\n// channel: a shopper should always know their region/currency, and be able to change it, WITHOUT a\n// wizard (the ceremony is the confirm, not the menu). Setting VALIDATES against the live regions and\n// fails CLOSED on a country we don't ship to (A1 / T2.3) — so config.region can never hold an\n// unshippable value, and the stage-time guard is a defence-in-depth backstop.\n//\n// runRegion is a PURE function of (client, config, args) → HandlerResult (the SET path returns a\n// `save` patch the register wrapper persists), so it's unit-testable without a backend or disk.\n\nimport type { Command } from \"commander\"\nimport { ok } from \"../voice\"\nimport { failResult, printResult, resolveOutput, regionLine, brandOf, type HandlerResult, type Branded } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport { dim } from \"../brand\"\nimport type { StoreClient, BtConfigLike, RegionLike } from \"./types-bridge\"\n\nexport interface RegionArgs extends Branded {\n /** set this ship-to country (ISO-2). */\n cc?: string\n /** list every shippable country. */\n list?: boolean\n json?: boolean\n}\n\n// How many country codes to show before collapsing to \"… (N)\" — the EU region carries 26.\nconst MAX_COUNTRIES_SHOWN = 8\n\nfunction regionRow(r: RegionLike): string {\n const ccs = (r.countries ?? []).map((c) => (c.iso_2 ?? \"\").toLowerCase()).filter(Boolean).sort()\n const shown = ccs.slice(0, MAX_COUNTRIES_SHOWN).join(\" · \")\n const more = ccs.length > MAX_COUNTRIES_SHOWN ? ` … (${ccs.length})` : \"\"\n return ` ${r.currency_code.toLowerCase().padEnd(5)} ${shown}${more}`.trimEnd()\n}\n\nexport async function runRegion(\n client: StoreClient,\n config: BtConfigLike,\n args: RegionArgs\n): Promise<HandlerResult> {\n const style = brandOf(args)\n\n // SET — validate against the live regions; fail CLOSED on a country we don't ship to (T2.3/A1).\n if (args.cc) {\n const cc = args.cc.trim().toLowerCase()\n const rr = await client.resolveRegionResult(cc)\n if (!rr.matched) {\n return failResult({\n code: EXIT.DATAERR,\n what: `we don't ship to ${cc} yet. nothing was set.`,\n fix: \"bt region --list (see where we ship)\",\n })\n }\n return {\n lines: [ok(`region → ${cc} · prices in ${rr.region.currency_code}`)],\n save: { region: cc },\n json: args.json ? { region: cc, currency: rr.region.currency_code } : undefined,\n }\n }\n\n // LIST — every region we ship to, grouped by currency.\n if (args.list) {\n const regions = await client.getRegions()\n const lines = [\n dim(style, \"where we ship, and what you pay in:\"),\n ...regions.map(regionRow),\n dim(style, \" set yours → bt region <cc>\"),\n ]\n return {\n lines,\n json: args.json\n ? { regions: regions.map((r) => ({ currency: r.currency_code, countries: (r.countries ?? []).map((c) => c.iso_2) })) }\n : undefined,\n }\n }\n\n // SHOW (default) — the current region/currency + how to change or list.\n const rr = await client.resolveRegionResult(config.region)\n return {\n lines: [regionLine(rr, style), dim(style, \" change → bt region <cc> · all → bt region --list\")],\n json: args.json\n ? { region: rr.requested ?? null, currency: rr.region.currency_code, matched: rr.matched, home: rr.home }\n : undefined,\n }\n}\n\nexport function registerRegion(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike,\n persist: (patch: Partial<BtConfigLike>) => void\n): void {\n program\n .command(\"region\")\n .argument(\"[cc]\", \"set your ship-to country (ISO-2, e.g. se / us / de)\")\n .option(\"--list\", \"list every country we ship to + its currency\")\n .description(\"see (or set) your ship-to country + currency.\")\n .action(async (cc: string | undefined, opts: { list?: boolean }) => {\n const { json, brand } = resolveOutput(program)\n const res = await runRegion(makeClient(), loadConfig(), { cc, list: opts.list, json, brand })\n if (res.save) {\n persist(res.save)\n }\n printResult(res, json)\n })\n}\n","// bt completion <shell> — emit a shell completion script (delight #2). Tab-completing subcommands is\n// the quietest possible \"this is tight\", and almost no store CLI ships it. Prints the script to\n// stdout so the user wires it up:\n// bash: eval \"$(bt completion bash)\" (or add to ~/.bashrc)\n// zsh: eval \"$(bt completion zsh)\" (or drop in your $fpath)\n// fish: bt completion fish | source (or > ~/.config/fish/completions/bt.fish)\n//\n// We complete the PUBLIC subcommands only — eggs + the hidden operator `drop` are intentionally\n// absent (they stay \"if you know, you know\"). runCompletion is pure (shell → script string).\n\nimport type { Command } from \"commander\"\nimport { failResult, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\n\n// The public, completable subcommands (+ the two aliases people actually type). Kept here rather than\n// derived from the program so eggs/hidden commands never leak into completion.\nconst COMMANDS = [\n \"browse\", \"search\", \"view\", \"stage\", \"buy\", \"cart\", \"unstage\", \"checkout\", \"commit\",\n \"order\", \"log\", \"status\", \"whoami\", \"region\", \"drops\", \"blame\", \"login\", \"logout\",\n \"config\", \"token\", \"doctor\", \"report\", \"connect\", \"init\", \"completion\",\n] as const\n\nexport type CompletionShell = \"bash\" | \"zsh\" | \"fish\"\n\nexport function completionScript(shell: CompletionShell): string {\n const list = COMMANDS.join(\" \")\n if (shell === \"bash\") {\n return [\n \"# bt bash completion — add to ~/.bashrc: eval \\\"$(bt completion bash)\\\"\",\n \"_bt_completions() {\",\n ' local cur=\"${COMP_WORDS[COMP_CWORD]}\"',\n ` COMPREPLY=( $(compgen -W \"${list}\" -- \"$cur\") )`,\n \"}\",\n \"complete -F _bt_completions bt btn\",\n \"\",\n ].join(\"\\n\")\n }\n if (shell === \"zsh\") {\n return [\n \"#compdef bt btn\",\n \"# bt zsh completion — add to ~/.zshrc: eval \\\"$(bt completion zsh)\\\"\",\n \"_bt() {\",\n \" local -a cmds\",\n ` cmds=(${list})`,\n \" _describe 'command' cmds\",\n \"}\",\n \"compdef _bt bt btn\",\n \"\",\n ].join(\"\\n\")\n }\n // fish\n return [\n \"# bt fish completion — bt completion fish | source\",\n \"complete -c bt -f\",\n `for c in ${list}`,\n \" complete -c bt -n __fish_use_subcommand -a $c\",\n \"end\",\n \"\",\n ].join(\"\\n\")\n}\n\nexport function runCompletion(args: { shell?: string; json?: boolean }): HandlerResult {\n const shell = (args.shell ?? \"\").trim().toLowerCase()\n if (shell !== \"bash\" && shell !== \"zsh\" && shell !== \"fish\") {\n return failResult({\n code: EXIT.DATAERR,\n what: `unknown shell \"${args.shell ?? \"\"}\".`,\n fix: \"bt completion <bash|zsh|fish>\",\n })\n }\n const script = completionScript(shell)\n return { lines: [script], json: args.json ? { shell, script } : undefined }\n}\n\nexport function registerCompletion(program: Command): void {\n program\n .command(\"completion\")\n .argument(\"<shell>\", \"bash | zsh | fish\")\n .description(\"print a shell completion script (eval it in your shell rc).\")\n .action((shell: string) => {\n const { json } = resolveOutput(program)\n printResult(runCompletion({ shell, json }), json)\n })\n}\n","// bt search <q> — browse, filtered by a query (title/handle/description substring match).\n//\n// A1: TITLE is the primary name (the query also matches it); handle shown dimmed/secondary.\n// A3: a compact colour marker per matching product.\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { productColours } from \"@binaryandthread/store-client\"\nimport {\n fmtPrice,\n firstPrice,\n stageMarker,\n displayName,\n brandOf,\n printResult,\n resolveOutput,\n type HandlerResult,\n type Branded,\n} from \"./shared\"\nimport { header, cyan, dim, colourMarker } from \"../brand\"\nimport type { StoreClient, ProductLike, BtConfigLike } from \"./types-bridge\"\n\nexport interface SearchArgs extends Branded {\n query: string\n json?: boolean\n}\n\nfunction matches(p: ProductLike, q: string): boolean {\n const needle = q.toLowerCase()\n return (\n (p.handle ?? \"\").toLowerCase().includes(needle) ||\n (p.title ?? \"\").toLowerCase().includes(needle) ||\n (p.description ?? \"\").toLowerCase().includes(needle)\n )\n}\n\nexport async function runSearch(\n client: StoreClient,\n config: BtConfigLike,\n args: SearchArgs\n): Promise<HandlerResult> {\n const style = brandOf(args)\n const region = await client.resolveRegion(config.region)\n const products = await client.listProducts({ region })\n const filtered = products.filter((p) => matches(p, args.query))\n\n const lines: string[] = []\n if (filtered.length === 0) {\n lines.push(empty(`no matches for \"${args.query}\". 0 results — try a looser query.`))\n lines.push(\" browse all → bt browse\")\n } else {\n lines.push(header(style, `bt search \"${args.query}\"`))\n for (const p of filtered) {\n const { amount, currency } = firstPrice(p)\n const { title, handle } = displayName(p)\n const stage = (p.metadata?.[\"channel_stage\"] as string) ?? \"main\"\n const colours = colourMarker(productColours(p))\n const row = [\n title.padEnd(22),\n cyan(style, fmtPrice(amount, currency).padEnd(11)),\n dim(style, handle.padEnd(34)),\n stageMarker(stage),\n ].join(\" \").trimEnd()\n lines.push(colours ? `${row}\\n ${dim(style, colours)}` : row)\n }\n lines.push(\" view one → bt view <handle>\")\n }\n\n return {\n lines,\n json: args.json\n ? filtered.map((p) => ({\n id: p.id,\n handle: p.handle,\n title: p.title,\n price: firstPrice(p).amount,\n currency: firstPrice(p).currency,\n colours: productColours(p),\n }))\n : undefined,\n }\n}\n\nexport function registerSearch(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"search\")\n .argument(\"<query>\", \"what to look for\")\n .description(\"filter the catalog by a query.\")\n .action(async (query: string) => {\n const { json, brand } = resolveOutput(program)\n const res = await runSearch(makeClient(), loadConfig(), { query, json, brand })\n printResult(res, json)\n })\n}\n","// bt cart — show the current cart from the server (authoritative), or the empty-state line.\n//\n// The server is the source of truth (F-B3). A stale/completed cart_id (RecoverableCartError)\n// is reported calmly, never crashed (VOICE §1.4 empty/error style).\n\nimport type { Command } from \"commander\"\nimport { empty, warn } from \"../voice\"\nimport { fmtPrice, formatCartLine, taxSuffix, isCartTaxInclusive, brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { header, cyan, dim } from \"../brand\"\nimport { RecoverableCartError } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface CartArgs extends Branded {\n json?: boolean\n}\n\n// VOICE §1.4 empty state — the dry one-liner.\nconst EMPTY_STATE = \"no commits yet. your wardrobe is a fresh repo.\"\n\nexport async function runCart(\n client: StoreClient,\n config: BtConfigLike,\n args: CartArgs\n): Promise<HandlerResult> {\n if (!config.cart_id) {\n return {\n lines: [empty(EMPTY_STATE), \" start one → bt browse\"],\n json: args.json ? { cart_id: null, items: [] } : undefined,\n }\n }\n\n const style = brandOf(args)\n try {\n const cart = await client.getCart(config.cart_id)\n const lines: string[] = []\n if (!cart.items || cart.items.length === 0) {\n lines.push(empty(EMPTY_STATE))\n lines.push(\" start one → bt browse\")\n } else {\n lines.push(header(style, \"bt cart — staged for commit\"))\n cart.items.forEach((item, i) => {\n lines.push(formatCartLine(item, i, cart.currency_code, style))\n })\n if (cart.total != null) {\n // The cart total is PRE-shipping until checkout attaches a method — say so, so it's never\n // mistaken for the final price (A2). Once a method is on the cart, the total is real.\n const shipNote =\n (cart.shipping_methods ?? []).length > 0 ? \"\" : dim(style, \" (excl. shipping — calculated at checkout)\")\n lines.push(` total ${cyan(style, fmtPrice(cart.total, cart.currency_code))}${taxSuffix(isCartTaxInclusive(cart))}${shipNote}`)\n }\n lines.push(\" remove one → bt unstage <#> · commit → bt commit\")\n }\n return {\n lines,\n json: args.json\n ? {\n cart_id: cart.id,\n items: cart.items ?? [],\n total: cart.total ?? null,\n total_excludes_shipping: (cart.shipping_methods ?? []).length === 0,\n }\n : undefined,\n }\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n warn(\"that cart is no longer valid (expired or already committed).\"),\n empty(EMPTY_STATE),\n \" start a fresh one → bt browse\",\n ],\n json: args.json ? { cart_id: null, items: [], stale: true } : undefined,\n }\n }\n throw e\n }\n}\n\nexport function registerCart(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"cart\")\n .description(\"show your current cart — the authoritative server state.\")\n .action(async () => {\n const { json, brand } = resolveOutput(program)\n const res = await runCart(makeClient(), loadConfig(), { json, brand })\n printResult(res, json)\n })\n}\n","// bt checkout (alias: bt commit) — the browser-hop floor, client side.\n//\n// THE single non-negotiable invariant: cards NEVER touch the terminal. The card/CVC AND the\n// shipping address are entered on the storefront checkout page (Stripe Elements + the address\n// form), which we open in the browser. The worst a buggy/malicious run can do is leave a junk\n// *unpaid* cart — money fails closed by construction (ROBUSTNESS §0).\n//\n// A2 — \"fill on the web\" (Sam's decision): the headless checkout route requires only\n// cart_id + items + shipping method + region. Email is OPTIONAL and NO address is needed (the\n// storefront collects address + email). So this command does NOT prompt for an address or email\n// in the terminal. It passes the keychain/whoami email if one is already known (no prompt), else\n// omits it.\n//\n// Flow (VOICE §1.4, §2.1 · F-B5/F-C5/F-I1):\n// 1. load cart_id (──resume requires one); nothing staged → empty state.\n// 2. getCart; a stale/completed cart → tell the user to re-stage.\n// 3. REVIEW the cart (items + colour · total, incl. VAT where the market applies it) + ask to\n// proceed (y/n); abort costs nothing.\n// 4. ensureCartShippingMethod(cart_id) — the headless checkout route requires one (BUG 1);\n// fail CLOSED if the region has no available option.\n// 5. mintCheckout(cart_id, email?, \"cli\") — email passed only if already known (no prompt).\n// 6. open the browser + QR; tell the user: enter details on the page, cards never touch the terminal.\n// 7. pollUntilPlaced: placed → the \"deploy successful\" beat; timeout → exit-75 resumable\n// (money line FIRST); expired → re-stage.\n\nimport type { Command } from \"commander\"\nimport { ok, warn, fail, empty, working } from \"../voice\"\nimport { fmtPrice, lineColour, taxSuffix, isCartTaxInclusive, brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { header, cyan, dim } from \"../brand\"\nimport { EXIT } from \"../errors\"\nimport { RecoverableCartError } from \"@binaryandthread/store-client\"\nimport type { OpenCheckoutResult } from \"../browser\"\nimport type { PollOutcome } from \"../poll\"\nimport type { StoreClient, BtConfigLike, RegionLike, CartLike } from \"./types-bridge\"\n\nexport interface CheckoutArgs extends Branded {\n resume?: boolean\n json?: boolean\n /** skip the interactive proceed confirm (scripts / CI / agents) — implied by --json (d8). */\n yes?: boolean\n}\n\n/** The terminal prompts the flow needs. Injected so the flow is testable without a TTY. */\nexport interface CheckoutPrompts {\n /** ask a single free-text question (label is the human prompt). */\n ask(label: string, opts?: { default?: string }): Promise<string>\n /** a yes/no confirm; returns true on \"y\". */\n confirm(label: string): Promise<boolean>\n}\n\n/** The side-effecting collaborators (browser, poll loop, config save), all injectable. */\nexport interface CheckoutDeps {\n prompts?: CheckoutPrompts\n /** open the browser + render a QR; returns whether it opened + the lines to print. */\n open(url: string): Promise<OpenCheckoutResult>\n /** poll the session until placed/expired/timeout (bounded — F-C5/F-I3). */\n poll(sessionId: string): Promise<PollOutcome>\n /** persist a config patch atomically (the email). */\n saveConfig(patch: Partial<BtConfigLike>): void\n /**\n * Print a line EAGERLY (the cart review must appear before the interactive proceed prompt;\n * the handler's returned `lines` only print after the flow returns). Defaults to stdout.\n */\n print?(line: string): void\n}\n\n/** the region's supported country codes (lowercased), for the \"ships to\" display line. */\nfunction supportedCountries(region: RegionLike): string[] {\n return (region.countries ?? [])\n .map((c) => (c.iso_2 ?? \"\").toLowerCase())\n .filter((c) => c.length > 0)\n}\n\n// The dim \"still waiting\" heartbeat during the browser hand-off. The poll can run up to 20 min\n// (poll.ts F-C5); with no pulse the terminal looks hung and a buyer Ctrl-Cs a live checkout — the\n// deploy that prints one line then goes dark. Returns the line to print on this tick, or null to\n// stay quiet: silent on the first tick (the buyer just got the link), then a calm elapsed line on a\n// ~30s cadence. Pure + exported so the cadence is unit-tested without burning wall-clock.\nconst HEARTBEAT_EVERY_TICKS = 6 // ~30s at poll.ts's 5s cadence\n\nexport function heartbeatLine(\n attempt: number,\n opts: { intervalMs?: number; everyTicks?: number } = {}\n): string | null {\n const everyTicks = opts.everyTicks ?? HEARTBEAT_EVERY_TICKS\n if (attempt <= 1 || (attempt - 1) % everyTicks !== 0) {\n return null\n }\n const intervalMs = opts.intervalMs ?? 5_000\n const elapsedS = Math.round(((attempt - 1) * intervalMs) / 1_000)\n return working(\n `still waiting for the browser hand-off, ${elapsedS}s in. ctrl-c is safe; resume with bt checkout --resume`\n )\n}\n\nexport async function runCheckout(\n client: StoreClient,\n config: BtConfigLike,\n args: CheckoutArgs,\n deps: CheckoutDeps\n): Promise<HandlerResult> {\n const cartId = config.cart_id\n\n // 1. nothing staged → empty state. --resume needs an existing cart (no local in-flight state).\n if (!cartId) {\n if (args.resume) {\n return {\n lines: [\n empty(\"nothing to resume — no cart on record.\"),\n \" stage something first → bt browse then bt stage <slug>\",\n ],\n }\n }\n return {\n lines: [\n empty(\"nothing staged. your wardrobe is a fresh repo.\"),\n \" start one → bt browse\",\n ],\n }\n }\n\n // 2. read the authoritative server cart; a stale/completed cart → re-stage (F-B2).\n let cart: CartLike\n try {\n cart = await client.getCart(cartId)\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n warn(\"that cart is no longer valid (expired or already committed).\"),\n \" re-stage → bt browse then bt stage <slug>\",\n ],\n }\n }\n throw e\n }\n if (!cart.items || cart.items.length === 0) {\n return {\n lines: [\n empty(\"nothing staged. your wardrobe is a fresh repo.\"),\n \" start one → bt browse\",\n ],\n }\n }\n\n const region = await client.resolveRegion(config.region)\n const style = brandOf(args)\n const prompts = deps.prompts\n if (!prompts) {\n throw new Error(\"checkout requires a prompter\")\n }\n\n // 3a. attach a shipping method BEFORE the review (AUD-10 + BUG 1). The headless checkout route\n // requires one, and the total the buyer consents to MUST include shipping. Attaching is\n // idempotent and NEVER charges (cards are entered later on the web), so doing it before the\n // proceed confirm is money-safe — an abort still mints nothing. A stale cart → a Recoverable\n // re-stage message; a region with no shipping option fails CLOSED (never mint a doomed checkout).\n let shippedCart: CartLike\n try {\n shippedCart = await client.ensureCartShippingMethod(cartId)\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n warn(\"that cart is no longer valid (expired or already committed).\"),\n \" re-stage → bt browse then bt stage <slug>\",\n ],\n }\n }\n return {\n lines: [\n fail({\n code: 1,\n what: \"couldn't attach a shipping method to your cart.\",\n fix: \"this region may not have shipping configured yet — try again shortly, or re-stage.\",\n }),\n ],\n exitCode: EXIT.GENERIC, // fail-closed, no order placed → non-zero (matches the shown exit 1)\n }\n }\n\n // 3b. REVIEW + ACCEPT the cart — show items (with colour) + total (incl. VAT where the market\n // applies it) + shipping, then ask to proceed. No address/email prompt: the storefront page\n // collects those (A2).\n const itemCount = cart.items.reduce((n, li) => n + (li.quantity ?? 1), 0)\n // Total from the SHIPPED cart so it INCLUDES shipping (AUD-10); fall back to the pre-shipping\n // total only if the client didn't echo one back.\n const totalLine = fmtPrice(shippedCart?.total ?? cart.total, cart.currency_code ?? region.currency_code)\n // VAT label follows the cart's OWN tax flag (derived from its line items — no cart-root flag),\n // never the currency: an SE cart shows \" incl. VAT\", a US (tax-exclusive) cart shows none.\n const taxIncl = isCartTaxInclusive(cart)\n const reviewLines: string[] = [header(style, \"bt checkout — staged for commit\")]\n for (const li of cart.items) {\n const colour = lineColour(li)\n const colourTag = colour ? ` · ${colour}` : \"\"\n reviewLines.push(\n ` ${(li.title ?? li.product_title ?? \"item\").toString()}${colourTag} · qty ${li.quantity}` +\n (li.total != null ? ` ${cyan(style, fmtPrice(li.total, cart.currency_code ?? region.currency_code))}` : \"\")\n )\n }\n reviewLines.push(` total ${cyan(style, totalLine)}${taxSuffix(taxIncl)}`)\n const print = deps.print ?? ((line: string) => process.stdout.write(line + \"\\n\"))\n for (const line of reviewLines) {\n print(line)\n }\n // In --json / --yes mode, SKIP the interactive proceed confirm: a hidden readline on a\n // non-interactive stdin (CI, a piped agent) blocks forever (d8). Minting a checkout does NOT\n // charge — the card is entered later on the Stripe page — so auto-proceeding is money-safe.\n const autoProceed = Boolean(args.json) || Boolean(args.yes)\n if (!autoProceed) {\n const proceed = await prompts.confirm(\n `proceed to checkout? ${itemCount} item${itemCount === 1 ? \"\" : \"s\"} · ${totalLine}${taxSuffix(taxIncl)} (y/n):`\n )\n if (!proceed) {\n return {\n lines: [empty(\"aborted. nothing was committed — your stage is still held.\")],\n }\n }\n }\n\n // \"ships to\" display line — the region's first supported country (informational, not a gate;\n // the storefront page collects + validates the real ship-to address).\n const allowed = supportedCountries(region)\n const shipsTo = (allowed[0] ?? \"\").toUpperCase()\n\n // 5. mint the checkout (idempotent in the client). Pass a KNOWN email (keychain/whoami/config)\n // WITHOUT prompting; omit it otherwise — the storefront collects it (A2).\n const email = (config.email ?? \"\").trim()\n const { checkout_url, session_id } = await client.mintCheckout(cartId, email || undefined, \"cli\")\n const save: Partial<BtConfigLike> = email ? { email } : {}\n\n // 6. hand off to the browser + QR. cards never touch the terminal — and now neither does the\n // address: tell the user clearly to fill their details on the page.\n const opened: OpenCheckoutResult = await deps.open(checkout_url)\n // Print the URL/QR + hand-off guidance EAGERLY, BEFORE the (blocking) poll (AUD-9): the buyer\n // needs the link to pay WHILE the CLI waits — the browser may not have opened (headless/CI/SSH).\n for (const line of opened.lines) {\n print(line)\n }\n print(\" enter your details on the page — address + card. cards never touch the terminal.\")\n\n // 7. poll the bt_session until placed/expired/timeout (bounded — F-C5/F-I3). A transient poll\n // failure must NEVER crash the checkout (AUD-11): a buyer who may already have paid needs the\n // link + money reassurance, not a raw stack trace.\n let outcome: PollOutcome\n try {\n outcome = await deps.poll(session_id)\n } catch {\n return {\n lines: [\n \"\",\n fail({\n code: 75,\n what: \"lost the connection while waiting for your order to complete.\",\n money:\n \"if you completed payment, your order is safe — we just couldn't confirm it here. check your email, or run bt order.\",\n fix: \"bt checkout --resume (or open the link below manually)\",\n link: checkout_url,\n }),\n ],\n save,\n exitCode: EXIT.TEMPFAIL, // lost the connection mid-poll → not confirmed → non-zero (75)\n }\n }\n\n // opened.lines were already printed eagerly above (AUD-9) — start the returned lines fresh.\n const lines: string[] = []\n\n if (outcome.status === \"placed\") {\n // the channel's signature beat — a log, not a party (VOICE §1.4). Fetch the order for the\n // display id where possible; fall back to the poll's order_id.\n const displayId = await resolveDisplayId(client, outcome.order_id, email)\n lines.push(\"\")\n lines.push(ok(\"deploy successful.\"))\n lines.push(` committed to wardrobe@main`)\n lines.push(` order #${displayId}`)\n // Gated on the SAME tax flag as the review lines. Kept in the success beat's parenthetical form\n // (\" (incl. VAT)\") so the SE confirmation stays byte-identical; a US order shows no VAT note.\n lines.push(` total ${cyan(style, totalLine)}${taxIncl ? \" (incl. VAT)\" : \"\"}`)\n if (shipsTo) {\n lines.push(` ships to ${shipsTo} · ~3–6 working days`)\n } else {\n lines.push(` ships ~3–6 working days`)\n }\n lines.push(` track bt order ${displayId}`)\n if (email) {\n lines.push(` receipt sent to ${maskEmail(email)}`)\n }\n return {\n lines,\n save,\n json: args.json\n ? {\n status: \"placed\",\n order_id: outcome.order_id,\n display_id: displayId,\n // A2 — the SHIPPING-INCLUSIVE total the buyer consented to (same figure as the review),\n // so a --json / bt buy consumer has the real amount, not just a status.\n total: shippedCart?.total ?? cart.total ?? null,\n currency: cart.currency_code ?? region.currency_code ?? null,\n }\n : undefined,\n }\n }\n\n if (outcome.status === \"expired\") {\n lines.push(\"\")\n lines.push(\n warn(\"your stage expired before checkout completed. nothing was charged.\")\n )\n lines.push(\" re-stage → bt stage <slug> then bt checkout\")\n return { lines, save, json: args.json ? { status: \"expired\" } : undefined, exitCode: EXIT.TEMPFAIL }\n }\n\n // timeout — the exit-75 resumable error. money reassurance FIRST (VOICE §1.4, non-negotiable).\n // A4: a poll TIMEOUT does NOT prove non-payment (the buyer may have paid at the last second) —\n // hedge honestly, unlike the `expired` branch above where non-payment is certain.\n lines.push(\"\")\n lines.push(\n fail({\n code: 75,\n what: \"checkout handoff timed out — we didn't see the order complete.\",\n money: \"if you completed payment, your order is safe; if not, your stage is still held — check your email or bt order.\",\n fix: \"bt checkout --resume (or open the link below manually)\",\n link: checkout_url,\n })\n )\n return {\n lines,\n save,\n json: args.json ? { status: \"timeout\", checkout_url } : undefined,\n exitCode: EXIT.TEMPFAIL, // handoff timed out → not placed → non-zero (matches the shown exit 75)\n }\n}\n\n/** Resolve a human display id for the confirmation beat; falls back to the raw order_id. */\nasync function resolveDisplayId(\n client: StoreClient,\n orderId: string | null,\n email: string\n): Promise<string | number> {\n if (!orderId) {\n return \"—\"\n }\n try {\n // TODO(04.5 followup): email-in-query → POST body, needs backend route (Wave-2 review note).\n const looked = (await client.getOrder(orderId, email)) as\n | { order?: { display_id?: number | string } }\n | { display_id?: number | string }\n | null\n const display =\n (looked as { order?: { display_id?: number | string } })?.order?.display_id ??\n (looked as { display_id?: number | string })?.display_id\n return display ?? orderId\n } catch {\n return orderId\n }\n}\n\n/** d***@example.com — minimal receipt masking on the confirmation beat (G10/G15 style). */\nfunction maskEmail(email: string): string {\n const at = email.indexOf(\"@\")\n if (at <= 0) {\n return \"***\"\n }\n const local = email.slice(0, at)\n const domain = email.slice(at + 1)\n const head = local[0] ?? \"\"\n return `${head}***@${domain}`\n}\n\nexport function registerCheckout(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n const action = async (opts: { resume?: boolean; yes?: boolean }) => {\n const { json, brand } = resolveOutput(program)\n const { makePrompts } = await import(\"../prompts\")\n const { openCheckout } = await import(\"../browser\")\n const { pollUntilPlaced } = await import(\"../poll\")\n const { saveConfig } = await import(\"../config\")\n const client = makeClient()\n // In --json mode the review + heartbeat are suppressed (machine output only); otherwise print\n // eagerly to stdout. Shared by the eager prints AND the poll heartbeat so both honor --json.\n const print = json ? () => {} : (line: string) => process.stdout.write(line + \"\\n\")\n const res = await runCheckout(\n client,\n loadConfig(),\n { resume: opts.resume, json, brand, yes: opts.yes },\n {\n prompts: makePrompts(),\n open: (url) => openCheckout(url),\n // Heartbeat the browser-hop wait so the terminal never looks hung (a dim, calm line every\n // ~30s). Suppressed under --json (print is a no-op there).\n poll: (sessionId) =>\n pollUntilPlaced(client, sessionId, {\n onTick: (attempt) => {\n const line = heartbeatLine(attempt)\n if (line) print(dim(brand, line))\n },\n }),\n saveConfig,\n print,\n }\n )\n if (res.save && Object.keys(res.save).length > 0) {\n saveConfig(res.save)\n }\n printResult(res, json)\n }\n\n program\n .command(\"checkout\")\n .alias(\"commit\")\n .description(\n \"turn your staged items into an order. opens browser checkout, polls, never touches cards.\"\n )\n .option(\"--resume\", \"resume an in-progress checkout from your existing cart\")\n .option(\"--yes\", \"skip the proceed confirmation (scripts / CI / agents); implied by --json\")\n .action(action)\n}\n","// bt order <id> — track one order: the staged→committed→printed→shipped→delivered timeline.\n//\n// Guest path (F-H1, SECURITY T4): the lookup needs the order display id AND the EXACT email;\n// the backend 404s on a mismatch (no enumeration), so the client returns null → we print a\n// flat \"not found\" that leaks NOTHING about whether the id or the email was wrong. The\n// merge-to-main 🎉 (the one sanctioned celebration, VOICE §1.4) renders ONLY at delivered.\n\nimport type { Command } from \"commander\"\nimport { fmtPrice, taxSuffix, brandOf, failResult, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport { cyan } from \"../brand\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface OrderArgs extends Branded {\n displayId: string\n json?: boolean\n}\n\n// The five-stage lifecycle, rendered as a git-ish graph (VOICE §2.3).\nconst STAGES = [\"staged\", \"committed\", \"printed\", \"shipped\", \"delivered\"] as const\n\n/** Map a Medusa order/fulfillment status onto our stage index (0..4). */\nfunction stageIndex(o: { status?: string; fulfillment_status?: string }): number {\n const f = (o.fulfillment_status ?? \"\").toLowerCase()\n if (f.includes(\"delivered\")) return 4\n if (f.includes(\"shipped\")) return 3\n if (f.includes(\"fulfilled\") || f.includes(\"printed\") || f.includes(\"partially_shipped\")) return 2\n // placed/captured but not yet fulfilled\n return 1\n}\n\nfunction timelineGraph(idx: number): string {\n // ●──●──●──● delivered — filled dots up to the current stage.\n const dots = STAGES.map((_s, i) => (i <= idx ? \"●\" : \"○\")).join(\"──\")\n return dots\n}\n\nexport async function runOrder(\n client: StoreClient,\n config: BtConfigLike,\n args: OrderArgs\n): Promise<HandlerResult> {\n const email = config.email\n if (!email) {\n return failResult({\n code: EXIT.DATAERR,\n what: \"order lookup needs your email.\",\n fix: \"bt config set email <you@example.com> (then retry)\",\n })\n }\n\n // id + EXACT email; the client returns null on a 404 miss (F-H1). AUD-8: the client POSTs to\n // /store/order-lookup (email in the body, never the query string).\n const looked = (await client.getOrder(args.displayId, email)) as\n | { order?: Record<string, unknown> }\n | Record<string, unknown>\n | null\n\n if (!looked) {\n // flat not-found — never reveal whether the id or the email was the wrong half (F-H1).\n return failResult({\n code: EXIT.UNAVAILABLE,\n what: `order ${args.displayId} not found for that email.`,\n fix: \"check the order number + the email it was placed with.\",\n })\n }\n\n const o = ((looked as { order?: Record<string, unknown> }).order ?? looked) as Record<string, unknown>\n const idx = stageIndex(o as { status?: string; fulfillment_status?: string })\n const display = (o.display_id ?? args.displayId) as string | number\n const total = fmtPrice((o.total as number) ?? null, (o.currency_code as string) ?? null)\n const items =\n (o.items as Array<{ title?: string; variant_title?: string; quantity?: number; is_tax_inclusive?: boolean | null }>) ??\n []\n // VAT label follows the order's OWN per-line-item tax flag (uniform per region), never the\n // currency: an SE order shows \" incl. VAT\", a US (tax-exclusive) order shows none. The backend\n // order-lookup route surfaces items.is_tax_inclusive for exactly this.\n const orderTaxInclusive = items.some((i) => i.is_tax_inclusive === true)\n const first = items[0]\n const itemLabel = first\n ? `${first.title ?? \"item\"}${first.variant_title ? ` · ${first.variant_title}` : \"\"}`\n : \"your order\"\n\n const style = brandOf(args)\n const lines: string[] = []\n lines.push(`${display} ${itemLabel} ${cyan(style, timelineGraph(idx))} ${STAGES[idx]}`)\n lines.push(` ${STAGES.join(\" → \")}${idx === 4 ? \" 🎉\" : \"\"}`)\n lines.push(` total ${cyan(style, total)}${taxSuffix(orderTaxInclusive)}`)\n\n return {\n lines,\n json: args.json\n ? { display_id: display, stage: STAGES[idx], total: o.total ?? null, currency: o.currency_code ?? null }\n : undefined,\n }\n}\n\nexport function registerOrder(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"order\")\n .argument(\"<id>\", \"the order number (display id)\")\n .description(\"track one order: staged → committed → printed → shipped → delivered.\")\n .action(async (id: string) => {\n const { json, brand } = resolveOutput(program)\n const res = await runOrder(makeClient(), loadConfig(), { displayId: id, json, brand })\n printResult(res, json)\n })\n}\n","// Decode a JWT's `exp` claim LOCALLY (no signature verification — display only) so `bt whoami\n// --json` can report token expiry for a pre-flight auth check without a network mutation (d25).\n// The token is short-lived; this is purely informational (\"is my session still valid / when does\n// it lapse\"), never an authorization decision (that's the backend's job).\n\nexport interface JwtExpiry {\n /** ISO timestamp the token expires, or null if no/invalid token or no exp claim. */\n expiresAt: string | null\n /** true if expired, false if still valid, null if unknown (no/invalid token / no exp). */\n expired: boolean | null\n}\n\nexport function jwtExpiry(jwt: string | null | undefined, now: number = Date.now()): JwtExpiry {\n if (!jwt) {\n return { expiresAt: null, expired: null }\n }\n const parts = jwt.split(\".\")\n if (parts.length < 2 || !parts[1]) {\n return { expiresAt: null, expired: null }\n }\n try {\n const b64 = parts[1].replace(/-/g, \"+\").replace(/_/g, \"/\")\n const payload = JSON.parse(Buffer.from(b64, \"base64\").toString(\"utf8\")) as { exp?: unknown }\n const exp = typeof payload.exp === \"number\" ? payload.exp : null\n if (exp == null) {\n return { expiresAt: null, expired: null }\n }\n const expMs = exp * 1000\n return { expiresAt: new Date(expMs).toISOString(), expired: expMs <= now }\n } catch {\n return { expiresAt: null, expired: null }\n }\n}\n","// bt token — export the keychain JWT for an MCP config's BT_TOKEN env (the keychain→MCP bridge, d18).\n//\n// The MCP server reads BT_TOKEN from its host config (it can't reach your OS keychain). `bt token`\n// bridges that gap: it prints your JWT to STDOUT (so `bt token | pbcopy` works) with a caveat on\n// STDERR (so a pipe stays clean). It's a bearer credential — your own, on your own machine — so we\n// warn but don't block. The CLI itself also reads BT_TOKEN (see makeClient) so CI can supply one\n// without the keychain.\n\nimport type { Command } from \"commander\"\nimport { warn, empty } from \"../voice\"\nimport { resolveOutput } from \"./shared\"\nimport { jwtExpiry } from \"../jwt\"\nimport { getToken } from \"../keychain\"\n\n/** env BT_TOKEN wins over the keychain (CI/non-interactive); null if neither. */\nexport function resolveBridgeToken(env: NodeJS.ProcessEnv, keychainToken: string | null): string | null {\n const fromEnv = env.BT_TOKEN?.trim()\n return fromEnv || keychainToken || null\n}\n\nexport function registerToken(program: Command): void {\n program\n .command(\"token\")\n .description(\"print your keychain JWT for an MCP config (env BT_TOKEN). a bearer credential — handle with care.\")\n .action(() => {\n const { json } = resolveOutput(program)\n const token = resolveBridgeToken(process.env, getToken())\n if (!token) {\n process.stderr.write(empty(\"not logged in — run bt login first.\") + \"\\n\")\n process.exitCode = 1\n return\n }\n if (jwtExpiry(token).expired) {\n process.stderr.write(warn(\"this token is expired — run bt login for a fresh one.\") + \"\\n\")\n }\n // caveat on stderr (keeps `bt token | pbcopy` clean); the token itself on stdout.\n process.stderr.write(\"⚠ bearer credential — paste only into your own MCP config (env BT_TOKEN), never anywhere public.\\n\")\n process.stdout.write((json ? JSON.stringify({ token }) : token) + \"\\n\")\n })\n}\n","// bt log rendering — your wardrobe as a git history (brand-delight #2, VOICE §2.2).\n//\n// Three views over the same order set:\n// - default : a flat \"display label status\" list (legacy behaviour, unchanged)\n// - --oneline: git-log --oneline style, newest = (HEAD -> main), short-hash per order\n// - --graph : git-log --graph style — '*' nodes + '|' edges, status as the lifecycle stage,\n// and the ONE sanctioned 🎉 at the merged-to-main (delivered) moment (VOICE §1.4).\n//\n// The \"commit hash\" is a DETERMINISTIC 7-char hex derived from the order identity (display id +\n// created_at). It is NOT a real git sha — it's a stable id rendered as a hash (the joke is that an\n// order IS a commit). Deterministic so the same order always shows the same hash (no Date/random —\n// those are unavailable here anyway), and so a screenshot is reproducible.\n//\n// C9 egg (VOICE §3.1): with orders present but ALL reverted, HEAD is \"(detached HEAD)\" — the git\n// term is correct (no branch ref points at a committed fit) and it's a real, warm empty-state.\n\nimport { green, dim, type BrandStyle } from \"../brand\"\n\n/** The order shape these renderers read (a subset of OrderSummary — all optional/defensive). */\nexport interface LogOrder {\n display_id?: number | string | null\n status?: string | null\n fulfillment_status?: string | null\n created_at?: string | null\n items?: Array<{ title?: string | null; variant_title?: string | null }> | null\n}\n\n/** The lifecycle stage word for an order (mirrors bt order's mapping; adds 'reverted'). */\nexport function orderStage(o: LogOrder): \"delivered\" | \"shipped\" | \"printed\" | \"committed\" | \"reverted\" {\n const status = (o.status ?? \"\").toLowerCase()\n if (status.includes(\"cancel\") || status.includes(\"refund\") || status.includes(\"revert\")) {\n return \"reverted\"\n }\n const f = (o.fulfillment_status ?? \"\").toLowerCase()\n if (f.includes(\"delivered\")) return \"delivered\"\n if (f.includes(\"shipped\")) return \"shipped\"\n if (f.includes(\"fulfilled\") || f.includes(\"printed\") || f.includes(\"partially\")) return \"printed\"\n return \"committed\"\n}\n\n/**\n * A deterministic 7-char hex \"commit hash\" for an order. FNV-1a over the order identity — stable,\n * collision-resistant enough for a display id, and reproducible (so a screenshot is stable). Never\n * uses Date.now()/random (unavailable here + would break determinism).\n */\nexport function shortHash(o: LogOrder): string {\n const seed = `${o.display_id ?? \"\"}:${o.created_at ?? \"\"}`\n let h = 0x811c9dc5 // FNV-1a 32-bit offset basis\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i)\n h = Math.imul(h, 0x01000193) >>> 0\n }\n return h.toString(16).padStart(8, \"0\").slice(0, 7)\n}\n\n/** \"the terminal piece · L\" — first item's title + variant. Never \"tee\"/\"shirt\" (brand voice). */\nfunction label(o: LogOrder): string {\n const items = o.items ?? []\n const first = items[0]\n if (!first) return \"order\"\n return `${first.title ?? \"order\"}${first.variant_title ? ` · ${first.variant_title}` : \"\"}`\n}\n\n/** Whether the order set has at least one non-reverted (still-on-a-branch) order. */\nfunction hasLiveHead(orders: LogOrder[]): boolean {\n return orders.some((o) => orderStage(o) !== \"reverted\")\n}\n\n/**\n * --oneline view. Newest order (orders[0]) carries the \"(HEAD -> main)\" ref — unless every order is\n * reverted, in which case HEAD is \"(detached HEAD)\" (C9). Each row: <hash> <ref> <label> <stage>.\n */\nexport function renderOneline(orders: LogOrder[], style: BrandStyle): string[] {\n if (orders.length === 0) return []\n const live = hasLiveHead(orders)\n // the ref decorates the newest LIVE order; if all reverted, the C9 detached-HEAD line leads.\n const headIdx = live ? orders.findIndex((o) => orderStage(o) !== \"reverted\") : -1\n const lines: string[] = []\n if (!live) {\n lines.push(dim(style, \"(detached HEAD) you have no committed fits. literally nothing to wear. we don't judge.\"))\n }\n orders.forEach((o, i) => {\n const hash = shortHash(o)\n const stage = orderStage(o)\n const ref = i === headIdx ? \"(HEAD -> main) \" : \"\"\n const tail = stage === \"delivered\" ? \"delivered 🎉\" : stage\n lines.push(`${hash} ${ref}${label(o).padEnd(34)} ${tail}`)\n })\n return lines\n}\n\n/**\n * --graph view. git-log --graph style: '*' nodes joined by '|' edges (correct for a linear history).\n * The newest live order is decorated \"(HEAD -> main)\"; a fully-reverted set shows the C9 detached\n * HEAD line. The merged-to-main 🎉 (the single sanctioned celebration) renders ONLY at delivered.\n */\nexport function renderGraph(orders: LogOrder[], style: BrandStyle): string[] {\n if (orders.length === 0) return []\n const live = hasLiveHead(orders)\n const headIdx = live ? orders.findIndex((o) => orderStage(o) !== \"reverted\") : -1\n const lines: string[] = []\n if (!live) {\n lines.push(dim(style, \"(detached HEAD) no committed fits. literally nothing to wear. we don't judge.\"))\n }\n orders.forEach((o, i) => {\n const hash = shortHash(o)\n const stage = orderStage(o)\n const ref = i === headIdx ? \" (HEAD -> main)\" : \"\"\n const node = stage === \"delivered\" ? green(style, \"*\") : \"*\"\n const tail = stage === \"delivered\" ? `${stage} ${green(style, \"🎉\")}` : stage\n lines.push(`${node} ${hash}${ref} ${label(o).padEnd(32)} ${tail}`)\n if (i < orders.length - 1) {\n lines.push(\"|\")\n }\n })\n return lines\n}\n\n/** The default flat list (legacy): \"<display> <label> <stage>\". */\nexport function renderFlat(orders: LogOrder[]): string[] {\n return orders.map((o) => {\n const display = String(o.display_id ?? \"\")\n return `${display.padEnd(8)} ${label(o).padEnd(36)} ${orderStage(o)}`\n })\n}\n","// bt log [--oneline|--graph] — your order history as a git log.\n//\n// Guest order *history* is a logged-in capability (the backend filters strictly by the\n// verified customer/email — F-H2); a guest with no session sees the empty state. The shared\n// client exposes single-order lookup (getOrder, id+exact-email) but no guest history listing,\n// so until login lands (Wave 5) `bt log` shows the \"fresh repo\" empty state. The C9 detached-\n// HEAD egg (reverted-everything) is a Wave-3 governed polish pass.\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { resolveBridgeToken } from \"./token\"\nimport { getToken } from \"../keychain\"\nimport { renderOneline, renderGraph, renderFlat, type LogOrder } from \"./log-graph\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface LogArgs extends Branded {\n oneline?: boolean\n graph?: boolean\n json?: boolean\n /**\n * Whether the user is authenticated (a customer JWT is present). The history route is JWT-bound\n * (d13), so this — NOT a saved email — is the real \"logged in\" signal: a BT_TOKEN/keychain session\n * with no config.email must still see history. registerLog computes it from the resolved token.\n */\n loggedIn?: boolean\n}\n\n// VOICE §1.4 empty state.\nconst EMPTY_STATE = \"no commits yet. your wardrobe is a fresh repo.\"\n\nexport async function runLog(\n client: StoreClient,\n config: BtConfigLike,\n args: LogArgs\n): Promise<HandlerResult> {\n // \"Logged in\" = a JWT is present (passed by registerLog). Fall back to a saved email so a caller\n // that doesn't pass the flag still behaves sensibly. Without a session we show the empty state\n // (no network) rather than firing a request we know will 401 — keeps the offline/guest path quiet.\n const loggedIn = args.loggedIn ?? Boolean(config.email)\n\n if (!loggedIn) {\n return {\n lines: [empty(EMPTY_STATE), \" start one → bt browse\"],\n json: args.json ? { commits: [] } : undefined,\n }\n }\n\n const orders = (await client.listOrders()) as LogOrder[]\n if (!orders || orders.length === 0) {\n return {\n lines: [empty(EMPTY_STATE), \" start one → bt browse\"],\n json: args.json ? { commits: [] } : undefined,\n }\n }\n\n // Render the wardrobe as a git history (brand-delight #2). --graph and --oneline carry the\n // git-log treatments (short-hash, HEAD ref, the 🎉 merged-to-main beat at delivered); the bare\n // `bt log` keeps the flat list. --json is always the raw order set (machine-clean).\n const style = brandOf(args)\n const lines = args.graph\n ? renderGraph(orders, style)\n : args.oneline\n ? renderOneline(orders, style)\n : renderFlat(orders)\n\n return {\n lines,\n json: args.json ? { commits: orders } : undefined,\n }\n}\n\nexport function registerLog(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"log\")\n .option(\"--oneline\", \"compact one-line-per-order format\")\n .option(\"--graph\", \"graph format\")\n .description(\"your order history as a git log.\")\n .action(async (opts: { oneline?: boolean; graph?: boolean }) => {\n const { json, brand } = resolveOutput(program)\n // The history route is JWT-bound (d13): \"logged in\" = a token resolves (BT_TOKEN env → keychain,\n // d18), NOT a saved email. A token-only session with no config.email must still see history.\n const loggedIn = Boolean(resolveBridgeToken(process.env, getToken()))\n const res = await runLog(makeClient(), loadConfig(), { oneline: opts.oneline, graph: opts.graph, json, loggedIn, brand })\n printResult(res, json)\n })\n}\n","// bt status — working-tree state: what's staged (the cart), what's in flight.\n//\n// The cart is the authoritative source of truth for \"staged\" (F-B3); a stale cart_id is\n// reported calmly (RecoverableCartError), never crashed. In-flight orders are a logged-in\n// capability (Wave 5) — until then `status` shows the staged tree + a clean-tree line.\n\nimport type { Command } from \"commander\"\nimport { empty, warn } from \"../voice\"\nimport { fmtPrice, formatCartLine, taxSuffix, isCartTaxInclusive, brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { cyan } from \"../brand\"\nimport { RecoverableCartError } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface StatusArgs extends Branded {\n json?: boolean\n}\n\nconst FRESH_REPO = \"no commits yet. your wardrobe is a fresh repo.\"\n\nexport async function runStatus(\n client: StoreClient,\n config: BtConfigLike,\n args: StatusArgs\n): Promise<HandlerResult> {\n if (!config.cart_id) {\n return {\n lines: [\n \"on branch main\",\n empty(FRESH_REPO),\n \" nothing staged. clean tree → bt browse\",\n ],\n json: args.json ? { branch: \"main\", staged: [], clean: true } : undefined,\n }\n }\n\n const style = brandOf(args)\n try {\n const cart = await client.getCart(config.cart_id)\n const items = cart.items ?? []\n const lines: string[] = [\"on branch main\"]\n if (items.length === 0) {\n lines.push(empty(FRESH_REPO))\n lines.push(\" nothing staged. clean tree → bt browse\")\n } else {\n lines.push(\"staged for commit:\")\n items.forEach((li, i) => {\n lines.push(formatCartLine(li, i, cart.currency_code, style))\n })\n if (cart.total != null) {\n lines.push(` total ${cyan(style, fmtPrice(cart.total, cart.currency_code))}${taxSuffix(isCartTaxInclusive(cart))}`)\n }\n lines.push(\" remove one → bt unstage <#> · commit → bt commit\")\n }\n return {\n lines,\n json: args.json\n ? { branch: \"main\", staged: items, total: cart.total ?? null, clean: items.length === 0 }\n : undefined,\n }\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n \"on branch main\",\n warn(\"your staged cart is no longer valid (expired or already committed).\"),\n empty(FRESH_REPO),\n \" re-stage → bt browse\",\n ],\n json: args.json ? { branch: \"main\", staged: [], clean: true, stale: true } : undefined,\n }\n }\n throw e\n }\n}\n\nexport function registerStatus(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"status\")\n .description(\"working-tree state: what's staged, what's in flight.\")\n .action(async () => {\n const { json, brand } = resolveOutput(program)\n const res = await runStatus(makeClient(), loadConfig(), { json, brand })\n printResult(res, json)\n })\n}\n","// bt unstage <ref> — remove a staged item from the cart, then re-read + VERIFY server state.\n//\n// \"git reset\" for the wardrobe. The cart is server-authoritative (F-B3): we read the live cart,\n// resolve <ref> (index / line-item id / short id / title word — BUG 2) to a real line-item id,\n// DELETE it, re-read, and confirm it actually went away. We print \"✓ unstaged\" ONLY when the\n// item is truly gone — never a false success (the prod bug Sam hit: a handle/word no-op'd the\n// delete but the CLI still printed \"✓\"). An unknown ref is a clear error, never a fake tick.\n\nimport type { Command } from \"commander\"\nimport { ok, empty, warn, fail } from \"../voice\"\nimport { formatCartLine, resolveLineItemRef, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport { RecoverableCartError } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike, CartLineItemLike } from \"./types-bridge\"\n\nexport interface UnstageArgs {\n /** the user-supplied reference: a 1-based index, a line-item id, or a product handle/title word. */\n itemId: string\n json?: boolean\n}\n\nconst FRESH_REPO = \"no commits yet. your wardrobe is a fresh repo.\"\n\nexport async function runUnstage(\n client: StoreClient,\n config: BtConfigLike,\n args: UnstageArgs\n): Promise<HandlerResult> {\n if (!config.cart_id) {\n return {\n lines: [empty(FRESH_REPO), \" nothing staged to unstage → bt browse\"],\n json: args.json ? { cart_id: null, items: [] } : undefined,\n }\n }\n\n try {\n // 1. read the authoritative cart so we can resolve the ref + verify the removal (BUG 2).\n const before = await client.getCart(config.cart_id)\n const beforeItems = before.items ?? []\n if (beforeItems.length === 0) {\n return {\n lines: [empty(FRESH_REPO), \" clean tree → bt browse\"],\n json: args.json ? { cart_id: before.id, items: [] } : undefined,\n }\n }\n\n // 2. resolve <ref> to a real line-item id. No match → a CLEAR error, never a false success.\n const target = resolveLineItemRef(beforeItems, args.itemId)\n if (!target) {\n return {\n lines: [\n warn(`no such item in your cart: \"${args.itemId}\"`),\n \" see what's staged (with its #) → bt cart\",\n ],\n json: args.json ? { cart_id: before.id, removed: null, items: beforeItems } : undefined,\n exitCode: EXIT.DATAERR, // bad ref → non-zero so a script can't proceed as if it removed something (B3)\n }\n }\n\n // 3. DELETE it, then re-read and VERIFY it's actually gone (the prod no-op guard).\n await client.removeLineItem(config.cart_id, target.id)\n const after = await client.getCart(config.cart_id)\n const afterItems = after.items ?? []\n const stillThere = afterItems.some((li: CartLineItemLike) => li.id === target.id)\n\n if (stillThere) {\n // honest failure — the server did NOT drop it. Never a fake ✓.\n return {\n lines: [\n fail({\n code: EXIT.GENERIC,\n what: `couldn't unstage \"${(target.title ?? target.product_title ?? args.itemId).toString()}\" — it's still in your cart.`,\n fix: \"check what's staged → bt cart (then try the # shown, or bt forget to clear)\",\n }),\n ],\n json: args.json ? { cart_id: after.id, removed: null, items: afterItems } : undefined,\n exitCode: EXIT.GENERIC, // the server didn't drop it → honest non-zero, never a fake success (B3)\n }\n }\n\n // 4. truly gone → the honest ✓ + the remaining tree.\n const removedTitle = (target.title ?? target.product_title ?? \"item\").toString()\n const lines: string[] = [ok(`unstaged ${removedTitle}.`)]\n if (afterItems.length === 0) {\n lines.push(empty(FRESH_REPO))\n lines.push(\" clean tree → bt browse\")\n } else {\n lines.push(\"still staged:\")\n afterItems.forEach((li: CartLineItemLike, i: number) => {\n lines.push(formatCartLine(li, i, after.currency_code))\n })\n }\n return {\n lines,\n json: args.json ? { cart_id: after.id, removed: target.id, items: afterItems } : undefined,\n }\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n warn(\"that cart is no longer valid (expired or already committed).\"),\n empty(FRESH_REPO),\n \" re-stage → bt browse\",\n ],\n json: args.json ? { cart_id: null, removed: null, items: [] } : undefined,\n }\n }\n throw e\n }\n}\n\nexport function registerUnstage(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"unstage\")\n .alias(\"reset\")\n .argument(\"<ref>\", \"the staged item: its # (from bt cart), its line-item id, or its name\")\n .description(\"remove a staged item from the cart (git reset).\")\n .action(async (ref: string) => {\n const { json } = resolveOutput(program)\n const res = await runUnstage(makeClient(), loadConfig(), { itemId: ref, json })\n printResult(res, json)\n })\n}\n","// bt whoami — your contribution profile (VOICE §4.3).\n//\n// JWT-bound: the headless route returns the AUTHENTICATED customer's own minimal, PII-stripped\n// profile (G15 — tier/commits/badges, never email/address). Login is Wave 5, so today a guest\n// gets a 401 → we print the guest line + a connect hint (no crash). `--json` emits ONLY the\n// non-PII profile fields (G15), shaped for the \"bio-on-your-site\" crowd.\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { cyan, green, contributionBar, box, rule, type BrandStyle } from \"../brand\"\nimport { StoreApiError } from \"@binaryandthread/store-client\"\nimport { jwtExpiry } from \"../jwt\"\nimport { getToken } from \"../keychain\"\nimport type { StoreClient, BtConfigLike, WhoAmI } from \"./types-bridge\"\n\nexport interface WhoamiArgs extends Branded {\n json?: boolean\n /** an optional local handle (derived from the saved email's local-part) for the card headline. */\n handle?: string\n}\n\n// Standing % per tier (VOICE §4.1) — shown flatly, \"earned, not bought\".\nconst NEXT_TIER: Record<string, { at: number; name: string; pct: number }> = {\n contributor: { at: 5, name: \"maintainer\", pct: 10 },\n maintainer: { at: 20, name: \"core\", pct: 15 },\n core: { at: 0, name: \"core\", pct: 20 },\n}\n\n// The contribution bar fills to the core threshold — a full bar literally means you reached core.\nconst GRAPH_CAP = 20\nconst CARD_WIDTH = 58\n\n/**\n * The `bt whoami` contributor card (VOICE §4.3, brand-delight #1 — the screenshot flex). An\n * ASCII-framed card: a headline (handle · tier), the standing facts, and the green contribution\n * graph. The graph is HONEST — one green cell per real committed order (see contributionBar). The\n * card is deadpan: the flex is the green row + the standing, stated flatly, no exclamation.\n */\nfunction profileCard(p: WhoAmI, style: BrandStyle, handle?: string): string[] {\n const tier = p.bt_tier ?? \"contributor\"\n const commits = p.bt_commit_count ?? 0\n const next = NEXT_TIER[tier]\n const isMax = tier === \"core\" || !next\n const toNext = next && !isMax ? Math.max(0, next.at - commits) : 0\n const standing = p.standing_pct ?? NEXT_TIER[tier]?.pct ?? null\n\n const inner: string[] = []\n\n // headline — \"<handle> · <tier>\" (the handle is the saved email's local-part; omitted if guest).\n inner.push(`${handle ? `${handle} · ` : \"\"}${cyan(style, tier)}`)\n inner.push(rule(CARD_WIDTH - 1))\n\n // tier line — unambiguous \"N more to <tier>\" (B4: never reads as \"you've made N commits\").\n if (isMax) {\n inner.push(`tier ${tier.padEnd(13)}max standing — ${standing ?? 20}%`)\n } else {\n inner.push(`tier ${tier.padEnd(13)}${toNext} more commit${toNext === 1 ? \"\" : \"s\"} to ${next!.name}`)\n }\n\n // commits — say what it IS (orders committed), never an ambiguous \"shirts in the repo\".\n if (commits === 0) {\n inner.push(`commits ${String(commits).padEnd(13)}your repo's empty — everyone starts at 0`)\n } else {\n inner.push(`commits ${String(commits).padEnd(13)}order${commits === 1 ? \"\" : \"s\"} committed`)\n }\n\n if (standing != null) {\n inner.push(`standing ${cyan(style, `${standing}%`.padEnd(13))}applied at every commit`)\n }\n\n // the green contribution graph — the flex. One filled cell per real commit (honest).\n const bar = contributionBar(style, commits, GRAPH_CAP)\n const graphLabel = commits === 0 ? \"no commits yet\" : `${commits} contribution${commits === 1 ? \"\" : \"s\"}`\n inner.push(`graph ${bar} ${graphLabel}`)\n\n if (p.bt_badges && p.bt_badges.length > 0) {\n inner.push(`badges ${p.bt_badges.join(\" · \")}`)\n }\n if (p.bt_connected_at) {\n inner.push(`since contributor since ${p.bt_connected_at.slice(0, 10)}`)\n }\n\n // closing line — earned, not bought; the next step stated flatly (VOICE §4.3, B2).\n inner.push(rule(CARD_WIDTH - 1))\n if (isMax) {\n inner.push(`in ${green(style, \"AUTHORS\")}. earned, not bought.`)\n } else if (commits === 0) {\n inner.push(\"your first commit makes this worth screenshotting → bt browse\")\n } else {\n inner.push(`${toNext} more to ${next!.name} → bt browse · earned, not bought`)\n }\n\n return box(inner, { width: CARD_WIDTH, title: \"bt whoami\", style })\n}\n\n/** A display handle from the saved email's local-part (THEIR machine, THEIR data) — never sent. */\nfunction handleFromConfig(config: BtConfigLike): string | undefined {\n const email = config.email\n if (!email || typeof email !== \"string\") return undefined\n const local = email.split(\"@\")[0]?.trim()\n return local || undefined\n}\n\nexport async function runWhoami(\n client: StoreClient,\n config: BtConfigLike,\n args: WhoamiArgs,\n token?: string | null\n): Promise<HandlerResult> {\n const style = brandOf(args)\n const handle = args.handle ?? handleFromConfig(config)\n // Local token-expiry decode (no network, no signature check) — lets a script pre-flight auth\n // (\"is my token still valid / when does it lapse\") without a real mutation (d25).\n const { expiresAt, expired } = jwtExpiry(token)\n try {\n const me = await client.whoami()\n if (args.json) {\n // G15: emit ONLY the non-PII profile fields — never an email/address.\n return {\n lines: profileCard(me, style, handle),\n json: {\n authenticated: true,\n tier: me.bt_tier,\n commits: me.bt_commit_count,\n badges: me.bt_badges,\n standing_pct: me.standing_pct ?? null,\n connected_at: me.bt_connected_at,\n token_expires_at: expiresAt,\n token_expired: expired,\n },\n }\n }\n return { lines: profileCard(me, style, handle) }\n } catch (e) {\n if (e instanceof StoreApiError && (e.status === 401 || e.status === 403)) {\n // Not authenticated — guest guidance, never a crash. The token (if any) is invalid/expired.\n return {\n lines: [\n empty(\"you're browsing as a guest — not connected yet.\"),\n \" connect → bt login (the contributor on-ramp for this channel)\",\n ],\n json: args.json\n ? {\n authenticated: false,\n tier: null,\n connected: false,\n token_expires_at: expiresAt,\n token_expired: expired,\n }\n : undefined,\n }\n }\n throw e\n }\n}\n\nexport function registerWhoami(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"whoami\")\n .description(\"your contribution profile + standing.\")\n .action(async () => {\n const { json, brand } = resolveOutput(program)\n const res = await runWhoami(makeClient(), loadConfig(), { json, brand }, getToken())\n printResult(res, json)\n })\n}\n","// bt drops — what's on `next` before it hits the web `main` (VOICE §2.3, §4.4).\n//\n// A contributor perk: the terminal sees drops before the web does. Thin over listDrops; the\n// \"merges to main in <t>\" countdown is DERIVED from the server-provided `next_until` timestamp\n// (F-I5 — never computed authoritatively from the client clock). --vote is maintainer+ (Wave 5).\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { fmtPrice, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport type { StoreClient, BtConfigLike, DropRow } from \"./types-bridge\"\n\nexport interface DropsArgs {\n json?: boolean\n}\n\n/** A human \"merges to main in …\" string from the server-provided next_until (F-I5). */\nfunction mergesIn(nextUntil: string | null): string {\n if (!nextUntil) return \"on next\"\n const until = Date.parse(nextUntil)\n if (Number.isNaN(until)) return \"on next\"\n const ms = until - Date.now()\n if (ms <= 0) return \"merging now\"\n const hours = Math.round(ms / (60 * 60 * 1000))\n if (hours < 48) return `merges to main in ${hours}h`\n return `merges to main in ${Math.round(hours / 24)}d`\n}\n\nexport async function runDrops(\n client: StoreClient,\n config: BtConfigLike,\n args: DropsArgs\n): Promise<HandlerResult> {\n // Resolve the region so drop prices carry a currency (A6 — was a bare number in `null` currency).\n const region = await client.resolveRegion(config.region)\n const drops = await client.listDrops()\n\n if (!drops || drops.length === 0) {\n return {\n lines: [\n empty(\"nothing on next right now. main is the latest.\"),\n \" browse main → bt browse\",\n ],\n json: args.json ? { drops: [] } : undefined,\n }\n }\n\n const lines: string[] = [\"on next — terminal-only, not yet on the web:\"]\n for (const d of drops as DropRow[]) {\n lines.push(\n [\n ` ${(d.handle ?? d.id).padEnd(32)}`,\n fmtPrice(d.price, region.currency_code).padEnd(10),\n mergesIn(d.next_until),\n ].join(\" \").trimEnd()\n )\n }\n lines.push(\" first dibs → bt stage <slug> then bt checkout\")\n\n return {\n lines,\n json: args.json\n ? (drops as DropRow[]).map((d) => ({\n id: d.id,\n handle: d.handle,\n title: d.title,\n price: d.price,\n next_until: d.next_until,\n }))\n : undefined,\n }\n}\n\nexport function registerDrops(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"drops\")\n // `next` is an unambiguous alias for the customer view — avoids the singular/plural footgun\n // with the operator-only (hidden) `bt drop` (d20).\n .alias(\"next\")\n .description(\"what's on next before it hits the web.\")\n .action(async () => {\n const { json } = resolveOutput(program)\n const res = await runDrops(makeClient(), loadConfig(), { json })\n printResult(res, json)\n })\n}\n","// bt connect — the contributor on-ramp explainer.\n//\n// The real auth flow (OS-keychain token + `bt login`/`logout`) is SHIPPED (SECURITY G15: the token\n// never touches the plaintext config). `bt connect` is the explainer: it says what connecting\n// unlocks (standing, access to `next`, the wardrobe repo) and points at `bt login`, which owns the\n// flow. No network, no side effects — pure copy. (d7: copy must not imply login is \"coming soon\".)\n\nimport type { Command } from \"commander\"\nimport { printResult, resolveOutput, type HandlerResult } from \"./shared\"\n\nexport interface ConnectArgs {\n json?: boolean\n}\n\nexport async function runConnect(args: ConnectArgs): Promise<HandlerResult> {\n const lines = [\n \"connect your wardrobe — become a contributor.\",\n \" connecting authenticates you and unlocks:\",\n \" · 10% standing (applied at every commit)\",\n \" · access to next (drops before the web sees them)\",\n \" · your wardrobe repo + the contributor badge\",\n \"\",\n \" connect now → bt login\",\n \" (we email you a token to paste; it lives in your OS keychain, never in plaintext config.)\",\n ]\n return {\n lines,\n json: args.json ? { connected: false, login_command: \"bt login\" } : undefined,\n }\n}\n\nexport function registerConnect(program: Command): void {\n program\n .command(\"connect\")\n .description(\"the contributor on-ramp — what connecting unlocks. run bt login to connect.\")\n .action(async () => {\n const { json } = resolveOutput(program)\n const res = await runConnect({ json })\n printResult(res, json)\n })\n}\n","// bt login — the passwordless magic-link on-ramp (VOICE §2.1, SECURITY G1/G7/G10).\n//\n// Flow (no password, ever — G1):\n// 1. prompt for email → POST request-link (the backend emails a single-use TOKEN to paste)\n// 2. \"check your inbox — i'll wait\" → the user copies the token from the email\n// 3. the user PASTES the token at the stdin prompt → POST verify → the backend returns a JWT\n// 4. the JWT is stored in the OS keychain (@napi-rs/keyring — the maintained lib, NOT plaintext — G7);\n// the (non-sensitive) email is persisted in ~/.config/bt config so whoami knows who you are\n//\n// SECURITY: there is NO `--token` flag and the email carries the TOKEN (not a clickable URL) — a token\n// in argv lands in shell history + the process list, and a token in a URL lands in browser/proxy logs\n// (G10). The interactive stdin paste is the normal path; CI may set BT_MAGIC_TOKEN (env, not argv).\n//\n// runLogin is a PURE function of (client, prompts, keychain, args) → HandlerResult so it's unit\n// testable without a backend, a browser, or a human (ROBUSTNESS §4.1). bin.ts wires the real deps.\n\nimport type { Command } from \"commander\"\nimport { ok, warn, empty, GLYPH } from \"../voice\"\nimport { failResult, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport { StoreApiError } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\n/** The keychain surface login needs (injected for tests). */\nexport interface KeychainPort {\n setToken(jwt: string): void\n}\n\n/** The prompter surface login needs (injected for tests). */\nexport interface LoginPrompts {\n ask(label: string, opts?: { default?: string }): Promise<string>\n}\n\nexport interface LoginArgs {\n email?: string\n /** A token from the BT_MAGIC_TOKEN env (CI/non-interactive), skipping the stdin paste prompt.\n * NEVER a CLI flag — a token in argv leaks to shell history + the process list. */\n token?: string\n json?: boolean\n}\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport async function runLogin(\n client: StoreClient,\n prompts: LoginPrompts,\n keychain: KeychainPort,\n config: BtConfigLike,\n args: LoginArgs\n): Promise<HandlerResult> {\n // 0. JSON / non-interactive mode is a self-contained token EXCHANGE — it NEVER prompts (a readline\n // prompt on stdin would hang a pipe/CI/agent forever, and leak the prompt to stdout — B1). It\n // requires --email + a token in BT_MAGIC_TOKEN (obtained out-of-band via the interactive flow).\n if (args.json) {\n const jsonEmail = (args.email ?? \"\").trim()\n const jsonToken = (args.token ?? \"\").trim()\n if (!jsonEmail || !EMAIL_RE.test(jsonEmail) || !jsonToken) {\n return failResult({\n code: EXIT.DATAERR,\n what: \"login --json is non-interactive — it needs --email and a token in BT_MAGIC_TOKEN.\",\n fix: \"bt login --email you@dev.to with BT_MAGIC_TOKEN=<the token from the email>\",\n })\n }\n let jsonResult: { jwt: string; customer: { id: string } }\n try {\n jsonResult = await client.verifyMagicLink(jsonToken)\n } catch (e) {\n if (e instanceof StoreApiError && (e.status === 401 || e.status === 403)) {\n return failResult({ code: EXIT.NOPERM, what: \"that token is invalid or expired.\", fix: \"request a fresh one, then set BT_MAGIC_TOKEN\" })\n }\n if (e instanceof StoreApiError) {\n return failResult({ code: EXIT.TEMPFAIL, what: \"login couldn't complete right now.\", fix: \"try again in a moment\" })\n }\n throw e\n }\n keychain.setToken(jsonResult.jwt)\n return {\n lines: [ok(\"authenticated. welcome — you're a contributor now.\")],\n save: { email: jsonEmail },\n json: { connected: true, customer_id: jsonResult.customer.id },\n }\n }\n\n // 1. Resolve the email (arg → prompt → saved default).\n let email = (args.email ?? \"\").trim()\n if (!email) {\n email = (await prompts.ask(\"email\", { default: config.email })).trim()\n }\n if (!email || !EMAIL_RE.test(email)) {\n return {\n lines: [warn(\"that doesn't look like an email. try: bt login --email you@dev.to\")],\n }\n }\n\n // 2. Request the magic link (uniform ack — no enumeration, G12).\n try {\n await client.requestMagicLink(email)\n } catch (e) {\n if (e instanceof StoreApiError) {\n return { lines: [warn(\"couldn't start login right now. try again in a moment.\")] }\n }\n throw e\n }\n\n const waitLines = [\n ok(\"check your inbox — a single-use login token is on its way.\"),\n empty(\" no password. the token expires shortly. i'll wait.\"),\n empty(\" (we email a token to paste, not a clickable link — so it never lands in your shell history or a browser log.)\"),\n ]\n\n // 3. Accept the token: from BT_MAGIC_TOKEN (CI), else paste it from the email at the stdin prompt\n // (never a CLI flag — G10). The verify endpoint exchanges it for a customer-scoped JWT.\n let token = (args.token ?? \"\").trim()\n if (!token) {\n token = (await prompts.ask(\"paste the token from the email\")).trim()\n }\n if (!token) {\n return { lines: [...waitLines, \"\", warn(\"no token entered — run bt login again when you have the email.\")] }\n }\n\n let result: { jwt: string; customer: { id: string } }\n try {\n result = await client.verifyMagicLink(token)\n } catch (e) {\n if (e instanceof StoreApiError && (e.status === 401 || e.status === 403)) {\n return {\n lines: [...waitLines, \"\", warn(\"that link is invalid or expired. run bt login to get a fresh one.\")],\n }\n }\n if (e instanceof StoreApiError) {\n return { lines: [...waitLines, \"\", warn(\"login couldn't complete. try again.\")] }\n }\n throw e\n }\n\n // 4. Store the JWT in the OS keychain (NOT plaintext — G7). Persist the email (non-sensitive) so\n // whoami can greet you; the TOKEN never touches the config (config.ts strips it).\n keychain.setToken(result.jwt)\n\n return {\n lines: [\n ok(\"authenticated. welcome — you're a contributor now.\"),\n ` ${GLYPH.arrow} your token is in your OS keychain (never plaintext).`,\n ` ${GLYPH.arrow} see your standing → bt whoami`,\n ],\n save: { email },\n json: args.json ? { connected: true, customer_id: result.customer.id } : undefined,\n }\n}\n\nexport function registerLogin(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike,\n prompts: LoginPrompts,\n keychain: KeychainPort,\n persist: (patch: Partial<BtConfigLike>) => void\n): void {\n program\n .command(\"login\")\n .description(\"connect your wardrobe with a passwordless magic-link (no password, ever).\")\n .option(\"--email <email>\", \"your email (skips the prompt)\")\n // NO --token flag: a token on the command line lands in shell history + the process list (a leak\n // of a bearer credential). The interactive paste prompt (stdin, not in history) is the normal\n // path; for non-interactive/CI, set BT_MAGIC_TOKEN (env vars aren't in argv/history) — read below.\n .action(async (opts: { email?: string }) => {\n const { json } = resolveOutput(program)\n const envToken = process.env.BT_MAGIC_TOKEN?.trim() || undefined\n const res = await runLogin(makeClient(), prompts, keychain, loadConfig(), {\n email: opts.email,\n token: envToken,\n json,\n })\n if (res.save) {\n persist(res.save)\n }\n printResult(res, json)\n })\n}\n","// bt logout — clear the local session (SECURITY G7/G15).\n//\n// Deletes the keychain token (and the 0600 fallback). The customer JWT is STATELESS server-side\n// (Medusa, G7), so logout cannot invalidate a stolen token remotely — we DON'T claim it does. The\n// real revocation story is the SHORT TTL the backend issues (minutes) + a future jti denylist. We\n// state this plainly rather than over-promising (VOICE: honest, no mascot).\n//\n// runLogout is a PURE function of (keychain) → HandlerResult — no network needed (the token is local).\n\nimport type { Command } from \"commander\"\nimport { ok, empty } from \"../voice\"\nimport { printResult, resolveOutput, type HandlerResult } from \"./shared\"\n\n/** The keychain surface logout needs (injected for tests). */\nexport interface LogoutKeychainPort {\n deleteToken(): void\n}\n\nexport async function runLogout(keychain: LogoutKeychainPort): Promise<HandlerResult> {\n keychain.deleteToken()\n return {\n lines: [\n ok(\"logged out. your token is wiped from this machine's keychain.\"),\n empty(\" (server tokens are short-lived by design — they expire on their own.)\"),\n ],\n json: { logged_out: true },\n }\n}\n\nexport function registerLogout(\n program: Command,\n keychain: LogoutKeychainPort\n): void {\n program\n .command(\"logout\")\n .description(\"clear your local session (wipes the keychain token).\")\n .action(async () => {\n const { json } = resolveOutput(program)\n const res = await runLogout(keychain)\n printResult(res, json)\n })\n}\n","// bt drop — the OPERATOR-side drop family (REQ-DN13): create / verify / promote / retire.\n//\n// These are NOT customer commands — they wire to the backend `medusa exec` drop scripts (Task 2:\n// bt-drop.ts), which run against the catalog. Sam runs them from the backend repo (or a deploy box).\n// The CLI surface is a thin convenience that shells out to the matching npm script with env vars.\n//\n// We gate this behind an explicit operator flag (BT_OPERATOR=1) so a regular contributor's CLI never\n// exposes catalog mutation. The actual catalog safety (idempotent, web-touched-only-by-promote,\n// PAGE-on-bad-verify) lives in the backend script — the CLI just forwards intent.\n//\n// runDrop is a PURE function of (args, deps) → HandlerResult: the shell-exec is INJECTED so the\n// command is unit-testable without spawning a real medusa process (ROBUSTNESS §4.1).\n\nimport type { Command } from \"commander\"\nimport { ok, warn, working, empty } from \"../voice\"\nimport { failResult, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\n\nexport type DropSub = \"create\" | \"verify\" | \"promote\" | \"retire\"\n\n/** The exec port: run a backend npm script with env. Returns the exit code. Injected for tests. */\nexport interface DropExecPort {\n run(script: string, env: Record<string, string>): Promise<number>\n}\n\nexport interface DropArgs {\n sub?: string\n /** --motif <slug> for create. */\n motif?: string\n /** --drop-id <id> for all subcommands. */\n dropId?: string\n /** --stage main|next for verify (DROP_EXPECT_STAGE). */\n stage?: string\n /** operator gate (BT_OPERATOR=1). */\n operator?: boolean\n json?: boolean\n}\n\nconst SCRIPT: Record<DropSub, string> = {\n create: \"drop:create\",\n verify: \"drop:verify\",\n promote: \"drop:promote\",\n retire: \"drop:retire\",\n}\n\nexport async function runDrop(args: DropArgs, exec: DropExecPort): Promise<HandlerResult> {\n // Operator gate: catalog mutation is not a contributor capability.\n if (!args.operator) {\n return {\n lines: [\n warn(\"bt drop is an operator command (catalog mutation).\"),\n empty(\" run it from the backend with BT_OPERATOR=1, or use the backend npm scripts directly.\"),\n ],\n }\n }\n\n const sub = (args.sub ?? \"\").trim() as DropSub\n if (!sub || !SCRIPT[sub]) {\n return { lines: [warn(\"usage: bt drop <create|verify|promote|retire> --drop-id <id> [--motif <slug>]\")] }\n }\n if (!args.dropId || !args.dropId.trim()) {\n return { lines: [warn(`bt drop ${sub}: --drop-id <id> is required.`)] }\n }\n if (sub === \"create\" && (!args.motif || !args.motif.trim())) {\n return { lines: [warn(\"bt drop create: --motif <slug> is required.\")] }\n }\n\n const env: Record<string, string> = { DROP_ID: args.dropId.trim() }\n if (sub === \"create\" && args.motif) {\n env.MOTIF_SLUG = args.motif.trim()\n }\n if (sub === \"verify\" && args.stage) {\n env.DROP_EXPECT_STAGE = args.stage.trim()\n }\n\n const code = await exec.run(SCRIPT[sub], env)\n if (code !== 0) {\n return {\n lines: [warn(`drop ${sub} reported a problem (exit ${code}). check the backend logs / ops alert.`)],\n json: args.json ? { sub, drop_id: args.dropId, exit: code } : undefined,\n exitCode: code, // forward the backend's exit code so operator CI can branch on $? (B3)\n }\n }\n\n const done: Record<DropSub, string> = {\n create: \"drop created on next (terminal-only ~48h).\",\n verify: \"drop verified (visible to the channel, invisible to the web).\",\n promote: \"drop promoted next → main (it's on the web now).\",\n retire: \"drop retired (archived).\",\n }\n return {\n lines: [ok(done[sub])],\n json: args.json ? { sub, drop_id: args.dropId, exit: 0 } : undefined,\n }\n}\n\nexport function registerDrop(\n program: Command,\n exec: DropExecPort\n): void {\n program\n // Operator-only — hidden from the customer `--help` (d17). Still runs (BT_OPERATOR gate at\n // runtime), just undiscoverable to a regular contributor; also avoids the drop/drops footgun (d20).\n .command(\"drop\", { hidden: true })\n .argument(\"<sub>\", \"create | verify | promote | retire\")\n .option(\"--motif <slug>\", \"motif slug (create)\")\n .option(\"--drop-id <id>\", \"the drop id\")\n .option(\"--stage <stage>\", \"expected stage for verify (next|main)\")\n .description(\"operator: manage a drop's lifecycle (create/verify/promote/retire).\")\n .action(async (sub: string, opts: { motif?: string; dropId?: string; stage?: string }) => {\n const { json } = resolveOutput(program)\n const operator = process.env.BT_OPERATOR === \"1\"\n // The progress line is human chrome — never on stdout in --json mode (keeps it machine-clean).\n if (!json) process.stdout.write(working(`drop ${sub}…`) + \"\\n\")\n const res = await runDrop(\n { sub, motif: opts.motif, dropId: opts.dropId, stage: opts.stage, operator, json },\n exec\n )\n printResult(res, json)\n })\n}\n","// bt init — the first-run welcome + 3-command happy path (d3).\n//\n// New users had nothing guiding them (the critique's onboarding gap). Since the publishable key +\n// prod URL are baked in (d2), there is no setup — `bt init` just orients you and shows the path\n// from zero to a placed order. Pure copy; no network, no side effects. --json emits the happy path\n// so an agent can discover the flow programmatically.\n\nimport type { Command } from \"commander\"\nimport { brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { header } from \"../brand\"\n\nexport interface InitArgs extends Branded {\n json?: boolean\n}\n\nconst HAPPY_PATH = [\"bt browse\", \"bt stage <handle> --size L\", \"bt checkout\"]\nconst DOCS_URL = \"https://binaryandthread.com/docs\"\n\nexport function runInit(args: InitArgs): HandlerResult {\n const style = brandOf(args)\n const lines = [\n header(style, \"bt — binary & thread, the terminal store\"),\n \" buy heavyweight pieces from your terminal. zero setup — you're already pointed at the live store.\",\n \"\",\n \" the happy path:\",\n \" bt browse # the catalog, numbered\",\n \" bt stage <n|slug> --size L # add to your cart (a browse number, or a slug)\",\n \" bt checkout # pay in your browser — cards never touch the terminal\",\n \"\",\n \" optional:\",\n \" bt login # contributor standing + order history\",\n \" bt whoami # your profile\",\n ` docs → ${DOCS_URL}`,\n ]\n return {\n lines,\n json: args.json ? { happy_path: HAPPY_PATH, docs: DOCS_URL, zero_setup: true } : undefined,\n }\n}\n\nexport function registerInit(program: Command): void {\n program\n .command(\"init\")\n .description(\"first-run welcome + the 3-command happy path.\")\n .action(async () => {\n const { json, brand } = resolveOutput(program)\n printResult(runInit({ json, brand }), json)\n })\n}\n","// bt buy <handle> — stage + checkout in one (d5).\n//\n// Referenced by `bt stage`'s output (\"or bt buy to do both\") but never existed → an unknown-command\n// error (the critique's \"the tool lies\"). This is the composition: runStage, then (if it staged\n// cleanly) runCheckout. Buying is explicit intent, so it proceeds WITHOUT the extra checkout confirm\n// (yes:true) — but the browser-hop is unchanged: cards never touch the terminal.\n\nimport type { Command } from \"commander\"\nimport { runStage } from \"./stage\"\nimport { runCheckout, heartbeatLine, type CheckoutDeps } from \"./checkout\"\nimport { printResult, resolveOutput } from \"./shared\"\nimport { dim } from \"../brand\"\nimport type { HandlerResult, Branded } from \"./shared\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface BuyArgs extends Branded {\n handle: string\n size?: string\n colour?: string\n json?: boolean\n}\n\nexport async function runBuy(\n client: StoreClient,\n config: BtConfigLike,\n args: BuyArgs,\n deps: CheckoutDeps\n): Promise<HandlerResult> {\n const staged = await runStage(client, config, {\n handle: args.handle,\n size: args.size,\n colour: args.colour,\n json: args.json,\n brand: args.brand,\n })\n // stage failed (variant not found / no cart) → surface its lines, NEVER proceed to checkout.\n const cartId = staged.save?.cart_id\n if (!cartId) {\n return staged\n }\n const checked = await runCheckout(\n client,\n { ...config, cart_id: cartId },\n { json: args.json, brand: args.brand, yes: true },\n deps\n )\n return {\n lines: [...staged.lines, \"\", ...checked.lines],\n save: { ...(staged.save ?? {}), ...(checked.save ?? {}) },\n json: args.json ? { cart_id: cartId, checkout: checked.json ?? null } : undefined,\n // forward the checkout outcome's exit code — bt buy runs the SAME money-path poll as bt\n // checkout, so a timed-out/failed composed checkout must not report success (d10).\n exitCode: checked.exitCode,\n }\n}\n\nexport function registerBuy(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"buy\")\n .argument(\"<handle>\", \"the design: a slug, a bt browse number (3), or a fuzzy hint (termnl)\")\n .option(\"--size <size>\", \"garment size\")\n .option(\"--colour <colour>\", \"colour, e.g. white / black\")\n .description(\"stage + checkout in one — reserve, then open browser checkout. cards never touch the terminal.\")\n .action(async (handle: string, opts: { size?: string; colour?: string }) => {\n const { json, brand } = resolveOutput(program)\n const { makePrompts } = await import(\"../prompts\")\n const { openCheckout } = await import(\"../browser\")\n const { pollUntilPlaced } = await import(\"../poll\")\n const { saveConfig } = await import(\"../config\")\n const client = makeClient()\n const print = json ? () => {} : (line: string) => process.stdout.write(line + \"\\n\")\n const res = await runBuy(client, loadConfig(), { handle, size: opts.size, colour: opts.colour, json, brand }, {\n prompts: makePrompts(),\n open: (url) => openCheckout(url),\n // Same heartbeat as bt checkout — bt buy's browser-hop wait is the identical 20-min poll.\n poll: (sessionId) =>\n pollUntilPlaced(client, sessionId, {\n onTick: (attempt) => {\n const line = heartbeatLine(attempt)\n if (line) print(dim(brand, line))\n },\n }),\n saveConfig,\n print,\n })\n if (res.save && Object.keys(res.save).length > 0) {\n saveConfig(res.save)\n }\n printResult(res, json)\n })\n}\n","// bt config get/set — view or set local, NON-sensitive prefs (d6).\n//\n// Backs onto src/config.ts (the atomic store). Only the allowlisted keys are settable — the auth\n// TOKEN is NEVER stored in config (it lives in the OS keychain; config.ts strips it, G15). Setting\n// `email` lets order-lookup know who you are without a prompt each time.\n\nimport type { Command } from \"commander\"\nimport { ok, empty } from \"../voice\"\nimport { failResult, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport type { BtConfig } from \"../config\"\n\nconst SETTABLE = [\"email\", \"region\", \"defaultSize\", \"defaultColour\", \"defaultBranch\"] as const\ntype SettableKey = (typeof SETTABLE)[number]\n\nexport interface ConfigDeps {\n load: () => BtConfig\n save: (patch: Partial<BtConfig>) => void\n}\n\nexport function runConfig(\n args: { sub?: string; key?: string; value?: string; json?: boolean },\n deps: ConfigDeps\n): HandlerResult {\n const cfg = deps.load()\n const sub = (args.sub ?? \"get\").toLowerCase()\n\n if (sub === \"get\") {\n if (args.key) {\n const v = (cfg as Record<string, unknown>)[args.key]\n return {\n lines: [v != null ? `${args.key} = ${String(v)}` : empty(`${args.key} is not set.`)],\n json: args.json ? { [args.key]: v ?? null } : undefined,\n }\n }\n const entries = Object.entries(cfg)\n const lines = entries.length\n ? entries.map(([k, v]) => `${k} = ${String(v)}`)\n : [empty(\"no local config set. (your auth token lives in the keychain, not here.)\")]\n return { lines, json: args.json ? cfg : undefined }\n }\n\n if (sub === \"set\") {\n if (!args.key || args.value == null || args.value === \"\") {\n return failResult({ code: EXIT.DATAERR, what: \"config set needs a key and a value.\", fix: \"bt config set <key> <value>\" })\n }\n if (!SETTABLE.includes(args.key as SettableKey)) {\n return failResult({\n code: EXIT.DATAERR,\n what: `can't set \"${args.key}\".`,\n fix: `settable keys: ${SETTABLE.join(\", \")} (the auth token is never stored in config — use bt login)`,\n })\n }\n deps.save({ [args.key]: args.value } as Partial<BtConfig>)\n return { lines: [ok(`set ${args.key} = ${args.value}`)], json: args.json ? { [args.key]: args.value } : undefined }\n }\n\n return failResult({ code: EXIT.DATAERR, what: `unknown config command \"${sub}\".`, fix: \"bt config get [key] | bt config set <key> <value>\" })\n}\n\nexport function registerConfig(program: Command): void {\n program\n .command(\"config\")\n .argument(\"[sub]\", \"get | set\", \"get\")\n .argument(\"[key]\", \"config key\")\n .argument(\"[value]\", \"value (for set)\")\n .description(\"view or set local prefs (email, region, defaults). the auth token is never stored here.\")\n .action(async (sub: string | undefined, key: string | undefined, value: string | undefined) => {\n const { json } = resolveOutput(program)\n const { loadConfig, saveConfig } = await import(\"../config\")\n const res = runConfig({ sub, key, value, json }, { load: loadConfig, save: saveConfig })\n printResult(res, json)\n })\n}\n","// bt doctor — local diagnostics for a bug report (d15). Sends NOTHING; reads only local state.\n//\n// Prints a redacted health snapshot (versions, the resolved store URL, whether a key/token is\n// present + the token's expiry, terminal capability) — the thing to paste into `bt report` or an\n// issue. The token itself is NEVER printed (only present/expiry). Pairs with the global --debug\n// flag (request tracing to stderr), wired in bin.ts via makeLogger.\n\nimport type { Command } from \"commander\"\nimport { ok, warn, empty } from \"../voice\"\nimport { printResult, type HandlerResult } from \"./shared\"\nimport { VERSION } from \"../version\"\nimport { resolveClientConfig } from \"../client-config\"\nimport { BT_DEFAULT_STORE_URL } from \"@binaryandthread/store-client\"\nimport { resolveBridgeToken } from \"./token\"\nimport { jwtExpiry } from \"../jwt\"\nimport { getToken } from \"../keychain\"\nimport { configPath } from \"../config\"\nimport * as fs from \"node:fs\"\n\nexport interface DoctorSnapshot {\n btVersion: string\n node: string\n platform: string\n storeUrl: string\n keySource: \"env\" | \"baked\"\n loggedIn: boolean\n tokenExpiresAt: string | null\n tokenExpired: boolean | null\n tty: boolean\n color: boolean\n configExists: boolean\n}\n\nexport function runDoctor(s: DoctorSnapshot, json?: boolean): HandlerResult {\n const auth = !s.loggedIn\n ? \"guest (not logged in)\"\n : s.tokenExpired\n ? `logged in but token EXPIRED${s.tokenExpiresAt ? ` (${s.tokenExpiresAt})` : \"\"} — run bt login`\n : `logged in${s.tokenExpiresAt ? ` · token valid until ${s.tokenExpiresAt}` : \"\"}`\n const lines = [\n ok(\"bt doctor — local checkup (nothing was sent)\"),\n ` bt ${s.btVersion}`,\n ` node ${s.node} · ${s.platform}`,\n // E4 — a friendly label for the production store; the raw URL only when pointed elsewhere\n // (local/staging), where it's genuinely diagnostic. The JSON snapshot keeps the raw URL.\n ` store ${s.storeUrl === BT_DEFAULT_STORE_URL ? \"binaryandthread.com (production)\" : s.storeUrl}`,\n ` key set (${s.keySource})`,\n ` auth ${auth}`,\n ` terminal ${s.tty ? \"tty\" : \"non-tty\"} · colour ${s.color ? \"on\" : \"off\"}`,\n ` config ${s.configExists ? configPath() : \"none yet\"}`,\n empty(\" paste this into bt report or an issue. re-run with --debug for request tracing.\"),\n ]\n return { lines, json: json ? { ...s } : undefined }\n}\n\n/**\n * Gather the local health snapshot — the redacted, non-sensitive diagnostics for a bug report. The\n * token itself is NEVER captured (only presence + expiry), so the snapshot is safe to attach to a\n * `bt report` (d14). Shared by `bt doctor` and `bt report`.\n */\nexport function gatherDoctorSnapshot(opts: { color?: boolean } = {}): DoctorSnapshot {\n const { baseUrl } = resolveClientConfig()\n const token = resolveBridgeToken(process.env, getToken())\n const exp = jwtExpiry(token)\n let configExists = false\n try {\n configExists = fs.existsSync(configPath())\n } catch {\n /* ignore */\n }\n return {\n btVersion: VERSION,\n node: process.versions.node,\n platform: `${process.platform}/${process.arch}`,\n storeUrl: baseUrl,\n keySource: process.env.BT_PUBLISHABLE_KEY || process.env.MEDUSA_PUBLISHABLE_KEY ? \"env\" : \"baked\",\n loggedIn: Boolean(token),\n tokenExpiresAt: exp.expiresAt,\n tokenExpired: exp.expired,\n tty: Boolean(process.stdout.isTTY),\n color: opts.color !== false && !process.env.NO_COLOR,\n configExists,\n }\n}\n\nexport function registerDoctor(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"local diagnostics for a bug report (sends nothing).\")\n .action(() => {\n const gOpts = program.opts() as { json?: boolean; color?: boolean }\n const json = Boolean(gOpts.json)\n const snapshot = gatherDoctorSnapshot({ color: gOpts.color })\n printResult(runDoctor(snapshot, json), json)\n })\n}\n","// bt report — file a bug report from the terminal (d14, decision #81 = email to the operator).\n//\n// The contributor on-ramp: filing an issue makes you a contributor. We attach the SAME local health\n// snapshot `bt doctor` prints (versions / store URL / auth state) as context — the token itself is\n// NEVER captured (only presence + expiry), so the snapshot is safe to send (G10/d15). The backend\n// re-redacts authoritatively before emailing. Sends NO cards, NO money path — purely additive.\n//\n// Flow: resolve the message (arg or prompt) → show what we'll attach + confirm → POST → print the\n// reference. --json / --yes auto-proceed (a hidden readline on a non-interactive stdin would hang —\n// d8). --debug echoes the full attached context.\n\nimport type { Command } from \"commander\"\nimport { ok, empty } from \"../voice\"\nimport { printResult, type HandlerResult } from \"./shared\"\nimport type { StoreClient } from \"./types-bridge\"\nimport { gatherDoctorSnapshot, type DoctorSnapshot } from \"./doctor\"\n\nexport interface ReportArgs {\n message?: string\n json?: boolean\n /** skip the confirm (scripts / CI / agents) — implied by --json. */\n yes?: boolean\n /** echo the full attached context. */\n debug?: boolean\n}\n\n/** The terminal prompts the flow needs. Injected so the flow is testable without a TTY. */\nexport interface ReportPrompts {\n ask(label: string, opts?: { default?: string }): Promise<string>\n confirm(label: string): Promise<boolean>\n}\n\nexport interface ReportDeps {\n prompts: ReportPrompts\n /** the redacted local health snapshot to attach as context (gatherDoctorSnapshot). */\n snapshot: DoctorSnapshot\n /** print a line EAGERLY (the preview must appear before the confirm prompt). Defaults to stdout. */\n print?(line: string): void\n}\n\n/** The client capability this command needs — typed structurally so the handler is testable. */\ninterface ReportClient {\n report(message: string, context?: Record<string, unknown>): Promise<{ reference: string }>\n}\n\nexport async function runReport(\n client: ReportClient,\n args: ReportArgs,\n deps: ReportDeps\n): Promise<HandlerResult> {\n // 1. resolve the message (arg → prompt). In --json we never prompt (non-interactive).\n let message = (args.message ?? \"\").trim()\n if (!message && !args.json) {\n message = (await deps.prompts.ask(\"what went wrong? (one line is fine)\")).trim()\n }\n if (!message) {\n return { lines: [empty(\"nothing to report — the message was empty. nothing was sent.\")] }\n }\n\n // 2. context = the redacted local snapshot (no token by construction — d15/G10).\n const context: Record<string, unknown> = { ...deps.snapshot }\n\n // 3. show what we'll attach + confirm. Skip the confirm under --json/--yes (d8): a hidden readline\n // on a non-interactive stdin blocks forever, and a report sends no money/PII so auto is safe.\n const print = deps.print ?? ((line: string) => process.stdout.write(line + \"\\n\"))\n const autoProceed = Boolean(args.json) || Boolean(args.yes)\n if (!autoProceed) {\n print(ok(\"bt report — about to send (tokens + emails are redacted server-side):\"))\n print(` message ${message}`)\n if (args.debug) {\n for (const [k, v] of Object.entries(context)) {\n print(` ${k.padEnd(11)} ${String(v)}`)\n }\n } else {\n print(\n ` context bt ${context.btVersion} · node ${context.node} · ${context.platform} · ${context.storeUrl}`\n )\n }\n const proceed = await deps.prompts.confirm(\"send this report? (y/n):\")\n if (!proceed) {\n return { lines: [empty(\"cancelled. nothing was sent.\")] }\n }\n }\n\n // 4. send + print the reference.\n const { reference } = await client.report(message, context)\n const lines = [ok(\"report filed. thank you — you're a contributor now.\"), ` ref ${reference}`]\n if (args.debug) {\n lines.push(empty(\" context attached:\"))\n for (const [k, v] of Object.entries(context)) {\n lines.push(` ${k.padEnd(11)} ${String(v)}`)\n }\n }\n return { lines, json: args.json ? { reference } : undefined }\n}\n\nexport function registerReport(program: Command, makeClient: () => StoreClient): void {\n program\n .command(\"report\")\n .argument(\"[message]\", \"what went wrong (omit to be prompted)\")\n .description(\"file a bug report — sends a redacted snapshot; never cards or tokens.\")\n .option(\"--yes\", \"skip the confirm (scripts / CI / agents); implied by --json\")\n .action(async (message: string | undefined, opts: { yes?: boolean }) => {\n const gOpts = program.opts() as { json?: boolean; color?: boolean }\n const json = Boolean(gOpts.json)\n const debug = process.argv.includes(\"--debug\") || process.argv.includes(\"--verbose\")\n const { makePrompts } = await import(\"../prompts\")\n const snapshot = gatherDoctorSnapshot({ color: gOpts.color })\n const res = await runReport(\n makeClient() as unknown as ReportClient,\n { message, json, yes: opts.yes, debug },\n { prompts: makePrompts(), snapshot }\n )\n printResult(res, json)\n })\n}\n","// bt blame <n|slug> — provenance. `git blame` for a design: who/what is responsible.\n//\n// Upgrades the old generic egg (which said \"a style × an idea, collided by hand\" because there was\n// no per-design lore) into REAL lore now that products carry metadata.lore (+ sources). With no\n// arg — or a design with no lore on record — it falls back to the generic provenance line (the egg\n// stays charming). Never a non-zero exit for the no-lore/no-arg case: blame is a delight, not a gate.\n\nimport type { Command } from \"commander\"\nimport { blame as genericBlame } from \"../eggs\"\nimport { working } from \"../voice\"\nimport {\n brandOf,\n displayName,\n printResult,\n resolveOutput,\n resolveProduct,\n type HandlerResult,\n type Branded,\n} from \"./shared\"\nimport { productLore } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike, RegionLike } from \"./types-bridge\"\n\nexport interface BlameArgs extends Branded {\n handle?: string\n json?: boolean\n}\n\nexport async function runBlame(\n client: StoreClient,\n config: BtConfigLike,\n args: BlameArgs\n): Promise<HandlerResult> {\n const slug = (args.handle ?? \"\").trim()\n // no arg → the generic \"who's responsible for all this\" provenance. No fetch (the egg still works\n // offline / with zero setup).\n if (!slug) {\n return { lines: genericBlame().split(\"\\n\") }\n }\n\n const region: RegionLike = await client.resolveRegion(config.region)\n const picked = await resolveProduct(client, region, slug)\n const product = picked.product\n if (!product) {\n // couldn't resolve it → the generic per-subject provenance (never an error; blame is a delight).\n return { lines: genericBlame(slug).split(\"\\n\") }\n }\n\n const { handle } = displayName(product)\n const lore = productLore(product)\n const lines: string[] = []\n if (picked.fuzzy && handle !== slug) {\n lines.push(working(`matched \"${handle}\" from \"${slug}\"`))\n }\n\n if (!lore.text) {\n // resolved, but no lore on record yet → the generic per-design provenance.\n lines.push(...genericBlame(handle).split(\"\\n\"))\n return { lines, json: args.json ? { handle, lore: null } : undefined }\n }\n\n // the real thing: the story behind the design + its sources.\n lines.push(`blame ${handle}`)\n lines.push(` ${lore.text}`)\n for (const s of lore.sources) {\n lines.push(` source ${s.label} (${s.url})`)\n }\n return { lines, json: args.json ? { handle, lore } : undefined }\n}\n\nexport function registerBlame(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n // Visible in --help: blame is a real content command now (the terminal way to read a design's\n // lore/provenance), not the generic egg it started as.\n .command(\"blame\")\n .argument(\"[slug]\", \"a design — a slug, a bt browse number, or a fuzzy hint\")\n .description(\"who's responsible for a design — its lore + sources (git blame, for motifs).\")\n .action(async (slug: string | undefined) => {\n const { json, brand } = resolveOutput(program)\n const res = await runBlame(makeClient(), loadConfig(), { handle: slug, json, brand })\n printResult(res, json)\n })\n}\n"],"mappings":"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","names":["fs","path","makeClient","loadConfig","rr","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makePrompts","saveConfig","makeClient","loadConfig","EMPTY_STATE","makeClient","loadConfig","makeClient","loadConfig","FRESH_REPO","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makePrompts","saveConfig","loadConfig","saveConfig","fs","makeClient","makePrompts","makeClient","loadConfig"]}
1
+ {"version":3,"sources":["../src/bin.ts","../src/client-config.ts","../src/version.ts","../src/eggs.ts","../src/is-main.ts","../src/update-notice.ts","../src/keychain.ts","../src/commands/browse.ts","../src/commands/region.ts","../src/commands/completion.ts","../src/commands/search.ts","../src/commands/cart.ts","../src/commands/checkout.ts","../src/commands/order.ts","../src/jwt.ts","../src/commands/token.ts","../src/commands/log-graph.ts","../src/commands/log.ts","../src/commands/status.ts","../src/commands/unstage.ts","../src/commands/whoami.ts","../src/commands/drops.ts","../src/commands/connect.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/drop.ts","../src/commands/init.ts","../src/commands/buy.ts","../src/commands/config.ts","../src/commands/doctor.ts","../src/commands/report.ts","../src/commands/blame.ts"],"sourcesContent":["// bt — the Binary & Thread terminal store entrypoint + command router.\n//\n// PRIMARY invocation is `npx @binaryandthread/cli` (SECURITY G14) — a bare `bt` may collide\n// with an existing binary on PATH, so the help text says so. Cards never touch the terminal;\n// this is a dumb client over the Store API (all safety lives in the backend).\n//\n// Task 2 wires: --version (codename egg deferred to Wave-3 polish), --help, --no-color/--json,\n// and the C1 teapot egg (`bt brew coffee`). Task 3 wires browse/search/view/stage/cart.\n\nimport { spawn } from \"node:child_process\"\nimport { Command } from \"commander\"\nimport { StoreClient } from \"@binaryandthread/store-client\"\nimport { forgetConfig, loadConfig, saveConfig, type BtConfig } from \"./config\"\nimport { resolveClientConfig, makeLogger } from \"./client-config\"\nimport { VERSION } from \"./version\"\nimport { versionLine } from \"./voice\"\nimport {\n teapot,\n sudo,\n vim,\n panic,\n deploy,\n shipIt,\n rmWardrobe,\n force,\n gitClone,\n gitStash,\n gitPush,\n gitPull,\n gitReflog,\n fortune,\n manPage,\n FORTUNES,\n} from \"./eggs\"\nimport { formatFatal } from \"./errors\"\nimport { isMainModule } from \"./is-main\"\nimport { maybeNotifyUpdate } from \"./update-notice\"\nimport { getToken, setToken, deleteToken } from \"./keychain\"\nimport { makePrompts } from \"./prompts\"\nimport { registerBrowse } from \"./commands/browse\"\nimport { registerRegion } from \"./commands/region\"\nimport { registerCompletion } from \"./commands/completion\"\nimport { registerSearch } from \"./commands/search\"\nimport { registerView } from \"./commands/view\"\nimport { registerStage } from \"./commands/stage\"\nimport { registerCart } from \"./commands/cart\"\nimport { registerCheckout } from \"./commands/checkout\"\nimport { registerOrder } from \"./commands/order\"\nimport { registerLog } from \"./commands/log\"\nimport { registerStatus } from \"./commands/status\"\nimport { registerUnstage } from \"./commands/unstage\"\nimport { registerWhoami } from \"./commands/whoami\"\nimport { registerDrops } from \"./commands/drops\"\nimport { registerConnect } from \"./commands/connect\"\nimport { registerLogin } from \"./commands/login\"\nimport { registerLogout } from \"./commands/logout\"\nimport { registerDrop, type DropExecPort } from \"./commands/drop\"\nimport { registerInit } from \"./commands/init\"\nimport { registerBuy } from \"./commands/buy\"\nimport { registerConfig } from \"./commands/config\"\nimport { registerToken, resolveBridgeToken } from \"./commands/token\"\nimport { registerDoctor } from \"./commands/doctor\"\nimport { registerReport } from \"./commands/report\"\nimport { registerBlame } from \"./commands/blame\"\n\nexport interface GlobalOpts {\n json: boolean\n color: boolean\n}\n\n/**\n * Build a StoreClient from env + baked-in prod defaults. The publishable key is PUBLIC by design\n * (T6) and ships baked in so `npx @binaryandthread/cli` Just Works with zero setup (d2); any env\n * var overrides it for local dev / staging (see resolveClientConfig).\n */\nexport function makeClient(): StoreClient {\n const { baseUrl, publishableKey } = resolveClientConfig()\n // The customer-scoped JWT: env BT_TOKEN (CI/non-interactive) wins, else the OS keychain (d18).\n // Guest (no token) by default. The token is NEVER read from the plaintext config (G15).\n const jwt = resolveBridgeToken(process.env, getToken()) ?? undefined\n // Quiet by default; --debug/--verbose enables redacted request tracing to stderr (d15).\n const debug = process.argv.includes(\"--debug\") || process.argv.includes(\"--verbose\")\n return new StoreClient({\n baseUrl,\n publishableKey,\n jwt,\n logger: makeLogger(debug),\n })\n}\n\nexport function buildProgram(): Command {\n const program = new Command()\n\n program\n .name(\"bt\")\n .description(\n \"the binary & thread terminal store. techno-minimalist clothing & lifestyle, bought with the ceremony of a deploy.\\n\" +\n \"primary invocation: npx @binaryandthread/cli (a bare `bt` may collide with another binary)\"\n )\n .version(versionLine(VERSION), \"-v, --version\", \"print the version\")\n .option(\"--json\", \"machine-readable output\", false)\n .option(\"--no-color\", \"disable ANSI colour + inline images (also honours NO_COLOR)\")\n .option(\"--debug, --verbose\", \"trace requests to stderr (redacted) — for bug reports (d15)\")\n // Ship-to country for THIS invocation, overriding the saved region (bt config set region / bt\n // region). Scriptable + parity with the MCP per-call region. Overlaid onto config by\n // effectiveConfig below, so every region-aware command honours it with no per-command wiring.\n .option(\"--region <cc>\", \"ship-to country for this command (ISO-2, overrides your saved region)\")\n // On a typo of a REAL command, suggest the closest one (\"did you mean bt browse?\") instead of a\n // bare \"unknown command\". Git-verb typos (clone/stash/push/reflog) are caught as eggs below.\n .showSuggestionAfterError()\n\n // First-run banner — surfaced where a newcomer looks (bare `bt` / `bt --help`). Not printed in\n // --json (help text never is). Points at `bt init` for the happy path (d3).\n program.addHelpText(\"beforeAll\", \"\\n bt — the binary & thread terminal store. new here? → bt init\\n\")\n\n // C1 teapot egg — `bt brew` → 418. Evergreen Core (governed copy). The 418 lives in the\n // MESSAGE, not the exit code: an egg must never set a non-zero exit (it would poison a script\n // that happens to run it) — d11.\n program\n .command(\"brew\")\n .argument(\"[what]\", \"what to brew\")\n .description(\"we make clothing, not coffee.\")\n .action(() => {\n process.stdout.write(teapot() + \"\\n\")\n })\n\n // The governed egg family (VOICE §3.1). Each prints a deadpan line and EXITS 0 — an egg must\n // never change behaviour or poison a script's exit code (d11). registerEggs keeps bin.ts lean.\n registerEggs(program)\n\n // `bt forget` — the GDPR erasure path (G15): wipe the keychain token AND the local PII config.\n program\n .command(\"forget\")\n .description(\"wipe your local session + config (keychain token, cart, email, defaults).\")\n .action(() => {\n deleteToken() // keychain JWT + the 0600 fallback (G15)\n forgetConfig() // ~/.config/bt PII (email/cart_id)\n const json = Boolean((program.opts() as { json?: boolean }).json)\n if (json) process.stdout.write(JSON.stringify({ wiped: true }) + \"\\n\")\n else process.stdout.write(\"✓ local session + config wiped. (your wardrobe on the server is untouched.)\\n\")\n })\n\n // Task-3 read + cart commands (browse/search/view/stage/cart) are registered here.\n registerCommands(program)\n\n return program\n}\n\n/**\n * The drop exec port: run a backend `medusa exec` drop script via npm. Uses spawn with an ARGUMENT\n * ARRAY (no shell string interpolation) so a drop_id/slug can never inject a shell command. The env\n * is passed through the child's env, not the command line.\n */\nconst dropExec: DropExecPort = {\n run(script, env) {\n return new Promise<number>((resolve) => {\n const cwd = process.env.BT_BACKEND_DIR || process.cwd()\n const child = spawn(\"npm\", [\"run\", script], {\n cwd,\n env: { ...process.env, ...env },\n stdio: \"inherit\",\n })\n child.on(\"close\", (code) => resolve(code ?? 1))\n child.on(\"error\", () => resolve(1))\n })\n },\n}\n\n/** The Task-3 read + cart commands; each is a thin function over StoreClient. */\nfunction registerCommands(program: Command): void {\n const persist = (patch: Partial<BtConfig>) => {\n saveConfig(patch)\n }\n // Effective config = the saved config with the global `--region <cc>` overlaid for THIS run. Every\n // region-aware command reads config.region, so passing this wrapper (instead of the raw loader)\n // makes the flag work everywhere with zero per-command wiring. `bt config get/set` deliberately\n // uses the RAW persisted config (it manages the saved value, not the per-invocation override).\n const effectiveConfig = (): BtConfig => {\n const saved = loadConfig()\n const flag = (program.opts() as { region?: string }).region\n return flag ? { ...saved, region: flag.trim().toLowerCase() } : saved\n }\n registerInit(program)\n registerBrowse(program, makeClient, effectiveConfig)\n registerSearch(program, makeClient, effectiveConfig)\n registerView(program, makeClient, effectiveConfig)\n registerStage(program, makeClient, effectiveConfig)\n registerBuy(program, makeClient, effectiveConfig)\n registerConfig(program)\n registerRegion(program, makeClient, effectiveConfig, persist)\n registerCompletion(program)\n registerToken(program)\n registerDoctor(program)\n registerReport(program, makeClient)\n registerBlame(program, makeClient, effectiveConfig)\n registerCart(program, makeClient, effectiveConfig)\n registerCheckout(program, makeClient, effectiveConfig)\n // Task-3 tracking + management commands.\n registerOrder(program, makeClient, effectiveConfig)\n registerLog(program, makeClient, effectiveConfig)\n registerStatus(program, makeClient, effectiveConfig)\n registerWhoami(program, makeClient, effectiveConfig)\n registerDrops(program, makeClient, effectiveConfig)\n registerConnect(program)\n registerUnstage(program, makeClient, effectiveConfig)\n // Wave-5 auth + operator commands.\n const prompts = makePrompts()\n registerLogin(\n program,\n makeClient,\n effectiveConfig,\n prompts,\n { setToken: (jwt: string) => setToken(jwt) },\n persist\n )\n registerLogout(program, { deleteToken: () => deleteToken() })\n registerDrop(program, dropExec)\n}\n\n/**\n * The governed easter-egg family (VOICE §3.1). HARD invariant: every egg prints a line and exits 0\n * — never a non-zero exit (it would poison a script that runs it — d11), never a behaviour change.\n * Most are hidden from `--help` (eggs are \"if you know, you know\"); `fortune` is visible because\n * it's a genuine, harmless utility. Unknown options are allowed where a command mimics a real one\n * (`rm -rf`, `deploy --prod`) so commander doesn't reject the joke.\n */\nfunction registerEggs(program: Command): void {\n const print = (s: string): void => {\n process.stdout.write(s + \"\\n\")\n }\n\n // C2 ★ — sudo. `bt sudo <anything>`.\n program.command(\"sudo\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(sudo()))\n // C7 ★ — vim.\n program.command(\"vim\", { hidden: true }).action(() => print(vim()))\n // C17 — panic.\n program.command(\"panic\", { hidden: true }).action(() => print(panic()))\n // C16 — deploy (did-you-mean → commit).\n program.command(\"deploy\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(deploy()))\n // C18 ★ — ship it.\n program.command(\"ship\", { hidden: true }).argument(\"[what]\").action(() => print(shipIt()))\n // C12 — rm -rf ~/wardrobe (defused warmly; never destructive).\n program.command(\"rm\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(rmWardrobe()))\n // --force flavour, as a hidden verb.\n program.command(\"force\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(force()))\n\n // git verbs that aren't ours — deadpan did-you-mean redirects (hidden; allow args so\n // `bt push origin main` / `bt clone <url>` don't error before the joke lands).\n program.command(\"clone\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitClone()))\n program.command(\"stash\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitStash()))\n program.command(\"push\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitPush()))\n program.command(\"pull\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitPull()))\n program.command(\"reflog\", { hidden: true }).allowUnknownOption().argument(\"[args...]\").action(() => print(gitReflog()))\n\n // C5 / delight #6 — blame is now a real, data-backed provenance command (see registerCommands →\n // registerBlame): it shows a design's actual lore + sources, falling back to the generic\n // provenance line. Kept out of registerEggs because it fetches.\n\n // C10 — fortune (visible: a real, harmless utility). Rotates through real dev aphorisms; the seed\n // rotates per invocation so successive runs differ, but each line is deterministic given a seed.\n program\n .command(\"fortune\")\n .description(\"a coding fortune. real aphorisms only.\")\n .action(() => {\n // Date is available in the real Node runtime (only workflow scripts forbid it); rotate by it.\n const seed = Math.floor(Date.now() / 1000) % FORTUNES.length\n print(fortune(seed))\n })\n\n // C3 ★ — man bt. `bt man` prints the real man page (the system `man bt` reads the bundled roff).\n program\n .command(\"man\", { hidden: true })\n .description(\"the bt man page (also installed for the system man(1)).\")\n .action(() => print(manPage(VERSION).join(\"\\n\")))\n}\n\n// Only auto-run when invoked as the binary (not when imported by tests). This compares the\n// invoked path against this module's own URL with symlinks resolved on both sides — so the npm\n// bin shim (a symlink named `bt`/`btn`, NOT `bin.js`) still counts as \"main\". See ./is-main for\n// why a `argv[1].endsWith(\"bin.js\")` check silently no-ops every real `npx` install.\nif (isMainModule(process.argv[1], import.meta.url)) {\n buildProgram()\n .parseAsync(process.argv)\n .catch((e) => {\n // Distinct exit codes + a JSON error envelope so CI/agents can branch on the failure (d10).\n const json = process.argv.includes(\"--json\")\n const { out, err, code } = formatFatal(e, json)\n if (out) process.stdout.write(out + \"\\n\")\n if (err) process.stderr.write(err + \"\\n\")\n process.exitCode = code\n })\n .finally(() => {\n // A gentle \"you're behind\" nudge AFTER the command, to STDERR only, human-terminal only.\n // Never touches stdout / --json / CI (see isUpdateCheckSuppressed); never blocks or throws.\n maybeNotifyUpdate({\n current: VERSION,\n env: process.env,\n argv: process.argv,\n stderrIsTTY: Boolean(process.stderr.isTTY),\n write: (s) => process.stderr.write(s),\n })\n })\n}\n","// Resolve the StoreClient transport config (base URL + publishable key) from the environment,\n// falling back to the baked-in PUBLIC production defaults so `npx @binaryandthread/cli` works\n// with zero setup (d2 / P4.5-7b). Env ALWAYS wins — set BT_API_URL / BT_PUBLISHABLE_KEY (or the\n// MEDUSA_* equivalents) to point at local dev or staging. An empty-string env value is ignored.\n\nimport { BT_DEFAULT_STORE_URL, BT_DEFAULT_PUBLISHABLE_KEY, redact } from \"@binaryandthread/store-client\"\nimport type { ClientLogger } from \"@binaryandthread/store-client\"\n\nexport interface ResolvedClientConfig {\n baseUrl: string\n publishableKey: string\n}\n\nexport function resolveClientConfig(env: NodeJS.ProcessEnv = process.env): ResolvedClientConfig {\n const baseUrl = env.BT_API_URL || env.MEDUSA_BACKEND_URL || BT_DEFAULT_STORE_URL\n const publishableKey =\n env.BT_PUBLISHABLE_KEY || env.MEDUSA_PUBLISHABLE_KEY || BT_DEFAULT_PUBLISHABLE_KEY\n return { baseUrl, publishableKey }\n}\n\n/**\n * The StoreClient logger. QUIET by default (the client's internal store.request.* events are noise\n * to a normal user — the friendly fatal handler covers real failures); --debug/--verbose turns on\n * redacted request tracing to stderr (d15). Everything passes through redact() (G10).\n */\nexport function makeLogger(debug: boolean, write: (s: string) => void = (s) => process.stderr.write(s)): ClientLogger {\n if (!debug) {\n const noop = (): void => {}\n return { info: noop, warn: noop, error: noop }\n }\n return {\n info: (...a) => write(\"· \" + JSON.stringify(redact(a)) + \"\\n\"),\n warn: (...a) => write(\"⚠ \" + JSON.stringify(redact(a)) + \"\\n\"),\n error: (...a) => write(\"✗ \" + JSON.stringify(redact(a)) + \"\\n\"),\n }\n}\n","// The single source of truth for the CLI version string.\n//\n// Mirrored into cli/package.json's \"version\" field; version.test.ts asserts the two never drift.\n// We don't import package.json directly (JSON imports complicate the ESM dist build), so this\n// literal is the canonical value the binary reports (bt --version) and bt doctor's snapshot.\nexport const VERSION = \"0.2.1\"\n","// The governed CLI easter-egg catalog (VOICE §3.1 + the five-gate governance §3.5).\n//\n// EVERY egg here is: opt-in (off the happy/critical path), deadpan, leans on a REAL dev reference\n// (RFC / exit code / git verb / a genuine holy war / a real dev aphorism), and — the hard rule —\n// NEVER changes behaviour or sets a non-zero exit code (an egg that poisoned a script's exit would\n// be a bug, not a joke; d11). These are pure string functions; bin.ts wires them to commands that\n// print the line and exit 0.\n//\n// Brand voice (memory brand-voice-no-pod-no-tshirt — the HARD rule, postdates VOICE.md): NEVER\n// \"t-shirt\"/\"tee\"/\"print\"/Gelato in any copy. Products are \"clothing\"/\"pieces\"/\"fits\"/\"the wardrobe\".\n\nimport { GLYPH } from \"./voice\"\n\n/** C1 ★ — the canonical teapot. Evergreen Core. Cites the RFC, delivered straight. (brew coffee → 418) */\nexport function teapot(): string {\n return `${GLYPH.fail} 418 i'm a teapot. we make clothing, not coffee. (RFC 2324)`\n}\n\n/** C2 ★ — sudo. One line, no follow-up. */\nexport function sudo(): string {\n return \"nice try. you don't have root on fashion.\"\n}\n\n/** C7 ★ — the eternal vim-exit gag, one line. */\nexport function vim(): string {\n return \"to exit, commit a piece. (:q won't save you here.)\"\n}\n\n/** C17 — bt panic. A genuinely kind response to a desperate command. */\nexport function panic(): string {\n return \"don't. nothing's on fire. your orders are safe. take a walk; the wardrobe will still be here.\"\n}\n\n/** C16 — bt deploy. A helpful did-you-mean that's also a joke about working too much. */\nexport function deploy(): string {\n return (\n `${GLYPH.fail} command not found: deploy. you mean \\`bt commit\\`?\\n` +\n \" we ship clothing, not services. did you fat-finger your day job?\"\n )\n}\n\n/** C18 ★ — bt ship it. Redirects to the real verb; no meme, just the did-you-mean. */\nexport function shipIt(): string {\n return `that's commit's job. ${GLYPH.arrow} bt commit`\n}\n\n/** C12 — bt rm -rf ~/wardrobe. Defuses a scary-looking command warmly; never destructive. */\nexport function rmWardrobe(): string {\n return (\n `${GLYPH.warn} this would delete your entire order history. it won't, obviously —\\n` +\n \" we don't have rm on your memories. (and you can't unship a delivered piece.)\"\n )\n}\n\n/** --force flavour. Deadpan: a commit to your wardrobe is already that decisive. */\nexport function force(): string {\n return (\n \"--force-pushing to prod, are we. there's no --force here —\\n\" +\n \" a commit to your wardrobe is already that decisive.\"\n )\n}\n\n// git verbs that aren't ours — deadpan did-you-mean redirects. Each leans on the real git verb,\n// points at the right bt command, and (like every egg) prints one line and exits 0. Turns the\n// off-brand \"unknown command\" surface into an on-brand one for muscle-memory git typos.\n\n/** `bt clone` — you can't clone a one-of-one motif. */\nexport function gitClone(): string {\n return \"no clone for a fit — each one's committed by hand. browse the originals → bt browse\"\n}\n\n/** `bt stash` — that's unstage; nothing is lost. */\nexport function gitStash(): string {\n return \"that's bt unstage here. your cart holds; nothing's lost.\"\n}\n\n/** `bt push` — the only push that ships is a commit. */\nexport function gitPush(): string {\n return \"no remote for your wardrobe. the only push that ships → bt commit\"\n}\n\n/** `bt pull` — the freshest designs arrive by drop, not by fetch. */\nexport function gitPull(): string {\n return \"nothing to pull — the freshest designs land as drops → bt drops\"\n}\n\n/** `bt reflog` — your history is bt log; nothing is ever truly lost. */\nexport function gitReflog(): string {\n return \"nothing's ever truly lost here. your history → bt log\"\n}\n\n/**\n * C10 — fortune. A rotating pool of REAL dev aphorisms (gate 1: never invented). Attributed where\n * the attribution is well-established. `fortune(seed)` is deterministic for tests + reproducible\n * screenshots; bin.ts passes a rotating seed.\n */\nexport const FORTUNES: ReadonlyArray<string> = [\n '// \"there are only two hard things in computer science: cache invalidation and naming things.\" — phil karlton',\n '// \"premature optimization is the root of all evil.\" — donald knuth',\n '// \"weeks of programming can save you hours of planning.\"',\n '// \"make it work, make it right, make it fast.\" — kent beck',\n '// \"talk is cheap. show me the code.\" — linus torvalds',\n '// \"given enough eyeballs, all bugs are shallow.\" — linus\\'s law',\n '// \"always code as if the person maintaining it is a violent psychopath who knows where you live.\" — john woods',\n '// \"it works on my machine.\"',\n]\n\nexport function fortune(seed = 0): string {\n const n = Number.isFinite(seed) ? Math.abs(Math.floor(seed)) : 0\n // modulo over a non-empty const pool always hits a real index (the ! is safe by construction).\n return FORTUNES[n % FORTUNES.length]!\n}\n\n/**\n * C5 / brand-delight #6 — bt blame. Provenance/lore, deadpan. We do NOT invent designer names\n * (gate 1: no invented references) — per-design author attribution needs a real crew/lore dataset\n * (noted as a follow-up). What we CAN state truthfully: every motif is a deliberate collision of a\n * style and an idea, curated by hand. With a slug, we name it; without, we credit the process.\n */\nexport function blame(slug?: string): string {\n const subject = slug ? slug.trim() : \"\"\n if (subject) {\n return (\n `blame ${subject}\\n` +\n \" motif a style × an idea, collided on purpose — then curated by hand, not shipped raw.\\n\" +\n \" crew the people at Binary & Thread. (per-designer credit is coming — bt drops to watch.)\"\n )\n }\n return (\n \"blame — who's responsible for all this?\\n\" +\n \" every piece here is a style collided with an idea, curated by hand at Binary & Thread.\\n\" +\n \" nothing auto-shipped. someone looked at each one. that's the whole point.\"\n )\n}\n\n/**\n * man bt — a real, correctly-structured man page (VOICE C3). The jokes live in the footer sections\n * devs actually read (BUGS / AUTHORS / SEE ALSO); the page itself is genuinely useful. Returned as\n * plain man-styled text for `bt man`; a roff `man/bt.1` ships alongside for the system `man bt`.\n */\nexport function manPage(version: string): string[] {\n return [\n \"BT(1) Binary & Thread BT(1)\",\n \"\",\n \"NAME\",\n \" bt — the Binary & Thread terminal store\",\n \"\",\n \"SYNOPSIS\",\n \" bt <command> [options]\",\n \" npx @binaryandthread/cli <command> [options]\",\n \"\",\n \"DESCRIPTION\",\n \" Binary & Thread is a techno-minimalist clothing & lifestyle\",\n \" company. bt is its terminal store: you browse, stage, and commit\",\n \" pieces with the ceremony of a deploy. Payment opens in your\",\n \" browser — cards never touch the terminal.\",\n \"\",\n \"COMMANDS\",\n \" init first-run welcome + the happy path\",\n \" browse list what's in stock\",\n \" view render one piece (image or ASCII) + specs\",\n \" stage reserve stock (like git add)\",\n \" commit turn your staged items into an order\",\n \" buy stage + commit in one\",\n \" log your order history as a git log (--graph, --oneline)\",\n \" order track one order through its lifecycle\",\n \" whoami your contribution profile + standing\",\n \" drops what's on next, before it hits the web\",\n \" login passwordless magic-link sign-in\",\n \" report file a bug report (you become a contributor)\",\n \"\",\n \"ENVIRONMENT\",\n \" NO_COLOR disable ANSI colour + inline images\",\n \" BT_TOKEN a customer JWT for non-interactive sessions\",\n \" BT_STORE_URL override the store base URL (defaults baked in)\",\n \"\",\n \"EXIT STATUS\",\n \" 0 success 1 general error\",\n \" 75 EX_TEMPFAIL — a transient failure; nothing was charged, retry\",\n \"\",\n \"BUGS\",\n \" none known. if you find one, you're now a contributor.\",\n \" file it: bt report (or bugs@binaryandthread.com)\",\n \"\",\n \"AUTHORS\",\n \" The crew at Binary & Thread, and every contributor who committed\",\n \" a fit. earned, not bought.\",\n \"\",\n \"SEE ALSO\",\n \" git(1), curl(1), a mirror. go build something.\",\n \"\",\n `Binary & Thread bt ${version} BT(1)`,\n ]\n}\n","// Is THIS module the program entry (a real invocation) — or is it being imported as a library\n// (by the test runner, or by another module)? The bin only auto-runs when the former is true.\n//\n// WHY NOT `process.argv[1].endsWith(\"bin.js\")`: npm installs the package's `bin` field as a shim\n// whose basename is the COMMAND name (`bt`/`btn`, or an `npx` cache path) — a symlink to\n// dist/bin.js — so `process.argv[1]` NEVER ends in \"bin.js\" for a real install. A filename check\n// therefore returns false for EVERY `npx @binaryandthread/cli …` invocation → the CLI loads,\n// concludes it's a library, and exits 0 in silence. (Reported by Simon Hagert, 2026-07-07.)\n//\n// The robust check: compare the invoked path (argv[1]) against this module's own URL, resolving\n// symlinks on BOTH sides so the npm shim (symlink → dist/bin.js) collapses onto the real file.\n// Resolving both sides also makes it correct regardless of Node's `--preserve-symlinks-main`.\n\nimport { realpathSync } from \"node:fs\"\nimport { fileURLToPath } from \"node:url\"\n\nexport function isMainModule(\n argv1: string | undefined,\n moduleUrl: string,\n realpath: (p: string) => string = realpathSync,\n): boolean {\n if (typeof argv1 !== \"string\" || argv1.length === 0) return false\n try {\n const invoked = realpath(argv1)\n const self = realpath(fileURLToPath(moduleUrl))\n return invoked === self\n } catch {\n // A non-existent path, a non-file URL, etc. — safest default is \"not the entry\" (stay quiet\n // as a library) rather than risk auto-running where we shouldn't.\n return false\n }\n}\n","// A gentle \"you're behind\" nudge — the update-notifier pattern. On a real terminal run, print ONE\n// dim line to STDERR if a newer bt is published, and refresh the check-cache in the background at\n// most once a day. HARD rules: never touch stdout (would corrupt --json / a pipe), never block the\n// command (the notice comes from cache; the registry fetch is fire-and-forget), never throw.\n\nimport * as fs from \"node:fs\"\nimport * as path from \"node:path\"\nimport { configDir } from \"./config\"\n\nconst CACHE_FILE = \"update-check.json\"\nconst CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000 // at most once a day\nconst REGISTRY_LATEST = \"https://registry.npmjs.org/@binaryandthread/cli/latest\"\nconst FETCH_TIMEOUT_MS = 2_000\n\nexport interface UpdateCache {\n lastCheck: number\n latest: string\n}\n\nfunction parseSemver(v: string): [number, number, number] | null {\n const m = /^(\\d+)\\.(\\d+)\\.(\\d+)/.exec((v ?? \"\").trim())\n return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null\n}\n\n/** Numeric major.minor.patch \"greater than\" (pre-release/build ignored; false on malformed). */\nexport function semverGt(a: string, b: string): boolean {\n const pa = parseSemver(a)\n const pb = parseSemver(b)\n if (!pa || !pb) return false\n for (let i = 0; i < 3; i++) {\n if (pa[i]! > pb[i]!) return true\n if (pa[i]! < pb[i]!) return false\n }\n return false\n}\n\n/** The dim, on-voice nudge when `latest` is newer than `current`, else null. */\nexport function updateNoticeLine(current: string, latest: string | null | undefined): string | null {\n if (!latest || !semverGt(latest, current)) return null\n return `⚙ a newer bt is out (${latest}). update → npm i -g @binaryandthread/cli@latest`\n}\n\n/** A nudge is for a human at a terminal — never on non-TTY, --json, CI, or an explicit opt-out. */\nexport function isUpdateCheckSuppressed(\n env: NodeJS.ProcessEnv,\n argv: string[],\n stderrIsTTY: boolean\n): boolean {\n if (!stderrIsTTY) return true\n if (argv.includes(\"--json\")) return true\n if (env.CI || env.BT_NO_UPDATE_NOTIFIER || env.NO_UPDATE_NOTIFIER) return true\n return false\n}\n\nexport interface NotifyDeps {\n current: string\n env: NodeJS.ProcessEnv\n argv: string[]\n stderrIsTTY: boolean\n write: (s: string) => void\n now?: number\n readCache?: () => UpdateCache | null\n refresh?: (now: number) => void\n}\n\n/**\n * Print the notice from the LAST-known latest (cache → instant, never blocks), then refresh the\n * cache in the background at most once a day (fire-and-forget). All I/O is injectable for tests.\n */\nexport function maybeNotifyUpdate(deps: NotifyDeps): void {\n if (isUpdateCheckSuppressed(deps.env, deps.argv, deps.stderrIsTTY)) return\n const now = deps.now ?? Date.now()\n const read = deps.readCache ?? readUpdateCache\n const refresh = deps.refresh ?? ((n: number) => void fetchLatestIntoCache(n))\n\n const cache = read()\n const line = updateNoticeLine(deps.current, cache?.latest)\n if (line) deps.write(line + \"\\n\")\n\n if (!cache || now - cache.lastCheck > CHECK_INTERVAL_MS) {\n refresh(now)\n }\n}\n\n// ---- best-effort cache I/O (never throws) ----\nfunction cachePath(): string {\n return path.join(configDir(), CACHE_FILE)\n}\n\nexport function readUpdateCache(): UpdateCache | null {\n try {\n const j = JSON.parse(fs.readFileSync(cachePath(), \"utf8\"))\n if (j && typeof j.latest === \"string\" && typeof j.lastCheck === \"number\") {\n return { latest: j.latest, lastCheck: j.lastCheck }\n }\n } catch {\n /* no/one bad cache — treat as absent */\n }\n return null\n}\n\nfunction writeUpdateCache(c: UpdateCache): void {\n try {\n fs.mkdirSync(configDir(), { recursive: true })\n const tmp = cachePath() + \".tmp\"\n fs.writeFileSync(tmp, JSON.stringify(c), \"utf8\")\n fs.renameSync(tmp, cachePath())\n } catch {\n /* best-effort */\n }\n}\n\nasync function fetchLatestIntoCache(now: number): Promise<void> {\n try {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS)\n try {\n const res = await fetch(REGISTRY_LATEST, { signal: ctrl.signal })\n if (!res.ok) return\n const data = (await res.json()) as { version?: unknown }\n if (typeof data.version === \"string\") {\n writeUpdateCache({ lastCheck: now, latest: data.version })\n }\n } finally {\n clearTimeout(timer)\n }\n } catch {\n /* offline / registry down / aborted — silently skip; try again next day */\n }\n}\n","// keychain.ts — OS-keychain token storage via @napi-rs/keyring (SECURITY G7/G8).\n//\n// The customer-scoped JWT lives in the OS keychain (macOS Keychain / Windows Credential Manager /\n// libsecret on Linux) — NEVER in the plaintext ~/.config/bt config (that's the leak G15 forbids).\n// We use @napi-rs/keyring, the MAINTAINED keychain lib (G7) — never the archived/unmaintained\n// alternative the threat model calls out.\n//\n// FALLBACK (SECURITY §4): if the OS keychain is unavailable (a headless CI box, an unusual Linux with\n// no secret service), we fall back to a 0600 file in ~/.config/bt — documented, owner-read-only, and\n// clearly second-best. The token is short-lived (the backend JWT TTL is minutes), so even the fallback\n// has a bounded exposure window. The keychain path is always tried FIRST.\n//\n// Service/account namespacing: service = \"binaryandthread/bt\", account = \"jwt\". One token per machine\n// user. deleteToken is used by `bt logout` + `bt forget`.\n\nimport * as fs from \"node:fs\"\nimport * as os from \"node:os\"\nimport * as path from \"node:path\"\n\n/** The keychain service + account names (namespaced to the project). */\nexport const KEYCHAIN_SERVICE = \"binaryandthread/bt\"\nexport const KEYCHAIN_ACCOUNT = \"jwt\"\n\n/** The 0600 fallback token path (only used when the OS keychain is unavailable). */\nfunction fallbackTokenPath(): string {\n const xdg = process.env.XDG_CONFIG_HOME\n const base = xdg && xdg.trim() ? xdg : path.join(os.homedir(), \".config\")\n return path.join(base, \"bt\", \"token\")\n}\n\n/** The keyring Entry interface we depend on (a structural subset of @napi-rs/keyring's Entry). */\nexport interface KeyringEntry {\n getPassword(): string | null\n setPassword(password: string): void\n deletePassword(): boolean\n}\n\nexport interface KeychainDeps {\n /** Build a keyring Entry for (service, account). Injected for tests; defaults to @napi-rs/keyring. */\n makeEntry?: (service: string, account: string) => KeyringEntry | null\n}\n\n/** Lazily load @napi-rs/keyring and build an Entry; returns null if the native lib can't load. */\nfunction defaultMakeEntry(service: string, account: string): KeyringEntry | null {\n try {\n // Lazy require so a missing native binary degrades to the file fallback rather than crashing import.\n const { Entry } = require(\"@napi-rs/keyring\") as {\n Entry: new (service: string, account: string) => KeyringEntry\n }\n return new Entry(service, account)\n } catch {\n return null\n }\n}\n\n/** Store the JWT in the OS keychain (preferred) or the 0600 fallback file. */\nexport function setToken(jwt: string, deps: KeychainDeps = {}): void {\n const make = deps.makeEntry ?? defaultMakeEntry\n const entry = make(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT)\n if (entry) {\n try {\n entry.setPassword(jwt)\n // Belt-and-suspenders: if a stale fallback file exists, remove it (the keychain is now truth).\n try {\n fs.rmSync(fallbackTokenPath(), { force: true })\n } catch {\n /* ignore */\n }\n return\n } catch {\n // Fall through to the file fallback.\n }\n }\n // Fallback: a 0600 file (owner-read-only). Documented second-best (SECURITY §4).\n const target = fallbackTokenPath()\n fs.mkdirSync(path.dirname(target), { recursive: true })\n const tmp = target + \".tmp\"\n fs.writeFileSync(tmp, jwt, { encoding: \"utf8\", mode: 0o600 })\n fs.renameSync(tmp, target)\n}\n\n/** Read the JWT from the OS keychain (preferred) or the 0600 fallback. null if none. */\nexport function getToken(deps: KeychainDeps = {}): string | null {\n const make = deps.makeEntry ?? defaultMakeEntry\n const entry = make(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT)\n if (entry) {\n try {\n const pw = entry.getPassword()\n if (pw) {\n return pw\n }\n } catch {\n // Fall through to the file fallback.\n }\n }\n try {\n const raw = fs.readFileSync(fallbackTokenPath(), \"utf8\").trim()\n return raw || null\n } catch {\n return null\n }\n}\n\n/** Delete the JWT from BOTH the keychain and the fallback file (bt logout / bt forget — G15). */\nexport function deleteToken(deps: KeychainDeps = {}): void {\n const make = deps.makeEntry ?? defaultMakeEntry\n const entry = make(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT)\n if (entry) {\n try {\n entry.deletePassword()\n } catch {\n /* ignore — still wipe the fallback below */\n }\n }\n try {\n fs.rmSync(fallbackTokenPath(), { force: true })\n } catch {\n /* ignore */\n }\n}\n","// bt browse — list in-stock products for the resolved region (VOICE §2.1).\n//\n// Region is RESOLVED (config.region or region #1 from the API) — never a hardcoded SEK/SE\n// literal (F-A2 / INV-11). --branch=next also pulls drops via listDrops. The cached list is\n// advisory only; the cart re-validates price/availability at stage (F-A4).\n//\n// A1: the product TITLE is the primary name (matches checkout/web), with the handle shown\n// secondarily/dimmed (still needed for bt view/bt stage).\n// A3: a compact colour marker per product (⬜⬛ white/black), DERIVED from the variants.\n// B1/B2: a header treatment + cyan price accent; degrades cleanly under --json / NO_COLOR.\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { productColours } from \"@binaryandthread/store-client\"\nimport {\n fmtPrice,\n firstPrice,\n stageMarker,\n displayName,\n brandOf,\n regionLine,\n printResult,\n resolveOutput,\n type HandlerResult,\n type Branded,\n} from \"./shared\"\nimport { header, cyan, dim, colourMarker, type BrandStyle } from \"../brand\"\nimport type { StoreClient, ProductLike, DropRow, BtConfigLike } from \"./types-bridge\"\n\nexport interface BrowseArgs extends Branded {\n branch?: string\n json?: boolean\n}\n\n/** Truncate to width with a trailing ellipsis (never mid-ANSI — callers pass raw text). */\nfunction truncate(s: string, w: number): string {\n if (s.length <= w) return s\n if (w <= 1) return s.slice(0, Math.max(0, w))\n return s.slice(0, w - 1) + \"…\"\n}\n\n/**\n * Lay out the in-stock rows as an aligned table that ADAPTS to the terminal (#3/E1) — measure the\n * real content + `stdout.columns`, right-align the price like a ledger, keep the SLUG full (it's the\n * copy-target for `bt stage <slug>`, #6), and truncate the descriptive TITLE when space is tight.\n * When the width is unknown (piped/non-TTY) nothing is constrained — `--json` is the tool there.\n */\nfunction layoutRows(rows: Array<{ p: ProductLike; stage: string }>, style: BrandStyle): string[] {\n const cells = rows.map(({ p, stage }, i) => {\n const { amount, currency } = firstPrice(p)\n const { title, handle } = displayName(p)\n return {\n ref: `[${i + 1}]`,\n title,\n price: fmtPrice(amount, currency),\n handle,\n stage,\n colours: colourMarker(productColours(p)),\n }\n })\n const refW = Math.max(...cells.map((c) => c.ref.length))\n const priceW = Math.max(...cells.map((c) => c.price.length))\n const handleW = Math.max(...cells.map((c) => c.handle.length))\n const maxTitle = Math.max(...cells.map((c) => c.title.length))\n const GAP = 2\n const STAGE_W = 12 // \"● in stock\" + slack — the stage marker is the last, un-padded column\n const term = process.stdout.columns ?? 0\n // Title is the only elastic column (slug stays full for copy-paste). Fit it to the terminal when\n // known; otherwise let it be its natural width.\n let titleW = maxTitle\n if (term > 0) {\n const fixed = refW + GAP + priceW + GAP + handleW + GAP + STAGE_W\n titleW = Math.max(12, Math.min(maxTitle, term - fixed))\n }\n const out: string[] = []\n for (const c of cells) {\n const row = [\n dim(style, c.ref.padEnd(refW)),\n truncate(c.title, titleW).padEnd(titleW),\n cyan(style, c.price.padStart(priceW)), // right-align money — reads like a ledger\n dim(style, c.handle.padEnd(handleW)),\n stageMarker(c.stage),\n ]\n .join(\" \")\n .trimEnd()\n out.push(c.colours ? `${row}\\n ${dim(style, c.colours)}` : row)\n }\n return out\n}\n\nexport async function runBrowse(\n client: StoreClient,\n config: BtConfigLike,\n args: BrowseArgs\n): Promise<HandlerResult> {\n const style = brandOf(args)\n // Region resolved WITH provenance, NEVER hardcoded — so we can show which region/currency these\n // prices are in (T3.2). config.region is a country code (derived), region #1 otherwise.\n const rr = await client.resolveRegionResult(config.region)\n const region = rr.region\n const products = await client.listProducts({ region })\n\n const rows: Array<{ p: ProductLike; stage: string }> = products.map((p) => ({\n p,\n stage: (p.metadata?.[\"channel_stage\"] as string) ?? \"main\",\n }))\n\n let drops: DropRow[] = []\n if (args.branch === \"next\") {\n drops = await client.listDrops()\n }\n\n const lines: string[] = []\n if (rows.length === 0 && drops.length === 0) {\n // empty state — a dry true line (VOICE §1.4).\n lines.push(empty(\"nothing in stock on this branch yet. main is the latest.\"))\n lines.push(\" peek at next → bt browse --branch=next\")\n } else {\n lines.push(header(style, \"bt browse — in stock\"))\n lines.push(regionLine(rr, style)) // one dim provenance line: region · currency (T3.2)\n lines.push(...layoutRows(rows, style))\n for (const d of drops) {\n const dt = (d.title ?? d.handle ?? d.id).toString()\n lines.push(\n [\n dt.padEnd(22),\n cyan(style, fmtPrice(d.price, region.currency_code).padEnd(11)),\n dim(style, (d.handle ?? d.id).padEnd(34)),\n stageMarker(d.channel_stage),\n ].join(\" \").trimEnd()\n )\n }\n if (drops.length > 0) {\n lines.push(\" on next, before the web → bt drops\")\n }\n // A5 — one subtle VAT-label line (not per-row: it's a table). Only when the region prices\n // tax-inclusive (SE/EU); a tax-exclusive market (US) shows no VAT claim. Parity with bt view/cart/MCP.\n const taxIncl = rows.length > 0 ? firstPrice(rows[0]!.p).taxInclusive : null\n if (taxIncl === true) {\n lines.push(dim(style, \" prices incl. VAT\"))\n }\n lines.push(\" view one → bt view <n|slug> · stage one → bt stage <n|slug> --size L\")\n }\n\n return {\n lines,\n json: args.json\n ? products.map((p) => ({\n id: p.id,\n handle: p.handle,\n title: p.title,\n price: firstPrice(p).amount,\n currency: firstPrice(p).currency,\n colours: productColours(p),\n channel_stage: (p.metadata?.[\"channel_stage\"] as string) ?? \"main\",\n }))\n : undefined,\n }\n}\n\nexport function registerBrowse(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"browse\")\n .alias(\"ls\")\n .description(\"list what's in stock on a branch.\")\n .option(\"--branch <branch>\", \"main (live) or next (terminal-only drops)\")\n .option(\"--pick\", \"opt into the arrow-key picker (default is the numbered table — use bt stage <n>)\")\n .option(\"--plain\", \"force the static table (the default; kept for back-compat)\")\n .action(async (opts: { branch?: string; pick?: boolean; plain?: boolean }) => {\n const { json, brand } = resolveOutput(program)\n // The numbered table is the DEFAULT now — typed slugs / quick-pick numbers are the on-brand,\n // scriptable, screenshot-able path (the arrow-key maze contradicted the deploy conceit). The\n // picker is opt-in via --pick, and only when we truly have an interactive stdin+stdout.\n if (opts.pick && !json && brand.color && process.stdout.isTTY && process.stdin.isTTY) {\n const { runInteractiveBrowse } = await import(\"../interactive\")\n const handled = await runInteractiveBrowse(makeClient(), loadConfig(), { branch: opts.branch, brand })\n if (handled) return\n // picker unavailable / aborted-to-static → fall through to the static table.\n }\n const res = await runBrowse(makeClient(), loadConfig(), { branch: opts.branch, json, brand })\n printResult(res, json)\n })\n}\n","// bt region — see (or set) your ship-to country + currency. The onboarding surface for the money\n// channel: a shopper should always know their region/currency, and be able to change it, WITHOUT a\n// wizard (the ceremony is the confirm, not the menu). Setting VALIDATES against the live regions and\n// fails CLOSED on a country we don't ship to (A1 / T2.3) — so config.region can never hold an\n// unshippable value, and the stage-time guard is a defence-in-depth backstop.\n//\n// runRegion is a PURE function of (client, config, args) → HandlerResult (the SET path returns a\n// `save` patch the register wrapper persists), so it's unit-testable without a backend or disk.\n\nimport type { Command } from \"commander\"\nimport { ok } from \"../voice\"\nimport { failResult, printResult, resolveOutput, regionLine, brandOf, type HandlerResult, type Branded } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport { dim } from \"../brand\"\nimport type { StoreClient, BtConfigLike, RegionLike } from \"./types-bridge\"\n\nexport interface RegionArgs extends Branded {\n /** set this ship-to country (ISO-2). */\n cc?: string\n /** list every shippable country. */\n list?: boolean\n json?: boolean\n}\n\n// How many country codes to show before collapsing to \"… (N)\" — the EU region carries 26.\nconst MAX_COUNTRIES_SHOWN = 8\n\nfunction regionRow(r: RegionLike): string {\n const ccs = (r.countries ?? []).map((c) => (c.iso_2 ?? \"\").toLowerCase()).filter(Boolean).sort()\n const shown = ccs.slice(0, MAX_COUNTRIES_SHOWN).join(\" · \")\n const more = ccs.length > MAX_COUNTRIES_SHOWN ? ` … (${ccs.length})` : \"\"\n return ` ${r.currency_code.toLowerCase().padEnd(5)} ${shown}${more}`.trimEnd()\n}\n\nexport async function runRegion(\n client: StoreClient,\n config: BtConfigLike,\n args: RegionArgs\n): Promise<HandlerResult> {\n const style = brandOf(args)\n\n // SET — validate against the live regions; fail CLOSED on a country we don't ship to (T2.3/A1).\n if (args.cc) {\n const cc = args.cc.trim().toLowerCase()\n const rr = await client.resolveRegionResult(cc)\n if (!rr.matched) {\n return failResult({\n code: EXIT.DATAERR,\n what: `we don't ship to ${cc} yet. nothing was set.`,\n fix: \"bt region --list (see where we ship)\",\n })\n }\n return {\n lines: [ok(`region → ${cc} · prices in ${rr.region.currency_code}`)],\n save: { region: cc },\n json: args.json ? { region: cc, currency: rr.region.currency_code } : undefined,\n }\n }\n\n // LIST — every region we ship to, grouped by currency.\n if (args.list) {\n const regions = await client.getRegions()\n const lines = [\n dim(style, \"where we ship, and what you pay in:\"),\n ...regions.map(regionRow),\n dim(style, \" set yours → bt region <cc>\"),\n ]\n return {\n lines,\n json: args.json\n ? { regions: regions.map((r) => ({ currency: r.currency_code, countries: (r.countries ?? []).map((c) => c.iso_2) })) }\n : undefined,\n }\n }\n\n // SHOW (default) — the current region/currency + how to change or list.\n const rr = await client.resolveRegionResult(config.region)\n return {\n lines: [regionLine(rr, style), dim(style, \" change → bt region <cc> · all → bt region --list\")],\n json: args.json\n ? { region: rr.requested ?? null, currency: rr.region.currency_code, matched: rr.matched, home: rr.home }\n : undefined,\n }\n}\n\nexport function registerRegion(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike,\n persist: (patch: Partial<BtConfigLike>) => void\n): void {\n program\n .command(\"region\")\n .argument(\"[cc]\", \"set your ship-to country (ISO-2, e.g. se / us / de)\")\n .option(\"--list\", \"list every country we ship to + its currency\")\n .description(\"see (or set) your ship-to country + currency.\")\n .action(async (cc: string | undefined, opts: { list?: boolean }) => {\n const { json, brand } = resolveOutput(program)\n const res = await runRegion(makeClient(), loadConfig(), { cc, list: opts.list, json, brand })\n if (res.save) {\n persist(res.save)\n }\n printResult(res, json)\n })\n}\n","// bt completion <shell> — emit a shell completion script (delight #2). Tab-completing subcommands is\n// the quietest possible \"this is tight\", and almost no store CLI ships it. Prints the script to\n// stdout so the user wires it up:\n// bash: eval \"$(bt completion bash)\" (or add to ~/.bashrc)\n// zsh: eval \"$(bt completion zsh)\" (or drop in your $fpath)\n// fish: bt completion fish | source (or > ~/.config/fish/completions/bt.fish)\n//\n// We complete the PUBLIC subcommands only — eggs + the hidden operator `drop` are intentionally\n// absent (they stay \"if you know, you know\"). runCompletion is pure (shell → script string).\n\nimport type { Command } from \"commander\"\nimport { failResult, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\n\n// The public, completable subcommands (+ the two aliases people actually type). Kept here rather than\n// derived from the program so eggs/hidden commands never leak into completion.\nconst COMMANDS = [\n \"browse\", \"search\", \"view\", \"stage\", \"buy\", \"cart\", \"unstage\", \"checkout\", \"commit\",\n \"order\", \"log\", \"status\", \"whoami\", \"region\", \"drops\", \"blame\", \"login\", \"logout\",\n \"config\", \"token\", \"doctor\", \"report\", \"connect\", \"init\", \"completion\",\n] as const\n\nexport type CompletionShell = \"bash\" | \"zsh\" | \"fish\"\n\nexport function completionScript(shell: CompletionShell): string {\n const list = COMMANDS.join(\" \")\n if (shell === \"bash\") {\n return [\n \"# bt bash completion — add to ~/.bashrc: eval \\\"$(bt completion bash)\\\"\",\n \"_bt_completions() {\",\n ' local cur=\"${COMP_WORDS[COMP_CWORD]}\"',\n ` COMPREPLY=( $(compgen -W \"${list}\" -- \"$cur\") )`,\n \"}\",\n \"complete -F _bt_completions bt btn\",\n \"\",\n ].join(\"\\n\")\n }\n if (shell === \"zsh\") {\n return [\n \"#compdef bt btn\",\n \"# bt zsh completion — add to ~/.zshrc: eval \\\"$(bt completion zsh)\\\"\",\n \"_bt() {\",\n \" local -a cmds\",\n ` cmds=(${list})`,\n \" _describe 'command' cmds\",\n \"}\",\n \"compdef _bt bt btn\",\n \"\",\n ].join(\"\\n\")\n }\n // fish\n return [\n \"# bt fish completion — bt completion fish | source\",\n \"complete -c bt -f\",\n `for c in ${list}`,\n \" complete -c bt -n __fish_use_subcommand -a $c\",\n \"end\",\n \"\",\n ].join(\"\\n\")\n}\n\nexport function runCompletion(args: { shell?: string; json?: boolean }): HandlerResult {\n const shell = (args.shell ?? \"\").trim().toLowerCase()\n if (shell !== \"bash\" && shell !== \"zsh\" && shell !== \"fish\") {\n return failResult({\n code: EXIT.DATAERR,\n what: `unknown shell \"${args.shell ?? \"\"}\".`,\n fix: \"bt completion <bash|zsh|fish>\",\n })\n }\n const script = completionScript(shell)\n return { lines: [script], json: args.json ? { shell, script } : undefined }\n}\n\nexport function registerCompletion(program: Command): void {\n program\n .command(\"completion\")\n .argument(\"<shell>\", \"bash | zsh | fish\")\n .description(\"print a shell completion script (eval it in your shell rc).\")\n .action((shell: string) => {\n const { json } = resolveOutput(program)\n printResult(runCompletion({ shell, json }), json)\n })\n}\n","// bt search <q> — browse, filtered by a query (title/handle/description substring match).\n//\n// A1: TITLE is the primary name (the query also matches it); handle shown dimmed/secondary.\n// A3: a compact colour marker per matching product.\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { productColours } from \"@binaryandthread/store-client\"\nimport {\n fmtPrice,\n firstPrice,\n stageMarker,\n displayName,\n brandOf,\n printResult,\n resolveOutput,\n type HandlerResult,\n type Branded,\n} from \"./shared\"\nimport { header, cyan, dim, colourMarker } from \"../brand\"\nimport type { StoreClient, ProductLike, BtConfigLike } from \"./types-bridge\"\n\nexport interface SearchArgs extends Branded {\n query: string\n json?: boolean\n}\n\nfunction matches(p: ProductLike, q: string): boolean {\n const needle = q.toLowerCase()\n return (\n (p.handle ?? \"\").toLowerCase().includes(needle) ||\n (p.title ?? \"\").toLowerCase().includes(needle) ||\n (p.description ?? \"\").toLowerCase().includes(needle)\n )\n}\n\nexport async function runSearch(\n client: StoreClient,\n config: BtConfigLike,\n args: SearchArgs\n): Promise<HandlerResult> {\n const style = brandOf(args)\n const region = await client.resolveRegion(config.region)\n const products = await client.listProducts({ region })\n const filtered = products.filter((p) => matches(p, args.query))\n\n const lines: string[] = []\n if (filtered.length === 0) {\n lines.push(empty(`no matches for \"${args.query}\". 0 results — try a looser query.`))\n lines.push(\" browse all → bt browse\")\n } else {\n lines.push(header(style, `bt search \"${args.query}\"`))\n for (const p of filtered) {\n const { amount, currency } = firstPrice(p)\n const { title, handle } = displayName(p)\n const stage = (p.metadata?.[\"channel_stage\"] as string) ?? \"main\"\n const colours = colourMarker(productColours(p))\n const row = [\n title.padEnd(22),\n cyan(style, fmtPrice(amount, currency).padEnd(11)),\n dim(style, handle.padEnd(34)),\n stageMarker(stage),\n ].join(\" \").trimEnd()\n lines.push(colours ? `${row}\\n ${dim(style, colours)}` : row)\n }\n lines.push(\" view one → bt view <handle>\")\n }\n\n return {\n lines,\n json: args.json\n ? filtered.map((p) => ({\n id: p.id,\n handle: p.handle,\n title: p.title,\n price: firstPrice(p).amount,\n currency: firstPrice(p).currency,\n colours: productColours(p),\n }))\n : undefined,\n }\n}\n\nexport function registerSearch(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"search\")\n .argument(\"<query>\", \"what to look for\")\n .description(\"filter the catalog by a query.\")\n .action(async (query: string) => {\n const { json, brand } = resolveOutput(program)\n const res = await runSearch(makeClient(), loadConfig(), { query, json, brand })\n printResult(res, json)\n })\n}\n","// bt cart — show the current cart from the server (authoritative), or the empty-state line.\n//\n// The server is the source of truth (F-B3). A stale/completed cart_id (RecoverableCartError)\n// is reported calmly, never crashed (VOICE §1.4 empty/error style).\n\nimport type { Command } from \"commander\"\nimport { empty, warn } from \"../voice\"\nimport { fmtPrice, formatCartLine, taxSuffix, isCartTaxInclusive, brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { header, cyan, dim } from \"../brand\"\nimport { RecoverableCartError } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface CartArgs extends Branded {\n json?: boolean\n}\n\n// VOICE §1.4 empty state — the dry one-liner.\nconst EMPTY_STATE = \"no commits yet. your wardrobe is a fresh repo.\"\n\nexport async function runCart(\n client: StoreClient,\n config: BtConfigLike,\n args: CartArgs\n): Promise<HandlerResult> {\n if (!config.cart_id) {\n return {\n lines: [empty(EMPTY_STATE), \" start one → bt browse\"],\n json: args.json ? { cart_id: null, items: [] } : undefined,\n }\n }\n\n const style = brandOf(args)\n try {\n const cart = await client.getCart(config.cart_id)\n const lines: string[] = []\n if (!cart.items || cart.items.length === 0) {\n lines.push(empty(EMPTY_STATE))\n lines.push(\" start one → bt browse\")\n } else {\n lines.push(header(style, \"bt cart — staged for commit\"))\n cart.items.forEach((item, i) => {\n lines.push(formatCartLine(item, i, cart.currency_code, style))\n })\n if (cart.total != null) {\n // The cart total is PRE-shipping until checkout attaches a method — say so, so it's never\n // mistaken for the final price (A2). Once a method is on the cart, the total is real.\n const shipNote =\n (cart.shipping_methods ?? []).length > 0 ? \"\" : dim(style, \" (excl. shipping — calculated at checkout)\")\n lines.push(` total ${cyan(style, fmtPrice(cart.total, cart.currency_code))}${taxSuffix(isCartTaxInclusive(cart))}${shipNote}`)\n }\n lines.push(\" remove one → bt unstage <#> · commit → bt commit\")\n }\n return {\n lines,\n json: args.json\n ? {\n cart_id: cart.id,\n items: cart.items ?? [],\n total: cart.total ?? null,\n total_excludes_shipping: (cart.shipping_methods ?? []).length === 0,\n }\n : undefined,\n }\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n warn(\"that cart is no longer valid (expired or already committed).\"),\n empty(EMPTY_STATE),\n \" start a fresh one → bt browse\",\n ],\n json: args.json ? { cart_id: null, items: [], stale: true } : undefined,\n }\n }\n throw e\n }\n}\n\nexport function registerCart(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"cart\")\n .description(\"show your current cart — the authoritative server state.\")\n .action(async () => {\n const { json, brand } = resolveOutput(program)\n const res = await runCart(makeClient(), loadConfig(), { json, brand })\n printResult(res, json)\n })\n}\n","// bt checkout (alias: bt commit) — the browser-hop floor, client side.\n//\n// THE single non-negotiable invariant: cards NEVER touch the terminal. The card/CVC AND the\n// shipping address are entered on the storefront checkout page (Stripe Elements + the address\n// form), which we open in the browser. The worst a buggy/malicious run can do is leave a junk\n// *unpaid* cart — money fails closed by construction (ROBUSTNESS §0).\n//\n// A2 — \"fill on the web\" (Sam's decision): the headless checkout route requires only\n// cart_id + items + shipping method + region. Email is OPTIONAL and NO address is needed (the\n// storefront collects address + email). So this command does NOT prompt for an address or email\n// in the terminal. It passes the keychain/whoami email if one is already known (no prompt), else\n// omits it.\n//\n// Flow (VOICE §1.4, §2.1 · F-B5/F-C5/F-I1):\n// 1. load cart_id (──resume requires one); nothing staged → empty state.\n// 2. getCart; a stale/completed cart → tell the user to re-stage.\n// 3. REVIEW the cart (items + colour · total, incl. VAT where the market applies it) + ask to\n// proceed (y/n); abort costs nothing.\n// 4. ensureCartShippingMethod(cart_id) — the headless checkout route requires one (BUG 1);\n// fail CLOSED if the region has no available option.\n// 5. mintCheckout(cart_id, email?, \"cli\") — email passed only if already known (no prompt).\n// 6. open the browser + QR; tell the user: enter details on the page, cards never touch the terminal.\n// 7. pollUntilPlaced: placed → the \"deploy successful\" beat; timeout → exit-75 resumable\n// (money line FIRST); expired → re-stage.\n\nimport type { Command } from \"commander\"\nimport { ok, warn, fail, empty, working } from \"../voice\"\nimport { fmtPrice, lineColour, taxSuffix, isCartTaxInclusive, brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { header, cyan, dim } from \"../brand\"\nimport { EXIT } from \"../errors\"\nimport { RecoverableCartError } from \"@binaryandthread/store-client\"\nimport type { OpenCheckoutResult } from \"../browser\"\nimport type { PollOutcome } from \"../poll\"\nimport type { StoreClient, BtConfigLike, RegionLike, CartLike } from \"./types-bridge\"\n\nexport interface CheckoutArgs extends Branded {\n resume?: boolean\n json?: boolean\n /** skip the interactive proceed confirm (scripts / CI / agents) — implied by --json (d8). */\n yes?: boolean\n}\n\n/** The terminal prompts the flow needs. Injected so the flow is testable without a TTY. */\nexport interface CheckoutPrompts {\n /** ask a single free-text question (label is the human prompt). */\n ask(label: string, opts?: { default?: string }): Promise<string>\n /** a yes/no confirm; returns true on \"y\". */\n confirm(label: string): Promise<boolean>\n}\n\n/** The side-effecting collaborators (browser, poll loop, config save), all injectable. */\nexport interface CheckoutDeps {\n prompts?: CheckoutPrompts\n /** open the browser + render a QR; returns whether it opened + the lines to print. */\n open(url: string): Promise<OpenCheckoutResult>\n /** poll the session until placed/expired/timeout (bounded — F-C5/F-I3). */\n poll(sessionId: string): Promise<PollOutcome>\n /** persist a config patch atomically (the email). */\n saveConfig(patch: Partial<BtConfigLike>): void\n /**\n * Print a line EAGERLY (the cart review must appear before the interactive proceed prompt;\n * the handler's returned `lines` only print after the flow returns). Defaults to stdout.\n */\n print?(line: string): void\n}\n\n/** the region's supported country codes (lowercased), for the \"ships to\" display line. */\nfunction supportedCountries(region: RegionLike): string[] {\n return (region.countries ?? [])\n .map((c) => (c.iso_2 ?? \"\").toLowerCase())\n .filter((c) => c.length > 0)\n}\n\n// The dim \"still waiting\" heartbeat during the browser hand-off. The poll can run up to 20 min\n// (poll.ts F-C5); with no pulse the terminal looks hung and a buyer Ctrl-Cs a live checkout — the\n// deploy that prints one line then goes dark. Returns the line to print on this tick, or null to\n// stay quiet: silent on the first tick (the buyer just got the link), then a calm elapsed line on a\n// ~30s cadence. Pure + exported so the cadence is unit-tested without burning wall-clock.\nconst HEARTBEAT_EVERY_TICKS = 6 // ~30s at poll.ts's 5s cadence\n\nexport function heartbeatLine(\n attempt: number,\n opts: { intervalMs?: number; everyTicks?: number } = {}\n): string | null {\n const everyTicks = opts.everyTicks ?? HEARTBEAT_EVERY_TICKS\n if (attempt <= 1 || (attempt - 1) % everyTicks !== 0) {\n return null\n }\n const intervalMs = opts.intervalMs ?? 5_000\n const elapsedS = Math.round(((attempt - 1) * intervalMs) / 1_000)\n return working(\n `still waiting for the browser hand-off, ${elapsedS}s in. ctrl-c is safe; resume with bt checkout --resume`\n )\n}\n\nexport async function runCheckout(\n client: StoreClient,\n config: BtConfigLike,\n args: CheckoutArgs,\n deps: CheckoutDeps\n): Promise<HandlerResult> {\n const cartId = config.cart_id\n\n // 1. nothing staged → empty state. --resume needs an existing cart (no local in-flight state).\n if (!cartId) {\n if (args.resume) {\n return {\n lines: [\n empty(\"nothing to resume — no cart on record.\"),\n \" stage something first → bt browse then bt stage <slug>\",\n ],\n }\n }\n return {\n lines: [\n empty(\"nothing staged. your wardrobe is a fresh repo.\"),\n \" start one → bt browse\",\n ],\n }\n }\n\n // 2. read the authoritative server cart; a stale/completed cart → re-stage (F-B2).\n let cart: CartLike\n try {\n cart = await client.getCart(cartId)\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n warn(\"that cart is no longer valid (expired or already committed).\"),\n \" re-stage → bt browse then bt stage <slug>\",\n ],\n }\n }\n throw e\n }\n if (!cart.items || cart.items.length === 0) {\n return {\n lines: [\n empty(\"nothing staged. your wardrobe is a fresh repo.\"),\n \" start one → bt browse\",\n ],\n }\n }\n\n const region = await client.resolveRegion(config.region)\n const style = brandOf(args)\n const prompts = deps.prompts\n if (!prompts) {\n throw new Error(\"checkout requires a prompter\")\n }\n\n // 3a. attach a shipping method BEFORE the review (AUD-10 + BUG 1). The headless checkout route\n // requires one, and the total the buyer consents to MUST include shipping. Attaching is\n // idempotent and NEVER charges (cards are entered later on the web), so doing it before the\n // proceed confirm is money-safe — an abort still mints nothing. A stale cart → a Recoverable\n // re-stage message; a region with no shipping option fails CLOSED (never mint a doomed checkout).\n let shippedCart: CartLike\n try {\n shippedCart = await client.ensureCartShippingMethod(cartId)\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n warn(\"that cart is no longer valid (expired or already committed).\"),\n \" re-stage → bt browse then bt stage <slug>\",\n ],\n }\n }\n return {\n lines: [\n fail({\n code: 1,\n what: \"couldn't attach a shipping method to your cart.\",\n fix: \"this region may not have shipping configured yet — try again shortly, or re-stage.\",\n }),\n ],\n exitCode: EXIT.GENERIC, // fail-closed, no order placed → non-zero (matches the shown exit 1)\n }\n }\n\n // 3b. REVIEW + ACCEPT the cart — show items (with colour) + total (incl. VAT where the market\n // applies it) + shipping, then ask to proceed. No address/email prompt: the storefront page\n // collects those (A2).\n const itemCount = cart.items.reduce((n, li) => n + (li.quantity ?? 1), 0)\n // Total from the SHIPPED cart so it INCLUDES shipping (AUD-10); fall back to the pre-shipping\n // total only if the client didn't echo one back.\n const totalLine = fmtPrice(shippedCart?.total ?? cart.total, cart.currency_code ?? region.currency_code)\n // VAT label follows the cart's OWN tax flag (derived from its line items — no cart-root flag),\n // never the currency: an SE cart shows \" incl. VAT\", a US (tax-exclusive) cart shows none.\n const taxIncl = isCartTaxInclusive(cart)\n const reviewLines: string[] = [header(style, \"bt checkout — staged for commit\")]\n for (const li of cart.items) {\n const colour = lineColour(li)\n const colourTag = colour ? ` · ${colour}` : \"\"\n reviewLines.push(\n ` ${(li.title ?? li.product_title ?? \"item\").toString()}${colourTag} · qty ${li.quantity}` +\n (li.total != null ? ` ${cyan(style, fmtPrice(li.total, cart.currency_code ?? region.currency_code))}` : \"\")\n )\n }\n reviewLines.push(` total ${cyan(style, totalLine)}${taxSuffix(taxIncl)}`)\n const print = deps.print ?? ((line: string) => process.stdout.write(line + \"\\n\"))\n for (const line of reviewLines) {\n print(line)\n }\n // In --json / --yes mode, SKIP the interactive proceed confirm: a hidden readline on a\n // non-interactive stdin (CI, a piped agent) blocks forever (d8). Minting a checkout does NOT\n // charge — the card is entered later on the Stripe page — so auto-proceeding is money-safe.\n const autoProceed = Boolean(args.json) || Boolean(args.yes)\n if (!autoProceed) {\n const proceed = await prompts.confirm(\n `proceed to checkout? ${itemCount} item${itemCount === 1 ? \"\" : \"s\"} · ${totalLine}${taxSuffix(taxIncl)} (y/n):`\n )\n if (!proceed) {\n return {\n lines: [empty(\"aborted. nothing was committed — your stage is still held.\")],\n }\n }\n }\n\n // \"ships to\" display line — the region's first supported country (informational, not a gate;\n // the storefront page collects + validates the real ship-to address).\n const allowed = supportedCountries(region)\n const shipsTo = (allowed[0] ?? \"\").toUpperCase()\n\n // 5. mint the checkout (idempotent in the client). Pass a KNOWN email (keychain/whoami/config)\n // WITHOUT prompting; omit it otherwise — the storefront collects it (A2).\n const email = (config.email ?? \"\").trim()\n const { checkout_url, session_id } = await client.mintCheckout(cartId, email || undefined, \"cli\")\n const save: Partial<BtConfigLike> = email ? { email } : {}\n\n // 6. hand off to the browser + QR. cards never touch the terminal — and now neither does the\n // address: tell the user clearly to fill their details on the page.\n const opened: OpenCheckoutResult = await deps.open(checkout_url)\n // Print the URL/QR + hand-off guidance EAGERLY, BEFORE the (blocking) poll (AUD-9): the buyer\n // needs the link to pay WHILE the CLI waits — the browser may not have opened (headless/CI/SSH).\n for (const line of opened.lines) {\n print(line)\n }\n print(\" enter your details on the page — address + card. cards never touch the terminal.\")\n\n // 7. poll the bt_session until placed/expired/timeout (bounded — F-C5/F-I3). A transient poll\n // failure must NEVER crash the checkout (AUD-11): a buyer who may already have paid needs the\n // link + money reassurance, not a raw stack trace.\n let outcome: PollOutcome\n try {\n outcome = await deps.poll(session_id)\n } catch {\n return {\n lines: [\n \"\",\n fail({\n code: 75,\n what: \"lost the connection while waiting for your order to complete.\",\n money:\n \"if you completed payment, your order is safe — we just couldn't confirm it here. check your email, or run bt order.\",\n fix: \"bt checkout --resume (or open the link below manually)\",\n link: checkout_url,\n }),\n ],\n save,\n exitCode: EXIT.TEMPFAIL, // lost the connection mid-poll → not confirmed → non-zero (75)\n }\n }\n\n // opened.lines were already printed eagerly above (AUD-9) — start the returned lines fresh.\n const lines: string[] = []\n\n if (outcome.status === \"placed\") {\n // the channel's signature beat — a log, not a party (VOICE §1.4). Fetch the order for the\n // display id where possible; fall back to the poll's order_id.\n const displayId = await resolveDisplayId(client, outcome.order_id, email)\n lines.push(\"\")\n lines.push(ok(\"deploy successful.\"))\n lines.push(` committed to wardrobe@main`)\n lines.push(` order #${displayId}`)\n // Gated on the SAME tax flag as the review lines. Kept in the success beat's parenthetical form\n // (\" (incl. VAT)\") so the SE confirmation stays byte-identical; a US order shows no VAT note.\n lines.push(` total ${cyan(style, totalLine)}${taxIncl ? \" (incl. VAT)\" : \"\"}`)\n if (shipsTo) {\n lines.push(` ships to ${shipsTo} · ~3–6 working days`)\n } else {\n lines.push(` ships ~3–6 working days`)\n }\n lines.push(` track bt order ${displayId}`)\n if (email) {\n lines.push(` receipt sent to ${maskEmail(email)}`)\n }\n return {\n lines,\n save,\n json: args.json\n ? {\n status: \"placed\",\n order_id: outcome.order_id,\n display_id: displayId,\n // A2 — the SHIPPING-INCLUSIVE total the buyer consented to (same figure as the review),\n // so a --json / bt buy consumer has the real amount, not just a status.\n total: shippedCart?.total ?? cart.total ?? null,\n currency: cart.currency_code ?? region.currency_code ?? null,\n }\n : undefined,\n }\n }\n\n if (outcome.status === \"expired\") {\n lines.push(\"\")\n lines.push(\n warn(\"your stage expired before checkout completed. nothing was charged.\")\n )\n lines.push(\" re-stage → bt stage <slug> then bt checkout\")\n return { lines, save, json: args.json ? { status: \"expired\" } : undefined, exitCode: EXIT.TEMPFAIL }\n }\n\n // timeout — the exit-75 resumable error. money reassurance FIRST (VOICE §1.4, non-negotiable).\n // A4: a poll TIMEOUT does NOT prove non-payment (the buyer may have paid at the last second) —\n // hedge honestly, unlike the `expired` branch above where non-payment is certain.\n lines.push(\"\")\n lines.push(\n fail({\n code: 75,\n what: \"checkout handoff timed out — we didn't see the order complete.\",\n money: \"if you completed payment, your order is safe; if not, your stage is still held — check your email or bt order.\",\n fix: \"bt checkout --resume (or open the link below manually)\",\n link: checkout_url,\n })\n )\n return {\n lines,\n save,\n json: args.json ? { status: \"timeout\", checkout_url } : undefined,\n exitCode: EXIT.TEMPFAIL, // handoff timed out → not placed → non-zero (matches the shown exit 75)\n }\n}\n\n/** Resolve a human display id for the confirmation beat; falls back to the raw order_id. */\nasync function resolveDisplayId(\n client: StoreClient,\n orderId: string | null,\n email: string\n): Promise<string | number> {\n if (!orderId) {\n return \"—\"\n }\n try {\n // TODO(04.5 followup): email-in-query → POST body, needs backend route (Wave-2 review note).\n const looked = (await client.getOrder(orderId, email)) as\n | { order?: { display_id?: number | string } }\n | { display_id?: number | string }\n | null\n const display =\n (looked as { order?: { display_id?: number | string } })?.order?.display_id ??\n (looked as { display_id?: number | string })?.display_id\n return display ?? orderId\n } catch {\n return orderId\n }\n}\n\n/** d***@example.com — minimal receipt masking on the confirmation beat (G10/G15 style). */\nfunction maskEmail(email: string): string {\n const at = email.indexOf(\"@\")\n if (at <= 0) {\n return \"***\"\n }\n const local = email.slice(0, at)\n const domain = email.slice(at + 1)\n const head = local[0] ?? \"\"\n return `${head}***@${domain}`\n}\n\nexport function registerCheckout(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n const action = async (opts: { resume?: boolean; yes?: boolean }) => {\n const { json, brand } = resolveOutput(program)\n const { makePrompts } = await import(\"../prompts\")\n const { openCheckout } = await import(\"../browser\")\n const { pollUntilPlaced } = await import(\"../poll\")\n const { saveConfig } = await import(\"../config\")\n const client = makeClient()\n // In --json mode the review + heartbeat are suppressed (machine output only); otherwise print\n // eagerly to stdout. Shared by the eager prints AND the poll heartbeat so both honor --json.\n const print = json ? () => {} : (line: string) => process.stdout.write(line + \"\\n\")\n const res = await runCheckout(\n client,\n loadConfig(),\n { resume: opts.resume, json, brand, yes: opts.yes },\n {\n prompts: makePrompts(),\n open: (url) => openCheckout(url),\n // Heartbeat the browser-hop wait so the terminal never looks hung (a dim, calm line every\n // ~30s). Suppressed under --json (print is a no-op there).\n poll: (sessionId) =>\n pollUntilPlaced(client, sessionId, {\n onTick: (attempt) => {\n const line = heartbeatLine(attempt)\n if (line) print(dim(brand, line))\n },\n }),\n saveConfig,\n print,\n }\n )\n if (res.save && Object.keys(res.save).length > 0) {\n saveConfig(res.save)\n }\n printResult(res, json)\n }\n\n program\n .command(\"checkout\")\n .alias(\"commit\")\n .description(\n \"turn your staged items into an order. opens browser checkout, polls, never touches cards.\"\n )\n .option(\"--resume\", \"resume an in-progress checkout from your existing cart\")\n .option(\"--yes\", \"skip the proceed confirmation (scripts / CI / agents); implied by --json\")\n .action(action)\n}\n","// bt order <id> — track one order: the staged→committed→printed→shipped→delivered timeline.\n//\n// Guest path (F-H1, SECURITY T4): the lookup needs the order display id AND the EXACT email;\n// the backend 404s on a mismatch (no enumeration), so the client returns null → we print a\n// flat \"not found\" that leaks NOTHING about whether the id or the email was wrong. The\n// merge-to-main 🎉 (the one sanctioned celebration, VOICE §1.4) renders ONLY at delivered.\n\nimport type { Command } from \"commander\"\nimport { fmtPrice, taxSuffix, brandOf, failResult, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport { cyan } from \"../brand\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface OrderArgs extends Branded {\n displayId: string\n json?: boolean\n}\n\n// The five-stage lifecycle, rendered as a git-ish graph (VOICE §2.3).\nconst STAGES = [\"staged\", \"committed\", \"printed\", \"shipped\", \"delivered\"] as const\n\n/** Map a Medusa order/fulfillment status onto our stage index (0..4). */\nfunction stageIndex(o: { status?: string; fulfillment_status?: string }): number {\n const f = (o.fulfillment_status ?? \"\").toLowerCase()\n if (f.includes(\"delivered\")) return 4\n if (f.includes(\"shipped\")) return 3\n if (f.includes(\"fulfilled\") || f.includes(\"printed\") || f.includes(\"partially_shipped\")) return 2\n // placed/captured but not yet fulfilled\n return 1\n}\n\nfunction timelineGraph(idx: number): string {\n // ●──●──●──● delivered — filled dots up to the current stage.\n const dots = STAGES.map((_s, i) => (i <= idx ? \"●\" : \"○\")).join(\"──\")\n return dots\n}\n\nexport async function runOrder(\n client: StoreClient,\n config: BtConfigLike,\n args: OrderArgs\n): Promise<HandlerResult> {\n const email = config.email\n if (!email) {\n return failResult({\n code: EXIT.DATAERR,\n what: \"order lookup needs your email.\",\n fix: \"bt config set email <you@example.com> (then retry)\",\n })\n }\n\n // id + EXACT email; the client returns null on a 404 miss (F-H1). AUD-8: the client POSTs to\n // /store/order-lookup (email in the body, never the query string).\n const looked = (await client.getOrder(args.displayId, email)) as\n | { order?: Record<string, unknown> }\n | Record<string, unknown>\n | null\n\n if (!looked) {\n // flat not-found — never reveal whether the id or the email was the wrong half (F-H1).\n return failResult({\n code: EXIT.UNAVAILABLE,\n what: `order ${args.displayId} not found for that email.`,\n fix: \"check the order number + the email it was placed with.\",\n })\n }\n\n const o = ((looked as { order?: Record<string, unknown> }).order ?? looked) as Record<string, unknown>\n const idx = stageIndex(o as { status?: string; fulfillment_status?: string })\n const display = (o.display_id ?? args.displayId) as string | number\n const total = fmtPrice((o.total as number) ?? null, (o.currency_code as string) ?? null)\n const items =\n (o.items as Array<{ title?: string; variant_title?: string; quantity?: number; is_tax_inclusive?: boolean | null }>) ??\n []\n // VAT label follows the order's OWN per-line-item tax flag (uniform per region), never the\n // currency: an SE order shows \" incl. VAT\", a US (tax-exclusive) order shows none. The backend\n // order-lookup route surfaces items.is_tax_inclusive for exactly this.\n const orderTaxInclusive = items.some((i) => i.is_tax_inclusive === true)\n const first = items[0]\n const itemLabel = first\n ? `${first.title ?? \"item\"}${first.variant_title ? ` · ${first.variant_title}` : \"\"}`\n : \"your order\"\n\n const style = brandOf(args)\n const lines: string[] = []\n lines.push(`${display} ${itemLabel} ${cyan(style, timelineGraph(idx))} ${STAGES[idx]}`)\n lines.push(` ${STAGES.join(\" → \")}${idx === 4 ? \" 🎉\" : \"\"}`)\n lines.push(` total ${cyan(style, total)}${taxSuffix(orderTaxInclusive)}`)\n\n return {\n lines,\n json: args.json\n ? { display_id: display, stage: STAGES[idx], total: o.total ?? null, currency: o.currency_code ?? null }\n : undefined,\n }\n}\n\nexport function registerOrder(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"order\")\n .argument(\"<id>\", \"the order number (display id)\")\n .description(\"track one order: staged → committed → printed → shipped → delivered.\")\n .action(async (id: string) => {\n const { json, brand } = resolveOutput(program)\n const res = await runOrder(makeClient(), loadConfig(), { displayId: id, json, brand })\n printResult(res, json)\n })\n}\n","// Decode a JWT's `exp` claim LOCALLY (no signature verification — display only) so `bt whoami\n// --json` can report token expiry for a pre-flight auth check without a network mutation (d25).\n// The token is short-lived; this is purely informational (\"is my session still valid / when does\n// it lapse\"), never an authorization decision (that's the backend's job).\n\nexport interface JwtExpiry {\n /** ISO timestamp the token expires, or null if no/invalid token or no exp claim. */\n expiresAt: string | null\n /** true if expired, false if still valid, null if unknown (no/invalid token / no exp). */\n expired: boolean | null\n}\n\nexport function jwtExpiry(jwt: string | null | undefined, now: number = Date.now()): JwtExpiry {\n if (!jwt) {\n return { expiresAt: null, expired: null }\n }\n const parts = jwt.split(\".\")\n if (parts.length < 2 || !parts[1]) {\n return { expiresAt: null, expired: null }\n }\n try {\n const b64 = parts[1].replace(/-/g, \"+\").replace(/_/g, \"/\")\n const payload = JSON.parse(Buffer.from(b64, \"base64\").toString(\"utf8\")) as { exp?: unknown }\n const exp = typeof payload.exp === \"number\" ? payload.exp : null\n if (exp == null) {\n return { expiresAt: null, expired: null }\n }\n const expMs = exp * 1000\n return { expiresAt: new Date(expMs).toISOString(), expired: expMs <= now }\n } catch {\n return { expiresAt: null, expired: null }\n }\n}\n","// bt token — export the keychain JWT for an MCP config's BT_TOKEN env (the keychain→MCP bridge, d18).\n//\n// The MCP server reads BT_TOKEN from its host config (it can't reach your OS keychain). `bt token`\n// bridges that gap: it prints your JWT to STDOUT (so `bt token | pbcopy` works) with a caveat on\n// STDERR (so a pipe stays clean). It's a bearer credential — your own, on your own machine — so we\n// warn but don't block. The CLI itself also reads BT_TOKEN (see makeClient) so CI can supply one\n// without the keychain.\n\nimport type { Command } from \"commander\"\nimport { warn, empty } from \"../voice\"\nimport { resolveOutput } from \"./shared\"\nimport { jwtExpiry } from \"../jwt\"\nimport { getToken } from \"../keychain\"\n\n/** env BT_TOKEN wins over the keychain (CI/non-interactive); null if neither. */\nexport function resolveBridgeToken(env: NodeJS.ProcessEnv, keychainToken: string | null): string | null {\n const fromEnv = env.BT_TOKEN?.trim()\n return fromEnv || keychainToken || null\n}\n\nexport function registerToken(program: Command): void {\n program\n .command(\"token\")\n .description(\"print your keychain JWT for an MCP config (env BT_TOKEN). a bearer credential — handle with care.\")\n .action(() => {\n const { json } = resolveOutput(program)\n const token = resolveBridgeToken(process.env, getToken())\n if (!token) {\n process.stderr.write(empty(\"not logged in — run bt login first.\") + \"\\n\")\n process.exitCode = 1\n return\n }\n if (jwtExpiry(token).expired) {\n process.stderr.write(warn(\"this token is expired — run bt login for a fresh one.\") + \"\\n\")\n }\n // caveat on stderr (keeps `bt token | pbcopy` clean); the token itself on stdout.\n process.stderr.write(\"⚠ bearer credential — paste only into your own MCP config (env BT_TOKEN), never anywhere public.\\n\")\n process.stdout.write((json ? JSON.stringify({ token }) : token) + \"\\n\")\n })\n}\n","// bt log rendering — your wardrobe as a git history (brand-delight #2, VOICE §2.2).\n//\n// Three views over the same order set:\n// - default : a flat \"display label status\" list (legacy behaviour, unchanged)\n// - --oneline: git-log --oneline style, newest = (HEAD -> main), short-hash per order\n// - --graph : git-log --graph style — '*' nodes + '|' edges, status as the lifecycle stage,\n// and the ONE sanctioned 🎉 at the merged-to-main (delivered) moment (VOICE §1.4).\n//\n// The \"commit hash\" is a DETERMINISTIC 7-char hex derived from the order identity (display id +\n// created_at). It is NOT a real git sha — it's a stable id rendered as a hash (the joke is that an\n// order IS a commit). Deterministic so the same order always shows the same hash (no Date/random —\n// those are unavailable here anyway), and so a screenshot is reproducible.\n//\n// C9 egg (VOICE §3.1): with orders present but ALL reverted, HEAD is \"(detached HEAD)\" — the git\n// term is correct (no branch ref points at a committed fit) and it's a real, warm empty-state.\n\nimport { green, dim, type BrandStyle } from \"../brand\"\n\n/** The order shape these renderers read (a subset of OrderSummary — all optional/defensive). */\nexport interface LogOrder {\n display_id?: number | string | null\n status?: string | null\n fulfillment_status?: string | null\n created_at?: string | null\n items?: Array<{ title?: string | null; variant_title?: string | null }> | null\n}\n\n/** The lifecycle stage word for an order (mirrors bt order's mapping; adds 'reverted'). */\nexport function orderStage(o: LogOrder): \"delivered\" | \"shipped\" | \"printed\" | \"committed\" | \"reverted\" {\n const status = (o.status ?? \"\").toLowerCase()\n if (status.includes(\"cancel\") || status.includes(\"refund\") || status.includes(\"revert\")) {\n return \"reverted\"\n }\n const f = (o.fulfillment_status ?? \"\").toLowerCase()\n if (f.includes(\"delivered\")) return \"delivered\"\n if (f.includes(\"shipped\")) return \"shipped\"\n if (f.includes(\"fulfilled\") || f.includes(\"printed\") || f.includes(\"partially\")) return \"printed\"\n return \"committed\"\n}\n\n/**\n * A deterministic 7-char hex \"commit hash\" for an order. FNV-1a over the order identity — stable,\n * collision-resistant enough for a display id, and reproducible (so a screenshot is stable). Never\n * uses Date.now()/random (unavailable here + would break determinism).\n */\nexport function shortHash(o: LogOrder): string {\n const seed = `${o.display_id ?? \"\"}:${o.created_at ?? \"\"}`\n let h = 0x811c9dc5 // FNV-1a 32-bit offset basis\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i)\n h = Math.imul(h, 0x01000193) >>> 0\n }\n return h.toString(16).padStart(8, \"0\").slice(0, 7)\n}\n\n/** \"the terminal piece · L\" — first item's title + variant. Never \"tee\"/\"shirt\" (brand voice). */\nfunction label(o: LogOrder): string {\n const items = o.items ?? []\n const first = items[0]\n if (!first) return \"order\"\n return `${first.title ?? \"order\"}${first.variant_title ? ` · ${first.variant_title}` : \"\"}`\n}\n\n/** Whether the order set has at least one non-reverted (still-on-a-branch) order. */\nfunction hasLiveHead(orders: LogOrder[]): boolean {\n return orders.some((o) => orderStage(o) !== \"reverted\")\n}\n\n/**\n * --oneline view. Newest order (orders[0]) carries the \"(HEAD -> main)\" ref — unless every order is\n * reverted, in which case HEAD is \"(detached HEAD)\" (C9). Each row: <hash> <ref> <label> <stage>.\n */\nexport function renderOneline(orders: LogOrder[], style: BrandStyle): string[] {\n if (orders.length === 0) return []\n const live = hasLiveHead(orders)\n // the ref decorates the newest LIVE order; if all reverted, the C9 detached-HEAD line leads.\n const headIdx = live ? orders.findIndex((o) => orderStage(o) !== \"reverted\") : -1\n const lines: string[] = []\n if (!live) {\n lines.push(dim(style, \"(detached HEAD) you have no committed fits. literally nothing to wear. we don't judge.\"))\n }\n orders.forEach((o, i) => {\n const hash = shortHash(o)\n const stage = orderStage(o)\n const ref = i === headIdx ? \"(HEAD -> main) \" : \"\"\n const tail = stage === \"delivered\" ? \"delivered 🎉\" : stage\n lines.push(`${hash} ${ref}${label(o).padEnd(34)} ${tail}`)\n })\n return lines\n}\n\n/**\n * --graph view. git-log --graph style: '*' nodes joined by '|' edges (correct for a linear history).\n * The newest live order is decorated \"(HEAD -> main)\"; a fully-reverted set shows the C9 detached\n * HEAD line. The merged-to-main 🎉 (the single sanctioned celebration) renders ONLY at delivered.\n */\nexport function renderGraph(orders: LogOrder[], style: BrandStyle): string[] {\n if (orders.length === 0) return []\n const live = hasLiveHead(orders)\n const headIdx = live ? orders.findIndex((o) => orderStage(o) !== \"reverted\") : -1\n const lines: string[] = []\n if (!live) {\n lines.push(dim(style, \"(detached HEAD) no committed fits. literally nothing to wear. we don't judge.\"))\n }\n orders.forEach((o, i) => {\n const hash = shortHash(o)\n const stage = orderStage(o)\n const ref = i === headIdx ? \" (HEAD -> main)\" : \"\"\n const node = stage === \"delivered\" ? green(style, \"*\") : \"*\"\n const tail = stage === \"delivered\" ? `${stage} ${green(style, \"🎉\")}` : stage\n lines.push(`${node} ${hash}${ref} ${label(o).padEnd(32)} ${tail}`)\n if (i < orders.length - 1) {\n lines.push(\"|\")\n }\n })\n return lines\n}\n\n/** The default flat list (legacy): \"<display> <label> <stage>\". */\nexport function renderFlat(orders: LogOrder[]): string[] {\n return orders.map((o) => {\n const display = String(o.display_id ?? \"\")\n return `${display.padEnd(8)} ${label(o).padEnd(36)} ${orderStage(o)}`\n })\n}\n","// bt log [--oneline|--graph] — your order history as a git log.\n//\n// Guest order *history* is a logged-in capability (the backend filters strictly by the\n// verified customer/email — F-H2); a guest with no session sees the empty state. The shared\n// client exposes single-order lookup (getOrder, id+exact-email) but no guest history listing,\n// so until login lands (Wave 5) `bt log` shows the \"fresh repo\" empty state. The C9 detached-\n// HEAD egg (reverted-everything) is a Wave-3 governed polish pass.\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { resolveBridgeToken } from \"./token\"\nimport { getToken } from \"../keychain\"\nimport { renderOneline, renderGraph, renderFlat, type LogOrder } from \"./log-graph\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface LogArgs extends Branded {\n oneline?: boolean\n graph?: boolean\n json?: boolean\n /**\n * Whether the user is authenticated (a customer JWT is present). The history route is JWT-bound\n * (d13), so this — NOT a saved email — is the real \"logged in\" signal: a BT_TOKEN/keychain session\n * with no config.email must still see history. registerLog computes it from the resolved token.\n */\n loggedIn?: boolean\n}\n\n// VOICE §1.4 empty state.\nconst EMPTY_STATE = \"no commits yet. your wardrobe is a fresh repo.\"\n\nexport async function runLog(\n client: StoreClient,\n config: BtConfigLike,\n args: LogArgs\n): Promise<HandlerResult> {\n // \"Logged in\" = a JWT is present (passed by registerLog). Fall back to a saved email so a caller\n // that doesn't pass the flag still behaves sensibly. Without a session we show the empty state\n // (no network) rather than firing a request we know will 401 — keeps the offline/guest path quiet.\n const loggedIn = args.loggedIn ?? Boolean(config.email)\n\n if (!loggedIn) {\n return {\n lines: [empty(EMPTY_STATE), \" start one → bt browse\"],\n json: args.json ? { commits: [] } : undefined,\n }\n }\n\n const orders = (await client.listOrders()) as LogOrder[]\n if (!orders || orders.length === 0) {\n return {\n lines: [empty(EMPTY_STATE), \" start one → bt browse\"],\n json: args.json ? { commits: [] } : undefined,\n }\n }\n\n // Render the wardrobe as a git history (brand-delight #2). --graph and --oneline carry the\n // git-log treatments (short-hash, HEAD ref, the 🎉 merged-to-main beat at delivered); the bare\n // `bt log` keeps the flat list. --json is always the raw order set (machine-clean).\n const style = brandOf(args)\n const lines = args.graph\n ? renderGraph(orders, style)\n : args.oneline\n ? renderOneline(orders, style)\n : renderFlat(orders)\n\n return {\n lines,\n json: args.json ? { commits: orders } : undefined,\n }\n}\n\nexport function registerLog(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"log\")\n .option(\"--oneline\", \"compact one-line-per-order format\")\n .option(\"--graph\", \"graph format\")\n .description(\"your order history as a git log.\")\n .action(async (opts: { oneline?: boolean; graph?: boolean }) => {\n const { json, brand } = resolveOutput(program)\n // The history route is JWT-bound (d13): \"logged in\" = a token resolves (BT_TOKEN env → keychain,\n // d18), NOT a saved email. A token-only session with no config.email must still see history.\n const loggedIn = Boolean(resolveBridgeToken(process.env, getToken()))\n const res = await runLog(makeClient(), loadConfig(), { oneline: opts.oneline, graph: opts.graph, json, loggedIn, brand })\n printResult(res, json)\n })\n}\n","// bt status — working-tree state: what's staged (the cart), what's in flight.\n//\n// The cart is the authoritative source of truth for \"staged\" (F-B3); a stale cart_id is\n// reported calmly (RecoverableCartError), never crashed. In-flight orders are a logged-in\n// capability (Wave 5) — until then `status` shows the staged tree + a clean-tree line.\n\nimport type { Command } from \"commander\"\nimport { empty, warn } from \"../voice\"\nimport { fmtPrice, formatCartLine, taxSuffix, isCartTaxInclusive, brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { cyan } from \"../brand\"\nimport { RecoverableCartError } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface StatusArgs extends Branded {\n json?: boolean\n}\n\nconst FRESH_REPO = \"no commits yet. your wardrobe is a fresh repo.\"\n\nexport async function runStatus(\n client: StoreClient,\n config: BtConfigLike,\n args: StatusArgs\n): Promise<HandlerResult> {\n if (!config.cart_id) {\n return {\n lines: [\n \"on branch main\",\n empty(FRESH_REPO),\n \" nothing staged. clean tree → bt browse\",\n ],\n json: args.json ? { branch: \"main\", staged: [], clean: true } : undefined,\n }\n }\n\n const style = brandOf(args)\n try {\n const cart = await client.getCart(config.cart_id)\n const items = cart.items ?? []\n const lines: string[] = [\"on branch main\"]\n if (items.length === 0) {\n lines.push(empty(FRESH_REPO))\n lines.push(\" nothing staged. clean tree → bt browse\")\n } else {\n lines.push(\"staged for commit:\")\n items.forEach((li, i) => {\n lines.push(formatCartLine(li, i, cart.currency_code, style))\n })\n if (cart.total != null) {\n lines.push(` total ${cyan(style, fmtPrice(cart.total, cart.currency_code))}${taxSuffix(isCartTaxInclusive(cart))}`)\n }\n lines.push(\" remove one → bt unstage <#> · commit → bt commit\")\n }\n return {\n lines,\n json: args.json\n ? { branch: \"main\", staged: items, total: cart.total ?? null, clean: items.length === 0 }\n : undefined,\n }\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n \"on branch main\",\n warn(\"your staged cart is no longer valid (expired or already committed).\"),\n empty(FRESH_REPO),\n \" re-stage → bt browse\",\n ],\n json: args.json ? { branch: \"main\", staged: [], clean: true, stale: true } : undefined,\n }\n }\n throw e\n }\n}\n\nexport function registerStatus(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"status\")\n .description(\"working-tree state: what's staged, what's in flight.\")\n .action(async () => {\n const { json, brand } = resolveOutput(program)\n const res = await runStatus(makeClient(), loadConfig(), { json, brand })\n printResult(res, json)\n })\n}\n","// bt unstage <ref> — remove a staged item from the cart, then re-read + VERIFY server state.\n//\n// \"git reset\" for the wardrobe. The cart is server-authoritative (F-B3): we read the live cart,\n// resolve <ref> (index / line-item id / short id / title word — BUG 2) to a real line-item id,\n// DELETE it, re-read, and confirm it actually went away. We print \"✓ unstaged\" ONLY when the\n// item is truly gone — never a false success (the prod bug Sam hit: a handle/word no-op'd the\n// delete but the CLI still printed \"✓\"). An unknown ref is a clear error, never a fake tick.\n\nimport type { Command } from \"commander\"\nimport { ok, empty, warn, fail } from \"../voice\"\nimport { formatCartLine, resolveLineItemRef, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport { RecoverableCartError } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike, CartLineItemLike } from \"./types-bridge\"\n\nexport interface UnstageArgs {\n /** the user-supplied reference: a 1-based index, a line-item id, or a product handle/title word. */\n itemId: string\n json?: boolean\n}\n\nconst FRESH_REPO = \"no commits yet. your wardrobe is a fresh repo.\"\n\nexport async function runUnstage(\n client: StoreClient,\n config: BtConfigLike,\n args: UnstageArgs\n): Promise<HandlerResult> {\n if (!config.cart_id) {\n return {\n lines: [empty(FRESH_REPO), \" nothing staged to unstage → bt browse\"],\n json: args.json ? { cart_id: null, items: [] } : undefined,\n }\n }\n\n try {\n // 1. read the authoritative cart so we can resolve the ref + verify the removal (BUG 2).\n const before = await client.getCart(config.cart_id)\n const beforeItems = before.items ?? []\n if (beforeItems.length === 0) {\n return {\n lines: [empty(FRESH_REPO), \" clean tree → bt browse\"],\n json: args.json ? { cart_id: before.id, items: [] } : undefined,\n }\n }\n\n // 2. resolve <ref> to a real line-item id. No match → a CLEAR error, never a false success.\n const target = resolveLineItemRef(beforeItems, args.itemId)\n if (!target) {\n return {\n lines: [\n warn(`no such item in your cart: \"${args.itemId}\"`),\n \" see what's staged (with its #) → bt cart\",\n ],\n json: args.json ? { cart_id: before.id, removed: null, items: beforeItems } : undefined,\n exitCode: EXIT.DATAERR, // bad ref → non-zero so a script can't proceed as if it removed something (B3)\n }\n }\n\n // 3. DELETE it, then re-read and VERIFY it's actually gone (the prod no-op guard).\n await client.removeLineItem(config.cart_id, target.id)\n const after = await client.getCart(config.cart_id)\n const afterItems = after.items ?? []\n const stillThere = afterItems.some((li: CartLineItemLike) => li.id === target.id)\n\n if (stillThere) {\n // honest failure — the server did NOT drop it. Never a fake ✓.\n return {\n lines: [\n fail({\n code: EXIT.GENERIC,\n what: `couldn't unstage \"${(target.title ?? target.product_title ?? args.itemId).toString()}\" — it's still in your cart.`,\n fix: \"check what's staged → bt cart (then try the # shown, or bt forget to clear)\",\n }),\n ],\n json: args.json ? { cart_id: after.id, removed: null, items: afterItems } : undefined,\n exitCode: EXIT.GENERIC, // the server didn't drop it → honest non-zero, never a fake success (B3)\n }\n }\n\n // 4. truly gone → the honest ✓ + the remaining tree.\n const removedTitle = (target.title ?? target.product_title ?? \"item\").toString()\n const lines: string[] = [ok(`unstaged ${removedTitle}.`)]\n if (afterItems.length === 0) {\n lines.push(empty(FRESH_REPO))\n lines.push(\" clean tree → bt browse\")\n } else {\n lines.push(\"still staged:\")\n afterItems.forEach((li: CartLineItemLike, i: number) => {\n lines.push(formatCartLine(li, i, after.currency_code))\n })\n }\n return {\n lines,\n json: args.json ? { cart_id: after.id, removed: target.id, items: afterItems } : undefined,\n }\n } catch (e) {\n if (e instanceof RecoverableCartError) {\n return {\n lines: [\n warn(\"that cart is no longer valid (expired or already committed).\"),\n empty(FRESH_REPO),\n \" re-stage → bt browse\",\n ],\n json: args.json ? { cart_id: null, removed: null, items: [] } : undefined,\n }\n }\n throw e\n }\n}\n\nexport function registerUnstage(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"unstage\")\n .alias(\"reset\")\n .argument(\"<ref>\", \"the staged item: its # (from bt cart), its line-item id, or its name\")\n .description(\"remove a staged item from the cart (git reset).\")\n .action(async (ref: string) => {\n const { json } = resolveOutput(program)\n const res = await runUnstage(makeClient(), loadConfig(), { itemId: ref, json })\n printResult(res, json)\n })\n}\n","// bt whoami — your contribution profile (VOICE §4.3).\n//\n// JWT-bound: the headless route returns the AUTHENTICATED customer's own minimal, PII-stripped\n// profile (G15 — tier/commits/badges, never email/address). Login is Wave 5, so today a guest\n// gets a 401 → we print the guest line + a connect hint (no crash). `--json` emits ONLY the\n// non-PII profile fields (G15), shaped for the \"bio-on-your-site\" crowd.\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { cyan, green, contributionBar, box, rule, type BrandStyle } from \"../brand\"\nimport { StoreApiError } from \"@binaryandthread/store-client\"\nimport { jwtExpiry } from \"../jwt\"\nimport { getToken } from \"../keychain\"\nimport type { StoreClient, BtConfigLike, WhoAmI } from \"./types-bridge\"\n\nexport interface WhoamiArgs extends Branded {\n json?: boolean\n /** an optional local handle (derived from the saved email's local-part) for the card headline. */\n handle?: string\n}\n\n// Standing % per tier (VOICE §4.1) — shown flatly, \"earned, not bought\".\nconst NEXT_TIER: Record<string, { at: number; name: string; pct: number }> = {\n contributor: { at: 5, name: \"maintainer\", pct: 10 },\n maintainer: { at: 20, name: \"core\", pct: 15 },\n core: { at: 0, name: \"core\", pct: 20 },\n}\n\n// The contribution bar fills to the core threshold — a full bar literally means you reached core.\nconst GRAPH_CAP = 20\nconst CARD_WIDTH = 58\n\n/**\n * The `bt whoami` contributor card (VOICE §4.3, brand-delight #1 — the screenshot flex). An\n * ASCII-framed card: a headline (handle · tier), the standing facts, and the green contribution\n * graph. The graph is HONEST — one green cell per real committed order (see contributionBar). The\n * card is deadpan: the flex is the green row + the standing, stated flatly, no exclamation.\n */\nfunction profileCard(p: WhoAmI, style: BrandStyle, handle?: string): string[] {\n const tier = p.bt_tier ?? \"contributor\"\n const commits = p.bt_commit_count ?? 0\n const next = NEXT_TIER[tier]\n const isMax = tier === \"core\" || !next\n const toNext = next && !isMax ? Math.max(0, next.at - commits) : 0\n const standing = p.standing_pct ?? NEXT_TIER[tier]?.pct ?? null\n\n const inner: string[] = []\n\n // headline — \"<handle> · <tier>\" (the handle is the saved email's local-part; omitted if guest).\n inner.push(`${handle ? `${handle} · ` : \"\"}${cyan(style, tier)}`)\n inner.push(rule(CARD_WIDTH - 1))\n\n // tier line — unambiguous \"N more to <tier>\" (B4: never reads as \"you've made N commits\").\n if (isMax) {\n inner.push(`tier ${tier.padEnd(13)}max standing — ${standing ?? 20}%`)\n } else {\n inner.push(`tier ${tier.padEnd(13)}${toNext} more commit${toNext === 1 ? \"\" : \"s\"} to ${next!.name}`)\n }\n\n // commits — say what it IS (orders committed), never an ambiguous \"shirts in the repo\".\n if (commits === 0) {\n inner.push(`commits ${String(commits).padEnd(13)}your repo's empty — everyone starts at 0`)\n } else {\n inner.push(`commits ${String(commits).padEnd(13)}order${commits === 1 ? \"\" : \"s\"} committed`)\n }\n\n if (standing != null) {\n inner.push(`standing ${cyan(style, `${standing}%`.padEnd(13))}applied at every commit`)\n }\n\n // the green contribution graph — the flex. One filled cell per real commit (honest).\n const bar = contributionBar(style, commits, GRAPH_CAP)\n const graphLabel = commits === 0 ? \"no commits yet\" : `${commits} contribution${commits === 1 ? \"\" : \"s\"}`\n inner.push(`graph ${bar} ${graphLabel}`)\n\n if (p.bt_badges && p.bt_badges.length > 0) {\n inner.push(`badges ${p.bt_badges.join(\" · \")}`)\n }\n if (p.bt_connected_at) {\n inner.push(`since contributor since ${p.bt_connected_at.slice(0, 10)}`)\n }\n\n // closing line — earned, not bought; the next step stated flatly (VOICE §4.3, B2).\n inner.push(rule(CARD_WIDTH - 1))\n if (isMax) {\n inner.push(`in ${green(style, \"AUTHORS\")}. earned, not bought.`)\n } else if (commits === 0) {\n inner.push(\"your first commit makes this worth screenshotting → bt browse\")\n } else {\n inner.push(`${toNext} more to ${next!.name} → bt browse · earned, not bought`)\n }\n\n return box(inner, { width: CARD_WIDTH, title: \"bt whoami\", style })\n}\n\n/** A display handle from the saved email's local-part (THEIR machine, THEIR data) — never sent. */\nfunction handleFromConfig(config: BtConfigLike): string | undefined {\n const email = config.email\n if (!email || typeof email !== \"string\") return undefined\n const local = email.split(\"@\")[0]?.trim()\n return local || undefined\n}\n\nexport async function runWhoami(\n client: StoreClient,\n config: BtConfigLike,\n args: WhoamiArgs,\n token?: string | null\n): Promise<HandlerResult> {\n const style = brandOf(args)\n const handle = args.handle ?? handleFromConfig(config)\n // Local token-expiry decode (no network, no signature check) — lets a script pre-flight auth\n // (\"is my token still valid / when does it lapse\") without a real mutation (d25).\n const { expiresAt, expired } = jwtExpiry(token)\n try {\n const me = await client.whoami()\n if (args.json) {\n // G15: emit ONLY the non-PII profile fields — never an email/address.\n return {\n lines: profileCard(me, style, handle),\n json: {\n authenticated: true,\n tier: me.bt_tier,\n commits: me.bt_commit_count,\n badges: me.bt_badges,\n standing_pct: me.standing_pct ?? null,\n connected_at: me.bt_connected_at,\n token_expires_at: expiresAt,\n token_expired: expired,\n },\n }\n }\n return { lines: profileCard(me, style, handle) }\n } catch (e) {\n if (e instanceof StoreApiError && (e.status === 401 || e.status === 403)) {\n // Not authenticated — guest guidance, never a crash. The token (if any) is invalid/expired.\n return {\n lines: [\n empty(\"you're browsing as a guest — not connected yet.\"),\n \" connect → bt login (the contributor on-ramp for this channel)\",\n ],\n json: args.json\n ? {\n authenticated: false,\n tier: null,\n connected: false,\n token_expires_at: expiresAt,\n token_expired: expired,\n }\n : undefined,\n }\n }\n throw e\n }\n}\n\nexport function registerWhoami(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"whoami\")\n .description(\"your contribution profile + standing.\")\n .action(async () => {\n const { json, brand } = resolveOutput(program)\n const res = await runWhoami(makeClient(), loadConfig(), { json, brand }, getToken())\n printResult(res, json)\n })\n}\n","// bt drops — what's on `next` before it hits the web `main` (VOICE §2.3, §4.4).\n//\n// A contributor perk: the terminal sees drops before the web does. Thin over listDrops; the\n// \"merges to main in <t>\" countdown is DERIVED from the server-provided `next_until` timestamp\n// (F-I5 — never computed authoritatively from the client clock). --vote is maintainer+ (Wave 5).\n\nimport type { Command } from \"commander\"\nimport { empty } from \"../voice\"\nimport { fmtPrice, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport type { StoreClient, BtConfigLike, DropRow } from \"./types-bridge\"\n\nexport interface DropsArgs {\n json?: boolean\n}\n\n/** A human \"merges to main in …\" string from the server-provided next_until (F-I5). */\nfunction mergesIn(nextUntil: string | null): string {\n if (!nextUntil) return \"on next\"\n const until = Date.parse(nextUntil)\n if (Number.isNaN(until)) return \"on next\"\n const ms = until - Date.now()\n if (ms <= 0) return \"merging now\"\n const hours = Math.round(ms / (60 * 60 * 1000))\n if (hours < 48) return `merges to main in ${hours}h`\n return `merges to main in ${Math.round(hours / 24)}d`\n}\n\nexport async function runDrops(\n client: StoreClient,\n config: BtConfigLike,\n args: DropsArgs\n): Promise<HandlerResult> {\n // Resolve the region so drop prices carry a currency (A6 — was a bare number in `null` currency).\n const region = await client.resolveRegion(config.region)\n const drops = await client.listDrops()\n\n if (!drops || drops.length === 0) {\n return {\n lines: [\n empty(\"nothing on next right now. main is the latest.\"),\n \" browse main → bt browse\",\n ],\n json: args.json ? { drops: [] } : undefined,\n }\n }\n\n const lines: string[] = [\"on next — terminal-only, not yet on the web:\"]\n for (const d of drops as DropRow[]) {\n lines.push(\n [\n ` ${(d.handle ?? d.id).padEnd(32)}`,\n fmtPrice(d.price, region.currency_code).padEnd(10),\n mergesIn(d.next_until),\n ].join(\" \").trimEnd()\n )\n }\n lines.push(\" first dibs → bt stage <slug> then bt checkout\")\n\n return {\n lines,\n json: args.json\n ? (drops as DropRow[]).map((d) => ({\n id: d.id,\n handle: d.handle,\n title: d.title,\n price: d.price,\n next_until: d.next_until,\n }))\n : undefined,\n }\n}\n\nexport function registerDrops(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"drops\")\n // `next` is an unambiguous alias for the customer view — avoids the singular/plural footgun\n // with the operator-only (hidden) `bt drop` (d20).\n .alias(\"next\")\n .description(\"what's on next before it hits the web.\")\n .action(async () => {\n const { json } = resolveOutput(program)\n const res = await runDrops(makeClient(), loadConfig(), { json })\n printResult(res, json)\n })\n}\n","// bt connect — the contributor on-ramp explainer.\n//\n// The real auth flow (OS-keychain token + `bt login`/`logout`) is SHIPPED (SECURITY G15: the token\n// never touches the plaintext config). `bt connect` is the explainer: it says what connecting\n// unlocks (standing, access to `next`, the wardrobe repo) and points at `bt login`, which owns the\n// flow. No network, no side effects — pure copy. (d7: copy must not imply login is \"coming soon\".)\n\nimport type { Command } from \"commander\"\nimport { printResult, resolveOutput, type HandlerResult } from \"./shared\"\n\nexport interface ConnectArgs {\n json?: boolean\n}\n\nexport async function runConnect(args: ConnectArgs): Promise<HandlerResult> {\n const lines = [\n \"connect your wardrobe — become a contributor.\",\n \" connecting authenticates you and unlocks:\",\n \" · 10% standing (applied at every commit)\",\n \" · access to next (drops before the web sees them)\",\n \" · your wardrobe repo + the contributor badge\",\n \"\",\n \" connect now → bt login\",\n \" (we email you a token to paste; it lives in your OS keychain, never in plaintext config.)\",\n ]\n return {\n lines,\n json: args.json ? { connected: false, login_command: \"bt login\" } : undefined,\n }\n}\n\nexport function registerConnect(program: Command): void {\n program\n .command(\"connect\")\n .description(\"the contributor on-ramp — what connecting unlocks. run bt login to connect.\")\n .action(async () => {\n const { json } = resolveOutput(program)\n const res = await runConnect({ json })\n printResult(res, json)\n })\n}\n","// bt login — the passwordless magic-link on-ramp (VOICE §2.1, SECURITY G1/G7/G10).\n//\n// Flow (no password, ever — G1):\n// 1. prompt for email → POST request-link (the backend emails a single-use TOKEN to paste)\n// 2. \"check your inbox — i'll wait\" → the user copies the token from the email\n// 3. the user PASTES the token at the stdin prompt → POST verify → the backend returns a JWT\n// 4. the JWT is stored in the OS keychain (@napi-rs/keyring — the maintained lib, NOT plaintext — G7);\n// the (non-sensitive) email is persisted in ~/.config/bt config so whoami knows who you are\n//\n// SECURITY: there is NO `--token` flag and the email carries the TOKEN (not a clickable URL) — a token\n// in argv lands in shell history + the process list, and a token in a URL lands in browser/proxy logs\n// (G10). The interactive stdin paste is the normal path; CI may set BT_MAGIC_TOKEN (env, not argv).\n//\n// runLogin is a PURE function of (client, prompts, keychain, args) → HandlerResult so it's unit\n// testable without a backend, a browser, or a human (ROBUSTNESS §4.1). bin.ts wires the real deps.\n\nimport type { Command } from \"commander\"\nimport { ok, warn, empty, GLYPH } from \"../voice\"\nimport { failResult, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport { StoreApiError } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\n/** The keychain surface login needs (injected for tests). */\nexport interface KeychainPort {\n setToken(jwt: string): void\n}\n\n/** The prompter surface login needs (injected for tests). */\nexport interface LoginPrompts {\n ask(label: string, opts?: { default?: string }): Promise<string>\n}\n\nexport interface LoginArgs {\n email?: string\n /** A token from the BT_MAGIC_TOKEN env (CI/non-interactive), skipping the stdin paste prompt.\n * NEVER a CLI flag — a token in argv leaks to shell history + the process list. */\n token?: string\n json?: boolean\n}\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport async function runLogin(\n client: StoreClient,\n prompts: LoginPrompts,\n keychain: KeychainPort,\n config: BtConfigLike,\n args: LoginArgs\n): Promise<HandlerResult> {\n // 0. JSON / non-interactive mode is a self-contained token EXCHANGE — it NEVER prompts (a readline\n // prompt on stdin would hang a pipe/CI/agent forever, and leak the prompt to stdout — B1). It\n // requires --email + a token in BT_MAGIC_TOKEN (obtained out-of-band via the interactive flow).\n if (args.json) {\n const jsonEmail = (args.email ?? \"\").trim()\n const jsonToken = (args.token ?? \"\").trim()\n if (!jsonEmail || !EMAIL_RE.test(jsonEmail) || !jsonToken) {\n return failResult({\n code: EXIT.DATAERR,\n what: \"login --json is non-interactive — it needs --email and a token in BT_MAGIC_TOKEN.\",\n fix: \"bt login --email you@dev.to with BT_MAGIC_TOKEN=<the token from the email>\",\n })\n }\n let jsonResult: { jwt: string; customer: { id: string } }\n try {\n jsonResult = await client.verifyMagicLink(jsonToken)\n } catch (e) {\n if (e instanceof StoreApiError && (e.status === 401 || e.status === 403)) {\n return failResult({ code: EXIT.NOPERM, what: \"that token is invalid or expired.\", fix: \"request a fresh one, then set BT_MAGIC_TOKEN\" })\n }\n if (e instanceof StoreApiError) {\n return failResult({ code: EXIT.TEMPFAIL, what: \"login couldn't complete right now.\", fix: \"try again in a moment\" })\n }\n throw e\n }\n keychain.setToken(jsonResult.jwt)\n return {\n lines: [ok(\"authenticated. welcome — you're a contributor now.\")],\n save: { email: jsonEmail },\n json: { connected: true, customer_id: jsonResult.customer.id },\n }\n }\n\n // 1. Resolve the email (arg → prompt → saved default).\n let email = (args.email ?? \"\").trim()\n if (!email) {\n email = (await prompts.ask(\"email\", { default: config.email })).trim()\n }\n if (!email || !EMAIL_RE.test(email)) {\n return {\n lines: [warn(\"that doesn't look like an email. try: bt login --email you@dev.to\")],\n }\n }\n\n // 2. Request the magic link (uniform ack — no enumeration, G12).\n try {\n await client.requestMagicLink(email)\n } catch (e) {\n if (e instanceof StoreApiError) {\n return { lines: [warn(\"couldn't start login right now. try again in a moment.\")] }\n }\n throw e\n }\n\n const waitLines = [\n ok(\"check your inbox — a single-use login token is on its way.\"),\n empty(\" no password. the token expires shortly. i'll wait.\"),\n empty(\" (we email a token to paste, not a clickable link — so it never lands in your shell history or a browser log.)\"),\n ]\n\n // 3. Accept the token: from BT_MAGIC_TOKEN (CI), else paste it from the email at the stdin prompt\n // (never a CLI flag — G10). The verify endpoint exchanges it for a customer-scoped JWT.\n let token = (args.token ?? \"\").trim()\n if (!token) {\n token = (await prompts.ask(\"paste the token from the email\")).trim()\n }\n if (!token) {\n return { lines: [...waitLines, \"\", warn(\"no token entered — run bt login again when you have the email.\")] }\n }\n\n let result: { jwt: string; customer: { id: string } }\n try {\n result = await client.verifyMagicLink(token)\n } catch (e) {\n if (e instanceof StoreApiError && (e.status === 401 || e.status === 403)) {\n return {\n lines: [...waitLines, \"\", warn(\"that link is invalid or expired. run bt login to get a fresh one.\")],\n }\n }\n if (e instanceof StoreApiError) {\n return { lines: [...waitLines, \"\", warn(\"login couldn't complete. try again.\")] }\n }\n throw e\n }\n\n // 4. Store the JWT in the OS keychain (NOT plaintext — G7). Persist the email (non-sensitive) so\n // whoami can greet you; the TOKEN never touches the config (config.ts strips it).\n keychain.setToken(result.jwt)\n\n return {\n lines: [\n ok(\"authenticated. welcome — you're a contributor now.\"),\n ` ${GLYPH.arrow} your token is in your OS keychain (never plaintext).`,\n ` ${GLYPH.arrow} see your standing → bt whoami`,\n ],\n save: { email },\n json: args.json ? { connected: true, customer_id: result.customer.id } : undefined,\n }\n}\n\nexport function registerLogin(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike,\n prompts: LoginPrompts,\n keychain: KeychainPort,\n persist: (patch: Partial<BtConfigLike>) => void\n): void {\n program\n .command(\"login\")\n .description(\"connect your wardrobe with a passwordless magic-link (no password, ever).\")\n .option(\"--email <email>\", \"your email (skips the prompt)\")\n // NO --token flag: a token on the command line lands in shell history + the process list (a leak\n // of a bearer credential). The interactive paste prompt (stdin, not in history) is the normal\n // path; for non-interactive/CI, set BT_MAGIC_TOKEN (env vars aren't in argv/history) — read below.\n .action(async (opts: { email?: string }) => {\n const { json } = resolveOutput(program)\n const envToken = process.env.BT_MAGIC_TOKEN?.trim() || undefined\n const res = await runLogin(makeClient(), prompts, keychain, loadConfig(), {\n email: opts.email,\n token: envToken,\n json,\n })\n if (res.save) {\n persist(res.save)\n }\n printResult(res, json)\n })\n}\n","// bt logout — clear the local session (SECURITY G7/G15).\n//\n// Deletes the keychain token (and the 0600 fallback). The customer JWT is STATELESS server-side\n// (Medusa, G7), so logout cannot invalidate a stolen token remotely — we DON'T claim it does. The\n// real revocation story is the SHORT TTL the backend issues (minutes) + a future jti denylist. We\n// state this plainly rather than over-promising (VOICE: honest, no mascot).\n//\n// runLogout is a PURE function of (keychain) → HandlerResult — no network needed (the token is local).\n\nimport type { Command } from \"commander\"\nimport { ok, empty } from \"../voice\"\nimport { printResult, resolveOutput, type HandlerResult } from \"./shared\"\n\n/** The keychain surface logout needs (injected for tests). */\nexport interface LogoutKeychainPort {\n deleteToken(): void\n}\n\nexport async function runLogout(keychain: LogoutKeychainPort): Promise<HandlerResult> {\n keychain.deleteToken()\n return {\n lines: [\n ok(\"logged out. your token is wiped from this machine's keychain.\"),\n empty(\" (server tokens are short-lived by design — they expire on their own.)\"),\n ],\n json: { logged_out: true },\n }\n}\n\nexport function registerLogout(\n program: Command,\n keychain: LogoutKeychainPort\n): void {\n program\n .command(\"logout\")\n .description(\"clear your local session (wipes the keychain token).\")\n .action(async () => {\n const { json } = resolveOutput(program)\n const res = await runLogout(keychain)\n printResult(res, json)\n })\n}\n","// bt drop — the OPERATOR-side drop family (REQ-DN13): create / verify / promote / retire.\n//\n// These are NOT customer commands — they wire to the backend `medusa exec` drop scripts (Task 2:\n// bt-drop.ts), which run against the catalog. Sam runs them from the backend repo (or a deploy box).\n// The CLI surface is a thin convenience that shells out to the matching npm script with env vars.\n//\n// We gate this behind an explicit operator flag (BT_OPERATOR=1) so a regular contributor's CLI never\n// exposes catalog mutation. The actual catalog safety (idempotent, web-touched-only-by-promote,\n// PAGE-on-bad-verify) lives in the backend script — the CLI just forwards intent.\n//\n// runDrop is a PURE function of (args, deps) → HandlerResult: the shell-exec is INJECTED so the\n// command is unit-testable without spawning a real medusa process (ROBUSTNESS §4.1).\n\nimport type { Command } from \"commander\"\nimport { ok, warn, working, empty } from \"../voice\"\nimport { failResult, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\n\nexport type DropSub = \"create\" | \"verify\" | \"promote\" | \"retire\"\n\n/** The exec port: run a backend npm script with env. Returns the exit code. Injected for tests. */\nexport interface DropExecPort {\n run(script: string, env: Record<string, string>): Promise<number>\n}\n\nexport interface DropArgs {\n sub?: string\n /** --motif <slug> for create. */\n motif?: string\n /** --drop-id <id> for all subcommands. */\n dropId?: string\n /** --stage main|next for verify (DROP_EXPECT_STAGE). */\n stage?: string\n /** operator gate (BT_OPERATOR=1). */\n operator?: boolean\n json?: boolean\n}\n\nconst SCRIPT: Record<DropSub, string> = {\n create: \"drop:create\",\n verify: \"drop:verify\",\n promote: \"drop:promote\",\n retire: \"drop:retire\",\n}\n\nexport async function runDrop(args: DropArgs, exec: DropExecPort): Promise<HandlerResult> {\n // Operator gate: catalog mutation is not a contributor capability.\n if (!args.operator) {\n return {\n lines: [\n warn(\"bt drop is an operator command (catalog mutation).\"),\n empty(\" run it from the backend with BT_OPERATOR=1, or use the backend npm scripts directly.\"),\n ],\n }\n }\n\n const sub = (args.sub ?? \"\").trim() as DropSub\n if (!sub || !SCRIPT[sub]) {\n return { lines: [warn(\"usage: bt drop <create|verify|promote|retire> --drop-id <id> [--motif <slug>]\")] }\n }\n if (!args.dropId || !args.dropId.trim()) {\n return { lines: [warn(`bt drop ${sub}: --drop-id <id> is required.`)] }\n }\n if (sub === \"create\" && (!args.motif || !args.motif.trim())) {\n return { lines: [warn(\"bt drop create: --motif <slug> is required.\")] }\n }\n\n const env: Record<string, string> = { DROP_ID: args.dropId.trim() }\n if (sub === \"create\" && args.motif) {\n env.MOTIF_SLUG = args.motif.trim()\n }\n if (sub === \"verify\" && args.stage) {\n env.DROP_EXPECT_STAGE = args.stage.trim()\n }\n\n const code = await exec.run(SCRIPT[sub], env)\n if (code !== 0) {\n return {\n lines: [warn(`drop ${sub} reported a problem (exit ${code}). check the backend logs / ops alert.`)],\n json: args.json ? { sub, drop_id: args.dropId, exit: code } : undefined,\n exitCode: code, // forward the backend's exit code so operator CI can branch on $? (B3)\n }\n }\n\n const done: Record<DropSub, string> = {\n create: \"drop created on next (terminal-only ~48h).\",\n verify: \"drop verified (visible to the channel, invisible to the web).\",\n promote: \"drop promoted next → main (it's on the web now).\",\n retire: \"drop retired (archived).\",\n }\n return {\n lines: [ok(done[sub])],\n json: args.json ? { sub, drop_id: args.dropId, exit: 0 } : undefined,\n }\n}\n\nexport function registerDrop(\n program: Command,\n exec: DropExecPort\n): void {\n program\n // Operator-only — hidden from the customer `--help` (d17). Still runs (BT_OPERATOR gate at\n // runtime), just undiscoverable to a regular contributor; also avoids the drop/drops footgun (d20).\n .command(\"drop\", { hidden: true })\n .argument(\"<sub>\", \"create | verify | promote | retire\")\n .option(\"--motif <slug>\", \"motif slug (create)\")\n .option(\"--drop-id <id>\", \"the drop id\")\n .option(\"--stage <stage>\", \"expected stage for verify (next|main)\")\n .description(\"operator: manage a drop's lifecycle (create/verify/promote/retire).\")\n .action(async (sub: string, opts: { motif?: string; dropId?: string; stage?: string }) => {\n const { json } = resolveOutput(program)\n const operator = process.env.BT_OPERATOR === \"1\"\n // The progress line is human chrome — never on stdout in --json mode (keeps it machine-clean).\n if (!json) process.stdout.write(working(`drop ${sub}…`) + \"\\n\")\n const res = await runDrop(\n { sub, motif: opts.motif, dropId: opts.dropId, stage: opts.stage, operator, json },\n exec\n )\n printResult(res, json)\n })\n}\n","// bt init — the first-run welcome + 3-command happy path (d3).\n//\n// New users had nothing guiding them (the critique's onboarding gap). Since the publishable key +\n// prod URL are baked in (d2), there is no setup — `bt init` just orients you and shows the path\n// from zero to a placed order. Pure copy; no network, no side effects. --json emits the happy path\n// so an agent can discover the flow programmatically.\n\nimport type { Command } from \"commander\"\nimport { brandOf, printResult, resolveOutput, type HandlerResult, type Branded } from \"./shared\"\nimport { header } from \"../brand\"\n\nexport interface InitArgs extends Branded {\n json?: boolean\n}\n\nconst HAPPY_PATH = [\"bt browse\", \"bt stage <handle> --size L\", \"bt checkout\"]\nconst DOCS_URL = \"https://binaryandthread.com/docs\"\n\nexport function runInit(args: InitArgs): HandlerResult {\n const style = brandOf(args)\n const lines = [\n header(style, \"bt — binary & thread, the terminal store\"),\n \" buy heavyweight pieces from your terminal. zero setup — you're already pointed at the live store.\",\n \"\",\n \" the happy path:\",\n \" bt browse # the catalog, numbered\",\n \" bt stage <n|slug> --size L # add to your cart (a browse number, or a slug)\",\n \" bt checkout # pay in your browser — cards never touch the terminal\",\n \"\",\n \" optional:\",\n \" bt login # contributor standing + order history\",\n \" bt whoami # your profile\",\n ` docs → ${DOCS_URL}`,\n ]\n return {\n lines,\n json: args.json ? { happy_path: HAPPY_PATH, docs: DOCS_URL, zero_setup: true } : undefined,\n }\n}\n\nexport function registerInit(program: Command): void {\n program\n .command(\"init\")\n .description(\"first-run welcome + the 3-command happy path.\")\n .action(async () => {\n const { json, brand } = resolveOutput(program)\n printResult(runInit({ json, brand }), json)\n })\n}\n","// bt buy <handle> — stage + checkout in one (d5).\n//\n// Referenced by `bt stage`'s output (\"or bt buy to do both\") but never existed → an unknown-command\n// error (the critique's \"the tool lies\"). This is the composition: runStage, then (if it staged\n// cleanly) runCheckout. Buying is explicit intent, so it proceeds WITHOUT the extra checkout confirm\n// (yes:true) — but the browser-hop is unchanged: cards never touch the terminal.\n\nimport type { Command } from \"commander\"\nimport { runStage } from \"./stage\"\nimport { runCheckout, heartbeatLine, type CheckoutDeps } from \"./checkout\"\nimport { printResult, resolveOutput } from \"./shared\"\nimport { dim } from \"../brand\"\nimport type { HandlerResult, Branded } from \"./shared\"\nimport type { StoreClient, BtConfigLike } from \"./types-bridge\"\n\nexport interface BuyArgs extends Branded {\n handle: string\n size?: string\n colour?: string\n json?: boolean\n}\n\nexport async function runBuy(\n client: StoreClient,\n config: BtConfigLike,\n args: BuyArgs,\n deps: CheckoutDeps\n): Promise<HandlerResult> {\n const staged = await runStage(client, config, {\n handle: args.handle,\n size: args.size,\n colour: args.colour,\n json: args.json,\n brand: args.brand,\n })\n // stage failed (variant not found / no cart) → surface its lines, NEVER proceed to checkout.\n const cartId = staged.save?.cart_id\n if (!cartId) {\n return staged\n }\n const checked = await runCheckout(\n client,\n { ...config, cart_id: cartId },\n { json: args.json, brand: args.brand, yes: true },\n deps\n )\n return {\n lines: [...staged.lines, \"\", ...checked.lines],\n save: { ...(staged.save ?? {}), ...(checked.save ?? {}) },\n json: args.json ? { cart_id: cartId, checkout: checked.json ?? null } : undefined,\n // forward the checkout outcome's exit code — bt buy runs the SAME money-path poll as bt\n // checkout, so a timed-out/failed composed checkout must not report success (d10).\n exitCode: checked.exitCode,\n }\n}\n\nexport function registerBuy(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n .command(\"buy\")\n .argument(\"<handle>\", \"the design: a slug, a bt browse number (3), or a fuzzy hint (termnl)\")\n .option(\"--size <size>\", \"garment size\")\n .option(\"--colour <colour>\", \"colour, e.g. white / black\")\n .description(\"stage + checkout in one — reserve, then open browser checkout. cards never touch the terminal.\")\n .action(async (handle: string, opts: { size?: string; colour?: string }) => {\n const { json, brand } = resolveOutput(program)\n const { makePrompts } = await import(\"../prompts\")\n const { openCheckout } = await import(\"../browser\")\n const { pollUntilPlaced } = await import(\"../poll\")\n const { saveConfig } = await import(\"../config\")\n const client = makeClient()\n const print = json ? () => {} : (line: string) => process.stdout.write(line + \"\\n\")\n const res = await runBuy(client, loadConfig(), { handle, size: opts.size, colour: opts.colour, json, brand }, {\n prompts: makePrompts(),\n open: (url) => openCheckout(url),\n // Same heartbeat as bt checkout — bt buy's browser-hop wait is the identical 20-min poll.\n poll: (sessionId) =>\n pollUntilPlaced(client, sessionId, {\n onTick: (attempt) => {\n const line = heartbeatLine(attempt)\n if (line) print(dim(brand, line))\n },\n }),\n saveConfig,\n print,\n })\n if (res.save && Object.keys(res.save).length > 0) {\n saveConfig(res.save)\n }\n printResult(res, json)\n })\n}\n","// bt config get/set — view or set local, NON-sensitive prefs (d6).\n//\n// Backs onto src/config.ts (the atomic store). Only the allowlisted keys are settable — the auth\n// TOKEN is NEVER stored in config (it lives in the OS keychain; config.ts strips it, G15). Setting\n// `email` lets order-lookup know who you are without a prompt each time.\n\nimport type { Command } from \"commander\"\nimport { ok, empty } from \"../voice\"\nimport { failResult, printResult, resolveOutput, type HandlerResult } from \"./shared\"\nimport { EXIT } from \"../errors\"\nimport type { BtConfig } from \"../config\"\n\nconst SETTABLE = [\"email\", \"region\", \"defaultSize\", \"defaultColour\", \"defaultBranch\"] as const\ntype SettableKey = (typeof SETTABLE)[number]\n\nexport interface ConfigDeps {\n load: () => BtConfig\n save: (patch: Partial<BtConfig>) => void\n}\n\nexport function runConfig(\n args: { sub?: string; key?: string; value?: string; json?: boolean },\n deps: ConfigDeps\n): HandlerResult {\n const cfg = deps.load()\n const sub = (args.sub ?? \"get\").toLowerCase()\n\n if (sub === \"get\") {\n if (args.key) {\n const v = (cfg as Record<string, unknown>)[args.key]\n return {\n lines: [v != null ? `${args.key} = ${String(v)}` : empty(`${args.key} is not set.`)],\n json: args.json ? { [args.key]: v ?? null } : undefined,\n }\n }\n const entries = Object.entries(cfg)\n const lines = entries.length\n ? entries.map(([k, v]) => `${k} = ${String(v)}`)\n : [empty(\"no local config set. (your auth token lives in the keychain, not here.)\")]\n return { lines, json: args.json ? cfg : undefined }\n }\n\n if (sub === \"set\") {\n if (!args.key || args.value == null || args.value === \"\") {\n return failResult({ code: EXIT.DATAERR, what: \"config set needs a key and a value.\", fix: \"bt config set <key> <value>\" })\n }\n if (!SETTABLE.includes(args.key as SettableKey)) {\n return failResult({\n code: EXIT.DATAERR,\n what: `can't set \"${args.key}\".`,\n fix: `settable keys: ${SETTABLE.join(\", \")} (the auth token is never stored in config — use bt login)`,\n })\n }\n deps.save({ [args.key]: args.value } as Partial<BtConfig>)\n return { lines: [ok(`set ${args.key} = ${args.value}`)], json: args.json ? { [args.key]: args.value } : undefined }\n }\n\n return failResult({ code: EXIT.DATAERR, what: `unknown config command \"${sub}\".`, fix: \"bt config get [key] | bt config set <key> <value>\" })\n}\n\nexport function registerConfig(program: Command): void {\n program\n .command(\"config\")\n .argument(\"[sub]\", \"get | set\", \"get\")\n .argument(\"[key]\", \"config key\")\n .argument(\"[value]\", \"value (for set)\")\n .description(\"view or set local prefs (email, region, defaults). the auth token is never stored here.\")\n .action(async (sub: string | undefined, key: string | undefined, value: string | undefined) => {\n const { json } = resolveOutput(program)\n const { loadConfig, saveConfig } = await import(\"../config\")\n const res = runConfig({ sub, key, value, json }, { load: loadConfig, save: saveConfig })\n printResult(res, json)\n })\n}\n","// bt doctor — local diagnostics for a bug report (d15). Sends NOTHING; reads only local state.\n//\n// Prints a redacted health snapshot (versions, the resolved store URL, whether a key/token is\n// present + the token's expiry, terminal capability) — the thing to paste into `bt report` or an\n// issue. The token itself is NEVER printed (only present/expiry). Pairs with the global --debug\n// flag (request tracing to stderr), wired in bin.ts via makeLogger.\n\nimport type { Command } from \"commander\"\nimport { ok, warn, empty } from \"../voice\"\nimport { printResult, type HandlerResult } from \"./shared\"\nimport { VERSION } from \"../version\"\nimport { resolveClientConfig } from \"../client-config\"\nimport { BT_DEFAULT_STORE_URL } from \"@binaryandthread/store-client\"\nimport { resolveBridgeToken } from \"./token\"\nimport { jwtExpiry } from \"../jwt\"\nimport { getToken } from \"../keychain\"\nimport { configPath } from \"../config\"\nimport * as fs from \"node:fs\"\n\nexport interface DoctorSnapshot {\n btVersion: string\n node: string\n platform: string\n storeUrl: string\n keySource: \"env\" | \"baked\"\n loggedIn: boolean\n tokenExpiresAt: string | null\n tokenExpired: boolean | null\n tty: boolean\n color: boolean\n configExists: boolean\n}\n\nexport function runDoctor(s: DoctorSnapshot, json?: boolean): HandlerResult {\n const auth = !s.loggedIn\n ? \"guest (not logged in)\"\n : s.tokenExpired\n ? `logged in but token EXPIRED${s.tokenExpiresAt ? ` (${s.tokenExpiresAt})` : \"\"} — run bt login`\n : `logged in${s.tokenExpiresAt ? ` · token valid until ${s.tokenExpiresAt}` : \"\"}`\n const lines = [\n ok(\"bt doctor — local checkup (nothing was sent)\"),\n ` bt ${s.btVersion}`,\n ` node ${s.node} · ${s.platform}`,\n // E4 — a friendly label for the production store; the raw URL only when pointed elsewhere\n // (local/staging), where it's genuinely diagnostic. The JSON snapshot keeps the raw URL.\n ` store ${s.storeUrl === BT_DEFAULT_STORE_URL ? \"binaryandthread.com (production)\" : s.storeUrl}`,\n ` key set (${s.keySource})`,\n ` auth ${auth}`,\n ` terminal ${s.tty ? \"tty\" : \"non-tty\"} · colour ${s.color ? \"on\" : \"off\"}`,\n ` config ${s.configExists ? configPath() : \"none yet\"}`,\n empty(\" paste this into bt report or an issue. re-run with --debug for request tracing.\"),\n ]\n return { lines, json: json ? { ...s } : undefined }\n}\n\n/**\n * Gather the local health snapshot — the redacted, non-sensitive diagnostics for a bug report. The\n * token itself is NEVER captured (only presence + expiry), so the snapshot is safe to attach to a\n * `bt report` (d14). Shared by `bt doctor` and `bt report`.\n */\nexport function gatherDoctorSnapshot(opts: { color?: boolean } = {}): DoctorSnapshot {\n const { baseUrl } = resolveClientConfig()\n const token = resolveBridgeToken(process.env, getToken())\n const exp = jwtExpiry(token)\n let configExists = false\n try {\n configExists = fs.existsSync(configPath())\n } catch {\n /* ignore */\n }\n return {\n btVersion: VERSION,\n node: process.versions.node,\n platform: `${process.platform}/${process.arch}`,\n storeUrl: baseUrl,\n keySource: process.env.BT_PUBLISHABLE_KEY || process.env.MEDUSA_PUBLISHABLE_KEY ? \"env\" : \"baked\",\n loggedIn: Boolean(token),\n tokenExpiresAt: exp.expiresAt,\n tokenExpired: exp.expired,\n tty: Boolean(process.stdout.isTTY),\n color: opts.color !== false && !process.env.NO_COLOR,\n configExists,\n }\n}\n\nexport function registerDoctor(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"local diagnostics for a bug report (sends nothing).\")\n .action(() => {\n const gOpts = program.opts() as { json?: boolean; color?: boolean }\n const json = Boolean(gOpts.json)\n const snapshot = gatherDoctorSnapshot({ color: gOpts.color })\n printResult(runDoctor(snapshot, json), json)\n })\n}\n","// bt report — file a bug report from the terminal (d14, decision #81 = email to the operator).\n//\n// The contributor on-ramp: filing an issue makes you a contributor. We attach the SAME local health\n// snapshot `bt doctor` prints (versions / store URL / auth state) as context — the token itself is\n// NEVER captured (only presence + expiry), so the snapshot is safe to send (G10/d15). The backend\n// re-redacts authoritatively before emailing. Sends NO cards, NO money path — purely additive.\n//\n// Flow: resolve the message (arg or prompt) → show what we'll attach + confirm → POST → print the\n// reference. --json / --yes auto-proceed (a hidden readline on a non-interactive stdin would hang —\n// d8). --debug echoes the full attached context.\n\nimport type { Command } from \"commander\"\nimport { ok, empty } from \"../voice\"\nimport { printResult, type HandlerResult } from \"./shared\"\nimport type { StoreClient } from \"./types-bridge\"\nimport { gatherDoctorSnapshot, type DoctorSnapshot } from \"./doctor\"\n\nexport interface ReportArgs {\n message?: string\n json?: boolean\n /** skip the confirm (scripts / CI / agents) — implied by --json. */\n yes?: boolean\n /** echo the full attached context. */\n debug?: boolean\n}\n\n/** The terminal prompts the flow needs. Injected so the flow is testable without a TTY. */\nexport interface ReportPrompts {\n ask(label: string, opts?: { default?: string }): Promise<string>\n confirm(label: string): Promise<boolean>\n}\n\nexport interface ReportDeps {\n prompts: ReportPrompts\n /** the redacted local health snapshot to attach as context (gatherDoctorSnapshot). */\n snapshot: DoctorSnapshot\n /** print a line EAGERLY (the preview must appear before the confirm prompt). Defaults to stdout. */\n print?(line: string): void\n}\n\n/** The client capability this command needs — typed structurally so the handler is testable. */\ninterface ReportClient {\n report(message: string, context?: Record<string, unknown>): Promise<{ reference: string }>\n}\n\nexport async function runReport(\n client: ReportClient,\n args: ReportArgs,\n deps: ReportDeps\n): Promise<HandlerResult> {\n // 1. resolve the message (arg → prompt). In --json we never prompt (non-interactive).\n let message = (args.message ?? \"\").trim()\n if (!message && !args.json) {\n message = (await deps.prompts.ask(\"what went wrong? (one line is fine)\")).trim()\n }\n if (!message) {\n return { lines: [empty(\"nothing to report — the message was empty. nothing was sent.\")] }\n }\n\n // 2. context = the redacted local snapshot (no token by construction — d15/G10).\n const context: Record<string, unknown> = { ...deps.snapshot }\n\n // 3. show what we'll attach + confirm. Skip the confirm under --json/--yes (d8): a hidden readline\n // on a non-interactive stdin blocks forever, and a report sends no money/PII so auto is safe.\n const print = deps.print ?? ((line: string) => process.stdout.write(line + \"\\n\"))\n const autoProceed = Boolean(args.json) || Boolean(args.yes)\n if (!autoProceed) {\n print(ok(\"bt report — about to send (tokens + emails are redacted server-side):\"))\n print(` message ${message}`)\n if (args.debug) {\n for (const [k, v] of Object.entries(context)) {\n print(` ${k.padEnd(11)} ${String(v)}`)\n }\n } else {\n print(\n ` context bt ${context.btVersion} · node ${context.node} · ${context.platform} · ${context.storeUrl}`\n )\n }\n const proceed = await deps.prompts.confirm(\"send this report? (y/n):\")\n if (!proceed) {\n return { lines: [empty(\"cancelled. nothing was sent.\")] }\n }\n }\n\n // 4. send + print the reference.\n const { reference } = await client.report(message, context)\n const lines = [ok(\"report filed. thank you — you're a contributor now.\"), ` ref ${reference}`]\n if (args.debug) {\n lines.push(empty(\" context attached:\"))\n for (const [k, v] of Object.entries(context)) {\n lines.push(` ${k.padEnd(11)} ${String(v)}`)\n }\n }\n return { lines, json: args.json ? { reference } : undefined }\n}\n\nexport function registerReport(program: Command, makeClient: () => StoreClient): void {\n program\n .command(\"report\")\n .argument(\"[message]\", \"what went wrong (omit to be prompted)\")\n .description(\"file a bug report — sends a redacted snapshot; never cards or tokens.\")\n .option(\"--yes\", \"skip the confirm (scripts / CI / agents); implied by --json\")\n .action(async (message: string | undefined, opts: { yes?: boolean }) => {\n const gOpts = program.opts() as { json?: boolean; color?: boolean }\n const json = Boolean(gOpts.json)\n const debug = process.argv.includes(\"--debug\") || process.argv.includes(\"--verbose\")\n const { makePrompts } = await import(\"../prompts\")\n const snapshot = gatherDoctorSnapshot({ color: gOpts.color })\n const res = await runReport(\n makeClient() as unknown as ReportClient,\n { message, json, yes: opts.yes, debug },\n { prompts: makePrompts(), snapshot }\n )\n printResult(res, json)\n })\n}\n","// bt blame <n|slug> — provenance. `git blame` for a design: who/what is responsible.\n//\n// Upgrades the old generic egg (which said \"a style × an idea, collided by hand\" because there was\n// no per-design lore) into REAL lore now that products carry metadata.lore (+ sources). With no\n// arg — or a design with no lore on record — it falls back to the generic provenance line (the egg\n// stays charming). Never a non-zero exit for the no-lore/no-arg case: blame is a delight, not a gate.\n\nimport type { Command } from \"commander\"\nimport { blame as genericBlame } from \"../eggs\"\nimport { working } from \"../voice\"\nimport {\n brandOf,\n displayName,\n printResult,\n resolveOutput,\n resolveProduct,\n type HandlerResult,\n type Branded,\n} from \"./shared\"\nimport { productLore } from \"@binaryandthread/store-client\"\nimport type { StoreClient, BtConfigLike, RegionLike } from \"./types-bridge\"\n\nexport interface BlameArgs extends Branded {\n handle?: string\n json?: boolean\n}\n\nexport async function runBlame(\n client: StoreClient,\n config: BtConfigLike,\n args: BlameArgs\n): Promise<HandlerResult> {\n const slug = (args.handle ?? \"\").trim()\n // no arg → the generic \"who's responsible for all this\" provenance. No fetch (the egg still works\n // offline / with zero setup).\n if (!slug) {\n return { lines: genericBlame().split(\"\\n\") }\n }\n\n const region: RegionLike = await client.resolveRegion(config.region)\n const picked = await resolveProduct(client, region, slug)\n const product = picked.product\n if (!product) {\n // couldn't resolve it → the generic per-subject provenance (never an error; blame is a delight).\n return { lines: genericBlame(slug).split(\"\\n\") }\n }\n\n const { handle } = displayName(product)\n const lore = productLore(product)\n const lines: string[] = []\n if (picked.fuzzy && handle !== slug) {\n lines.push(working(`matched \"${handle}\" from \"${slug}\"`))\n }\n\n if (!lore.text) {\n // resolved, but no lore on record yet → the generic per-design provenance.\n lines.push(...genericBlame(handle).split(\"\\n\"))\n return { lines, json: args.json ? { handle, lore: null } : undefined }\n }\n\n // the real thing: the story behind the design + its sources.\n lines.push(`blame ${handle}`)\n lines.push(` ${lore.text}`)\n for (const s of lore.sources) {\n lines.push(` source ${s.label} (${s.url})`)\n }\n return { lines, json: args.json ? { handle, lore } : undefined }\n}\n\nexport function registerBlame(\n program: Command,\n makeClient: () => StoreClient,\n loadConfig: () => BtConfigLike\n): void {\n program\n // Visible in --help: blame is a real content command now (the terminal way to read a design's\n // lore/provenance), not the generic egg it started as.\n .command(\"blame\")\n .argument(\"[slug]\", \"a design — a slug, a bt browse number, or a fuzzy hint\")\n .description(\"who's responsible for a design — its lore + sources (git blame, for motifs).\")\n .action(async (slug: string | undefined) => {\n const { json, brand } = resolveOutput(program)\n const res = await runBlame(makeClient(), loadConfig(), { handle: slug, json, brand })\n printResult(res, json)\n })\n}\n"],"mappings":"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","names":["fs","path","makeClient","loadConfig","rr","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makePrompts","saveConfig","makeClient","loadConfig","EMPTY_STATE","makeClient","loadConfig","makeClient","loadConfig","FRESH_REPO","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makeClient","loadConfig","makePrompts","saveConfig","loadConfig","saveConfig","fs","makeClient","makePrompts","makeClient","loadConfig"]}