hacksh 0.1.2 → 0.2.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 +217 -26
- package/dist/index.d.ts +283 -28
- package/dist/index.js +1154 -49
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { globalRegistry, safeParseAsync } from "zod/v4/core";
|
|
2
|
-
import { parseArgs as parseArgs$1 } from "node:util";
|
|
2
|
+
import { inspect, parseArgs as parseArgs$1, stripVTControlCharacters, styleText } from "node:util";
|
|
3
|
+
import { emitKeypressEvents } from "node:readline";
|
|
4
|
+
import { PassThrough } from "node:stream";
|
|
3
5
|
//#region src/options.ts
|
|
4
6
|
function kebabCase(value) {
|
|
5
7
|
return value.replaceAll(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
@@ -144,6 +146,182 @@ var ZittyValidationError = class extends ZittyUsageError {
|
|
|
144
146
|
this.issues = issues;
|
|
145
147
|
}
|
|
146
148
|
};
|
|
149
|
+
/** An input request that could not be completed safely. */
|
|
150
|
+
var HackshPromptError = class extends Error {
|
|
151
|
+
reason;
|
|
152
|
+
prompt;
|
|
153
|
+
constructor(reason, prompt, message, options) {
|
|
154
|
+
super(message, options);
|
|
155
|
+
this.name = "HackshPromptError";
|
|
156
|
+
this.reason = reason;
|
|
157
|
+
this.prompt = prompt;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
function safeString$1(value, fallback) {
|
|
161
|
+
try {
|
|
162
|
+
return String(value);
|
|
163
|
+
} catch {
|
|
164
|
+
return fallback;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function readProperty(value, key) {
|
|
168
|
+
try {
|
|
169
|
+
return Reflect.get(value, key);
|
|
170
|
+
} catch {
|
|
171
|
+
return "[Unserializable]";
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function enumerableKeys(value) {
|
|
175
|
+
try {
|
|
176
|
+
return Object.keys(value);
|
|
177
|
+
} catch {
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function hasToJSON(value) {
|
|
182
|
+
try {
|
|
183
|
+
return typeof Reflect.get(value, "toJSON") === "function";
|
|
184
|
+
} catch {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function isPlainObject(value) {
|
|
189
|
+
try {
|
|
190
|
+
const prototype = Object.getPrototypeOf(value);
|
|
191
|
+
return prototype === Object.prototype || prototype === null;
|
|
192
|
+
} catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function summarizeIssue({ arg, message, issue }, seen) {
|
|
197
|
+
if (!issue) return {
|
|
198
|
+
arg,
|
|
199
|
+
message
|
|
200
|
+
};
|
|
201
|
+
const details = {};
|
|
202
|
+
for (const key of enumerableKeys(issue)) {
|
|
203
|
+
if ([
|
|
204
|
+
"code",
|
|
205
|
+
"path",
|
|
206
|
+
"message",
|
|
207
|
+
"inst"
|
|
208
|
+
].includes(key)) continue;
|
|
209
|
+
details[key] = summarizeErrors(readProperty(issue, key), seen);
|
|
210
|
+
}
|
|
211
|
+
const code = readProperty(issue, "code");
|
|
212
|
+
const path = readProperty(issue, "path");
|
|
213
|
+
return {
|
|
214
|
+
arg,
|
|
215
|
+
message,
|
|
216
|
+
...typeof code === "string" ? { code } : {},
|
|
217
|
+
...Array.isArray(path) ? { path } : {},
|
|
218
|
+
...Object.keys(details).length === 0 ? {} : { details }
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function errorKind(error) {
|
|
222
|
+
if (error instanceof HackshPromptError) return "prompt";
|
|
223
|
+
if (error instanceof ZittyValidationError) return "validation";
|
|
224
|
+
if (error instanceof ZittyUsageError) return "usage";
|
|
225
|
+
return "error";
|
|
226
|
+
}
|
|
227
|
+
function summarizeErrorWithSeen(error, seen) {
|
|
228
|
+
const summary = {
|
|
229
|
+
kind: errorKind(error),
|
|
230
|
+
name: safeString$1(readProperty(error, "name"), "Error"),
|
|
231
|
+
message: safeString$1(readProperty(error, "message"), "[Unserializable error message]")
|
|
232
|
+
};
|
|
233
|
+
seen.set(error, summary);
|
|
234
|
+
const stack = readProperty(error, "stack");
|
|
235
|
+
const cause = readProperty(error, "cause");
|
|
236
|
+
if (typeof stack === "string") summary.stack = stack;
|
|
237
|
+
if (cause !== void 0) summary.cause = summarizeErrors(cause, seen);
|
|
238
|
+
if (error instanceof ZittyValidationError) summary.issues = error.issues.map((issue) => summarizeIssue(issue, seen));
|
|
239
|
+
const reserved = /* @__PURE__ */ new Set([
|
|
240
|
+
"name",
|
|
241
|
+
"message",
|
|
242
|
+
"stack",
|
|
243
|
+
"cause",
|
|
244
|
+
"command",
|
|
245
|
+
"issues"
|
|
246
|
+
]);
|
|
247
|
+
const properties = {};
|
|
248
|
+
for (const key of enumerableKeys(error)) {
|
|
249
|
+
if (reserved.has(key)) continue;
|
|
250
|
+
properties[key] = summarizeErrors(readProperty(error, key), seen);
|
|
251
|
+
}
|
|
252
|
+
if (Object.keys(properties).length > 0) summary.properties = properties;
|
|
253
|
+
return summary;
|
|
254
|
+
}
|
|
255
|
+
/** Recursively replace Error values with command- and schema-free summaries. */
|
|
256
|
+
function summarizeErrors(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
257
|
+
if (typeof value !== "object" || value === null) return value;
|
|
258
|
+
const existing = seen.get(value);
|
|
259
|
+
if (existing !== void 0) return existing;
|
|
260
|
+
if (value instanceof Error) return summarizeErrorWithSeen(value, seen);
|
|
261
|
+
if (Array.isArray(value)) {
|
|
262
|
+
const result = [];
|
|
263
|
+
seen.set(value, result);
|
|
264
|
+
let changed = false;
|
|
265
|
+
for (const item of value) {
|
|
266
|
+
const summarized = summarizeErrors(item, seen);
|
|
267
|
+
result.push(summarized);
|
|
268
|
+
changed ||= summarized !== item;
|
|
269
|
+
}
|
|
270
|
+
if (changed) return result;
|
|
271
|
+
seen.set(value, value);
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
if (value instanceof Map) {
|
|
275
|
+
const result = /* @__PURE__ */ new Map();
|
|
276
|
+
seen.set(value, result);
|
|
277
|
+
let changed = false;
|
|
278
|
+
for (const [key, item] of value) {
|
|
279
|
+
const summarizedKey = summarizeErrors(key, seen);
|
|
280
|
+
const summarizedItem = summarizeErrors(item, seen);
|
|
281
|
+
result.set(summarizedKey, summarizedItem);
|
|
282
|
+
changed ||= summarizedKey !== key || summarizedItem !== item;
|
|
283
|
+
}
|
|
284
|
+
if (changed) return result;
|
|
285
|
+
seen.set(value, value);
|
|
286
|
+
return value;
|
|
287
|
+
}
|
|
288
|
+
if (value instanceof Set) {
|
|
289
|
+
const result = /* @__PURE__ */ new Set();
|
|
290
|
+
seen.set(value, result);
|
|
291
|
+
let changed = false;
|
|
292
|
+
for (const item of value) {
|
|
293
|
+
const summarized = summarizeErrors(item, seen);
|
|
294
|
+
result.add(summarized);
|
|
295
|
+
changed ||= summarized !== item;
|
|
296
|
+
}
|
|
297
|
+
if (changed) return result;
|
|
298
|
+
seen.set(value, value);
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
if (ArrayBuffer.isView(value) || hasToJSON(value) || !isPlainObject(value)) return value;
|
|
302
|
+
const result = {};
|
|
303
|
+
seen.set(value, result);
|
|
304
|
+
let changed = false;
|
|
305
|
+
for (const key of enumerableKeys(value)) {
|
|
306
|
+
const original = readProperty(value, key);
|
|
307
|
+
const summarized = summarizeErrors(original, seen);
|
|
308
|
+
result[key] = summarized;
|
|
309
|
+
changed ||= summarized !== original;
|
|
310
|
+
}
|
|
311
|
+
if (changed) return result;
|
|
312
|
+
seen.set(value, value);
|
|
313
|
+
return value;
|
|
314
|
+
}
|
|
315
|
+
/** Convert any thrown value into a canonical error description. */
|
|
316
|
+
function summarizeError(error) {
|
|
317
|
+
if (error instanceof Error) return summarizeErrorWithSeen(error, /* @__PURE__ */ new WeakMap());
|
|
318
|
+
return {
|
|
319
|
+
kind: "thrown",
|
|
320
|
+
name: "NonErrorThrown",
|
|
321
|
+
message: safeString$1(error, "[Unserializable thrown value]"),
|
|
322
|
+
value: summarizeErrors(error)
|
|
323
|
+
};
|
|
324
|
+
}
|
|
147
325
|
//#endregion
|
|
148
326
|
//#region src/parser.ts
|
|
149
327
|
function optionModel(command) {
|
|
@@ -360,6 +538,801 @@ async function parseArgs(command, argv) {
|
|
|
360
538
|
return (await parseCommandArgs(command, argv)).args;
|
|
361
539
|
}
|
|
362
540
|
//#endregion
|
|
541
|
+
//#region src/serialization.ts
|
|
542
|
+
function safeString(value) {
|
|
543
|
+
try {
|
|
544
|
+
return String(value);
|
|
545
|
+
} catch {
|
|
546
|
+
return "[Unserializable]";
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function normalizeProperty(value, key, ancestors) {
|
|
550
|
+
try {
|
|
551
|
+
return normalizeJson(Reflect.get(value, key), ancestors);
|
|
552
|
+
} catch {
|
|
553
|
+
return "[Unserializable]";
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function normalizedKeys(value) {
|
|
557
|
+
try {
|
|
558
|
+
return Object.keys(value);
|
|
559
|
+
} catch {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
const noToJson = Symbol("noToJson");
|
|
564
|
+
function normalizedToJson(value, ancestors) {
|
|
565
|
+
let toJSON;
|
|
566
|
+
try {
|
|
567
|
+
toJSON = Reflect.get(value, "toJSON");
|
|
568
|
+
} catch {
|
|
569
|
+
return noToJson;
|
|
570
|
+
}
|
|
571
|
+
if (typeof toJSON !== "function") return noToJson;
|
|
572
|
+
try {
|
|
573
|
+
const result = Reflect.apply(toJSON, value, []);
|
|
574
|
+
return result === value ? noToJson : normalizeJson(result, ancestors);
|
|
575
|
+
} catch {
|
|
576
|
+
return noToJson;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
function isArrayBufferView(value) {
|
|
580
|
+
try {
|
|
581
|
+
return ArrayBuffer.isView(value);
|
|
582
|
+
} catch {
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
/** Normalize arbitrary event data into values accepted by JSON.stringify. */
|
|
587
|
+
function normalizeJson(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
588
|
+
switch (typeof value) {
|
|
589
|
+
case "string": return stripVTControlCharacters(value);
|
|
590
|
+
case "boolean": return value;
|
|
591
|
+
case "number": return Number.isFinite(value) ? value : null;
|
|
592
|
+
case "bigint": return value.toString();
|
|
593
|
+
case "undefined": return "[undefined]";
|
|
594
|
+
case "symbol": return `[symbol:${stripVTControlCharacters(value.description ?? "")}]`;
|
|
595
|
+
case "function": return `[function:${stripVTControlCharacters(value.name || "anonymous")}]`;
|
|
596
|
+
}
|
|
597
|
+
if (value === null) return null;
|
|
598
|
+
if (ancestors.has(value)) return "[Circular]";
|
|
599
|
+
const nextAncestors = new Set(ancestors).add(value);
|
|
600
|
+
if (value instanceof Error) return normalizeJson(summarizeError(value), nextAncestors);
|
|
601
|
+
const jsonValue = normalizedToJson(value, nextAncestors);
|
|
602
|
+
if (jsonValue !== noToJson) return jsonValue;
|
|
603
|
+
if (isArrayBufferView(value)) {
|
|
604
|
+
if (value instanceof DataView) return Array.from(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
|
|
605
|
+
try {
|
|
606
|
+
return Array.from(value, (item) => normalizeJson(item, nextAncestors));
|
|
607
|
+
} catch {
|
|
608
|
+
return "[Unserializable]";
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (value instanceof ArrayBuffer) return Array.from(new Uint8Array(value));
|
|
612
|
+
if (Array.isArray(value)) return Array.from({ length: value.length }, (_, index) => normalizeProperty(value, index, nextAncestors));
|
|
613
|
+
if (value instanceof Map) try {
|
|
614
|
+
return [...value].map(([key, item]) => [normalizeJson(key, nextAncestors), normalizeJson(item, nextAncestors)]);
|
|
615
|
+
} catch {
|
|
616
|
+
return "[Unserializable]";
|
|
617
|
+
}
|
|
618
|
+
if (value instanceof Set) try {
|
|
619
|
+
return [...value].map((item) => normalizeJson(item, nextAncestors));
|
|
620
|
+
} catch {
|
|
621
|
+
return "[Unserializable]";
|
|
622
|
+
}
|
|
623
|
+
const keys = normalizedKeys(value);
|
|
624
|
+
if (!keys) return safeString(value);
|
|
625
|
+
const result = {};
|
|
626
|
+
for (const key of keys) result[stripVTControlCharacters(key)] = normalizeProperty(value, key, nextAncestors);
|
|
627
|
+
return result;
|
|
628
|
+
}
|
|
629
|
+
//#endregion
|
|
630
|
+
//#region src/printer.ts
|
|
631
|
+
function fallbackValue(value) {
|
|
632
|
+
try {
|
|
633
|
+
return String(value);
|
|
634
|
+
} catch {
|
|
635
|
+
return "[Unserializable]";
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
function validatePreference(value, source) {
|
|
639
|
+
if (value === void 0) return void 0;
|
|
640
|
+
if (value === "auto" || value === "pretty" || value === "json") return value;
|
|
641
|
+
throw new TypeError(`Invalid ${source} value ${fallbackValue(value)}; expected auto, pretty, or json`);
|
|
642
|
+
}
|
|
643
|
+
function readEnvironment(env, key) {
|
|
644
|
+
try {
|
|
645
|
+
return env[key];
|
|
646
|
+
} catch {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
/** Resolve output behavior once, before command routing or argument parsing. */
|
|
651
|
+
function resolveOutputMode(options = {}) {
|
|
652
|
+
const env = options.env ?? process.env;
|
|
653
|
+
const configured = validatePreference(options.output, "output");
|
|
654
|
+
const requested = validatePreference(readEnvironment(env, "HACKSH_OUTPUT"), "HACKSH_OUTPUT") ?? configured ?? "auto";
|
|
655
|
+
const ci = Boolean(readEnvironment(env, "CI"));
|
|
656
|
+
const format = requested === "auto" ? ci ? "json" : "pretty" : requested;
|
|
657
|
+
const inputIsTTY = options.inputIsTTY ?? process.stdin.isTTY === true;
|
|
658
|
+
const outputIsTTY = options.outputIsTTY ?? process.stdout.isTTY === true;
|
|
659
|
+
return {
|
|
660
|
+
format,
|
|
661
|
+
interactive: format === "pretty" && !ci && inputIsTTY && outputIsTTY,
|
|
662
|
+
color: format === "pretty" && outputIsTTY && !readEnvironment(env, "NO_COLOR")
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
function isErrorLevel(level) {
|
|
666
|
+
return level === "warning" || level === "error" || level === "fatal";
|
|
667
|
+
}
|
|
668
|
+
function eventStream(event) {
|
|
669
|
+
if (event.type === "error") return "stderr";
|
|
670
|
+
if (event.type === "usage") return event.stream;
|
|
671
|
+
if (event.type === "log" && isErrorLevel(event.record.level)) return "stderr";
|
|
672
|
+
return "stdout";
|
|
673
|
+
}
|
|
674
|
+
function formatTextEvent(event) {
|
|
675
|
+
switch (event.type) {
|
|
676
|
+
case "usage": return event.text;
|
|
677
|
+
case "version": return event.version;
|
|
678
|
+
case "error": return event.error.kind === "usage" || event.error.kind === "validation" ? event.error.message : `Error: ${event.error.message}`;
|
|
679
|
+
case "log": return event.record.message;
|
|
680
|
+
case "prompt": return event.prompt.message;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
/** Undecorated console compatibility adapter; automatic output uses the selected format printer. */
|
|
684
|
+
const consolePrinter = { print(event) {
|
|
685
|
+
const text = formatTextEvent(event);
|
|
686
|
+
return eventStream(event) === "stdout" ? console.log(text) : console.error(text);
|
|
687
|
+
} };
|
|
688
|
+
/** Create an undecorated stream-backed compatibility adapter. */
|
|
689
|
+
function createStreamPrinter(options) {
|
|
690
|
+
return { print(event) {
|
|
691
|
+
(eventStream(event) === "stdout" ? options.stdout : options.stderr).write(`${formatTextEvent(event)}\n`);
|
|
692
|
+
} };
|
|
693
|
+
}
|
|
694
|
+
/** Create a one-semantic-event-per-line JSON printer. */
|
|
695
|
+
function createJsonPrinter(options = {}) {
|
|
696
|
+
const stdout = options.stdout ?? process.stdout;
|
|
697
|
+
const stderr = options.stderr ?? process.stderr;
|
|
698
|
+
return { print(event) {
|
|
699
|
+
let serialized;
|
|
700
|
+
try {
|
|
701
|
+
serialized = JSON.stringify(normalizeJson(event));
|
|
702
|
+
} catch {
|
|
703
|
+
serialized = JSON.stringify({
|
|
704
|
+
type: event.type,
|
|
705
|
+
serializationError: "Event data could not be serialized"
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
const line = `${serialized}\n`;
|
|
709
|
+
(eventStream(event) === "stdout" ? stdout : stderr).write(line);
|
|
710
|
+
} };
|
|
711
|
+
}
|
|
712
|
+
/** Serialize printer calls and retain failures until the invocation drains its output. */
|
|
713
|
+
function createPrintQueue(target) {
|
|
714
|
+
let pending;
|
|
715
|
+
let failure;
|
|
716
|
+
let failed = false;
|
|
717
|
+
function recordFailure(error) {
|
|
718
|
+
if (!failed) failure = error;
|
|
719
|
+
failed = true;
|
|
720
|
+
}
|
|
721
|
+
function track(execution, retainFailure) {
|
|
722
|
+
const barrier = execution.catch((error) => {
|
|
723
|
+
if (retainFailure) recordFailure(error);
|
|
724
|
+
});
|
|
725
|
+
pending = barrier;
|
|
726
|
+
barrier.then(() => {
|
|
727
|
+
if (pending === barrier) pending = void 0;
|
|
728
|
+
});
|
|
729
|
+
return retainFailure ? barrier : execution;
|
|
730
|
+
}
|
|
731
|
+
function enqueue(event, retainFailure) {
|
|
732
|
+
if (pending) return track(pending.then(() => target.print(event)), retainFailure);
|
|
733
|
+
try {
|
|
734
|
+
const result = target.print(event);
|
|
735
|
+
if (result) return track(Promise.resolve(result), retainFailure);
|
|
736
|
+
} catch (error) {
|
|
737
|
+
if (retainFailure) recordFailure(error);
|
|
738
|
+
else return Promise.reject(error);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
printer: { print(event) {
|
|
743
|
+
return enqueue(event, true);
|
|
744
|
+
} },
|
|
745
|
+
async printChecked(event) {
|
|
746
|
+
await enqueue(event, false);
|
|
747
|
+
},
|
|
748
|
+
async drain() {
|
|
749
|
+
await pending;
|
|
750
|
+
if (failed) throw failure;
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
//#endregion
|
|
755
|
+
//#region src/pretty.ts
|
|
756
|
+
const unicodeSymbols = {
|
|
757
|
+
bar: "│",
|
|
758
|
+
marks: {
|
|
759
|
+
trace: "·",
|
|
760
|
+
debug: "◆",
|
|
761
|
+
info: "●",
|
|
762
|
+
warning: "▲",
|
|
763
|
+
error: "■",
|
|
764
|
+
fatal: "✖",
|
|
765
|
+
step: "◇",
|
|
766
|
+
success: "✔",
|
|
767
|
+
usage: "◆",
|
|
768
|
+
version: "●",
|
|
769
|
+
errorEvent: "■",
|
|
770
|
+
prompt: "?"
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
const asciiSymbols = {
|
|
774
|
+
bar: "|",
|
|
775
|
+
marks: {
|
|
776
|
+
trace: ".",
|
|
777
|
+
debug: ":",
|
|
778
|
+
info: "i",
|
|
779
|
+
warning: "!",
|
|
780
|
+
error: "x",
|
|
781
|
+
fatal: "X",
|
|
782
|
+
step: ">",
|
|
783
|
+
success: "+",
|
|
784
|
+
usage: "?",
|
|
785
|
+
version: "i",
|
|
786
|
+
errorEvent: "x",
|
|
787
|
+
prompt: "?"
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
const markStyles = {
|
|
791
|
+
trace: "gray",
|
|
792
|
+
debug: "magenta",
|
|
793
|
+
info: "blue",
|
|
794
|
+
warning: "yellow",
|
|
795
|
+
error: "red",
|
|
796
|
+
fatal: [
|
|
797
|
+
"bgRed",
|
|
798
|
+
"white",
|
|
799
|
+
"bold"
|
|
800
|
+
],
|
|
801
|
+
step: "cyan",
|
|
802
|
+
success: "green",
|
|
803
|
+
usage: "cyan",
|
|
804
|
+
version: "blue",
|
|
805
|
+
errorEvent: "red",
|
|
806
|
+
prompt: "cyan"
|
|
807
|
+
};
|
|
808
|
+
function safelyInspect(value) {
|
|
809
|
+
if (typeof value === "string") return value;
|
|
810
|
+
try {
|
|
811
|
+
return inspect(value, {
|
|
812
|
+
breakLength: 80,
|
|
813
|
+
colors: false,
|
|
814
|
+
compact: false,
|
|
815
|
+
depth: null,
|
|
816
|
+
sorted: true
|
|
817
|
+
});
|
|
818
|
+
} catch {
|
|
819
|
+
return "[Unserializable]";
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
function propertyLines(properties) {
|
|
823
|
+
const lines = [];
|
|
824
|
+
for (const key of Object.keys(properties).sort()) {
|
|
825
|
+
const rendered = ` ${key}: ${safelyInspect(properties[key])}`.split("\n");
|
|
826
|
+
lines.push(rendered[0] ?? "");
|
|
827
|
+
for (const continuation of rendered.slice(1)) lines.push(` ${continuation}`);
|
|
828
|
+
}
|
|
829
|
+
return lines;
|
|
830
|
+
}
|
|
831
|
+
function logLines(record) {
|
|
832
|
+
const category = record.category.length > 0 ? `[${record.category.join(":")}] ` : "";
|
|
833
|
+
const message = record.message.split("\n");
|
|
834
|
+
return [
|
|
835
|
+
`${category}${message[0] ?? ""}`,
|
|
836
|
+
...message.slice(1),
|
|
837
|
+
...propertyLines(record.properties)
|
|
838
|
+
];
|
|
839
|
+
}
|
|
840
|
+
function errorLines(error) {
|
|
841
|
+
const lines = error.message.split("\n");
|
|
842
|
+
const details = {};
|
|
843
|
+
if (error.cause !== void 0) details.cause = error.cause;
|
|
844
|
+
if (error.properties !== void 0) Object.assign(details, error.properties);
|
|
845
|
+
if (error.value !== void 0) details.value = error.value;
|
|
846
|
+
return [...lines, ...propertyLines(details)];
|
|
847
|
+
}
|
|
848
|
+
function eventMark(event) {
|
|
849
|
+
if (event.type === "usage") return "usage";
|
|
850
|
+
if (event.type === "version") return "version";
|
|
851
|
+
if (event.type === "error") return "errorEvent";
|
|
852
|
+
if (event.type === "prompt") return event.prompt.status === "submitted" ? "success" : "prompt";
|
|
853
|
+
return event.record.kind === "message" ? event.record.level : event.record.kind;
|
|
854
|
+
}
|
|
855
|
+
function eventLines(event) {
|
|
856
|
+
switch (event.type) {
|
|
857
|
+
case "usage": return event.text.split("\n");
|
|
858
|
+
case "version": return event.version.split("\n");
|
|
859
|
+
case "error": return errorLines(event.error);
|
|
860
|
+
case "log": return logLines(event.record);
|
|
861
|
+
case "prompt": {
|
|
862
|
+
const { prompt } = event;
|
|
863
|
+
if (prompt.status === "submitted") {
|
|
864
|
+
const result = prompt.kind === "select" ? prompt.choices.find(({ value }) => value === prompt.value)?.label ?? prompt.value : prompt.kind === "confirm" ? prompt.value ? "Yes" : "No" : prompt.value;
|
|
865
|
+
return [`${prompt.message}: ${result}`];
|
|
866
|
+
}
|
|
867
|
+
const lines = [prompt.message];
|
|
868
|
+
if (prompt.kind === "select") for (const choice of prompt.choices) lines.push(`${choice.selected ? ">" : " "} ${choice.label}${choice.hint ? ` — ${choice.hint}` : ""}`);
|
|
869
|
+
else if (prompt.kind === "confirm") lines.push(`${prompt.value ? "Yes" : "No"}${prompt.defaultValue === void 0 ? "" : ` (default: ${prompt.defaultValue ? "yes" : "no"})`}`);
|
|
870
|
+
else lines.push(prompt.value || (prompt.placeholder ? `(${prompt.placeholder})` : ""));
|
|
871
|
+
if (prompt.error) lines.push(prompt.error);
|
|
872
|
+
return lines;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function colorize(enabled, style, text) {
|
|
877
|
+
return enabled ? styleText(style, text, { validateStream: false }) : text;
|
|
878
|
+
}
|
|
879
|
+
const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
880
|
+
const combiningMark = /\p{Mark}/u;
|
|
881
|
+
const pictograph = /\p{Extended_Pictographic}/u;
|
|
882
|
+
function isWideCodePoint(codePoint) {
|
|
883
|
+
return codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || codePoint >= 11904 && codePoint <= 42191 && codePoint !== 12351 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65135 || codePoint >= 65280 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 131072 && codePoint <= 262141);
|
|
884
|
+
}
|
|
885
|
+
function displayWidth(text) {
|
|
886
|
+
let width = 0;
|
|
887
|
+
for (const { segment } of graphemeSegmenter.segment(stripVTControlCharacters(text))) {
|
|
888
|
+
if (segment === " ") {
|
|
889
|
+
width += 8 - width % 8;
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
if (pictograph.test(segment) || Array.from(segment).some((value) => isWideCodePoint(value.codePointAt(0)))) {
|
|
893
|
+
width += 2;
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
for (const value of segment) {
|
|
897
|
+
const codePoint = value.codePointAt(0);
|
|
898
|
+
if (codePoint < 32 || codePoint >= 127 && codePoint < 160) continue;
|
|
899
|
+
if (codePoint === 8205 || codePoint >= 65024 && codePoint <= 65039) continue;
|
|
900
|
+
if (!combiningMark.test(value)) width += 1;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return width;
|
|
904
|
+
}
|
|
905
|
+
function renderedRows(rendered, columns) {
|
|
906
|
+
const width = Number.isInteger(columns) && columns !== void 0 && columns > 0 ? columns : void 0;
|
|
907
|
+
return rendered.split("\n").reduce((rows, line) => {
|
|
908
|
+
if (!width) return rows + 1;
|
|
909
|
+
return rows + Math.max(1, Math.ceil(displayWidth(line) / width));
|
|
910
|
+
}, 0);
|
|
911
|
+
}
|
|
912
|
+
/** Create the fixed human-readable renderer used for pretty output. */
|
|
913
|
+
function createPrettyPrinter(options) {
|
|
914
|
+
const stdout = options.stdout ?? process.stdout;
|
|
915
|
+
const stderr = options.stderr ?? process.stderr;
|
|
916
|
+
const symbols = options.unicode ? unicodeSymbols : asciiSymbols;
|
|
917
|
+
let activePrompt;
|
|
918
|
+
function render(event) {
|
|
919
|
+
const mark = eventMark(event);
|
|
920
|
+
const lines = eventLines(event);
|
|
921
|
+
const firstPrefix = colorize(options.color, markStyles[mark], symbols.marks[mark]);
|
|
922
|
+
const barPrefix = colorize(options.color, "gray", symbols.bar);
|
|
923
|
+
return lines.map((line, index) => `${index === 0 ? firstPrefix : barPrefix}${line ? ` ${line}` : ""}`).join("\n");
|
|
924
|
+
}
|
|
925
|
+
function eraseActivePrompt() {
|
|
926
|
+
return activePrompt ? "\x1B[1A\x1B[2K".repeat(activePrompt.lines) : "";
|
|
927
|
+
}
|
|
928
|
+
return { print(event) {
|
|
929
|
+
const rendered = render(event);
|
|
930
|
+
if (event.type === "prompt") {
|
|
931
|
+
const erase = eraseActivePrompt();
|
|
932
|
+
if (event.prompt.status === "closed") {
|
|
933
|
+
activePrompt = void 0;
|
|
934
|
+
if (erase) stdout.write(erase);
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
if (event.prompt.status === "submitted") activePrompt = void 0;
|
|
938
|
+
else activePrompt = {
|
|
939
|
+
rendered,
|
|
940
|
+
lines: renderedRows(rendered, stdout.columns)
|
|
941
|
+
};
|
|
942
|
+
stdout.write(`${erase}${rendered}\n`);
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
const erase = eraseActivePrompt();
|
|
946
|
+
if (!activePrompt) {
|
|
947
|
+
(eventStream(event) === "stdout" ? stdout : stderr).write(`${rendered}\n`);
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
stdout.write(erase);
|
|
951
|
+
if (event.type === "error") activePrompt = void 0;
|
|
952
|
+
(eventStream(event) === "stdout" ? stdout : stderr).write(`${rendered}\n`);
|
|
953
|
+
if (activePrompt) stdout.write(`${activePrompt.rendered}\n`);
|
|
954
|
+
} };
|
|
955
|
+
}
|
|
956
|
+
//#endregion
|
|
957
|
+
//#region src/prompts.ts
|
|
958
|
+
function details$1(kind, message, choices) {
|
|
959
|
+
let normalizedMessage;
|
|
960
|
+
try {
|
|
961
|
+
normalizedMessage = typeof message === "string" ? message : String(message);
|
|
962
|
+
} catch {
|
|
963
|
+
normalizedMessage = "[Unserializable prompt message]";
|
|
964
|
+
}
|
|
965
|
+
return {
|
|
966
|
+
kind,
|
|
967
|
+
message: normalizedMessage,
|
|
968
|
+
...choices === void 0 ? {} : { choices }
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
function promptError(reason, prompt, message, cause) {
|
|
972
|
+
return new HackshPromptError(reason, prompt, message, cause === void 0 ? void 0 : { cause });
|
|
973
|
+
}
|
|
974
|
+
function validateMessage(kind, message, choices) {
|
|
975
|
+
if (typeof message !== "string" || message.length === 0) throw promptError("invalid-options", details$1(kind, message, choices), `Invalid ${kind} prompt: message must be a non-empty string`);
|
|
976
|
+
}
|
|
977
|
+
function asInput(value, prompt) {
|
|
978
|
+
if (typeof value !== "object" || value === null || typeof Reflect.get(value, "on") !== "function" || typeof Reflect.get(value, "removeListener") !== "function" || typeof Reflect.get(value, "resume") !== "function" || typeof Reflect.get(value, "pause") !== "function") throw promptError("input-error", prompt, "Interactive input is not a readable stream");
|
|
979
|
+
return value;
|
|
980
|
+
}
|
|
981
|
+
var PromptController = class {
|
|
982
|
+
#interactive;
|
|
983
|
+
#inputValue;
|
|
984
|
+
#printEvent;
|
|
985
|
+
#bufferedKeys = [];
|
|
986
|
+
#active = false;
|
|
987
|
+
constructor(options) {
|
|
988
|
+
this.#interactive = options.interactive;
|
|
989
|
+
this.#inputValue = options.input;
|
|
990
|
+
this.#printEvent = (event) => options.print(event);
|
|
991
|
+
}
|
|
992
|
+
async #print(state, prompt) {
|
|
993
|
+
try {
|
|
994
|
+
await this.#printEvent({
|
|
995
|
+
type: "prompt",
|
|
996
|
+
prompt: state
|
|
997
|
+
});
|
|
998
|
+
} catch (cause) {
|
|
999
|
+
throw promptError("printer-error", prompt, "The prompt could not be displayed", cause);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
async #run(prompt, initial, accept, update, submitted, closed) {
|
|
1003
|
+
if (!this.#interactive) throw promptError("non-interactive", prompt, `Cannot request ${prompt.kind} input in non-interactive mode: ${prompt.message}`);
|
|
1004
|
+
if (this.#active) throw promptError("overlapping", prompt, "Another prompt is already active");
|
|
1005
|
+
const input = asInput(this.#inputValue, prompt);
|
|
1006
|
+
this.#active = true;
|
|
1007
|
+
let originallyFlowing = false;
|
|
1008
|
+
let rawChanged = false;
|
|
1009
|
+
let outcome;
|
|
1010
|
+
try {
|
|
1011
|
+
originallyFlowing = input.readableFlowing === true;
|
|
1012
|
+
if (input.setRawMode && input.isRaw !== true) {
|
|
1013
|
+
input.setRawMode(true);
|
|
1014
|
+
rawChanged = true;
|
|
1015
|
+
}
|
|
1016
|
+
await this.#print(initial, prompt);
|
|
1017
|
+
outcome = {
|
|
1018
|
+
ok: true,
|
|
1019
|
+
value: await new Promise((resolve, reject) => {
|
|
1020
|
+
const keypressInput = new PassThrough();
|
|
1021
|
+
emitKeypressEvents(keypressInput);
|
|
1022
|
+
let settled = false;
|
|
1023
|
+
let draining = false;
|
|
1024
|
+
let finalized = false;
|
|
1025
|
+
let completion;
|
|
1026
|
+
const queuedKeys = this.#bufferedKeys.splice(0);
|
|
1027
|
+
const finalize = () => {
|
|
1028
|
+
if (finalized || !settled || draining) return;
|
|
1029
|
+
finalized = true;
|
|
1030
|
+
cleanup();
|
|
1031
|
+
completion?.();
|
|
1032
|
+
};
|
|
1033
|
+
const finish = (action) => {
|
|
1034
|
+
if (settled) return;
|
|
1035
|
+
settled = true;
|
|
1036
|
+
completion = action;
|
|
1037
|
+
finalize();
|
|
1038
|
+
};
|
|
1039
|
+
const fail = (reason, message, cause) => {
|
|
1040
|
+
finish(() => reject(promptError(reason, prompt, message, cause)));
|
|
1041
|
+
};
|
|
1042
|
+
const handleKeypress = async (character, key = {}) => {
|
|
1043
|
+
if (settled) return;
|
|
1044
|
+
if (key.ctrl && key.name === "c" || key.name === "escape") {
|
|
1045
|
+
fail("cancelled", "Prompt cancelled");
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
if (key.ctrl && key.name === "d") {
|
|
1049
|
+
fail("eof", "Prompt input ended before a value was submitted");
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
try {
|
|
1053
|
+
const value = accept(character ?? "", key);
|
|
1054
|
+
if (value !== void 0) {
|
|
1055
|
+
finish(() => resolve(value));
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
const state = update(character ?? "", key);
|
|
1059
|
+
if (state) await this.#print(state, prompt);
|
|
1060
|
+
} catch (cause) {
|
|
1061
|
+
if (cause instanceof HackshPromptError) finish(() => reject(cause));
|
|
1062
|
+
else fail("input-error", "Prompt input could not be processed", cause);
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
const drainKeys = async () => {
|
|
1066
|
+
if (draining || finalized) return;
|
|
1067
|
+
draining = true;
|
|
1068
|
+
try {
|
|
1069
|
+
while (queuedKeys.length > 0) {
|
|
1070
|
+
if (settled) {
|
|
1071
|
+
this.#bufferedKeys.push(...queuedKeys.splice(0));
|
|
1072
|
+
break;
|
|
1073
|
+
}
|
|
1074
|
+
const next = queuedKeys.shift();
|
|
1075
|
+
await handleKeypress(next.character, next.key);
|
|
1076
|
+
}
|
|
1077
|
+
} finally {
|
|
1078
|
+
draining = false;
|
|
1079
|
+
finalize();
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
const onKeypress = (character, key = {}) => {
|
|
1083
|
+
queuedKeys.push({
|
|
1084
|
+
character,
|
|
1085
|
+
key
|
|
1086
|
+
});
|
|
1087
|
+
drainKeys().catch((cause) => fail("input-error", "Prompt input could not be processed", cause));
|
|
1088
|
+
};
|
|
1089
|
+
const onEnd = () => fail("eof", "Prompt input ended before a value was submitted");
|
|
1090
|
+
const onError = (cause) => fail("input-error", "Prompt input failed", cause);
|
|
1091
|
+
const onData = (chunk) => {
|
|
1092
|
+
if (typeof chunk === "string" || chunk instanceof Uint8Array) keypressInput.write(chunk);
|
|
1093
|
+
else fail("input-error", "Prompt input produced a non-byte value");
|
|
1094
|
+
};
|
|
1095
|
+
const cleanup = () => {
|
|
1096
|
+
keypressInput.removeListener("keypress", onKeypress);
|
|
1097
|
+
keypressInput.destroy();
|
|
1098
|
+
input.removeListener("data", onData);
|
|
1099
|
+
input.removeListener("end", onEnd);
|
|
1100
|
+
input.removeListener("close", onEnd);
|
|
1101
|
+
input.removeListener("error", onError);
|
|
1102
|
+
};
|
|
1103
|
+
keypressInput.on("keypress", onKeypress);
|
|
1104
|
+
input.on("data", onData);
|
|
1105
|
+
input.on("end", onEnd);
|
|
1106
|
+
input.on("close", onEnd);
|
|
1107
|
+
input.on("error", onError);
|
|
1108
|
+
input.resume();
|
|
1109
|
+
drainKeys().catch((cause) => fail("input-error", "Prompt input could not be processed", cause));
|
|
1110
|
+
})
|
|
1111
|
+
};
|
|
1112
|
+
} catch (cause) {
|
|
1113
|
+
outcome = {
|
|
1114
|
+
ok: false,
|
|
1115
|
+
error: cause instanceof HackshPromptError ? cause : promptError("input-error", prompt, "Prompt input could not be initialized", cause)
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
let restoreError;
|
|
1119
|
+
try {
|
|
1120
|
+
if (rawChanged) input.setRawMode?.(false);
|
|
1121
|
+
if (!originallyFlowing) input.pause();
|
|
1122
|
+
} catch (cause) {
|
|
1123
|
+
restoreError = promptError("input-error", prompt, "Prompt input could not be restored", cause);
|
|
1124
|
+
}
|
|
1125
|
+
const closeWithFailure = async (failure) => {
|
|
1126
|
+
try {
|
|
1127
|
+
await this.#print(closed(), prompt);
|
|
1128
|
+
} catch {} finally {
|
|
1129
|
+
this.#active = false;
|
|
1130
|
+
}
|
|
1131
|
+
throw failure;
|
|
1132
|
+
};
|
|
1133
|
+
if (restoreError) return closeWithFailure(restoreError);
|
|
1134
|
+
if (!outcome.ok) return closeWithFailure(outcome.error);
|
|
1135
|
+
try {
|
|
1136
|
+
await this.#print(submitted(outcome.value), prompt);
|
|
1137
|
+
return outcome.value;
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
try {
|
|
1140
|
+
await this.#print(closed(), prompt);
|
|
1141
|
+
} catch {}
|
|
1142
|
+
throw error;
|
|
1143
|
+
} finally {
|
|
1144
|
+
this.#active = false;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
async select(options) {
|
|
1148
|
+
const choices = Array.isArray(options?.options) ? options.options.map((option) => typeof option === "object" && option !== null && typeof option.value === "string" ? option.value : "[Invalid choice]") : [];
|
|
1149
|
+
const prompt = details$1("select", options?.message, choices);
|
|
1150
|
+
validateMessage("select", options?.message, choices);
|
|
1151
|
+
if (!Array.isArray(options.options) || options.options.length === 0) throw promptError("invalid-options", prompt, "A select prompt requires at least one choice");
|
|
1152
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1153
|
+
for (const option of options.options) {
|
|
1154
|
+
if (typeof option !== "object" || option === null || typeof option.value !== "string" || option.value.length === 0 || option.label !== void 0 && typeof option.label !== "string" || option.hint !== void 0 && typeof option.hint !== "string") throw promptError("invalid-options", prompt, "Select choices must have valid string values");
|
|
1155
|
+
if (seen.has(option.value)) throw promptError("invalid-options", prompt, `Duplicate select choice: ${option.value}`);
|
|
1156
|
+
seen.add(option.value);
|
|
1157
|
+
}
|
|
1158
|
+
let selected = options.initialValue === void 0 ? 0 : choices.indexOf(options.initialValue);
|
|
1159
|
+
if (selected < 0) throw promptError("invalid-options", prompt, `Unknown initial select value: ${String(options.initialValue)}`);
|
|
1160
|
+
const state = (status = "active") => ({
|
|
1161
|
+
kind: "select",
|
|
1162
|
+
message: options.message,
|
|
1163
|
+
status,
|
|
1164
|
+
value: options.options[selected].value,
|
|
1165
|
+
choices: options.options.map(({ value, label, hint }, index) => ({
|
|
1166
|
+
value,
|
|
1167
|
+
label: label ?? value,
|
|
1168
|
+
...hint === void 0 ? {} : { hint },
|
|
1169
|
+
selected: index === selected
|
|
1170
|
+
}))
|
|
1171
|
+
});
|
|
1172
|
+
return await this.#run(prompt, state(), (_character, key) => key.name === "return" || key.name === "enter" ? options.options[selected].value : void 0, (_character, key) => {
|
|
1173
|
+
if (key.name !== "up" && key.name !== "down") return void 0;
|
|
1174
|
+
selected = (selected + (key.name === "up" ? -1 : 1) + options.options.length) % options.options.length;
|
|
1175
|
+
return state();
|
|
1176
|
+
}, () => state("submitted"), () => state("closed"));
|
|
1177
|
+
}
|
|
1178
|
+
async confirm(options) {
|
|
1179
|
+
const prompt = details$1("confirm", options?.message);
|
|
1180
|
+
validateMessage("confirm", options?.message);
|
|
1181
|
+
if (options.initialValue !== void 0 && typeof options.initialValue !== "boolean") throw promptError("invalid-options", prompt, "Confirm initialValue must be a boolean");
|
|
1182
|
+
const value = options.initialValue ?? false;
|
|
1183
|
+
const state = (result, status = "active") => ({
|
|
1184
|
+
kind: "confirm",
|
|
1185
|
+
message: options.message,
|
|
1186
|
+
status,
|
|
1187
|
+
value: result,
|
|
1188
|
+
...options.initialValue === void 0 ? {} : { defaultValue: options.initialValue }
|
|
1189
|
+
});
|
|
1190
|
+
return await this.#run(prompt, state(value), (character, key) => {
|
|
1191
|
+
if (key.name === "return" || key.name === "enter") return value;
|
|
1192
|
+
if (character.toLowerCase() === "y") return true;
|
|
1193
|
+
if (character.toLowerCase() === "n") return false;
|
|
1194
|
+
}, () => void 0, (submitted) => state(submitted, "submitted"), () => state(value, "closed"));
|
|
1195
|
+
}
|
|
1196
|
+
async text(options) {
|
|
1197
|
+
const prompt = details$1("text", options?.message);
|
|
1198
|
+
validateMessage("text", options?.message);
|
|
1199
|
+
if (options.placeholder !== void 0 && typeof options.placeholder !== "string") throw promptError("invalid-options", prompt, "Text placeholder must be a string");
|
|
1200
|
+
if (options.validate !== void 0 && typeof options.validate !== "function") throw promptError("invalid-options", prompt, "Text validate must be a function");
|
|
1201
|
+
let value = "";
|
|
1202
|
+
let validationError;
|
|
1203
|
+
const state = (status = validationError ? "error" : "active") => ({
|
|
1204
|
+
kind: "text",
|
|
1205
|
+
message: options.message,
|
|
1206
|
+
status,
|
|
1207
|
+
value,
|
|
1208
|
+
...options.placeholder === void 0 ? {} : { placeholder: options.placeholder },
|
|
1209
|
+
...validationError === void 0 ? {} : { error: validationError }
|
|
1210
|
+
});
|
|
1211
|
+
return await this.#run(prompt, state(), (_character, key) => {
|
|
1212
|
+
if (key.name !== "return" && key.name !== "enter") return void 0;
|
|
1213
|
+
let error;
|
|
1214
|
+
try {
|
|
1215
|
+
error = options.validate?.(value);
|
|
1216
|
+
} catch (cause) {
|
|
1217
|
+
throw promptError("input-error", prompt, "Text validation failed", cause);
|
|
1218
|
+
}
|
|
1219
|
+
if (error !== void 0 && typeof error !== "string") throw promptError("input-error", prompt, "Text validation must return a string or undefined");
|
|
1220
|
+
validationError = error || void 0;
|
|
1221
|
+
return validationError === void 0 ? value : void 0;
|
|
1222
|
+
}, (character, key) => {
|
|
1223
|
+
if (key.name === "return" || key.name === "enter") return state();
|
|
1224
|
+
validationError = void 0;
|
|
1225
|
+
if (key.name === "backspace") value = Array.from(value).slice(0, -1).join("");
|
|
1226
|
+
else if (!key.ctrl && !key.meta && character.length > 0) value += character;
|
|
1227
|
+
else return void 0;
|
|
1228
|
+
return state();
|
|
1229
|
+
}, () => state("submitted"), () => state("closed"));
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
//#endregion
|
|
1233
|
+
//#region src/logger.ts
|
|
1234
|
+
function interpolate(message, properties) {
|
|
1235
|
+
return message.replace(/\{([^{}]+)\}/g, (placeholder, key) => {
|
|
1236
|
+
if (!Object.hasOwn(properties, key)) return placeholder;
|
|
1237
|
+
try {
|
|
1238
|
+
return String(properties[key]);
|
|
1239
|
+
} catch {
|
|
1240
|
+
return placeholder;
|
|
1241
|
+
}
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
function createBoundLogger(printer, category, boundProperties, prompts) {
|
|
1245
|
+
function emit(level, kind, input, properties = {}) {
|
|
1246
|
+
const rawMessage = input instanceof Error ? input.message : input;
|
|
1247
|
+
const mergedProperties = {
|
|
1248
|
+
...boundProperties,
|
|
1249
|
+
...properties
|
|
1250
|
+
};
|
|
1251
|
+
if (input instanceof Error) mergedProperties.error = input;
|
|
1252
|
+
const summarizedProperties = summarizeErrors(mergedProperties);
|
|
1253
|
+
printer.print({
|
|
1254
|
+
type: "log",
|
|
1255
|
+
record: {
|
|
1256
|
+
level,
|
|
1257
|
+
kind,
|
|
1258
|
+
category,
|
|
1259
|
+
message: interpolate(rawMessage, mergedProperties),
|
|
1260
|
+
rawMessage,
|
|
1261
|
+
properties: summarizedProperties,
|
|
1262
|
+
timestamp: Date.now()
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
return {
|
|
1267
|
+
category,
|
|
1268
|
+
trace: (message, properties) => emit("trace", "message", message, properties),
|
|
1269
|
+
debug: (message, properties) => emit("debug", "message", message, properties),
|
|
1270
|
+
info: (message, properties) => emit("info", "message", message, properties),
|
|
1271
|
+
warn: (message, properties) => emit("warning", "message", message, properties),
|
|
1272
|
+
error: (message, properties) => emit("error", "message", message, properties),
|
|
1273
|
+
fatal: (message, properties) => emit("fatal", "message", message, properties),
|
|
1274
|
+
step: (message, properties) => emit("info", "step", message, properties),
|
|
1275
|
+
success: (message, properties) => emit("info", "success", message, properties),
|
|
1276
|
+
select: (options) => prompts.select(options),
|
|
1277
|
+
confirm: (options) => prompts.confirm(options),
|
|
1278
|
+
text: (options) => prompts.text(options),
|
|
1279
|
+
with: (properties) => createBoundLogger(printer, category, {
|
|
1280
|
+
...boundProperties,
|
|
1281
|
+
...properties
|
|
1282
|
+
}, prompts),
|
|
1283
|
+
getChild: (child) => createBoundLogger(printer, [...category, child], boundProperties, prompts)
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
/** Create the logger for one command invocation. */
|
|
1287
|
+
function createLogger(printer, category, options) {
|
|
1288
|
+
const prompts = new PromptController({
|
|
1289
|
+
interactive: options.interactive,
|
|
1290
|
+
input: options.input,
|
|
1291
|
+
print: (event) => options.printPrompt(event)
|
|
1292
|
+
});
|
|
1293
|
+
return createBoundLogger(printer, [...category], {}, prompts);
|
|
1294
|
+
}
|
|
1295
|
+
//#endregion
|
|
1296
|
+
//#region src/output.ts
|
|
1297
|
+
function consoleWriter(method, stream) {
|
|
1298
|
+
return {
|
|
1299
|
+
get isTTY() {
|
|
1300
|
+
return stream.isTTY;
|
|
1301
|
+
},
|
|
1302
|
+
get columns() {
|
|
1303
|
+
return stream.columns;
|
|
1304
|
+
},
|
|
1305
|
+
write(text) {
|
|
1306
|
+
if (!text.endsWith("\n")) return stream.write(text);
|
|
1307
|
+
console[method](text.slice(0, -1));
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
/** Resolve the automatic output policy and select its printer for one operation. */
|
|
1312
|
+
function selectOutputPrinter(options, override, resolvedMode) {
|
|
1313
|
+
const stdin = options.stdin ?? process.stdin;
|
|
1314
|
+
const stdout = options.stdout ?? process.stdout;
|
|
1315
|
+
const stderr = options.stderr ?? process.stderr;
|
|
1316
|
+
const mode = resolvedMode ?? resolveOutputMode({
|
|
1317
|
+
output: options.output,
|
|
1318
|
+
env: options.env,
|
|
1319
|
+
inputIsTTY: stdin.isTTY,
|
|
1320
|
+
outputIsTTY: stdout.isTTY
|
|
1321
|
+
});
|
|
1322
|
+
if (override) return override;
|
|
1323
|
+
if (mode.format === "json") return createJsonPrinter({
|
|
1324
|
+
stdout,
|
|
1325
|
+
stderr
|
|
1326
|
+
});
|
|
1327
|
+
const useConsole = options.stdout === void 0 && options.stderr === void 0;
|
|
1328
|
+
return createPrettyPrinter({
|
|
1329
|
+
color: mode.color,
|
|
1330
|
+
unicode: options.unicode ?? true,
|
|
1331
|
+
stdout: options.stdout ?? (useConsole ? consoleWriter("log", stdout) : stdout),
|
|
1332
|
+
stderr: options.stderr ?? (useConsole ? consoleWriter("error", process.stderr) : stderr)
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
//#endregion
|
|
363
1336
|
//#region src/usage.ts
|
|
364
1337
|
function details(description, required, defaultValue, choices) {
|
|
365
1338
|
const parts = [description];
|
|
@@ -372,64 +1345,118 @@ function formatDefault(value) {
|
|
|
372
1345
|
if (typeof value === "string") return value;
|
|
373
1346
|
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return value.toString();
|
|
374
1347
|
if (value === null) return "null";
|
|
375
|
-
|
|
1348
|
+
try {
|
|
1349
|
+
return JSON.stringify(value) ?? "undefined";
|
|
1350
|
+
} catch {
|
|
1351
|
+
return "[Unserializable]";
|
|
1352
|
+
}
|
|
376
1353
|
}
|
|
377
1354
|
function heading(command) {
|
|
378
1355
|
const identity = command.name ? `${command.name}${command.version ? ` v${command.version}` : ""}` : command.version ? `v${command.version}` : void 0;
|
|
379
1356
|
if (command.description && identity) return `${command.description} (${identity})`;
|
|
380
1357
|
return command.description ?? identity;
|
|
381
1358
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const title = heading(command);
|
|
385
|
-
if (title) lines.push(title, "");
|
|
1359
|
+
/** Build a serializable help summary without retaining command or schema objects. */
|
|
1360
|
+
function summarizeUsage(command) {
|
|
386
1361
|
const shape = command.args ? schemaShape(command.args) : {};
|
|
387
1362
|
const positionals = readPositionals(shape);
|
|
388
|
-
const
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
if (rest) syntax.push(`[${rest.label}...]`);
|
|
1363
|
+
const positionalItems = positionals?.items ?? [];
|
|
1364
|
+
const syntax = positionalItems.map(({ schema, label }) => readArgInfo(schema).required ? `<${label}>` : `[${label}]`);
|
|
1365
|
+
if (positionals?.rest) syntax.push(`[${positionals.rest.label}...]`);
|
|
392
1366
|
if (command.subCommands && Object.keys(command.subCommands).length > 0) syntax.push("<COMMAND>");
|
|
393
|
-
|
|
394
|
-
|
|
1367
|
+
const args = positionalItems.map(({ schema, label }) => {
|
|
1368
|
+
const info = readArgInfo(schema);
|
|
1369
|
+
return {
|
|
1370
|
+
name: label,
|
|
1371
|
+
required: info.required,
|
|
1372
|
+
variadic: false,
|
|
1373
|
+
...info.description === void 0 ? {} : { description: info.description },
|
|
1374
|
+
...info.choices === void 0 ? {} : { choices: info.choices },
|
|
1375
|
+
...info.defaultValue === void 0 ? {} : { defaultValue: summarizeErrors(info.defaultValue) }
|
|
1376
|
+
};
|
|
1377
|
+
});
|
|
1378
|
+
if (positionals?.rest) {
|
|
1379
|
+
const info = readArgInfo(positionals.rest.schema);
|
|
1380
|
+
args.push({
|
|
1381
|
+
name: positionals.rest.label,
|
|
1382
|
+
required: false,
|
|
1383
|
+
variadic: true,
|
|
1384
|
+
...info.description === void 0 ? {} : { description: info.description },
|
|
1385
|
+
...info.choices === void 0 ? {} : { choices: info.choices }
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
const options = Object.entries(shape).filter(([key]) => key !== "_").map(([key, schema]) => {
|
|
1389
|
+
const info = readArgInfo(schema);
|
|
1390
|
+
const argOptions = command.argOptions?.[key];
|
|
1391
|
+
const aliases = argOptions?.alias ? aliasList(argOptions.alias).map((item) => `-${item}`) : [];
|
|
1392
|
+
const name = kebabCase(key);
|
|
1393
|
+
const valueName = argOptions?.valueName ?? name;
|
|
1394
|
+
return {
|
|
1395
|
+
name,
|
|
1396
|
+
flags: [...aliases, `--${name}`],
|
|
1397
|
+
takesValue: info.takesValue,
|
|
1398
|
+
required: info.required,
|
|
1399
|
+
...info.takesValue ? { valueName } : {},
|
|
1400
|
+
...info.description === void 0 ? {} : { description: info.description },
|
|
1401
|
+
...info.choices === void 0 ? {} : { choices: info.choices },
|
|
1402
|
+
...info.defaultValue === void 0 ? {} : { defaultValue: summarizeErrors(info.defaultValue) },
|
|
1403
|
+
...argOptions?.negatedDescription === void 0 ? {} : { negatedDescription: argOptions.negatedDescription }
|
|
1404
|
+
};
|
|
1405
|
+
});
|
|
1406
|
+
const commands = Object.entries(command.subCommands ?? {}).filter(([, child]) => !child.hidden).map(([name, child]) => ({
|
|
1407
|
+
name,
|
|
1408
|
+
...child.description === void 0 ? {} : { description: child.description }
|
|
1409
|
+
}));
|
|
1410
|
+
const name = command.name ?? "command";
|
|
1411
|
+
const title = heading(command);
|
|
1412
|
+
return {
|
|
1413
|
+
name,
|
|
1414
|
+
...title === void 0 ? {} : { heading: title },
|
|
1415
|
+
...command.version === void 0 ? {} : { version: command.version },
|
|
1416
|
+
...command.description === void 0 ? {} : { description: command.description },
|
|
1417
|
+
synopsis: `${name} [OPTIONS]${syntax.length ? ` ${syntax.join(" ")}` : ""}`,
|
|
1418
|
+
arguments: args,
|
|
1419
|
+
options,
|
|
1420
|
+
commands
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
function formatUsage(summary) {
|
|
1424
|
+
const lines = [];
|
|
1425
|
+
if (summary.heading) lines.push(summary.heading, "");
|
|
1426
|
+
lines.push(`USAGE ${summary.synopsis}`);
|
|
1427
|
+
if (summary.arguments.length > 0) {
|
|
395
1428
|
lines.push("", "ARGUMENTS", "");
|
|
396
|
-
for (const {
|
|
397
|
-
const info = readArgInfo(schema);
|
|
398
|
-
lines.push(` ${label} ${details(info.description, info.required, info.defaultValue, info.choices)}`.trimEnd());
|
|
399
|
-
}
|
|
400
|
-
if (rest) {
|
|
401
|
-
const info = readArgInfo(rest.schema);
|
|
402
|
-
lines.push(` ${rest.label}... ${details(info.description, false, void 0, info.choices)}`.trimEnd());
|
|
403
|
-
}
|
|
1429
|
+
for (const argument of summary.arguments) lines.push(` ${argument.name}${argument.variadic ? "..." : ""} ${details(argument.description, argument.required, argument.defaultValue, argument.choices)}`.trimEnd());
|
|
404
1430
|
}
|
|
405
|
-
|
|
406
|
-
if (options.length > 0) {
|
|
1431
|
+
if (summary.options.length > 0) {
|
|
407
1432
|
lines.push("", "OPTIONS", "");
|
|
408
|
-
for (const
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const valueName = argOptions?.valueName ?? kebabCase(key);
|
|
413
|
-
const long = `--${kebabCase(key)}${info.takesValue ? `=<${valueName}>` : ""}`;
|
|
414
|
-
lines.push(` ${prefix}${long} ${details(info.description, info.required, info.defaultValue, info.choices)}`.trimEnd());
|
|
415
|
-
if (!info.takesValue && argOptions?.negatedDescription) lines.push(` --no-${kebabCase(key)} ${argOptions.negatedDescription}`);
|
|
1433
|
+
for (const option of summary.options) {
|
|
1434
|
+
const flags = option.flags.map((flag) => flag.startsWith("--") && option.takesValue ? `${flag}=<${option.valueName}>` : flag);
|
|
1435
|
+
lines.push(` ${flags.join(", ")} ${details(option.description, option.required, option.defaultValue, option.choices)}`.trimEnd());
|
|
1436
|
+
if (!option.takesValue && option.negatedDescription) lines.push(` --no-${option.name} ${option.negatedDescription}`);
|
|
416
1437
|
}
|
|
417
1438
|
}
|
|
418
|
-
|
|
419
|
-
if (visibleSubCommands.length > 0) {
|
|
1439
|
+
if (summary.commands.length > 0) {
|
|
420
1440
|
lines.push("", "COMMANDS", "");
|
|
421
|
-
for (const
|
|
1441
|
+
for (const command of summary.commands) lines.push(` ${command.name} ${command.description ?? ""}`.trimEnd());
|
|
422
1442
|
}
|
|
423
1443
|
return lines.join("\n");
|
|
424
1444
|
}
|
|
425
1445
|
/** Generate usage text without writing to stdout or stderr. */
|
|
426
1446
|
async function renderUsage(command) {
|
|
427
|
-
return formatUsage(command);
|
|
1447
|
+
return formatUsage(summarizeUsage(command));
|
|
428
1448
|
}
|
|
429
1449
|
/** Generate and write usage text, awaiting asynchronous writers. */
|
|
430
1450
|
async function showUsage(command, options = {}) {
|
|
431
|
-
const
|
|
432
|
-
|
|
1451
|
+
const usage = summarizeUsage(command);
|
|
1452
|
+
const text = formatUsage(usage);
|
|
1453
|
+
if (options.write) return options.write(text);
|
|
1454
|
+
return (options.printer ?? selectOutputPrinter(options)).print({
|
|
1455
|
+
type: "usage",
|
|
1456
|
+
usage,
|
|
1457
|
+
text,
|
|
1458
|
+
stream: options.stream ?? "stdout"
|
|
1459
|
+
});
|
|
433
1460
|
}
|
|
434
1461
|
//#endregion
|
|
435
1462
|
//#region src/run.ts
|
|
@@ -475,46 +1502,124 @@ function resolveCommand(root, rawArgs) {
|
|
|
475
1502
|
remaining = remaining.slice(index + 1);
|
|
476
1503
|
}
|
|
477
1504
|
}
|
|
478
|
-
async function executeCommand(root, argv, displayUsage) {
|
|
1505
|
+
async function executeCommand(root, argv, displayUsage, printer, loggerOptions) {
|
|
479
1506
|
const resolved = resolveCommand(root, argv);
|
|
480
1507
|
if (resolved.segments[0]?.tokenized.version) {
|
|
481
|
-
|
|
1508
|
+
await printer.print({
|
|
1509
|
+
type: "version",
|
|
1510
|
+
version: root.version ?? ""
|
|
1511
|
+
});
|
|
482
1512
|
return;
|
|
483
1513
|
}
|
|
484
1514
|
if (resolved.segments.some(({ tokenized }) => tokenized.help)) {
|
|
485
|
-
await displayUsage
|
|
1515
|
+
await printUsage(displayUsage, resolved.command, printer, "stdout");
|
|
486
1516
|
return;
|
|
487
1517
|
}
|
|
488
1518
|
for (const parent of resolved.parents) await parseCommandArgs(parent.command, parent.rawArgs, parent.tokenized);
|
|
489
1519
|
const parsed = await parseCommandArgs(resolved.command, resolved.rawArgs, resolved.tokenized);
|
|
490
1520
|
if (!resolved.command.run) throw new ZittyUsageError("No command specified", resolved.command);
|
|
1521
|
+
const category = resolved.segments.flatMap(({ command }) => command.name === void 0 ? [] : [command.name]);
|
|
491
1522
|
return resolved.command.run({
|
|
492
1523
|
...parsed,
|
|
493
1524
|
cmd: resolved.command,
|
|
494
|
-
rawArgs: resolved.rawArgs
|
|
1525
|
+
rawArgs: resolved.rawArgs,
|
|
1526
|
+
logger: createLogger(printer, category, loggerOptions)
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
function printUsage(displayUsage, command, printer, stream) {
|
|
1530
|
+
return displayUsage(command, { write: (text) => printer.print({
|
|
1531
|
+
type: "usage",
|
|
1532
|
+
usage: summarizeUsage(command),
|
|
1533
|
+
text,
|
|
1534
|
+
stream
|
|
1535
|
+
}) });
|
|
1536
|
+
}
|
|
1537
|
+
function prepareOutput(options) {
|
|
1538
|
+
const input = options.stdin ?? process.stdin;
|
|
1539
|
+
const mode = resolveOutputMode({
|
|
1540
|
+
output: options.output,
|
|
1541
|
+
env: options.env,
|
|
1542
|
+
inputIsTTY: input.isTTY,
|
|
1543
|
+
outputIsTTY: (options.stdout ?? process.stdout).isTTY
|
|
495
1544
|
});
|
|
1545
|
+
return {
|
|
1546
|
+
...createPrintQueue(selectOutputPrinter(options, options.printer, mode)),
|
|
1547
|
+
interactive: mode.interactive,
|
|
1548
|
+
input
|
|
1549
|
+
};
|
|
1550
|
+
}
|
|
1551
|
+
async function runCommand(root, argv, options = {}) {
|
|
1552
|
+
const output = prepareOutput(options);
|
|
1553
|
+
try {
|
|
1554
|
+
return await executeCommand(root, argv, options.showUsage ?? showUsage, output.printer, {
|
|
1555
|
+
interactive: output.interactive,
|
|
1556
|
+
input: output.input,
|
|
1557
|
+
printPrompt: (event) => output.printChecked(event)
|
|
1558
|
+
});
|
|
1559
|
+
} finally {
|
|
1560
|
+
await output.drain();
|
|
1561
|
+
}
|
|
496
1562
|
}
|
|
497
|
-
async function
|
|
498
|
-
|
|
1563
|
+
async function drainAndExit(output, code = 1) {
|
|
1564
|
+
try {
|
|
1565
|
+
await output.drain();
|
|
1566
|
+
} finally {
|
|
1567
|
+
process.exit(code);
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
function commandErrorExitCode(error) {
|
|
1571
|
+
return error instanceof HackshPromptError && error.reason === "cancelled" ? 130 : 1;
|
|
1572
|
+
}
|
|
1573
|
+
async function reportOutputSetupError(error, options) {
|
|
1574
|
+
if (options.onError) {
|
|
1575
|
+
await options.onError(error);
|
|
1576
|
+
return drainAndExit(createPrintQueue(options.printer ?? { print: () => void 0 }));
|
|
1577
|
+
}
|
|
1578
|
+
const output = createPrintQueue(options.printer ?? createJsonPrinter({
|
|
1579
|
+
stdout: options.stdout ?? process.stdout,
|
|
1580
|
+
stderr: options.stderr ?? process.stderr
|
|
1581
|
+
}));
|
|
1582
|
+
await output.printer.print({
|
|
1583
|
+
type: "error",
|
|
1584
|
+
error: summarizeError(error)
|
|
1585
|
+
});
|
|
1586
|
+
return drainAndExit(output);
|
|
499
1587
|
}
|
|
500
1588
|
async function runMain(command, options = {}) {
|
|
501
1589
|
const displayUsage = options.showUsage ?? showUsage;
|
|
1590
|
+
let output;
|
|
502
1591
|
try {
|
|
503
|
-
|
|
1592
|
+
output = prepareOutput(options);
|
|
1593
|
+
} catch (error) {
|
|
1594
|
+
return reportOutputSetupError(error, options);
|
|
1595
|
+
}
|
|
1596
|
+
try {
|
|
1597
|
+
await executeCommand(command, options.argv ?? process.argv.slice(2), displayUsage, output.printer, {
|
|
1598
|
+
interactive: output.interactive,
|
|
1599
|
+
input: output.input,
|
|
1600
|
+
printPrompt: (event) => output.printChecked(event)
|
|
1601
|
+
});
|
|
504
1602
|
} catch (error) {
|
|
505
1603
|
if (options.onError) {
|
|
506
1604
|
await options.onError(error);
|
|
507
|
-
|
|
1605
|
+
return drainAndExit(output, commandErrorExitCode(error));
|
|
508
1606
|
}
|
|
509
1607
|
try {
|
|
510
1608
|
if (error instanceof ZittyUsageError) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
1609
|
+
await output.printer.print({
|
|
1610
|
+
type: "error",
|
|
1611
|
+
error: summarizeError(error)
|
|
1612
|
+
});
|
|
1613
|
+
await printUsage(displayUsage, error.command, output.printer, "stderr");
|
|
1614
|
+
} else await output.printer.print({
|
|
1615
|
+
type: "error",
|
|
1616
|
+
error: summarizeError(error)
|
|
1617
|
+
});
|
|
514
1618
|
} finally {
|
|
515
|
-
|
|
1619
|
+
await drainAndExit(output, commandErrorExitCode(error));
|
|
516
1620
|
}
|
|
517
1621
|
}
|
|
1622
|
+
await output.drain();
|
|
518
1623
|
}
|
|
519
1624
|
function createMain(command, options = {}) {
|
|
520
1625
|
return (argv) => runMain(command, argv === void 0 ? options : {
|
|
@@ -523,6 +1628,6 @@ function createMain(command, options = {}) {
|
|
|
523
1628
|
});
|
|
524
1629
|
}
|
|
525
1630
|
//#endregion
|
|
526
|
-
export { ZittyUsageError, ZittyValidationError, createMain, defineCommand, parseArgs, renderUsage, runCommand, runMain, showUsage };
|
|
1631
|
+
export { HackshPromptError, ZittyUsageError, ZittyValidationError, consolePrinter, createJsonPrinter, createMain, createPrettyPrinter, createStreamPrinter, defineCommand, parseArgs, renderUsage, resolveOutputMode, runCommand, runMain, showUsage, summarizeUsage };
|
|
527
1632
|
|
|
528
1633
|
//# sourceMappingURL=index.js.map
|