@binaryandthread/cli 0.2.0 → 0.3.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/dist/bin.js CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  versionLine,
54
54
  warn,
55
55
  working
56
- } from "./chunk-NJ3DW5AX.js";
56
+ } from "./chunk-RDJJLYXB.js";
57
57
  import {
58
58
  __require
59
59
  } from "./chunk-7OCVIDC7.js";
@@ -82,7 +82,7 @@ function makeLogger(debug, write = (s) => process.stderr.write(s)) {
82
82
  }
83
83
 
84
84
  // src/version.ts
85
- var VERSION = "0.2.0";
85
+ var VERSION = "0.3.0";
86
86
 
87
87
  // src/eggs.ts
88
88
  function teapot() {
@@ -222,7 +222,7 @@ function isMainModule(argv1, moduleUrl, realpath = realpathSync) {
222
222
  import * as fs from "fs";
223
223
  import * as path from "path";
224
224
  var CACHE_FILE = "update-check.json";
225
- var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
225
+ var CHECK_INTERVAL_MS = 6 * 60 * 60 * 1e3;
226
226
  var REGISTRY_LATEST = "https://registry.npmjs.org/@binaryandthread/cli/latest";
227
227
  var FETCH_TIMEOUT_MS = 2e3;
228
228
  function parseSemver(v) {
@@ -478,7 +478,7 @@ function registerBrowse(program, makeClient2, loadConfig2) {
478
478
  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) => {
479
479
  const { json, brand } = resolveOutput(program);
480
480
  if (opts.pick && !json && brand.color && process.stdout.isTTY && process.stdin.isTTY) {
481
- const { runInteractiveBrowse } = await import("./interactive-5PBJCENZ.js");
481
+ const { runInteractiveBrowse } = await import("./interactive-DJXIUVBM.js");
482
482
  const handled = await runInteractiveBrowse(makeClient2(), loadConfig2(), { branch: opts.branch, brand });
483
483
  if (handled) return;
484
484
  }
@@ -820,8 +820,13 @@ async function runCheckout(client, config, args, deps) {
820
820
  // fail-closed, no order placed → non-zero (matches the shown exit 1)
821
821
  };
822
822
  }
823
+ const email = (config.email ?? "").trim();
824
+ const mint = await client.mintCheckout(cartId, email || void 0, "cli");
825
+ const { checkout_url, session_id } = mint;
826
+ const save = email ? { email } : {};
827
+ const currency = mint.currency ?? cart.currency_code ?? region.currency_code;
823
828
  const itemCount = cart.items.reduce((n, li) => n + (li.quantity ?? 1), 0);
824
- const totalLine = fmtPrice(shippedCart?.total ?? cart.total, cart.currency_code ?? region.currency_code);
829
+ const totalLine = fmtPrice(mint.total ?? shippedCart?.total ?? cart.total, currency);
825
830
  const taxIncl = isCartTaxInclusive(cart);
826
831
  const reviewLines = [header(style, "bt checkout \u2014 staged for commit")];
827
832
  for (const li of cart.items) {
@@ -831,6 +836,11 @@ async function runCheckout(client, config, args, deps) {
831
836
  ` ${(li.title ?? li.product_title ?? "item").toString()}${colourTag} \xB7 qty ${li.quantity}` + (li.total != null ? ` ${cyan(style, fmtPrice(li.total, cart.currency_code ?? region.currency_code))}` : "")
832
837
  );
833
838
  }
839
+ if (mint.discount && mint.discount.amount > 0) {
840
+ reviewLines.push(
841
+ dim(style, ` dev channel \u2212${fmtPrice(mint.discount.amount, currency)} (${mint.discount.pct}% \u2014 for shopping the terminal)`)
842
+ );
843
+ }
834
844
  reviewLines.push(` total ${cyan(style, totalLine)}${taxSuffix(taxIncl)}`);
835
845
  const print = deps.print ?? ((line) => process.stdout.write(line + "\n"));
836
846
  for (const line of reviewLines) {
@@ -849,9 +859,6 @@ async function runCheckout(client, config, args, deps) {
849
859
  }
850
860
  const allowed = supportedCountries(region);
851
861
  const shipsTo = (allowed[0] ?? "").toUpperCase();
852
- const email = (config.email ?? "").trim();
853
- const { checkout_url, session_id } = await client.mintCheckout(cartId, email || void 0, "cli");
854
- const save = email ? { email } : {};
855
862
  const opened = await deps.open(checkout_url);
856
863
  for (const line of opened.lines) {
857
864
  print(line);
@@ -884,6 +891,9 @@ async function runCheckout(client, config, args, deps) {
884
891
  lines.push(ok("deploy successful."));
885
892
  lines.push(` committed to wardrobe@main`);
886
893
  lines.push(` order #${displayId}`);
894
+ if (mint.discount && mint.discount.amount > 0) {
895
+ lines.push(dim(style, ` dev channel \u2212${fmtPrice(mint.discount.amount, currency)} (${mint.discount.pct}% \u2014 the terminal's cut for you)`));
896
+ }
887
897
  lines.push(` total ${cyan(style, totalLine)}${taxIncl ? " (incl. VAT)" : ""}`);
888
898
  if (shipsTo) {
889
899
  lines.push(` ships to ${shipsTo} \xB7 ~3\u20136 working days`);
@@ -901,10 +911,11 @@ async function runCheckout(client, config, args, deps) {
901
911
  status: "placed",
902
912
  order_id: outcome.order_id,
903
913
  display_id: displayId,
904
- // A2 — the SHIPPING-INCLUSIVE total the buyer consented to (same figure as the review),
905
- // so a --json / bt buy consumer has the real amount, not just a status.
906
- total: shippedCart?.total ?? cart.total ?? null,
907
- currency: cart.currency_code ?? region.currency_code ?? null
914
+ // A2 — the SHIPPING-INCLUSIVE, dev-channel-discounted total the buyer consented to (same
915
+ // figure as the review), so a --json / bt buy consumer has the real amount, not just a status.
916
+ total: mint.total ?? shippedCart?.total ?? cart.total ?? null,
917
+ currency: mint.currency ?? cart.currency_code ?? region.currency_code ?? null,
918
+ discount: mint.discount ?? null
908
919
  } : void 0
909
920
  };
910
921
  }
@@ -1348,52 +1359,31 @@ function registerUnstage(program, makeClient2, loadConfig2) {
1348
1359
  }
1349
1360
 
1350
1361
  // src/commands/whoami.ts
1351
- var NEXT_TIER = {
1352
- contributor: { at: 5, name: "maintainer", pct: 10 },
1353
- maintainer: { at: 20, name: "core", pct: 15 },
1354
- core: { at: 0, name: "core", pct: 20 }
1355
- };
1362
+ var DEV_CHANNEL_PCT = 10;
1356
1363
  var GRAPH_CAP = 20;
1357
1364
  var CARD_WIDTH = 58;
1358
1365
  function profileCard(p, style, handle) {
1359
- const tier = p.bt_tier ?? "contributor";
1360
1366
  const commits = p.bt_commit_count ?? 0;
1361
- const next = NEXT_TIER[tier];
1362
- const isMax = tier === "core" || !next;
1363
- const toNext = next && !isMax ? Math.max(0, next.at - commits) : 0;
1364
- const standing = p.standing_pct ?? NEXT_TIER[tier]?.pct ?? null;
1365
1367
  const inner = [];
1366
- inner.push(`${handle ? `${handle} \xB7 ` : ""}${cyan(style, tier)}`);
1368
+ inner.push(`${handle ? `${handle} \xB7 ` : ""}${cyan(style, "terminal")}`);
1367
1369
  inner.push(rule(CARD_WIDTH - 1));
1368
- if (isMax) {
1369
- inner.push(`tier ${tier.padEnd(13)}max standing \u2014 ${standing ?? 20}%`);
1370
- } else {
1371
- inner.push(`tier ${tier.padEnd(13)}${toNext} more commit${toNext === 1 ? "" : "s"} to ${next.name}`);
1372
- }
1373
1370
  if (commits === 0) {
1374
- inner.push(`commits ${String(commits).padEnd(13)}your repo's empty \u2014 everyone starts at 0`);
1371
+ inner.push(`orders ${String(commits).padEnd(13)}your repo's empty \u2014 everyone starts at 0`);
1375
1372
  } else {
1376
- inner.push(`commits ${String(commits).padEnd(13)}order${commits === 1 ? "" : "s"} committed`);
1377
- }
1378
- if (standing != null) {
1379
- inner.push(`standing ${cyan(style, `${standing}%`.padEnd(13))}applied at every commit`);
1373
+ inner.push(`orders ${String(commits).padEnd(13)}committed`);
1380
1374
  }
1375
+ inner.push(`discount ${cyan(style, `${DEV_CHANNEL_PCT}%`.padEnd(13))}off every order \u2014 for shopping the terminal`);
1381
1376
  const bar = contributionBar(style, commits, GRAPH_CAP);
1382
1377
  const graphLabel = commits === 0 ? "no commits yet" : `${commits} contribution${commits === 1 ? "" : "s"}`;
1383
1378
  inner.push(`graph ${bar} ${graphLabel}`);
1384
- if (p.bt_badges && p.bt_badges.length > 0) {
1385
- inner.push(`badges ${p.bt_badges.join(" \xB7 ")}`);
1386
- }
1387
1379
  if (p.bt_connected_at) {
1388
- inner.push(`since contributor since ${p.bt_connected_at.slice(0, 10)}`);
1380
+ inner.push(`since connected ${p.bt_connected_at.slice(0, 10)}`);
1389
1381
  }
1390
1382
  inner.push(rule(CARD_WIDTH - 1));
1391
- if (isMax) {
1392
- inner.push(`in ${green(style, "AUTHORS")}. earned, not bought.`);
1393
- } else if (commits === 0) {
1383
+ if (commits === 0) {
1394
1384
  inner.push("your first commit makes this worth screenshotting \u2192 bt browse");
1395
1385
  } else {
1396
- inner.push(`${toNext} more to ${next.name} \u2192 bt browse \xB7 earned, not bought`);
1386
+ inner.push(`in ${green(style, "AUTHORS")}. earned, not bought.`);
1397
1387
  }
1398
1388
  return box(inner, { width: CARD_WIDTH, title: "bt whoami", style });
1399
1389
  }
@@ -1414,10 +1404,8 @@ async function runWhoami(client, config, args, token) {
1414
1404
  lines: profileCard(me, style, handle),
1415
1405
  json: {
1416
1406
  authenticated: true,
1417
- tier: me.bt_tier,
1418
- commits: me.bt_commit_count,
1419
- badges: me.bt_badges,
1420
- standing_pct: me.standing_pct ?? null,
1407
+ orders: me.bt_commit_count ?? 0,
1408
+ discount_pct: DEV_CHANNEL_PCT,
1421
1409
  connected_at: me.bt_connected_at,
1422
1410
  token_expires_at: expiresAt,
1423
1411
  token_expired: expired
@@ -1430,11 +1418,10 @@ async function runWhoami(client, config, args, token) {
1430
1418
  return {
1431
1419
  lines: [
1432
1420
  empty("you're browsing as a guest \u2014 not connected yet."),
1433
- " connect \u2192 bt login (the contributor on-ramp for this channel)"
1421
+ " connect \u2192 bt login (order history + a persistent cart; the terminal's 10% applies either way)"
1434
1422
  ],
1435
1423
  json: args.json ? {
1436
1424
  authenticated: false,
1437
- tier: null,
1438
1425
  connected: false,
1439
1426
  token_expires_at: expiresAt,
1440
1427
  token_expired: expired
@@ -1445,7 +1432,7 @@ async function runWhoami(client, config, args, token) {
1445
1432
  }
1446
1433
  }
1447
1434
  function registerWhoami(program, makeClient2, loadConfig2) {
1448
- program.command("whoami").description("your contribution profile + standing.").action(async () => {
1435
+ program.command("whoami").description("your profile + order history.").action(async () => {
1449
1436
  const { json, brand } = resolveOutput(program);
1450
1437
  const res = await runWhoami(makeClient2(), loadConfig2(), { json, brand }, getToken());
1451
1438
  printResult(res, json);
@@ -1505,31 +1492,6 @@ function registerDrops(program, makeClient2, loadConfig2) {
1505
1492
  });
1506
1493
  }
1507
1494
 
1508
- // src/commands/connect.ts
1509
- async function runConnect(args) {
1510
- const lines = [
1511
- "connect your wardrobe \u2014 become a contributor.",
1512
- " connecting authenticates you and unlocks:",
1513
- " \xB7 10% standing (applied at every commit)",
1514
- " \xB7 access to next (drops before the web sees them)",
1515
- " \xB7 your wardrobe repo + the contributor badge",
1516
- "",
1517
- " connect now \u2192 bt login",
1518
- " (we email you a token to paste; it lives in your OS keychain, never in plaintext config.)"
1519
- ];
1520
- return {
1521
- lines,
1522
- json: args.json ? { connected: false, login_command: "bt login" } : void 0
1523
- };
1524
- }
1525
- function registerConnect(program) {
1526
- program.command("connect").description("the contributor on-ramp \u2014 what connecting unlocks. run bt login to connect.").action(async () => {
1527
- const { json } = resolveOutput(program);
1528
- const res = await runConnect({ json });
1529
- printResult(res, json);
1530
- });
1531
- }
1532
-
1533
1495
  // src/commands/login.ts
1534
1496
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1535
1497
  async function runLogin(client, prompts, keychain, config, args) {
@@ -1557,7 +1519,7 @@ async function runLogin(client, prompts, keychain, config, args) {
1557
1519
  }
1558
1520
  keychain.setToken(jsonResult.jwt);
1559
1521
  return {
1560
- lines: [ok("authenticated. welcome \u2014 you're a contributor now.")],
1522
+ lines: [ok("authenticated. welcome back.")],
1561
1523
  save: { email: jsonEmail },
1562
1524
  json: { connected: true, customer_id: jsonResult.customer.id }
1563
1525
  };
@@ -1608,9 +1570,9 @@ async function runLogin(client, prompts, keychain, config, args) {
1608
1570
  keychain.setToken(result.jwt);
1609
1571
  return {
1610
1572
  lines: [
1611
- ok("authenticated. welcome \u2014 you're a contributor now."),
1573
+ ok("authenticated. welcome back."),
1612
1574
  ` ${GLYPH.arrow} your token is in your OS keychain (never plaintext).`,
1613
- ` ${GLYPH.arrow} see your standing \u2192 bt whoami`
1575
+ ` ${GLYPH.arrow} your profile \u2192 bt whoami \xB7 order history \u2192 bt log`
1614
1576
  ],
1615
1577
  save: { email },
1616
1578
  json: args.json ? { connected: true, customer_id: result.customer.id } : void 0
@@ -1725,20 +1687,24 @@ function runInit(args) {
1725
1687
  const lines = [
1726
1688
  header(style, "bt \u2014 binary & thread, the terminal store"),
1727
1689
  " buy heavyweight pieces from your terminal. zero setup \u2014 you're already pointed at the live store.",
1690
+ " shopping here is 10% off the web \u2014 always, applied at checkout. no code, no login.",
1728
1691
  "",
1729
1692
  " the happy path:",
1730
1693
  " bt browse # the catalog, numbered",
1731
1694
  " bt stage <n|slug> --size L # add to your cart (a browse number, or a slug)",
1732
- " bt checkout # pay in your browser \u2014 cards never touch the terminal",
1695
+ " bt checkout # pay in your browser \u2014 cards never touch the terminal (10% applied)",
1696
+ "",
1697
+ " ships worldwide \u2014 set your country so prices show your currency:",
1698
+ " bt region <cc> # e.g. se / us / de \xB7 see all \u2192 bt region --list",
1733
1699
  "",
1734
1700
  " optional:",
1735
- " bt login # contributor standing + order history",
1701
+ " bt login # order history + a persistent cart",
1736
1702
  " bt whoami # your profile",
1737
1703
  ` docs \u2192 ${DOCS_URL}`
1738
1704
  ];
1739
1705
  return {
1740
1706
  lines,
1741
- json: args.json ? { happy_path: HAPPY_PATH, docs: DOCS_URL, zero_setup: true } : void 0
1707
+ json: args.json ? { happy_path: HAPPY_PATH, docs: DOCS_URL, zero_setup: true, dev_channel_discount_pct: 10 } : void 0
1742
1708
  };
1743
1709
  }
1744
1710
  function registerInit(program) {
@@ -2066,7 +2032,6 @@ function registerCommands(program) {
2066
2032
  registerStatus(program, makeClient, effectiveConfig);
2067
2033
  registerWhoami(program, makeClient, effectiveConfig);
2068
2034
  registerDrops(program, makeClient, effectiveConfig);
2069
- registerConnect(program);
2070
2035
  registerUnstage(program, makeClient, effectiveConfig);
2071
2036
  const prompts = makePrompts();
2072
2037
  registerLogin(