@binaryandthread/cli 0.3.1 → 0.4.0
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 +4 -4
- package/dist/bin.js +55 -34
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-ZNDKXHMV.js → chunk-T7MFWTB7.js} +2 -1
- package/dist/chunk-T7MFWTB7.js.map +1 -0
- package/dist/{chunk-VDOFLQ2P.js → chunk-X3RWS3AG.js} +298 -73
- package/dist/chunk-X3RWS3AG.js.map +1 -0
- package/dist/{config-GVEB4R7I.js → config-L4X7G563.js} +2 -2
- package/dist/{interactive-JALKLT56.js → interactive-VBATIHRD.js} +29 -11
- package/dist/interactive-VBATIHRD.js.map +1 -0
- package/dist/{poll-O3VUD5WV.js → poll-II3TVJLK.js} +2 -2
- package/dist/poll-II3TVJLK.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-VDOFLQ2P.js.map +0 -1
- package/dist/chunk-ZNDKXHMV.js.map +0 -1
- package/dist/interactive-JALKLT56.js.map +0 -1
- package/dist/poll-O3VUD5WV.js.map +0 -1
- /package/dist/{config-GVEB4R7I.js.map → config-L4X7G563.js.map} +0 -0
package/README.md
CHANGED
|
@@ -33,8 +33,8 @@ unambiguous form.)
|
|
|
33
33
|
| --- | --- |
|
|
34
34
|
| `bt browse` | the catalog as a numbered table (`bt stage <n>`); `--pick` opts into the ↑/↓ picker; `--json` for scripts |
|
|
35
35
|
| `bt search <q>` | filter the catalog |
|
|
36
|
-
| `bt view <n\|slug>` | one piece, specs + mockup (`--colour black` renders the black row) |
|
|
37
|
-
| `bt stage <n\|slug>` | add to your cart (`--size`, `--colour`) |
|
|
36
|
+
| `bt view <n\|slug>` | one piece, specs + mockup (`--colour black` renders the black row; `--fit oversize` shows the other fit of a two-fit design) |
|
|
37
|
+
| `bt stage <n\|slug>` | add to your cart (`--size`, `--colour`, `--fit regular\|oversize`; a design sold in both fits needs `--fit`, or `bt config set defaultFit …`) |
|
|
38
38
|
| `bt blame <n\|slug>` | the design's lore + sources (git blame, for motifs) |
|
|
39
39
|
| `bt cart` / `bt unstage <ref>` | show / remove a line |
|
|
40
40
|
| `bt checkout` | mint a checkout, hand off to the browser to pay, then poll |
|
|
@@ -70,8 +70,8 @@ skips the interactive confirm so it never hangs in CI. Field shapes (stable, saf
|
|
|
70
70
|
|
|
71
71
|
| command | `--json` shape |
|
|
72
72
|
| --- | --- |
|
|
73
|
-
| `bt browse` / `bt search` | `[{ id, handle, title, price, currency, colours[], channel_stage }]` |
|
|
74
|
-
| `bt view <handle>` | `{ id, handle, title,
|
|
73
|
+
| `bt browse` / `bt search` | `[{ id, handle, title, price, price_from, currency, colours[], fits[], channel_stage }]` (`price` is the cheapest fit when `price_from`) |
|
|
74
|
+
| `bt view <handle>` | `{ id, handle, title, fits[], fit, colours[], unavailable_colours[], specs, variants: [{ id, fit, colour, size, price, currency }] }` |
|
|
75
75
|
| `bt cart` | `{ cart_id, items: [{ id, title, colour, qty, total }], total, total_excludes_shipping }` |
|
|
76
76
|
| `bt checkout` | `{ status: "placed"\|"timeout"\|"expired", order_id?, display_id?, total?, currency?, checkout_url? }` |
|
|
77
77
|
| `bt region` | `{ region, currency, matched, home }` · `--list` → `{ regions: [{ currency, countries[] }] }` |
|
package/dist/bin.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
forgetConfig,
|
|
6
6
|
loadConfig,
|
|
7
7
|
saveConfig
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-T7MFWTB7.js";
|
|
9
9
|
import {
|
|
10
10
|
makePrompts
|
|
11
11
|
} from "./chunk-AAN4VWP3.js";
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
empty,
|
|
28
28
|
fail,
|
|
29
29
|
failResult,
|
|
30
|
-
firstPrice,
|
|
31
30
|
fmtPrice,
|
|
32
31
|
formatCartLine,
|
|
33
32
|
formatFatal,
|
|
@@ -36,8 +35,10 @@ import {
|
|
|
36
35
|
isCartTaxInclusive,
|
|
37
36
|
lineColour,
|
|
38
37
|
ok,
|
|
38
|
+
priceLine,
|
|
39
39
|
printResult,
|
|
40
40
|
productColours,
|
|
41
|
+
productFits,
|
|
41
42
|
productLore,
|
|
42
43
|
redact,
|
|
43
44
|
regionLine,
|
|
@@ -53,7 +54,7 @@ import {
|
|
|
53
54
|
versionLine,
|
|
54
55
|
warn,
|
|
55
56
|
working
|
|
56
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-X3RWS3AG.js";
|
|
57
58
|
import {
|
|
58
59
|
__require
|
|
59
60
|
} from "./chunk-7OCVIDC7.js";
|
|
@@ -102,7 +103,7 @@ function makeLogger(debug, write = (s) => process.stderr.write(s)) {
|
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
// src/version.ts
|
|
105
|
-
var VERSION = "0.
|
|
106
|
+
var VERSION = "0.4.0";
|
|
106
107
|
|
|
107
108
|
// src/eggs.ts
|
|
108
109
|
function teapot() {
|
|
@@ -418,15 +419,18 @@ function truncate(s, w) {
|
|
|
418
419
|
}
|
|
419
420
|
function layoutRows(rows, style) {
|
|
420
421
|
const cells = rows.map(({ p, stage }, i) => {
|
|
421
|
-
const { amount, currency } =
|
|
422
|
+
const { amount, currency, from } = priceLine(p);
|
|
422
423
|
const { title, handle } = displayName(p);
|
|
424
|
+
const fits = productFits(p);
|
|
425
|
+
const fitsMarker = fits.length > 1 ? fits.join(" \xB7 ") : "";
|
|
426
|
+
const colours = colourMarker(productColours(p));
|
|
423
427
|
return {
|
|
424
428
|
ref: `[${i + 1}]`,
|
|
425
429
|
title,
|
|
426
|
-
price: fmtPrice(amount, currency)
|
|
430
|
+
price: `${from ? "from " : ""}${fmtPrice(amount, currency)}`,
|
|
427
431
|
handle,
|
|
428
432
|
stage,
|
|
429
|
-
colours:
|
|
433
|
+
colours: [colours, fitsMarker].filter(Boolean).join(" ")
|
|
430
434
|
};
|
|
431
435
|
});
|
|
432
436
|
const refW = Math.max(...cells.map((c) => c.ref.length));
|
|
@@ -491,11 +495,14 @@ async function runBrowse(client, config, args) {
|
|
|
491
495
|
if (drops.length > 0) {
|
|
492
496
|
lines.push(" on next, before the web \u2192 bt drops");
|
|
493
497
|
}
|
|
494
|
-
const taxIncl = rows.length > 0 ?
|
|
498
|
+
const taxIncl = rows.length > 0 ? priceLine(rows[0].p).taxInclusive : null;
|
|
495
499
|
if (taxIncl === true) {
|
|
496
500
|
lines.push(dim(style, " prices incl. VAT"));
|
|
497
501
|
}
|
|
498
502
|
lines.push(" view one \u2192 bt view <n|slug> \xB7 stage one \u2192 bt stage <n|slug> --size L");
|
|
503
|
+
if (rows.some(({ p }) => productFits(p).length > 1)) {
|
|
504
|
+
lines.push(dim(style, " two fits? add --fit regular|oversize (or bt config set defaultFit \u2026)"));
|
|
505
|
+
}
|
|
499
506
|
}
|
|
500
507
|
return {
|
|
501
508
|
lines,
|
|
@@ -503,9 +510,11 @@ async function runBrowse(client, config, args) {
|
|
|
503
510
|
id: p.id,
|
|
504
511
|
handle: p.handle,
|
|
505
512
|
title: p.title,
|
|
506
|
-
price:
|
|
507
|
-
|
|
513
|
+
price: priceLine(p).amount,
|
|
514
|
+
price_from: priceLine(p).from,
|
|
515
|
+
currency: priceLine(p).currency,
|
|
508
516
|
colours: productColours(p),
|
|
517
|
+
fits: productFits(p),
|
|
509
518
|
channel_stage: p.metadata?.["channel_stage"] ?? "main"
|
|
510
519
|
})) : void 0
|
|
511
520
|
};
|
|
@@ -514,7 +523,7 @@ function registerBrowse(program, makeClient2, loadConfig2) {
|
|
|
514
523
|
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("--pick", "opt into the arrow-key picker (default is the numbered table \u2014 use bt stage <n>)").option("--plain", "force the static table (the default; kept for back-compat)").action(async (opts) => {
|
|
515
524
|
const { json, brand } = resolveOutput(program);
|
|
516
525
|
if (opts.pick && !json && brand.color && process.stdout.isTTY && process.stdin.isTTY) {
|
|
517
|
-
const { runInteractiveBrowse } = await import("./interactive-
|
|
526
|
+
const { runInteractiveBrowse } = await import("./interactive-VBATIHRD.js");
|
|
518
527
|
const handled = await runInteractiveBrowse(makeClient2(), loadConfig2(), { branch: opts.branch, brand });
|
|
519
528
|
if (handled) return;
|
|
520
529
|
}
|
|
@@ -677,13 +686,14 @@ async function runSearch(client, config, args) {
|
|
|
677
686
|
} else {
|
|
678
687
|
lines.push(header(style, `bt search "${args.query}"`));
|
|
679
688
|
for (const p of filtered) {
|
|
680
|
-
const { amount, currency } =
|
|
689
|
+
const { amount, currency, from } = priceLine(p);
|
|
681
690
|
const { title, handle } = displayName(p);
|
|
682
691
|
const stage = p.metadata?.["channel_stage"] ?? "main";
|
|
683
|
-
const
|
|
692
|
+
const fits = productFits(p);
|
|
693
|
+
const colours = [colourMarker(productColours(p)), fits.length > 1 ? fits.join(" \xB7 ") : ""].filter(Boolean).join(" ");
|
|
684
694
|
const row = [
|
|
685
695
|
title.padEnd(22),
|
|
686
|
-
cyan(style, fmtPrice(amount, currency)
|
|
696
|
+
cyan(style, `${from ? "from " : ""}${fmtPrice(amount, currency)}`.padEnd(11)),
|
|
687
697
|
dim(style, handle.padEnd(34)),
|
|
688
698
|
stageMarker(stage)
|
|
689
699
|
].join(" ").trimEnd();
|
|
@@ -698,9 +708,11 @@ async function runSearch(client, config, args) {
|
|
|
698
708
|
id: p.id,
|
|
699
709
|
handle: p.handle,
|
|
700
710
|
title: p.title,
|
|
701
|
-
price:
|
|
702
|
-
|
|
703
|
-
|
|
711
|
+
price: priceLine(p).amount,
|
|
712
|
+
price_from: priceLine(p).from,
|
|
713
|
+
currency: priceLine(p).currency,
|
|
714
|
+
colours: productColours(p),
|
|
715
|
+
fits: productFits(p)
|
|
704
716
|
})) : void 0
|
|
705
717
|
};
|
|
706
718
|
}
|
|
@@ -927,10 +939,16 @@ async function runCheckout(client, config, args, deps) {
|
|
|
927
939
|
lines.push(ok("deploy successful."));
|
|
928
940
|
lines.push(` committed to wardrobe@main`);
|
|
929
941
|
lines.push(` order #${displayId}`);
|
|
930
|
-
|
|
942
|
+
const settled = outcome.summary;
|
|
943
|
+
const finalTotal = settled?.total ?? mint.total ?? shippedCart?.total ?? cart.total;
|
|
944
|
+
const finalCurrency = settled?.currency_code ?? currency;
|
|
945
|
+
if (settled?.discount_total) {
|
|
946
|
+
const codes = settled.discount_codes.length ? ` (${settled.discount_codes.join(", ")})` : "";
|
|
947
|
+
lines.push(dim(style, ` discount${codes} \u2212${fmtPrice(settled.discount_total, finalCurrency)}`));
|
|
948
|
+
} else if (mint.discount && mint.discount.amount > 0) {
|
|
931
949
|
lines.push(dim(style, ` dev channel \u2212${fmtPrice(mint.discount.amount, currency)} (${mint.discount.pct}% \u2014 the terminal's cut for you)`));
|
|
932
950
|
}
|
|
933
|
-
lines.push(` total ${cyan(style,
|
|
951
|
+
lines.push(` total ${cyan(style, fmtPrice(finalTotal, finalCurrency))}${taxIncl ? " (incl. VAT)" : ""}`);
|
|
934
952
|
if (shipsTo) {
|
|
935
953
|
lines.push(` ships to ${shipsTo} \xB7 ~3\u20136 working days`);
|
|
936
954
|
} else {
|
|
@@ -947,11 +965,13 @@ async function runCheckout(client, config, args, deps) {
|
|
|
947
965
|
status: "placed",
|
|
948
966
|
order_id: outcome.order_id,
|
|
949
967
|
display_id: displayId,
|
|
950
|
-
// A2 — the
|
|
951
|
-
//
|
|
952
|
-
total: mint.total ?? shippedCart?.total ?? cart.total ?? null,
|
|
953
|
-
currency: mint.currency ?? cart.currency_code ?? region.currency_code ?? null,
|
|
954
|
-
discount: mint.discount ?? null
|
|
968
|
+
// A2/ENG-39 — the REAL settled total (every discount applied, incl. at payment); fall back
|
|
969
|
+
// to the mint estimate for an older backend. A --json / bt buy consumer gets the true amount.
|
|
970
|
+
total: settled?.total ?? mint.total ?? shippedCart?.total ?? cart.total ?? null,
|
|
971
|
+
currency: settled?.currency_code ?? mint.currency ?? cart.currency_code ?? region.currency_code ?? null,
|
|
972
|
+
discount: mint.discount ?? null,
|
|
973
|
+
// The full settled summary (subtotal, discount_total, promo codes, line items) when available.
|
|
974
|
+
summary: settled ?? null
|
|
955
975
|
} : void 0
|
|
956
976
|
};
|
|
957
977
|
}
|
|
@@ -1008,8 +1028,8 @@ function registerCheckout(program, makeClient2, loadConfig2) {
|
|
|
1008
1028
|
const { json, brand } = resolveOutput(program);
|
|
1009
1029
|
const { makePrompts: makePrompts2 } = await import("./prompts-DDVV5RE6.js");
|
|
1010
1030
|
const { openCheckout } = await import("./browser-WCNC4AWS.js");
|
|
1011
|
-
const { pollUntilPlaced } = await import("./poll-
|
|
1012
|
-
const { saveConfig: saveConfig2 } = await import("./config-
|
|
1031
|
+
const { pollUntilPlaced } = await import("./poll-II3TVJLK.js");
|
|
1032
|
+
const { saveConfig: saveConfig2 } = await import("./config-L4X7G563.js");
|
|
1013
1033
|
const client = makeClient2();
|
|
1014
1034
|
const print = json ? () => {
|
|
1015
1035
|
} : (line) => process.stdout.write(line + "\n");
|
|
@@ -1716,7 +1736,7 @@ function registerDrop(program, exec) {
|
|
|
1716
1736
|
}
|
|
1717
1737
|
|
|
1718
1738
|
// src/commands/init.ts
|
|
1719
|
-
var HAPPY_PATH = ["bt browse", "bt stage <handle> --size L", "bt checkout"];
|
|
1739
|
+
var HAPPY_PATH = ["bt browse", "bt stage <handle> --size L # add --fit regular|oversize for a two-fit design", "bt checkout"];
|
|
1720
1740
|
var DOCS_URL = "https://binaryandthread.com/docs";
|
|
1721
1741
|
function runInit(args) {
|
|
1722
1742
|
const style = brandOf(args);
|
|
@@ -1727,7 +1747,7 @@ function runInit(args) {
|
|
|
1727
1747
|
"",
|
|
1728
1748
|
" the happy path:",
|
|
1729
1749
|
" bt browse # the catalog, numbered",
|
|
1730
|
-
" bt stage <n|slug> --size L # add to your cart (a browse number, or a slug)",
|
|
1750
|
+
" bt stage <n|slug> --size L # add to your cart (a browse number, or a slug; --fit for a two-fit design)",
|
|
1731
1751
|
" bt checkout # pay in your browser \u2014 cards never touch the terminal (10% applied)",
|
|
1732
1752
|
"",
|
|
1733
1753
|
" ships worldwide \u2014 set your country so prices show your currency:",
|
|
@@ -1756,6 +1776,7 @@ async function runBuy(client, config, args, deps) {
|
|
|
1756
1776
|
handle: args.handle,
|
|
1757
1777
|
size: args.size,
|
|
1758
1778
|
colour: args.colour,
|
|
1779
|
+
fit: args.fit,
|
|
1759
1780
|
json: args.json,
|
|
1760
1781
|
brand: args.brand
|
|
1761
1782
|
});
|
|
@@ -1779,16 +1800,16 @@ async function runBuy(client, config, args, deps) {
|
|
|
1779
1800
|
};
|
|
1780
1801
|
}
|
|
1781
1802
|
function registerBuy(program, makeClient2, loadConfig2) {
|
|
1782
|
-
program.command("buy").argument("<handle>", "the design: a slug, a bt browse number (3), or a fuzzy hint (termnl)").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) => {
|
|
1803
|
+
program.command("buy").argument("<handle>", "the design: a slug, a bt browse number (3), or a fuzzy hint (termnl)").option("--size <size>", "garment size").option("--colour <colour>", "colour, e.g. white / black").option("--fit <fit>", "regular or oversize (required when a design comes in both)").description("stage + checkout in one \u2014 reserve, then open browser checkout. cards never touch the terminal.").action(async (handle, opts) => {
|
|
1783
1804
|
const { json, brand } = resolveOutput(program);
|
|
1784
1805
|
const { makePrompts: makePrompts2 } = await import("./prompts-DDVV5RE6.js");
|
|
1785
1806
|
const { openCheckout } = await import("./browser-WCNC4AWS.js");
|
|
1786
|
-
const { pollUntilPlaced } = await import("./poll-
|
|
1787
|
-
const { saveConfig: saveConfig2 } = await import("./config-
|
|
1807
|
+
const { pollUntilPlaced } = await import("./poll-II3TVJLK.js");
|
|
1808
|
+
const { saveConfig: saveConfig2 } = await import("./config-L4X7G563.js");
|
|
1788
1809
|
const client = makeClient2();
|
|
1789
1810
|
const print = json ? () => {
|
|
1790
1811
|
} : (line) => process.stdout.write(line + "\n");
|
|
1791
|
-
const res = await runBuy(client, loadConfig2(), { handle, size: opts.size, colour: opts.colour, json, brand }, {
|
|
1812
|
+
const res = await runBuy(client, loadConfig2(), { handle, size: opts.size, colour: opts.colour, fit: opts.fit, json, brand }, {
|
|
1792
1813
|
prompts: makePrompts2(),
|
|
1793
1814
|
open: (url) => openCheckout(url),
|
|
1794
1815
|
// Same heartbeat as bt checkout — bt buy's browser-hop wait is the identical 20-min poll.
|
|
@@ -1809,7 +1830,7 @@ function registerBuy(program, makeClient2, loadConfig2) {
|
|
|
1809
1830
|
}
|
|
1810
1831
|
|
|
1811
1832
|
// src/commands/config.ts
|
|
1812
|
-
var SETTABLE = ["email", "region", "defaultSize", "defaultColour", "defaultBranch"];
|
|
1833
|
+
var SETTABLE = ["email", "region", "defaultSize", "defaultColour", "defaultFit", "defaultBranch"];
|
|
1813
1834
|
function runConfig(args, deps) {
|
|
1814
1835
|
const cfg = deps.load();
|
|
1815
1836
|
const sub = (args.sub ?? "get").toLowerCase();
|
|
@@ -1844,7 +1865,7 @@ function runConfig(args, deps) {
|
|
|
1844
1865
|
function registerConfig(program) {
|
|
1845
1866
|
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) => {
|
|
1846
1867
|
const { json } = resolveOutput(program);
|
|
1847
|
-
const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await import("./config-
|
|
1868
|
+
const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await import("./config-L4X7G563.js");
|
|
1848
1869
|
const res = runConfig({ sub, key, value, json }, { load: loadConfig2, save: saveConfig2 });
|
|
1849
1870
|
printResult(res, json);
|
|
1850
1871
|
});
|