@binaryandthread/cli 0.1.2 → 0.1.4
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 +107 -82
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-IM3HF7NN.js → chunk-AAN4VWP3.js} +2 -2
- package/dist/{chunk-IM3HF7NN.js.map → chunk-AAN4VWP3.js.map} +1 -1
- package/dist/{chunk-WYCZ6BPV.js → chunk-V7YRJ67J.js} +164 -17
- package/dist/chunk-V7YRJ67J.js.map +1 -0
- package/dist/{interactive-DYY27KBC.js → interactive-GY4AK7D2.js} +2 -2
- package/dist/{prompts-GTC5VYM6.js → prompts-DDVV5RE6.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-WYCZ6BPV.js.map +0 -1
- /package/dist/{interactive-DYY27KBC.js.map → interactive-GY4AK7D2.js.map} +0 -0
- /package/dist/{prompts-GTC5VYM6.js.map → prompts-DDVV5RE6.js.map} +0 -0
|
@@ -17,7 +17,7 @@ function makePrompts() {
|
|
|
17
17
|
async function confirm(label) {
|
|
18
18
|
const rl = readline.createInterface({ input, output });
|
|
19
19
|
try {
|
|
20
|
-
const answer = (await rl.question(
|
|
20
|
+
const answer = (await rl.question(` ${label} `)).trim().toLowerCase();
|
|
21
21
|
return answer === "y" || answer === "yes";
|
|
22
22
|
} finally {
|
|
23
23
|
rl.close();
|
|
@@ -29,4 +29,4 @@ function makePrompts() {
|
|
|
29
29
|
export {
|
|
30
30
|
makePrompts
|
|
31
31
|
};
|
|
32
|
-
//# sourceMappingURL=chunk-
|
|
32
|
+
//# sourceMappingURL=chunk-AAN4VWP3.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/prompts.ts"],"sourcesContent":["// Terminal prompts — the real readline-backed prompter for the interactive flows.\n//\n// Kept tiny + dependency-free (node:readline/promises). The command handlers take a prompts\n// object INJECTED (CheckoutPrompts), so this concrete implementation is only wired by bin.ts;\n// the flows are unit-tested with a fake prompter. NOTE: this prompter NEVER asks for a card —\n// the only PII it collects is an email + shipping address (cards live on the storefront page).\n\nimport * as readline from \"node:readline/promises\"\nimport { stdin as input, stdout as output } from \"node:process\"\n\nexport interface Prompts {\n ask(label: string, opts?: { default?: string }): Promise<string>\n confirm(label: string): Promise<boolean>\n}\n\n/** Build a readline-backed prompter. Each call opens + closes its own interface (simple, safe). */\nexport function makePrompts(): Prompts {\n async function ask(label: string, opts?: { default?: string }): Promise<string> {\n const rl = readline.createInterface({ input, output })\n try {\n const suffix = opts?.default ? ` [${opts.default}]` : \"\"\n const answer = (await rl.question(` ${label}${suffix}: `)).trim()\n return answer || (opts?.default ?? \"\")\n } finally {\n rl.close()\n }\n }\n\n async function confirm(label: string): Promise<boolean> {\n const rl = readline.createInterface({ input, output })\n try {\n const answer = (await rl.question(
|
|
1
|
+
{"version":3,"sources":["../src/prompts.ts"],"sourcesContent":["// Terminal prompts — the real readline-backed prompter for the interactive flows.\n//\n// Kept tiny + dependency-free (node:readline/promises). The command handlers take a prompts\n// object INJECTED (CheckoutPrompts), so this concrete implementation is only wired by bin.ts;\n// the flows are unit-tested with a fake prompter. NOTE: this prompter NEVER asks for a card —\n// the only PII it collects is an email + shipping address (cards live on the storefront page).\n\nimport * as readline from \"node:readline/promises\"\nimport { stdin as input, stdout as output } from \"node:process\"\n\nexport interface Prompts {\n ask(label: string, opts?: { default?: string }): Promise<string>\n confirm(label: string): Promise<boolean>\n}\n\n/** Build a readline-backed prompter. Each call opens + closes its own interface (simple, safe). */\nexport function makePrompts(): Prompts {\n async function ask(label: string, opts?: { default?: string }): Promise<string> {\n const rl = readline.createInterface({ input, output })\n try {\n const suffix = opts?.default ? ` [${opts.default}]` : \"\"\n const answer = (await rl.question(` ${label}${suffix}: `)).trim()\n return answer || (opts?.default ?? \"\")\n } finally {\n rl.close()\n }\n }\n\n async function confirm(label: string): Promise<boolean> {\n const rl = readline.createInterface({ input, output })\n try {\n // A neutral question marker — NOT ⚠. The confirms we ask (proceed to checkout, send a report)\n // are benign: nothing is charged, nothing is destroyed. Reserve ⚠ for real warnings so the\n // voice never cries wolf; a caller that truly needs a warning puts ⚠ in its own label.\n const answer = (await rl.question(` ${label} `)).trim().toLowerCase()\n return answer === \"y\" || answer === \"yes\"\n } finally {\n rl.close()\n }\n }\n\n return { ask, confirm }\n}\n"],"mappings":";;;AAOA,YAAY,cAAc;AAC1B,SAAS,SAAS,OAAO,UAAU,cAAc;AAQ1C,SAAS,cAAuB;AACrC,iBAAe,IAAI,OAAe,MAA8C;AAC9E,UAAM,KAAc,yBAAgB,EAAE,OAAO,OAAO,CAAC;AACrD,QAAI;AACF,YAAM,SAAS,MAAM,UAAU,KAAK,KAAK,OAAO,MAAM;AACtD,YAAM,UAAU,MAAM,GAAG,SAAS,MAAM,KAAK,GAAG,MAAM,IAAI,GAAG,KAAK;AAClE,aAAO,WAAW,MAAM,WAAW;AAAA,IACrC,UAAE;AACA,SAAG,MAAM;AAAA,IACX;AAAA,EACF;AAEA,iBAAe,QAAQ,OAAiC;AACtD,UAAM,KAAc,yBAAgB,EAAE,OAAO,OAAO,CAAC;AACrD,QAAI;AAIF,YAAM,UAAU,MAAM,GAAG,SAAS,MAAM,KAAK,GAAG,GAAG,KAAK,EAAE,YAAY;AACtE,aAAO,WAAW,OAAO,WAAW;AAAA,IACtC,UAAE;AACA,SAAG,MAAM;AAAA,IACX;AAAA,EACF;AAEA,SAAO,EAAE,KAAK,QAAQ;AACxB;","names":[]}
|
|
@@ -76,6 +76,7 @@ var DEFAULT_RETRY = {
|
|
|
76
76
|
maxDelayMs: 2e3
|
|
77
77
|
};
|
|
78
78
|
var RETRY_AFTER_MAX_MS = 1e4;
|
|
79
|
+
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
79
80
|
function parseRetryAfterMs(res) {
|
|
80
81
|
let raw = null;
|
|
81
82
|
try {
|
|
@@ -140,6 +141,7 @@ var StoreClient = class {
|
|
|
140
141
|
logger;
|
|
141
142
|
retry;
|
|
142
143
|
sleepImpl;
|
|
144
|
+
timeoutMs;
|
|
143
145
|
/** Cached resolved regions (read-only catalog optimisation). */
|
|
144
146
|
regionsCache = null;
|
|
145
147
|
constructor(opts) {
|
|
@@ -159,6 +161,7 @@ var StoreClient = class {
|
|
|
159
161
|
this.logger = opts.logger ?? console;
|
|
160
162
|
this.retry = { ...DEFAULT_RETRY, ...opts.retry ?? {} };
|
|
161
163
|
this.sleepImpl = opts.sleepImpl ?? sleep;
|
|
164
|
+
this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
162
165
|
}
|
|
163
166
|
// ----- the request engine --------------------------------------------------
|
|
164
167
|
buildUrl(path, query) {
|
|
@@ -201,8 +204,10 @@ var StoreClient = class {
|
|
|
201
204
|
let lastErr;
|
|
202
205
|
for (let attempt = 0; attempt < this.retry.attempts; attempt++) {
|
|
203
206
|
let retryAfterMs = null;
|
|
207
|
+
const controller = new AbortController();
|
|
208
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
204
209
|
try {
|
|
205
|
-
const res = await this.fetchImpl(url, init);
|
|
210
|
+
const res = await this.fetchImpl(url, { ...init, signal: controller.signal });
|
|
206
211
|
if (res.ok) {
|
|
207
212
|
const text = await res.text();
|
|
208
213
|
return text ? JSON.parse(text) : {};
|
|
@@ -250,6 +255,8 @@ var StoreClient = class {
|
|
|
250
255
|
}
|
|
251
256
|
lastErr = e;
|
|
252
257
|
this.logWarn("store.request.network_retry", { path, attempt: attempt + 1 });
|
|
258
|
+
} finally {
|
|
259
|
+
clearTimeout(timer);
|
|
253
260
|
}
|
|
254
261
|
if (attempt < this.retry.attempts - 1) {
|
|
255
262
|
await this.sleepImpl(retryAfterMs ?? this.backoffMs(attempt));
|
|
@@ -666,15 +673,67 @@ var CODENAMES = [
|
|
|
666
673
|
"tabs-over-spaces",
|
|
667
674
|
"vim-not-emacs",
|
|
668
675
|
"2-space-indent",
|
|
669
|
-
"trailing-comma"
|
|
676
|
+
"trailing-comma",
|
|
677
|
+
"rebase-not-merge",
|
|
678
|
+
"lf-not-crlf",
|
|
679
|
+
"semicolons-optional",
|
|
680
|
+
"dark-mode-only"
|
|
670
681
|
];
|
|
671
|
-
function codename(
|
|
672
|
-
|
|
682
|
+
function codename(version) {
|
|
683
|
+
const minor = Number.parseInt(version.split(".")[1] ?? "", 10);
|
|
684
|
+
const idx = Number.isFinite(minor) ? Math.abs(minor) % CODENAMES.length : 0;
|
|
685
|
+
return CODENAMES[idx];
|
|
673
686
|
}
|
|
674
687
|
function versionLine(version) {
|
|
675
688
|
return `bt ${version} "${codename(version)}"`;
|
|
676
689
|
}
|
|
677
690
|
|
|
691
|
+
// src/errors.ts
|
|
692
|
+
var EXIT = {
|
|
693
|
+
OK: 0,
|
|
694
|
+
GENERIC: 1,
|
|
695
|
+
DATAERR: 65,
|
|
696
|
+
// EX_DATAERR — bad request / unprocessable / stale cart (400/409/422)
|
|
697
|
+
UNAVAILABLE: 69,
|
|
698
|
+
// EX_UNAVAILABLE — not found (404)
|
|
699
|
+
TEMPFAIL: 75,
|
|
700
|
+
// EX_TEMPFAIL — temporary: 5xx, network/exhausted, rate-limited (429)
|
|
701
|
+
NOPERM: 77
|
|
702
|
+
// EX_NOPERM — auth required / forbidden (401/403)
|
|
703
|
+
};
|
|
704
|
+
function messageOf(e) {
|
|
705
|
+
if (e instanceof Error && e.message) {
|
|
706
|
+
return e.message;
|
|
707
|
+
}
|
|
708
|
+
const s = String(e ?? "").trim();
|
|
709
|
+
return s || "unexpected error";
|
|
710
|
+
}
|
|
711
|
+
function classifyError(e) {
|
|
712
|
+
const message = String(redact(messageOf(e)));
|
|
713
|
+
if (e instanceof RecoverableCartError) {
|
|
714
|
+
return { code: EXIT.DATAERR, type: "stale_cart", status: e.status, message };
|
|
715
|
+
}
|
|
716
|
+
if (e instanceof StoreApiError) {
|
|
717
|
+
const s = e.status;
|
|
718
|
+
if (s === 401 || s === 403) return { code: EXIT.NOPERM, type: "auth", status: s, message };
|
|
719
|
+
if (s === 404) return { code: EXIT.UNAVAILABLE, type: "not_found", status: s, message };
|
|
720
|
+
if (s === 429) return { code: EXIT.TEMPFAIL, type: "rate_limited", status: s, message };
|
|
721
|
+
if (s === 0 || s === 408 || s >= 500) return { code: EXIT.TEMPFAIL, type: "upstream", status: s, message };
|
|
722
|
+
if (s >= 400) return { code: EXIT.DATAERR, type: "client_error", status: s, message };
|
|
723
|
+
}
|
|
724
|
+
return { code: EXIT.GENERIC, type: "error", message };
|
|
725
|
+
}
|
|
726
|
+
function formatFatal(e, json) {
|
|
727
|
+
const info = classifyError(e);
|
|
728
|
+
if (json) {
|
|
729
|
+
const envelope = { error: { code: info.code, type: info.type, message: info.message } };
|
|
730
|
+
return { out: JSON.stringify(envelope, null, 2), err: null, code: info.code };
|
|
731
|
+
}
|
|
732
|
+
const reassurance = "nothing was lost. if a checkout was in flight, your order is safe. file it \u2192 bt report";
|
|
733
|
+
return { out: null, err: `\u2717 ${info.message}
|
|
734
|
+
${reassurance}`, code: info.code };
|
|
735
|
+
}
|
|
736
|
+
|
|
678
737
|
// src/brand.ts
|
|
679
738
|
var ANSI = {
|
|
680
739
|
reset: "\x1B[0m",
|
|
@@ -848,6 +907,53 @@ function resolveLineItemRef(items, ref) {
|
|
|
848
907
|
);
|
|
849
908
|
return byTitle ?? null;
|
|
850
909
|
}
|
|
910
|
+
function isSubsequence(needle, hay) {
|
|
911
|
+
let i = 0;
|
|
912
|
+
for (let j = 0; j < hay.length && i < needle.length; j++) {
|
|
913
|
+
if (hay[j] === needle[i]) i++;
|
|
914
|
+
}
|
|
915
|
+
return i === needle.length;
|
|
916
|
+
}
|
|
917
|
+
function resolveProductSelector(products, selector) {
|
|
918
|
+
const needle = (selector ?? "").trim();
|
|
919
|
+
if (!needle || products.length === 0) {
|
|
920
|
+
return { candidates: [], fuzzy: false };
|
|
921
|
+
}
|
|
922
|
+
if (/^\d+$/.test(needle)) {
|
|
923
|
+
const idx = Number(needle) - 1;
|
|
924
|
+
if (idx >= 0 && idx < products.length) {
|
|
925
|
+
return { match: products[idx], candidates: [], fuzzy: true };
|
|
926
|
+
}
|
|
927
|
+
return { candidates: [], fuzzy: true };
|
|
928
|
+
}
|
|
929
|
+
const lower = needle.toLowerCase();
|
|
930
|
+
const exact = products.find((p) => (p.handle ?? "").toLowerCase() === lower || p.id === needle);
|
|
931
|
+
if (exact) {
|
|
932
|
+
return { match: exact, candidates: [], fuzzy: false };
|
|
933
|
+
}
|
|
934
|
+
const hits = products.filter(
|
|
935
|
+
(p) => isSubsequence(lower, (p.handle ?? "").toLowerCase()) || isSubsequence(lower, (p.title ?? "").toLowerCase())
|
|
936
|
+
);
|
|
937
|
+
if (hits.length === 1) {
|
|
938
|
+
return { match: hits[0], candidates: [], fuzzy: true };
|
|
939
|
+
}
|
|
940
|
+
return { candidates: hits, fuzzy: true };
|
|
941
|
+
}
|
|
942
|
+
async function resolveProduct(client, region, selector) {
|
|
943
|
+
const needle = (selector ?? "").trim();
|
|
944
|
+
if (needle && !/^\d+$/.test(needle)) {
|
|
945
|
+
const exact = await client.getProduct(needle, { region });
|
|
946
|
+
if (exact) {
|
|
947
|
+
return { product: exact };
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
const products = await client.listProducts({ region });
|
|
951
|
+
const r = resolveProductSelector(products, needle);
|
|
952
|
+
if (r.match) {
|
|
953
|
+
return { product: r.match, fuzzy: r.fuzzy };
|
|
954
|
+
}
|
|
955
|
+
return { candidates: r.candidates, fuzzy: r.fuzzy };
|
|
956
|
+
}
|
|
851
957
|
function resolveOutput(program) {
|
|
852
958
|
const opts = program.opts();
|
|
853
959
|
const json = Boolean(opts.json);
|
|
@@ -855,6 +961,9 @@ function resolveOutput(program) {
|
|
|
855
961
|
return { json, brand };
|
|
856
962
|
}
|
|
857
963
|
function printResult(res, json) {
|
|
964
|
+
if (res.exitCode) {
|
|
965
|
+
process.exitCode = res.exitCode;
|
|
966
|
+
}
|
|
858
967
|
if (json && res.json !== void 0) {
|
|
859
968
|
process.stdout.write(JSON.stringify(res.json, null, 2) + "\n");
|
|
860
969
|
return;
|
|
@@ -932,21 +1041,36 @@ async function defaultRender(url, opts) {
|
|
|
932
1041
|
async function runView(client, config, args) {
|
|
933
1042
|
const style = brandOf(args);
|
|
934
1043
|
const region = await client.resolveRegion(config.region);
|
|
935
|
-
const
|
|
1044
|
+
const picked = await resolveProduct(client, region, args.handle);
|
|
1045
|
+
const product = picked.product;
|
|
936
1046
|
if (!product) {
|
|
1047
|
+
if (picked.candidates && picked.candidates.length > 1) {
|
|
1048
|
+
return {
|
|
1049
|
+
lines: [
|
|
1050
|
+
fail({ code: EXIT.DATAERR, what: `"${args.handle}" matches ${picked.candidates.length} designs \u2014 pick one:` }),
|
|
1051
|
+
...picked.candidates.map((p) => ` ${p.handle ?? p.id}`),
|
|
1052
|
+
" or be exact \u2192 bt view <slug>"
|
|
1053
|
+
],
|
|
1054
|
+
exitCode: EXIT.DATAERR
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
937
1057
|
return {
|
|
938
1058
|
lines: [
|
|
939
1059
|
fail({
|
|
940
|
-
code:
|
|
941
|
-
what: `
|
|
1060
|
+
code: EXIT.UNAVAILABLE,
|
|
1061
|
+
what: `no design here called "${args.handle}".`,
|
|
942
1062
|
fix: "bt browse (to see what's in stock)"
|
|
943
1063
|
})
|
|
944
|
-
]
|
|
1064
|
+
],
|
|
1065
|
+
exitCode: EXIT.UNAVAILABLE
|
|
945
1066
|
};
|
|
946
1067
|
}
|
|
947
1068
|
const { title, handle } = displayName(product);
|
|
948
1069
|
const colours = productColours(product);
|
|
949
1070
|
const lines = [];
|
|
1071
|
+
if (picked.fuzzy && handle !== args.handle.trim()) {
|
|
1072
|
+
lines.push(working(`matched "${handle}" from "${args.handle}"`));
|
|
1073
|
+
}
|
|
950
1074
|
lines.push(header(style, title));
|
|
951
1075
|
lines.push(` ${dim(style, handle)}`);
|
|
952
1076
|
if (product.description) {
|
|
@@ -1013,7 +1137,7 @@ async function runView(client, config, args) {
|
|
|
1013
1137
|
};
|
|
1014
1138
|
}
|
|
1015
1139
|
function registerView(program, makeClient, loadConfig) {
|
|
1016
|
-
program.command("view").alias("show").argument("<handle>", "the
|
|
1140
|
+
program.command("view").alias("show").argument("<handle>", "the design: a slug, a bt browse number (3), or a fuzzy hint (termnl)").option("--colour <colour>", "render a specific colour's mockup (e.g. black)").description("render a design: specs + image (always with the link as the floor).").action(async (handle, opts) => {
|
|
1017
1141
|
const { json, brand } = resolveOutput(program);
|
|
1018
1142
|
const noColor = program.opts().color === false;
|
|
1019
1143
|
const res = await runView(makeClient(), loadConfig(), {
|
|
@@ -1031,14 +1155,29 @@ function registerView(program, makeClient, loadConfig) {
|
|
|
1031
1155
|
async function runStage(client, config, args) {
|
|
1032
1156
|
const style = brandOf(args);
|
|
1033
1157
|
const region = await client.resolveRegion(config.region);
|
|
1034
|
-
const
|
|
1035
|
-
if (!product) {
|
|
1158
|
+
const resolved = await resolveProduct(client, region, args.handle);
|
|
1159
|
+
if (!resolved.product) {
|
|
1160
|
+
if (resolved.candidates && resolved.candidates.length > 1) {
|
|
1161
|
+
return {
|
|
1162
|
+
lines: [
|
|
1163
|
+
fail({ code: EXIT.DATAERR, what: `"${args.handle}" matches ${resolved.candidates.length} designs \u2014 pick one:` }),
|
|
1164
|
+
...resolved.candidates.map((p) => ` ${p.handle ?? p.id}`),
|
|
1165
|
+
" or be exact \u2192 bt stage <slug>"
|
|
1166
|
+
],
|
|
1167
|
+
exitCode: EXIT.DATAERR
|
|
1168
|
+
// ambiguous input → non-zero so `bt stage x && bt checkout` halts (d10)
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1036
1171
|
return {
|
|
1037
1172
|
lines: [
|
|
1038
|
-
fail({ code:
|
|
1039
|
-
]
|
|
1173
|
+
fail({ code: EXIT.UNAVAILABLE, what: `no design here called "${args.handle}".`, fix: "bt browse" })
|
|
1174
|
+
],
|
|
1175
|
+
exitCode: EXIT.UNAVAILABLE
|
|
1176
|
+
// not-found → non-zero (d10)
|
|
1040
1177
|
};
|
|
1041
1178
|
}
|
|
1179
|
+
const product = resolved.product;
|
|
1180
|
+
const matchNote = resolved.fuzzy && (product.handle ?? "") !== args.handle.trim() ? working(`matched "${product.handle}" from "${args.handle}"`) : null;
|
|
1042
1181
|
const size = args.size ?? config.defaultSize;
|
|
1043
1182
|
const colours = productColours(product);
|
|
1044
1183
|
const colour = args.colour ?? config.defaultColour ?? (colours.length > 0 ? colours[0] : void 0);
|
|
@@ -1048,17 +1187,20 @@ async function runStage(client, config, args) {
|
|
|
1048
1187
|
return {
|
|
1049
1188
|
lines: [
|
|
1050
1189
|
fail({
|
|
1051
|
-
code:
|
|
1190
|
+
code: EXIT.DATAERR,
|
|
1052
1191
|
what: `no variant for ${args.handle}${size ? `#size=${size}` : ""}${colour ? ` (${colour})` : ""}.`,
|
|
1053
1192
|
fix: `bt view ${args.handle} (to see available sizes + colours)${have}`
|
|
1054
1193
|
})
|
|
1055
|
-
]
|
|
1194
|
+
],
|
|
1195
|
+
exitCode: EXIT.DATAERR
|
|
1196
|
+
// unprocessable size+colour combo → non-zero (d10)
|
|
1056
1197
|
};
|
|
1057
1198
|
}
|
|
1058
1199
|
if (args.dryRun) {
|
|
1059
1200
|
const colourSuffix2 = colour ? ` (${colour})` : "";
|
|
1060
1201
|
return {
|
|
1061
1202
|
lines: [
|
|
1203
|
+
...matchNote ? [matchNote] : [],
|
|
1062
1204
|
ok(`dry-run \u2014 would stage ${product.handle ?? args.handle}${size ? `#${size}` : ""}${colourSuffix2} (nothing staged).`),
|
|
1063
1205
|
" run without --dry-run to acquire the inventory lock."
|
|
1064
1206
|
],
|
|
@@ -1074,6 +1216,9 @@ async function runStage(client, config, args) {
|
|
|
1074
1216
|
};
|
|
1075
1217
|
}
|
|
1076
1218
|
const lines = [];
|
|
1219
|
+
if (matchNote) {
|
|
1220
|
+
lines.push(matchNote);
|
|
1221
|
+
}
|
|
1077
1222
|
let cartId = config.cart_id;
|
|
1078
1223
|
let recovered = false;
|
|
1079
1224
|
if (!cartId) {
|
|
@@ -1119,7 +1264,7 @@ async function runStage(client, config, args) {
|
|
|
1119
1264
|
};
|
|
1120
1265
|
}
|
|
1121
1266
|
function registerStage(program, makeClient, loadConfig) {
|
|
1122
|
-
program.command("stage").alias("add").argument("<handle>", "the
|
|
1267
|
+
program.command("stage").alias("add").argument("<handle>", "the design: a slug (terminal-velocity), a bt browse number (3), or a fuzzy hint (termnl)").option("--size <size>", "garment size (default: your last commit's size)").option("--colour <colour>", "colour, e.g. white / black (default: the product's first colour)").option("--dry-run", "resolve the variant + show what would be staged, without staging").description("reserve stock \u2014 acquires an inventory lock, reserves nothing permanent.").action(async (handle, opts) => {
|
|
1123
1268
|
const { json, brand } = resolveOutput(program);
|
|
1124
1269
|
const res = await runStage(makeClient(), loadConfig(), {
|
|
1125
1270
|
handle,
|
|
@@ -1154,6 +1299,8 @@ export {
|
|
|
1154
1299
|
empty,
|
|
1155
1300
|
fail,
|
|
1156
1301
|
versionLine,
|
|
1302
|
+
EXIT,
|
|
1303
|
+
formatFatal,
|
|
1157
1304
|
cyan,
|
|
1158
1305
|
dim,
|
|
1159
1306
|
green,
|
|
@@ -1178,4 +1325,4 @@ export {
|
|
|
1178
1325
|
runStage,
|
|
1179
1326
|
registerStage
|
|
1180
1327
|
};
|
|
1181
|
-
//# sourceMappingURL=chunk-
|
|
1328
|
+
//# sourceMappingURL=chunk-V7YRJ67J.js.map
|