@binaryandthread/cli 0.1.0 → 0.1.2
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/README.md +17 -16
- package/dist/bin.js +154 -85
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-DWTH7CNI.js → chunk-WYCZ6BPV.js} +180 -125
- package/dist/chunk-WYCZ6BPV.js.map +1 -0
- package/dist/{interactive-TFZOY3JU.js → interactive-DYY27KBC.js} +3 -5
- package/dist/{interactive-TFZOY3JU.js.map → interactive-DYY27KBC.js.map} +1 -1
- package/package.json +4 -4
- package/dist/brand-TMOYK6QE.js +0 -35
- package/dist/brand-TMOYK6QE.js.map +0 -1
- package/dist/chunk-DWTH7CNI.js.map +0 -1
- package/dist/chunk-P3LSUCEO.js +0 -120
- package/dist/chunk-P3LSUCEO.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
# @binaryandthread/cli
|
|
1
|
+
# @binaryandthread/cli, `bt`
|
|
2
2
|
|
|
3
|
-
Buy a Binary & Thread heavyweight
|
|
4
|
-
deploy. A small, well-tested client over the Store API
|
|
3
|
+
Buy a Binary & Thread heavyweight piece **from your terminal**, with the ceremony of a production
|
|
4
|
+
deploy. A small, well-tested client over the Store API, the card never touches the terminal.
|
|
5
5
|
|
|
6
6
|
> `bt` is a dumb client. Every dangerous operation (payment, fulfilment) lives in the backend.
|
|
7
7
|
> Checkout hands you a URL; you pay on the storefront's Stripe page in your own browser.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
-
Zero-config
|
|
11
|
+
Zero-config, it ships pointed at the live store (the publishable key is public by design):
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
#
|
|
15
|
-
npm i -g
|
|
14
|
+
# recommended: install globally for a persistent `bt` on your PATH
|
|
15
|
+
npm i -g @binaryandthread/cli
|
|
16
16
|
bt browse
|
|
17
17
|
|
|
18
|
-
# or
|
|
18
|
+
# or run without installing (no persistent command):
|
|
19
19
|
npx @binaryandthread/cli browse
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
A bare `bt` may collide with another binary on your `PATH
|
|
23
|
-
|
|
22
|
+
A bare `bt` may collide with another binary on your `PATH`. If it does, this package also installs
|
|
23
|
+
**`btn`** as an alias, `btn browse` works identically. (`npx @binaryandthread/cli …` is always the
|
|
24
|
+
unambiguous form.)
|
|
24
25
|
|
|
25
26
|
## Commands
|
|
26
27
|
|
|
@@ -28,7 +29,7 @@ unambiguous form.
|
|
|
28
29
|
| --- | --- |
|
|
29
30
|
| `bt browse` | the catalog (interactive ↑/↓ picker on a TTY; `--json` for scripts) |
|
|
30
31
|
| `bt search <q>` | filter the catalog |
|
|
31
|
-
| `bt view <handle>` | one
|
|
32
|
+
| `bt view <handle>` | one piece, specs + mockup (`--colour black` renders the black row) |
|
|
32
33
|
| `bt stage <handle>` | add to your cart (`--size`, `--colour`) |
|
|
33
34
|
| `bt cart` / `bt unstage <ref>` | show / remove a line |
|
|
34
35
|
| `bt checkout` | mint a checkout, hand off to the browser to pay, then poll |
|
|
@@ -37,22 +38,22 @@ unambiguous form.
|
|
|
37
38
|
| `bt drops` | terminal-visible drops |
|
|
38
39
|
| `bt forget` | wipe your local session + config (keychain token, cart, email) |
|
|
39
40
|
|
|
40
|
-
## Config (all optional
|
|
41
|
+
## Config (all optional, env overrides the baked-in prod defaults)
|
|
41
42
|
|
|
42
43
|
| var | notes |
|
|
43
44
|
| --- | --- |
|
|
44
45
|
| `BT_API_URL` | Store API base URL (default: production; set for local dev / staging) |
|
|
45
|
-
| `BT_PUBLISHABLE_KEY` | the **publishable** key
|
|
46
|
+
| `BT_PUBLISHABLE_KEY` | the **publishable** key, public by design (a secret `sk_` key is rejected) |
|
|
46
47
|
| `NO_COLOR` / `--no-color` | plain output, no ANSI / inline images |
|
|
47
48
|
| `--json` | machine-readable output for scripts / CI |
|
|
48
49
|
|
|
49
|
-
Your auth token is **never** stored in config
|
|
50
|
+
Your auth token is **never** stored in config, it lives in the OS keychain (`bt login`).
|
|
50
51
|
Local config (cart id, email, defaults) lives at `~/.config/bt/config.json`.
|
|
51
52
|
|
|
52
53
|
## Scripting: `--json` output & exit codes
|
|
53
54
|
|
|
54
55
|
Every command takes `--json` for stable, machine-readable output. `bt checkout --json` (or `--yes`)
|
|
55
|
-
skips the interactive confirm so it never hangs in CI. Field shapes (stable
|
|
56
|
+
skips the interactive confirm so it never hangs in CI. Field shapes (stable, safe to depend on):
|
|
56
57
|
|
|
57
58
|
| command | `--json` shape |
|
|
58
59
|
| --- | --- |
|
|
@@ -71,8 +72,8 @@ exits with a distinct code so CI/agents can branch:
|
|
|
71
72
|
| `0` | — | success |
|
|
72
73
|
| `65` | `client_error` / `stale_cart` | bad request / re-stage the cart |
|
|
73
74
|
| `69` | `not_found` | no such product/order |
|
|
74
|
-
| `75` | `rate_limited` / `upstream` | temporary
|
|
75
|
-
| `77` | `auth` | not logged in / forbidden
|
|
75
|
+
| `75` | `rate_limited` / `upstream` | temporary, retry later (a `429` is auto-retried honoring `Retry-After`) |
|
|
76
|
+
| `77` | `auth` | not logged in / forbidden, run `bt login` |
|
|
76
77
|
| `1` | `error` | anything else |
|
|
77
78
|
|
|
78
79
|
**Rate limits:** the client auto-retries `429` responses, honoring the server's `Retry-After`
|
package/dist/bin.js
CHANGED
|
@@ -15,39 +15,36 @@ import {
|
|
|
15
15
|
RecoverableCartError,
|
|
16
16
|
StoreApiError,
|
|
17
17
|
StoreClient,
|
|
18
|
+
box,
|
|
18
19
|
brandOf,
|
|
20
|
+
colourMarker,
|
|
21
|
+
contributionBar,
|
|
22
|
+
cyan,
|
|
23
|
+
dim,
|
|
19
24
|
displayName,
|
|
20
25
|
empty,
|
|
21
26
|
fail,
|
|
22
27
|
firstPrice,
|
|
23
28
|
fmtPrice,
|
|
24
29
|
formatCartLine,
|
|
30
|
+
green,
|
|
31
|
+
header,
|
|
25
32
|
lineColour,
|
|
26
33
|
ok,
|
|
27
34
|
printResult,
|
|
28
35
|
productColours,
|
|
29
36
|
redact,
|
|
30
|
-
registerBrowse,
|
|
31
37
|
registerStage,
|
|
32
38
|
registerView,
|
|
33
39
|
resolveLineItemRef,
|
|
40
|
+
resolveOutput,
|
|
41
|
+
rule,
|
|
34
42
|
runStage,
|
|
35
43
|
stageMarker,
|
|
36
44
|
versionLine,
|
|
37
45
|
warn,
|
|
38
46
|
working
|
|
39
|
-
} from "./chunk-
|
|
40
|
-
import {
|
|
41
|
-
box,
|
|
42
|
-
colourMarker,
|
|
43
|
-
contributionBar,
|
|
44
|
-
cyan,
|
|
45
|
-
dim,
|
|
46
|
-
green,
|
|
47
|
-
header,
|
|
48
|
-
makeBrand,
|
|
49
|
-
rule
|
|
50
|
-
} from "./chunk-P3LSUCEO.js";
|
|
47
|
+
} from "./chunk-WYCZ6BPV.js";
|
|
51
48
|
import {
|
|
52
49
|
__require
|
|
53
50
|
} from "./chunk-7OCVIDC7.js";
|
|
@@ -75,6 +72,9 @@ function makeLogger(debug, write = (s) => process.stderr.write(s)) {
|
|
|
75
72
|
};
|
|
76
73
|
}
|
|
77
74
|
|
|
75
|
+
// src/version.ts
|
|
76
|
+
var VERSION = "0.1.2";
|
|
77
|
+
|
|
78
78
|
// src/eggs.ts
|
|
79
79
|
function teapot() {
|
|
80
80
|
return `${GLYPH.fail} 418 i'm a teapot. we make clothing, not coffee. (RFC 2324)`;
|
|
@@ -297,6 +297,84 @@ function deleteToken(deps = {}) {
|
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
+
// src/commands/browse.ts
|
|
301
|
+
function productRow(p, stage, style) {
|
|
302
|
+
const { amount, currency } = firstPrice(p);
|
|
303
|
+
const { title, handle } = displayName(p);
|
|
304
|
+
const colours = colourMarker(productColours(p));
|
|
305
|
+
const parts = [
|
|
306
|
+
title.padEnd(22),
|
|
307
|
+
cyan(style, fmtPrice(amount, currency).padEnd(11)),
|
|
308
|
+
dim(style, handle.padEnd(34)),
|
|
309
|
+
stageMarker(stage)
|
|
310
|
+
];
|
|
311
|
+
const row = parts.join(" ").trimEnd();
|
|
312
|
+
return colours ? `${row}
|
|
313
|
+
${dim(style, colours)}` : row;
|
|
314
|
+
}
|
|
315
|
+
async function runBrowse(client, config, args) {
|
|
316
|
+
const style = brandOf(args);
|
|
317
|
+
const region = await client.resolveRegion(config.region);
|
|
318
|
+
const products = await client.listProducts({ region });
|
|
319
|
+
const rows = products.map((p) => ({
|
|
320
|
+
p,
|
|
321
|
+
stage: p.metadata?.["channel_stage"] ?? "main"
|
|
322
|
+
}));
|
|
323
|
+
let drops = [];
|
|
324
|
+
if (args.branch === "next") {
|
|
325
|
+
drops = await client.listDrops();
|
|
326
|
+
}
|
|
327
|
+
const lines = [];
|
|
328
|
+
if (rows.length === 0 && drops.length === 0) {
|
|
329
|
+
lines.push(empty("nothing in stock on this branch yet. main is the latest."));
|
|
330
|
+
lines.push(" peek at next \u2192 bt browse --branch=next");
|
|
331
|
+
} else {
|
|
332
|
+
lines.push(header(style, "bt browse \u2014 in stock"));
|
|
333
|
+
for (const { p, stage } of rows) {
|
|
334
|
+
lines.push(productRow(p, stage, style));
|
|
335
|
+
}
|
|
336
|
+
for (const d of drops) {
|
|
337
|
+
const dt = (d.title ?? d.handle ?? d.id).toString();
|
|
338
|
+
lines.push(
|
|
339
|
+
[
|
|
340
|
+
dt.padEnd(22),
|
|
341
|
+
cyan(style, fmtPrice(d.price, region.currency_code).padEnd(11)),
|
|
342
|
+
dim(style, (d.handle ?? d.id).padEnd(34)),
|
|
343
|
+
stageMarker(d.channel_stage)
|
|
344
|
+
].join(" ").trimEnd()
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
if (drops.length > 0) {
|
|
348
|
+
lines.push(" on next, before the web \u2192 bt drops");
|
|
349
|
+
}
|
|
350
|
+
lines.push(" view one \u2192 bt view <handle> \xB7 stage one \u2192 bt stage <handle> --size L");
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
lines,
|
|
354
|
+
json: args.json ? products.map((p) => ({
|
|
355
|
+
id: p.id,
|
|
356
|
+
handle: p.handle,
|
|
357
|
+
title: p.title,
|
|
358
|
+
price: firstPrice(p).amount,
|
|
359
|
+
currency: firstPrice(p).currency,
|
|
360
|
+
colours: productColours(p),
|
|
361
|
+
channel_stage: p.metadata?.["channel_stage"] ?? "main"
|
|
362
|
+
})) : void 0
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function registerBrowse(program, makeClient2, loadConfig2) {
|
|
366
|
+
program.command("browse").alias("ls").description("list what's in stock on a branch.").option("--branch <branch>", "main (live) or next (terminal-only drops)").option("--plain", "force the static table (skip the interactive picker)").action(async (opts) => {
|
|
367
|
+
const { json, brand } = resolveOutput(program);
|
|
368
|
+
if (!json && !opts.plain && brand.color && process.stdout.isTTY) {
|
|
369
|
+
const { runInteractiveBrowse } = await import("./interactive-DYY27KBC.js");
|
|
370
|
+
const handled = await runInteractiveBrowse(makeClient2(), loadConfig2(), { branch: opts.branch, brand });
|
|
371
|
+
if (handled) return;
|
|
372
|
+
}
|
|
373
|
+
const res = await runBrowse(makeClient2(), loadConfig2(), { branch: opts.branch, json, brand });
|
|
374
|
+
printResult(res, json);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
300
378
|
// src/commands/search.ts
|
|
301
379
|
function matches(p, q) {
|
|
302
380
|
const needle = q.toLowerCase();
|
|
@@ -343,9 +421,7 @@ async function runSearch(client, config, args) {
|
|
|
343
421
|
}
|
|
344
422
|
function registerSearch(program, makeClient2, loadConfig2) {
|
|
345
423
|
program.command("search").argument("<query>", "what to look for").description("filter the catalog by a query.").action(async (query) => {
|
|
346
|
-
const
|
|
347
|
-
const json = Boolean(gOpts.json);
|
|
348
|
-
const brand = json ? makeBrand({ noColor: true }) : makeBrand({ noColor: gOpts.color === false });
|
|
424
|
+
const { json, brand } = resolveOutput(program);
|
|
349
425
|
const res = await runSearch(makeClient2(), loadConfig2(), { query, json, brand });
|
|
350
426
|
printResult(res, json);
|
|
351
427
|
});
|
|
@@ -397,9 +473,7 @@ async function runCart(client, config, args) {
|
|
|
397
473
|
}
|
|
398
474
|
function registerCart(program, makeClient2, loadConfig2) {
|
|
399
475
|
program.command("cart").description("show your current cart \u2014 the authoritative server state.").action(async () => {
|
|
400
|
-
const
|
|
401
|
-
const json = Boolean(gOpts.json);
|
|
402
|
-
const brand = json ? makeBrand({ noColor: true }) : makeBrand({ noColor: gOpts.color === false });
|
|
476
|
+
const { json, brand } = resolveOutput(program);
|
|
403
477
|
const res = await runCart(makeClient2(), loadConfig2(), { json, brand });
|
|
404
478
|
printResult(res, json);
|
|
405
479
|
});
|
|
@@ -455,8 +529,30 @@ async function runCheckout(client, config, args, deps) {
|
|
|
455
529
|
if (!prompts) {
|
|
456
530
|
throw new Error("checkout requires a prompter");
|
|
457
531
|
}
|
|
532
|
+
let shippedCart;
|
|
533
|
+
try {
|
|
534
|
+
shippedCart = await client.ensureCartShippingMethod(cartId);
|
|
535
|
+
} catch (e) {
|
|
536
|
+
if (e instanceof RecoverableCartError) {
|
|
537
|
+
return {
|
|
538
|
+
lines: [
|
|
539
|
+
warn("that cart is no longer valid (expired or already committed)."),
|
|
540
|
+
" re-stage \u2192 bt browse then bt stage <slug>"
|
|
541
|
+
]
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
lines: [
|
|
546
|
+
fail({
|
|
547
|
+
code: 1,
|
|
548
|
+
what: "couldn't attach a shipping method to your cart.",
|
|
549
|
+
fix: "this region may not have shipping configured yet \u2014 try again shortly, or re-stage."
|
|
550
|
+
})
|
|
551
|
+
]
|
|
552
|
+
};
|
|
553
|
+
}
|
|
458
554
|
const itemCount = cart.items.reduce((n, li) => n + (li.quantity ?? 1), 0);
|
|
459
|
-
const totalLine = fmtPrice(cart.total, cart.currency_code ?? region.currency_code);
|
|
555
|
+
const totalLine = fmtPrice(shippedCart?.total ?? cart.total, cart.currency_code ?? region.currency_code);
|
|
460
556
|
const reviewLines = [header(style, "bt checkout \u2014 staged for commit")];
|
|
461
557
|
for (const li of cart.items) {
|
|
462
558
|
const colour = lineColour(li);
|
|
@@ -483,34 +579,33 @@ async function runCheckout(client, config, args, deps) {
|
|
|
483
579
|
}
|
|
484
580
|
const allowed = supportedCountries(region);
|
|
485
581
|
const shipsTo = (allowed[0] ?? "").toUpperCase();
|
|
582
|
+
const email = (config.email ?? "").trim();
|
|
583
|
+
const { checkout_url, session_id } = await client.mintCheckout(cartId, email || void 0, "cli");
|
|
584
|
+
const save = email ? { email } : {};
|
|
585
|
+
const opened = await deps.open(checkout_url);
|
|
586
|
+
for (const line of opened.lines) {
|
|
587
|
+
print(line);
|
|
588
|
+
}
|
|
589
|
+
print(" enter your details on the page \u2014 address + card. cards never touch the terminal.");
|
|
590
|
+
let outcome;
|
|
486
591
|
try {
|
|
487
|
-
await
|
|
488
|
-
} catch
|
|
489
|
-
if (e instanceof RecoverableCartError) {
|
|
490
|
-
return {
|
|
491
|
-
lines: [
|
|
492
|
-
warn("that cart is no longer valid (expired or already committed)."),
|
|
493
|
-
" re-stage \u2192 bt browse then bt stage <slug>"
|
|
494
|
-
]
|
|
495
|
-
};
|
|
496
|
-
}
|
|
592
|
+
outcome = await deps.poll(session_id);
|
|
593
|
+
} catch {
|
|
497
594
|
return {
|
|
498
595
|
lines: [
|
|
596
|
+
"",
|
|
499
597
|
fail({
|
|
500
|
-
code:
|
|
501
|
-
what: "
|
|
502
|
-
|
|
598
|
+
code: 75,
|
|
599
|
+
what: "lost the connection while waiting for your order to complete.",
|
|
600
|
+
money: "if you completed payment, your order is safe \u2014 we just couldn't confirm it here. check your email, or run bt order.",
|
|
601
|
+
fix: "bt checkout --resume (or open the link below manually)",
|
|
602
|
+
link: checkout_url
|
|
503
603
|
})
|
|
504
|
-
]
|
|
604
|
+
],
|
|
605
|
+
save
|
|
505
606
|
};
|
|
506
607
|
}
|
|
507
|
-
const
|
|
508
|
-
const { checkout_url, session_id } = await client.mintCheckout(cartId, email || void 0, "cli");
|
|
509
|
-
const save = email ? { email } : {};
|
|
510
|
-
const opened = await deps.open(checkout_url);
|
|
511
|
-
print(" enter your details on the page \u2014 address + card. cards never touch the terminal.");
|
|
512
|
-
const outcome = await deps.poll(session_id);
|
|
513
|
-
const lines = [...opened.lines];
|
|
608
|
+
const lines = [];
|
|
514
609
|
if (outcome.status === "placed") {
|
|
515
610
|
const displayId = await resolveDisplayId(client, outcome.order_id, email);
|
|
516
611
|
lines.push("");
|
|
@@ -577,9 +672,7 @@ function maskEmail(email) {
|
|
|
577
672
|
}
|
|
578
673
|
function registerCheckout(program, makeClient2, loadConfig2) {
|
|
579
674
|
const action = async (opts) => {
|
|
580
|
-
const
|
|
581
|
-
const json = Boolean(gOpts.json);
|
|
582
|
-
const brand = json ? makeBrand({ noColor: true }) : makeBrand({ noColor: gOpts.color === false });
|
|
675
|
+
const { json, brand } = resolveOutput(program);
|
|
583
676
|
const { makePrompts: makePrompts2 } = await import("./prompts-GTC5VYM6.js");
|
|
584
677
|
const { openCheckout } = await import("./browser-EO5EQUXQ.js");
|
|
585
678
|
const { pollUntilPlaced } = await import("./poll-O3VUD5WV.js");
|
|
@@ -666,9 +759,7 @@ async function runOrder(client, config, args) {
|
|
|
666
759
|
}
|
|
667
760
|
function registerOrder(program, makeClient2, loadConfig2) {
|
|
668
761
|
program.command("order").argument("<id>", "the order number (display id)").description("track one order: staged \u2192 committed \u2192 printed \u2192 shipped \u2192 delivered.").action(async (id) => {
|
|
669
|
-
const
|
|
670
|
-
const json = Boolean(gOpts.json);
|
|
671
|
-
const brand = json ? makeBrand({ noColor: true }) : makeBrand({ noColor: gOpts.color === false });
|
|
762
|
+
const { json, brand } = resolveOutput(program);
|
|
672
763
|
const res = await runOrder(makeClient2(), loadConfig2(), { displayId: id, json, brand });
|
|
673
764
|
printResult(res, json);
|
|
674
765
|
});
|
|
@@ -704,7 +795,7 @@ function resolveBridgeToken(env, keychainToken) {
|
|
|
704
795
|
}
|
|
705
796
|
function registerToken(program) {
|
|
706
797
|
program.command("token").description("print your keychain JWT for an MCP config (env BT_TOKEN). a bearer credential \u2014 handle with care.").action(() => {
|
|
707
|
-
const json =
|
|
798
|
+
const { json } = resolveOutput(program);
|
|
708
799
|
const token = resolveBridgeToken(process.env, getToken());
|
|
709
800
|
if (!token) {
|
|
710
801
|
process.stderr.write(empty("not logged in \u2014 run bt login first.") + "\n");
|
|
@@ -797,15 +888,14 @@ function renderFlat(orders) {
|
|
|
797
888
|
// src/commands/log.ts
|
|
798
889
|
var EMPTY_STATE2 = "no commits yet. your wardrobe is a fresh repo.";
|
|
799
890
|
async function runLog(client, config, args) {
|
|
800
|
-
const history = client;
|
|
801
891
|
const loggedIn = args.loggedIn ?? Boolean(config.email);
|
|
802
|
-
if (!loggedIn
|
|
892
|
+
if (!loggedIn) {
|
|
803
893
|
return {
|
|
804
894
|
lines: [empty(EMPTY_STATE2), " start one \u2192 bt browse"],
|
|
805
895
|
json: args.json ? { commits: [] } : void 0
|
|
806
896
|
};
|
|
807
897
|
}
|
|
808
|
-
const orders = await
|
|
898
|
+
const orders = await client.listOrders();
|
|
809
899
|
if (!orders || orders.length === 0) {
|
|
810
900
|
return {
|
|
811
901
|
lines: [empty(EMPTY_STATE2), " start one \u2192 bt browse"],
|
|
@@ -821,9 +911,7 @@ async function runLog(client, config, args) {
|
|
|
821
911
|
}
|
|
822
912
|
function registerLog(program, makeClient2, loadConfig2) {
|
|
823
913
|
program.command("log").option("--oneline", "compact one-line-per-order format").option("--graph", "graph format").description("your order history as a git log.").action(async (opts) => {
|
|
824
|
-
const
|
|
825
|
-
const json = Boolean(gOpts.json);
|
|
826
|
-
const brand = json ? makeBrand({ noColor: true }) : makeBrand({ noColor: gOpts.color === false });
|
|
914
|
+
const { json, brand } = resolveOutput(program);
|
|
827
915
|
const loggedIn = Boolean(resolveBridgeToken(process.env, getToken()));
|
|
828
916
|
const res = await runLog(makeClient2(), loadConfig2(), { oneline: opts.oneline, graph: opts.graph, json, loggedIn, brand });
|
|
829
917
|
printResult(res, json);
|
|
@@ -882,9 +970,7 @@ async function runStatus(client, config, args) {
|
|
|
882
970
|
}
|
|
883
971
|
function registerStatus(program, makeClient2, loadConfig2) {
|
|
884
972
|
program.command("status").description("working-tree state: what's staged, what's in flight.").action(async () => {
|
|
885
|
-
const
|
|
886
|
-
const json = Boolean(gOpts.json);
|
|
887
|
-
const brand = json ? makeBrand({ noColor: true }) : makeBrand({ noColor: gOpts.color === false });
|
|
973
|
+
const { json, brand } = resolveOutput(program);
|
|
888
974
|
const res = await runStatus(makeClient2(), loadConfig2(), { json, brand });
|
|
889
975
|
printResult(res, json);
|
|
890
976
|
});
|
|
@@ -899,15 +985,6 @@ async function runUnstage(client, config, args) {
|
|
|
899
985
|
json: args.json ? { cart_id: null, items: [] } : void 0
|
|
900
986
|
};
|
|
901
987
|
}
|
|
902
|
-
const remover = client;
|
|
903
|
-
if (typeof remover.removeLineItem !== "function") {
|
|
904
|
-
return {
|
|
905
|
-
lines: [
|
|
906
|
-
warn("unstage isn't wired to this client build yet."),
|
|
907
|
-
" for now: bt forget clears your local cart, or re-stage to overwrite."
|
|
908
|
-
]
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
988
|
try {
|
|
912
989
|
const before = await client.getCart(config.cart_id);
|
|
913
990
|
const beforeItems = before.items ?? [];
|
|
@@ -927,7 +1004,7 @@ async function runUnstage(client, config, args) {
|
|
|
927
1004
|
json: args.json ? { cart_id: before.id, removed: null, items: beforeItems } : void 0
|
|
928
1005
|
};
|
|
929
1006
|
}
|
|
930
|
-
await
|
|
1007
|
+
await client.removeLineItem(config.cart_id, target.id);
|
|
931
1008
|
const after = await client.getCart(config.cart_id);
|
|
932
1009
|
const afterItems = after.items ?? [];
|
|
933
1010
|
const stillThere = afterItems.some((li) => li.id === target.id);
|
|
@@ -973,7 +1050,7 @@ async function runUnstage(client, config, args) {
|
|
|
973
1050
|
}
|
|
974
1051
|
function registerUnstage(program, makeClient2, loadConfig2) {
|
|
975
1052
|
program.command("unstage").alias("reset").argument("<ref>", "the staged item: its # (from bt cart), its line-item id, or its name").description("remove a staged item from the cart (git reset).").action(async (ref) => {
|
|
976
|
-
const json =
|
|
1053
|
+
const { json } = resolveOutput(program);
|
|
977
1054
|
const res = await runUnstage(makeClient2(), loadConfig2(), { itemId: ref, json });
|
|
978
1055
|
printResult(res, json);
|
|
979
1056
|
});
|
|
@@ -1078,9 +1155,7 @@ async function runWhoami(client, config, args, token) {
|
|
|
1078
1155
|
}
|
|
1079
1156
|
function registerWhoami(program, makeClient2, loadConfig2) {
|
|
1080
1157
|
program.command("whoami").description("your contribution profile + standing.").action(async () => {
|
|
1081
|
-
const
|
|
1082
|
-
const json = Boolean(gOpts.json);
|
|
1083
|
-
const brand = json ? makeBrand({ noColor: true }) : makeBrand({ noColor: gOpts.color === false });
|
|
1158
|
+
const { json, brand } = resolveOutput(program);
|
|
1084
1159
|
const res = await runWhoami(makeClient2(), loadConfig2(), { json, brand }, getToken());
|
|
1085
1160
|
printResult(res, json);
|
|
1086
1161
|
});
|
|
@@ -1132,7 +1207,7 @@ async function runDrops(client, _config, args) {
|
|
|
1132
1207
|
}
|
|
1133
1208
|
function registerDrops(program, makeClient2, loadConfig2) {
|
|
1134
1209
|
program.command("drops").alias("next").description("what's on next before it hits the web.").action(async () => {
|
|
1135
|
-
const json =
|
|
1210
|
+
const { json } = resolveOutput(program);
|
|
1136
1211
|
const res = await runDrops(makeClient2(), loadConfig2(), { json });
|
|
1137
1212
|
printResult(res, json);
|
|
1138
1213
|
});
|
|
@@ -1157,7 +1232,7 @@ async function runConnect(args) {
|
|
|
1157
1232
|
}
|
|
1158
1233
|
function registerConnect(program) {
|
|
1159
1234
|
program.command("connect").description("the contributor on-ramp \u2014 what connecting unlocks. run bt login to connect.").action(async () => {
|
|
1160
|
-
const json =
|
|
1235
|
+
const { json } = resolveOutput(program);
|
|
1161
1236
|
const res = await runConnect({ json });
|
|
1162
1237
|
printResult(res, json);
|
|
1163
1238
|
});
|
|
@@ -1222,7 +1297,7 @@ async function runLogin(client, prompts, keychain, config, args) {
|
|
|
1222
1297
|
}
|
|
1223
1298
|
function registerLogin(program, makeClient2, loadConfig2, prompts, keychain, persist) {
|
|
1224
1299
|
program.command("login").description("connect your wardrobe with a passwordless magic-link (no password, ever).").option("--email <email>", "your email (skips the prompt)").action(async (opts) => {
|
|
1225
|
-
const json =
|
|
1300
|
+
const { json } = resolveOutput(program);
|
|
1226
1301
|
const envToken = process.env.BT_MAGIC_TOKEN?.trim() || void 0;
|
|
1227
1302
|
const res = await runLogin(makeClient2(), prompts, keychain, loadConfig2(), {
|
|
1228
1303
|
email: opts.email,
|
|
@@ -1310,7 +1385,7 @@ async function runDrop(args, exec) {
|
|
|
1310
1385
|
}
|
|
1311
1386
|
function registerDrop(program, exec) {
|
|
1312
1387
|
program.command("drop", { hidden: true }).argument("<sub>", "create | verify | promote | retire").option("--motif <slug>", "motif slug (create)").option("--drop-id <id>", "the drop id").option("--stage <stage>", "expected stage for verify (next|main)").description("operator: manage a drop's lifecycle (create/verify/promote/retire).").action(async (sub, opts) => {
|
|
1313
|
-
const json =
|
|
1388
|
+
const { json } = resolveOutput(program);
|
|
1314
1389
|
const operator = process.env.BT_OPERATOR === "1";
|
|
1315
1390
|
process.stdout.write(working(`drop ${sub}\u2026`) + "\n");
|
|
1316
1391
|
const res = await runDrop(
|
|
@@ -1351,10 +1426,7 @@ function runInit(args) {
|
|
|
1351
1426
|
}
|
|
1352
1427
|
function registerInit(program) {
|
|
1353
1428
|
program.command("init").description("first-run welcome + the 3-command happy path.").action(async () => {
|
|
1354
|
-
const
|
|
1355
|
-
const json = Boolean(gOpts.json);
|
|
1356
|
-
const { makeBrand: makeBrand2 } = await import("./brand-TMOYK6QE.js");
|
|
1357
|
-
const brand = json ? makeBrand2({ noColor: true }) : makeBrand2({ noColor: gOpts.color === false });
|
|
1429
|
+
const { json, brand } = resolveOutput(program);
|
|
1358
1430
|
printResult(runInit({ json, brand }), json);
|
|
1359
1431
|
});
|
|
1360
1432
|
}
|
|
@@ -1386,9 +1458,7 @@ async function runBuy(client, config, args, deps) {
|
|
|
1386
1458
|
}
|
|
1387
1459
|
function registerBuy(program, makeClient2, loadConfig2) {
|
|
1388
1460
|
program.command("buy").argument("<handle>", "the product handle/slug").option("--size <size>", "garment size").option("--colour <colour>", "colour, e.g. white / black").description("stage + checkout in one \u2014 reserve, then open browser checkout. cards never touch the terminal.").action(async (handle, opts) => {
|
|
1389
|
-
const
|
|
1390
|
-
const json = Boolean(gOpts.json);
|
|
1391
|
-
const brand = json ? makeBrand({ noColor: true }) : makeBrand({ noColor: gOpts.color === false });
|
|
1461
|
+
const { json, brand } = resolveOutput(program);
|
|
1392
1462
|
const { makePrompts: makePrompts2 } = await import("./prompts-GTC5VYM6.js");
|
|
1393
1463
|
const { openCheckout } = await import("./browser-EO5EQUXQ.js");
|
|
1394
1464
|
const { pollUntilPlaced } = await import("./poll-O3VUD5WV.js");
|
|
@@ -1446,7 +1516,7 @@ function runConfig(args, deps) {
|
|
|
1446
1516
|
}
|
|
1447
1517
|
function registerConfig(program) {
|
|
1448
1518
|
program.command("config").argument("[sub]", "get | set", "get").argument("[key]", "config key").argument("[value]", "value (for set)").description("view or set local prefs (email, region, defaults). the auth token is never stored here.").action(async (sub, key, value) => {
|
|
1449
|
-
const json =
|
|
1519
|
+
const { json } = resolveOutput(program);
|
|
1450
1520
|
const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await import("./config-FXGCWC6Y.js");
|
|
1451
1521
|
const res = runConfig({ sub, key, value, json }, { load: loadConfig2, save: saveConfig2 });
|
|
1452
1522
|
printResult(res, json);
|
|
@@ -1480,7 +1550,7 @@ function gatherDoctorSnapshot(opts = {}) {
|
|
|
1480
1550
|
} catch {
|
|
1481
1551
|
}
|
|
1482
1552
|
return {
|
|
1483
|
-
btVersion:
|
|
1553
|
+
btVersion: VERSION,
|
|
1484
1554
|
node: process.versions.node,
|
|
1485
1555
|
platform: `${process.platform}/${process.arch}`,
|
|
1486
1556
|
storeUrl: baseUrl,
|
|
@@ -1558,7 +1628,6 @@ function registerReport(program, makeClient2) {
|
|
|
1558
1628
|
}
|
|
1559
1629
|
|
|
1560
1630
|
// src/bin.ts
|
|
1561
|
-
var VERSION = "0.1.0";
|
|
1562
1631
|
function makeClient() {
|
|
1563
1632
|
const { baseUrl, publishableKey } = resolveClientConfig();
|
|
1564
1633
|
const jwt = resolveBridgeToken(process.env, getToken()) ?? void 0;
|