@bcts/seedtool-cli 1.0.0-alpha.22 → 1.0.0-beta.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/main.mjs CHANGED
@@ -3,6 +3,7 @@ import { Command, Option } from "commander";
3
3
  import { SecureRandomNumberGenerator } from "@bcts/rand";
4
4
  import { SSKRGroupSpec, SSKRSecret, SSKRShare, SSKRSpec, Seed, sskrCombine, sskrGenerate } from "@bcts/components";
5
5
  import * as readline from "node:readline";
6
+ import * as fs from "node:fs";
6
7
  import { Envelope, SymmetricKey } from "@bcts/envelope";
7
8
  import { DATE, NAME, NOTE, SEED_TYPE } from "@bcts/known-values";
8
9
  import { CborDate, decodeCbor, expectBytes, toByteString, toTaggedValue } from "@bcts/dcbor";
@@ -12,8 +13,6 @@ import { BytewordsStyle, MultipartDecoder, MultipartEncoder, UR, decodeBytewords
12
13
  import { SSKR_SHARE, SSKR_SHARE_V1 } from "@bcts/tags";
13
14
  import { sha256 } from "@noble/hashes/sha2.js";
14
15
  import { hkdf } from "@noble/hashes/hkdf.js";
15
- import fs from "node:fs";
16
-
17
16
  //#region src/cli.ts
18
17
  /**
19
18
  * Copyright © 2023-2026 Blockchain Commons, LLC
@@ -24,63 +23,6 @@ import fs from "node:fs";
24
23
  * Ported from seedtool-cli-rust/src/cli.rs
25
24
  */
26
25
  /**
27
- * Input format keys.
28
- * Matches Rust InputFormatKey enum in format.rs
29
- */
30
- let InputFormatKey = /* @__PURE__ */ function(InputFormatKey) {
31
- InputFormatKey["Random"] = "random";
32
- InputFormatKey["Hex"] = "hex";
33
- InputFormatKey["Btw"] = "btw";
34
- InputFormatKey["Btwu"] = "btwu";
35
- InputFormatKey["Btwm"] = "btwm";
36
- InputFormatKey["Bits"] = "bits";
37
- InputFormatKey["Cards"] = "cards";
38
- InputFormatKey["Dice"] = "dice";
39
- InputFormatKey["Base6"] = "base6";
40
- InputFormatKey["Base10"] = "base10";
41
- InputFormatKey["Ints"] = "ints";
42
- InputFormatKey["Bip39"] = "bip39";
43
- InputFormatKey["Sskr"] = "sskr";
44
- InputFormatKey["Envelope"] = "envelope";
45
- InputFormatKey["Multipart"] = "multipart";
46
- InputFormatKey["Seed"] = "seed";
47
- return InputFormatKey;
48
- }({});
49
- /**
50
- * Output format keys.
51
- * Matches Rust OutputFormatKey enum in format.rs
52
- */
53
- let OutputFormatKey = /* @__PURE__ */ function(OutputFormatKey) {
54
- OutputFormatKey["Hex"] = "hex";
55
- OutputFormatKey["Btw"] = "btw";
56
- OutputFormatKey["Btwu"] = "btwu";
57
- OutputFormatKey["Btwm"] = "btwm";
58
- OutputFormatKey["Bits"] = "bits";
59
- OutputFormatKey["Cards"] = "cards";
60
- OutputFormatKey["Dice"] = "dice";
61
- OutputFormatKey["Base6"] = "base6";
62
- OutputFormatKey["Base10"] = "base10";
63
- OutputFormatKey["Ints"] = "ints";
64
- OutputFormatKey["Bip39"] = "bip39";
65
- OutputFormatKey["Sskr"] = "sskr";
66
- OutputFormatKey["Envelope"] = "envelope";
67
- OutputFormatKey["Multipart"] = "multipart";
68
- OutputFormatKey["Seed"] = "seed";
69
- return OutputFormatKey;
70
- }({});
71
- /**
72
- * SSKR output format keys.
73
- * Matches Rust SSKRFormatKey enum in sskr.rs
74
- */
75
- let SSKRFormatKey = /* @__PURE__ */ function(SSKRFormatKey) {
76
- SSKRFormatKey["Envelope"] = "envelope";
77
- SSKRFormatKey["Btw"] = "btw";
78
- SSKRFormatKey["Btwm"] = "btwm";
79
- SSKRFormatKey["Btwu"] = "btwu";
80
- SSKRFormatKey["Ur"] = "ur";
81
- return SSKRFormatKey;
82
- }({});
83
- /**
84
26
  * CLI state and configuration.
85
27
  * Matches Rust Cli struct.
86
28
  */
@@ -90,9 +32,9 @@ var Cli = class Cli {
90
32
  /** The number of output units (hex bytes, base-10 digits, etc.) */
91
33
  count = 16;
92
34
  /** The input format. Default: Random */
93
- in = InputFormatKey.Random;
35
+ in = "random";
94
36
  /** The output format. Default: Hex */
95
- out = OutputFormatKey.Hex;
37
+ out = "hex";
96
38
  /** The lowest int returned (0-254). Default: 0 */
97
39
  low = 0;
98
40
  /** The highest int returned (1-255), low < high. Default: 9 */
@@ -112,7 +54,7 @@ var Cli = class Cli {
112
54
  /** The number of groups that must meet their threshold. Default: 1 */
113
55
  groupThreshold = 1;
114
56
  /** SSKR output format. Default: Envelope */
115
- sskrFormat = SSKRFormatKey.Envelope;
57
+ sskrFormat = "envelope";
116
58
  /** Deterministic RNG seed string. */
117
59
  deterministic;
118
60
  /** The seed being processed (internal state). */
@@ -120,12 +62,21 @@ var Cli = class Cli {
120
62
  /** The RNG source (internal state). */
121
63
  rng;
122
64
  /**
123
- * Get input from argument or read from stdin.
124
- * Matches Rust expect_input method.
65
+ * Get input from argument or lazily read it from stdin.
66
+ *
67
+ * Mirrors Rust's `Cli::expect_input` (seedtool-cli-rust/src/cli.rs:191-200):
68
+ * stdin is touched only when an input-consuming code path actually needs it.
69
+ * Modes like `--in random` or `-d <SEED>` (deterministic) never call this,
70
+ * so they exit cleanly even when stdin is a non-TTY but no input is piped.
71
+ *
72
+ * Reads the stdin file descriptor synchronously via `fs.readFileSync(0, ...)`
73
+ * and caches the trimmed result on `this.input` so subsequent calls don't
74
+ * re-read.
125
75
  */
126
76
  expectInput() {
127
77
  if (this.input !== void 0) return this.input;
128
- throw new Error("Input required but not provided. Use stdin or pass as argument.");
78
+ this.input = fs.readFileSync(0, "utf-8").trim();
79
+ return this.input;
129
80
  }
130
81
  /**
131
82
  * Get input from argument or read from stdin asynchronously.
@@ -218,7 +169,6 @@ var Cli = class Cli {
218
169
  return cli;
219
170
  }
220
171
  };
221
-
222
172
  //#endregion
223
173
  //#region src/seed.ts
224
174
  /**
@@ -426,7 +376,6 @@ var Seed$1 = class Seed$1 {
426
376
  return true;
427
377
  }
428
378
  };
429
-
430
379
  //#endregion
431
380
  //#region src/util.ts
432
381
  /**
@@ -446,18 +395,34 @@ function dataToHex(bytes) {
446
395
  }
447
396
  /**
448
397
  * Convert hex string to bytes.
449
- * Matches Rust hex_to_data function.
398
+ *
399
+ * Mirrors the error wording produced by Rust's `hex` crate
400
+ * (`FromHexError::OddLength` and `FromHexError::InvalidHexCharacter`),
401
+ * which seedtool-cli-rust surfaces unchanged through anyhow:
402
+ *
403
+ * "Odd number of digits"
404
+ * "Invalid character '{c}' at position {n}"
405
+ *
406
+ * The outer CLI layer adds the `Error: ` prefix to match Rust's anyhow
407
+ * output.
450
408
  */
451
409
  function hexToData(hex) {
452
- if (hex.length % 2 !== 0) throw new Error("Hex string must have even length");
410
+ if (hex.length % 2 !== 0) throw new Error("Odd number of digits");
453
411
  const bytes = new Uint8Array(hex.length / 2);
454
412
  for (let i = 0; i < hex.length; i += 2) {
455
- const byte = parseInt(hex.substring(i, i + 2), 16);
456
- if (isNaN(byte)) throw new Error(`Invalid hex character at position ${i}`);
457
- bytes[i / 2] = byte;
413
+ const hi = hexCharToNibble(hex, i);
414
+ const lo = hexCharToNibble(hex, i + 1);
415
+ bytes[i / 2] = hi << 4 | lo;
458
416
  }
459
417
  return bytes;
460
418
  }
419
+ function hexCharToNibble(hex, index) {
420
+ const c = hex.charCodeAt(index);
421
+ if (c >= 48 && c <= 57) return c - 48;
422
+ if (c >= 97 && c <= 102) return c - 97 + 10;
423
+ if (c >= 65 && c <= 70) return c - 65 + 10;
424
+ throw new Error(`Invalid character '${hex[index]}' at position ${index}`);
425
+ }
461
426
  /**
462
427
  * Convert byte values to a different base range [0, base-1].
463
428
  * Each byte (0-255) is scaled proportionally to the target base.
@@ -535,12 +500,11 @@ function digitsToData(inStr, low, high) {
535
500
  const result = [];
536
501
  for (const c of inStr) {
537
502
  const n = c.charCodeAt(0) - "0".charCodeAt(0);
538
- if (n < low || n > high) throw new Error(`Invalid digit: ${c}. Expected range [${low}-${high}].`);
503
+ if (n < low || n > high) throw new Error("Invalid digit.");
539
504
  result.push(n);
540
505
  }
541
506
  return new Uint8Array(result);
542
507
  }
543
-
544
508
  //#endregion
545
509
  //#region src/formats/hex.ts
546
510
  /**
@@ -563,7 +527,6 @@ var HexFormat = class {
563
527
  return dataToHex(state.expectSeed().data());
564
528
  }
565
529
  };
566
-
567
530
  //#endregion
568
531
  //#region src/formats/bip39.ts
569
532
  /**
@@ -588,18 +551,9 @@ var Bip39Format = class {
588
551
  return entropyToMnemonic(state.expectSeed().data(), wordlist);
589
552
  }
590
553
  };
591
-
592
554
  //#endregion
593
555
  //#region src/formats/sskr.ts
594
556
  /**
595
- * Copyright © 2023-2026 Blockchain Commons, LLC
596
- * Copyright © 2025-2026 Parity Technologies
597
- *
598
- *
599
- * SSKR format
600
- * Ported from seedtool-cli-rust/src/formats/sskr.rs
601
- */
602
- /**
603
557
  * SSKR format handler.
604
558
  * Round-trippable: sskr shares → seed → sskr shares.
605
559
  * Supports multiple sub-formats: envelope, btw, btwm, btwu, ur.
@@ -624,15 +578,15 @@ var SSKRFormat = class {
624
578
  };
625
579
  function outputSskrSeed(seed, spec, format) {
626
580
  switch (format) {
627
- case SSKRFormatKey.Envelope: {
581
+ case "envelope": {
628
582
  const seedEnvelope = seed.toEnvelope();
629
583
  const contentKey = SymmetricKey.new();
630
584
  return seedEnvelope.wrap().encryptSubject(contentKey).sskrSplitFlattened(spec, contentKey).map((env) => env.urString()).join("\n");
631
585
  }
632
- case SSKRFormatKey.Btw: return makeBytewordsShares(spec, seed, BytewordsStyle.Standard);
633
- case SSKRFormatKey.Btwm: return makeBytewordsShares(spec, seed, BytewordsStyle.Minimal);
634
- case SSKRFormatKey.Btwu: return makeBytewordsShares(spec, seed, BytewordsStyle.Uri);
635
- case SSKRFormatKey.Ur: return makeShares(spec, seed).map((share) => {
586
+ case "btw": return makeBytewordsShares(spec, seed, BytewordsStyle.Standard);
587
+ case "btwm": return makeBytewordsShares(spec, seed, BytewordsStyle.Minimal);
588
+ case "btwu": return makeBytewordsShares(spec, seed, BytewordsStyle.Uri);
589
+ case "ur": return makeShares(spec, seed).map((share) => {
636
590
  return UR.new("sskr", toByteString(share.asBytes())).toString();
637
591
  }).join("\n");
638
592
  }
@@ -742,7 +696,6 @@ function parseSskrSeed(input) {
742
696
  if (urLegacyResult !== null) return urLegacyResult;
743
697
  throw new Error("Insufficient or invalid SSKR shares.");
744
698
  }
745
-
746
699
  //#endregion
747
700
  //#region src/formats/envelope.ts
748
701
  /**
@@ -766,7 +719,6 @@ var EnvelopeFormat = class {
766
719
  return state.toEnvelope().urString();
767
720
  }
768
721
  };
769
-
770
722
  //#endregion
771
723
  //#region src/formats/seed-format.ts
772
724
  /**
@@ -791,7 +743,6 @@ var SeedFormat = class {
791
743
  return state.seedWithOverrides().toComponentsSeed().urString();
792
744
  }
793
745
  };
794
-
795
746
  //#endregion
796
747
  //#region src/formats/multipart.ts
797
748
  /**
@@ -813,7 +764,7 @@ var MultipartFormat = class {
813
764
  decoder.receive(share);
814
765
  if (decoder.isComplete()) break;
815
766
  }
816
- if (!decoder.isComplete()) throw new Error("Insufficient multipart shares");
767
+ if (!decoder.isComplete()) throw new Error("Insufficient SSKR shares");
817
768
  const ur = decoder.message();
818
769
  if (ur === void 0 || ur === null) throw new Error("Failed to decode multipart message");
819
770
  const envelope = Envelope.fromUR(ur);
@@ -828,7 +779,6 @@ var MultipartFormat = class {
828
779
  return parts.join("\n");
829
780
  }
830
781
  };
831
-
832
782
  //#endregion
833
783
  //#region src/formats/random.ts
834
784
  /**
@@ -848,7 +798,6 @@ var RandomFormat = class {
848
798
  return state;
849
799
  }
850
800
  };
851
-
852
801
  //#endregion
853
802
  //#region src/random.ts
854
803
  /**
@@ -956,7 +905,6 @@ function sha256DeterministicRandomString(str, n) {
956
905
  function deterministicRandom(entropy, n) {
957
906
  return hkdfHmacSha256(sha256(entropy), new Uint8Array(0), n);
958
907
  }
959
-
960
908
  //#endregion
961
909
  //#region src/formats/base6.ts
962
910
  /**
@@ -982,7 +930,6 @@ var Base6Format = class {
982
930
  return dataToInts(state.expectSeed().data(), 0, 5, "");
983
931
  }
984
932
  };
985
-
986
933
  //#endregion
987
934
  //#region src/formats/base10.ts
988
935
  /**
@@ -1008,7 +955,6 @@ var Base10Format = class {
1008
955
  return dataToInts(state.expectSeed().data(), 0, 9, "");
1009
956
  }
1010
957
  };
1011
-
1012
958
  //#endregion
1013
959
  //#region src/formats/bits.ts
1014
960
  /**
@@ -1034,7 +980,6 @@ var BitsFormat = class {
1034
980
  return dataToInts(state.expectSeed().data(), 0, 1, "");
1035
981
  }
1036
982
  };
1037
-
1038
983
  //#endregion
1039
984
  //#region src/formats/dice.ts
1040
985
  /**
@@ -1060,7 +1005,6 @@ var DiceFormat = class {
1060
1005
  return dataToInts(state.expectSeed().data(), 1, 6, "");
1061
1006
  }
1062
1007
  };
1063
-
1064
1008
  //#endregion
1065
1009
  //#region src/formats/cards.ts
1066
1010
  const CARD_SUITS = "cdhs";
@@ -1072,7 +1016,7 @@ const CARD_RANKS = "a23456789tjqk";
1072
1016
  function parseRank(c) {
1073
1017
  const lower = c.toLowerCase();
1074
1018
  const index = CARD_RANKS.indexOf(lower);
1075
- if (index === -1) throw new Error(`Invalid card rank: ${c}. Allowed: [A,2-9,T,J,Q,K]`);
1019
+ if (index === -1) throw new Error("Invalid card rank. Allowed: [A,2-9,T,J,Q,K]");
1076
1020
  return index;
1077
1021
  }
1078
1022
  /**
@@ -1082,7 +1026,7 @@ function parseRank(c) {
1082
1026
  function parseSuit(c) {
1083
1027
  const lower = c.toLowerCase();
1084
1028
  const index = CARD_SUITS.indexOf(lower);
1085
- if (index === -1) throw new Error(`Invalid card suit: ${c}. Allowed: [C,D,H,S]`);
1029
+ if (index === -1) throw new Error("Invalid card rank. Allowed: [D,C,H,S]");
1086
1030
  return index;
1087
1031
  }
1088
1032
  /**
@@ -1130,7 +1074,6 @@ var CardsFormat = class {
1130
1074
  return dataToAlphabet(state.expectSeed().data(), 52, toCard);
1131
1075
  }
1132
1076
  };
1133
-
1134
1077
  //#endregion
1135
1078
  //#region src/formats/ints.ts
1136
1079
  /**
@@ -1154,7 +1097,6 @@ var IntsFormat = class {
1154
1097
  return dataToInts(state.expectSeed().data(), state.low, state.high, " ");
1155
1098
  }
1156
1099
  };
1157
-
1158
1100
  //#endregion
1159
1101
  //#region src/formats/bytewords-standard.ts
1160
1102
  /**
@@ -1178,7 +1120,6 @@ var BytewordsStandardFormat = class {
1178
1120
  return encodeBytewords(state.expectSeed().data(), BytewordsStyle.Standard);
1179
1121
  }
1180
1122
  };
1181
-
1182
1123
  //#endregion
1183
1124
  //#region src/formats/bytewords-minimal.ts
1184
1125
  /**
@@ -1202,7 +1143,6 @@ var BytewordsMinimalFormat = class {
1202
1143
  return encodeBytewords(state.expectSeed().data(), BytewordsStyle.Minimal);
1203
1144
  }
1204
1145
  };
1205
-
1206
1146
  //#endregion
1207
1147
  //#region src/formats/bytewords-uri.ts
1208
1148
  /**
@@ -1226,39 +1166,30 @@ var BytewordsUriFormat = class {
1226
1166
  return encodeBytewords(state.expectSeed().data(), BytewordsStyle.Uri);
1227
1167
  }
1228
1168
  };
1229
-
1230
1169
  //#endregion
1231
1170
  //#region src/formats/format.ts
1232
1171
  /**
1233
- * Copyright © 2023-2026 Blockchain Commons, LLC
1234
- * Copyright © 2025-2026 Parity Technologies
1235
- *
1236
- *
1237
- * Format traits and factory functions
1238
- * Ported from seedtool-cli-rust/src/formats/format.rs
1239
- */
1240
- /**
1241
1172
  * Select input format by key.
1242
1173
  * Matches Rust select_input_format function.
1243
1174
  */
1244
1175
  function selectInputFormat(key) {
1245
1176
  switch (key) {
1246
- case InputFormatKey.Random: return new RandomFormat();
1247
- case InputFormatKey.Hex: return new HexFormat();
1248
- case InputFormatKey.Btw: return new BytewordsStandardFormat();
1249
- case InputFormatKey.Btwu: return new BytewordsUriFormat();
1250
- case InputFormatKey.Btwm: return new BytewordsMinimalFormat();
1251
- case InputFormatKey.Bits: return new BitsFormat();
1252
- case InputFormatKey.Cards: return new CardsFormat();
1253
- case InputFormatKey.Dice: return new DiceFormat();
1254
- case InputFormatKey.Base6: return new Base6Format();
1255
- case InputFormatKey.Base10: return new Base10Format();
1256
- case InputFormatKey.Ints: return new IntsFormat();
1257
- case InputFormatKey.Bip39: return new Bip39Format();
1258
- case InputFormatKey.Sskr: return new SSKRFormat();
1259
- case InputFormatKey.Envelope: return new EnvelopeFormat();
1260
- case InputFormatKey.Multipart: return new MultipartFormat();
1261
- case InputFormatKey.Seed: return new SeedFormat();
1177
+ case "random": return new RandomFormat();
1178
+ case "hex": return new HexFormat();
1179
+ case "btw": return new BytewordsStandardFormat();
1180
+ case "btwu": return new BytewordsUriFormat();
1181
+ case "btwm": return new BytewordsMinimalFormat();
1182
+ case "bits": return new BitsFormat();
1183
+ case "cards": return new CardsFormat();
1184
+ case "dice": return new DiceFormat();
1185
+ case "base6": return new Base6Format();
1186
+ case "base10": return new Base10Format();
1187
+ case "ints": return new IntsFormat();
1188
+ case "bip39": return new Bip39Format();
1189
+ case "sskr": return new SSKRFormat();
1190
+ case "envelope": return new EnvelopeFormat();
1191
+ case "multipart": return new MultipartFormat();
1192
+ case "seed": return new SeedFormat();
1262
1193
  }
1263
1194
  }
1264
1195
  /**
@@ -1267,24 +1198,23 @@ function selectInputFormat(key) {
1267
1198
  */
1268
1199
  function selectOutputFormat(key) {
1269
1200
  switch (key) {
1270
- case OutputFormatKey.Hex: return new HexFormat();
1271
- case OutputFormatKey.Btw: return new BytewordsStandardFormat();
1272
- case OutputFormatKey.Btwu: return new BytewordsUriFormat();
1273
- case OutputFormatKey.Btwm: return new BytewordsMinimalFormat();
1274
- case OutputFormatKey.Bits: return new BitsFormat();
1275
- case OutputFormatKey.Cards: return new CardsFormat();
1276
- case OutputFormatKey.Dice: return new DiceFormat();
1277
- case OutputFormatKey.Base6: return new Base6Format();
1278
- case OutputFormatKey.Base10: return new Base10Format();
1279
- case OutputFormatKey.Ints: return new IntsFormat();
1280
- case OutputFormatKey.Bip39: return new Bip39Format();
1281
- case OutputFormatKey.Sskr: return new SSKRFormat();
1282
- case OutputFormatKey.Envelope: return new EnvelopeFormat();
1283
- case OutputFormatKey.Multipart: return new MultipartFormat();
1284
- case OutputFormatKey.Seed: return new SeedFormat();
1201
+ case "hex": return new HexFormat();
1202
+ case "btw": return new BytewordsStandardFormat();
1203
+ case "btwu": return new BytewordsUriFormat();
1204
+ case "btwm": return new BytewordsMinimalFormat();
1205
+ case "bits": return new BitsFormat();
1206
+ case "cards": return new CardsFormat();
1207
+ case "dice": return new DiceFormat();
1208
+ case "base6": return new Base6Format();
1209
+ case "base10": return new Base10Format();
1210
+ case "ints": return new IntsFormat();
1211
+ case "bip39": return new Bip39Format();
1212
+ case "sskr": return new SSKRFormat();
1213
+ case "envelope": return new EnvelopeFormat();
1214
+ case "multipart": return new MultipartFormat();
1215
+ case "seed": return new SeedFormat();
1285
1216
  }
1286
1217
  }
1287
-
1288
1218
  //#endregion
1289
1219
  //#region src/main.ts
1290
1220
  /**
@@ -1295,7 +1225,74 @@ function selectOutputFormat(key) {
1295
1225
  * A tool for generating and transforming cryptographic seeds.
1296
1226
  * Ported from seedtool-cli-rust/src/main.rs
1297
1227
  */
1298
- const VERSION = "0.4.0";
1228
+ /**
1229
+ * Package version, sourced from `package.json` so the CLI's `--version` output
1230
+ * never drifts from the published version.
1231
+ */
1232
+ const VERSION = "1.0.0-beta.0";
1233
+ /**
1234
+ * Build an argParser that validates a value against the given choices and,
1235
+ * on failure, emits the clap-style error format used by Rust's seedtool-cli:
1236
+ *
1237
+ * error: invalid value 'X' for '--<long> <UPPER>'
1238
+ * [possible values: a, b, c]
1239
+ *
1240
+ * For more information, try '--help'.
1241
+ *
1242
+ * `metavar` is the value-name placeholder (e.g. INPUT_TYPE), normally derived
1243
+ * from the option's `<META>` declaration. Used in conjunction with `.choices()`
1244
+ * for help-text generation — argParser runs first, so on a bad value we exit
1245
+ * before commander's own choice-validation message can fire.
1246
+ */
1247
+ function clapChoiceParser(longName, metavar, choices) {
1248
+ return (value) => {
1249
+ if (choices.includes(value)) return value;
1250
+ process.stderr.write(`error: invalid value '${value}' for '--${longName} <${metavar}>'\n [possible values: ${choices.join(", ")}]\n\nFor more information, try '--help'.\n`);
1251
+ process.exit(2);
1252
+ };
1253
+ }
1254
+ const IN_CHOICES = [
1255
+ "random",
1256
+ "hex",
1257
+ "btw",
1258
+ "btwu",
1259
+ "btwm",
1260
+ "bits",
1261
+ "cards",
1262
+ "dice",
1263
+ "base6",
1264
+ "base10",
1265
+ "ints",
1266
+ "bip39",
1267
+ "sskr",
1268
+ "envelope",
1269
+ "multipart",
1270
+ "seed"
1271
+ ];
1272
+ const OUT_CHOICES = [
1273
+ "hex",
1274
+ "btw",
1275
+ "btwu",
1276
+ "btwm",
1277
+ "bits",
1278
+ "cards",
1279
+ "dice",
1280
+ "base6",
1281
+ "base10",
1282
+ "ints",
1283
+ "bip39",
1284
+ "sskr",
1285
+ "envelope",
1286
+ "multipart",
1287
+ "seed"
1288
+ ];
1289
+ const SSKR_FORMAT_CHOICES = [
1290
+ "envelope",
1291
+ "btw",
1292
+ "btwm",
1293
+ "btwu",
1294
+ "ur"
1295
+ ];
1299
1296
  function parseLowInt(value) {
1300
1297
  const num = parseInt(value, 10);
1301
1298
  if (isNaN(num) || num < 0 || num > 254) throw new Error("LOW must be between 0 and 254");
@@ -1323,52 +1320,12 @@ function parseGroupSpec(value, previous) {
1323
1320
  }
1324
1321
  function main() {
1325
1322
  const program = new Command();
1326
- program.name("seedtool").description("A tool for generating and transforming cryptographic seeds.\n\nby Wolf McNally and Christopher Allen\n\nReport bugs to ChristopherA@BlockchainCommons.com.\n© 2024 Blockchain Commons.").version(VERSION).argument("[INPUT]", "The input to be transformed. If required and not present, it will be read from stdin.").option("-c, --count <COUNT>", "The number of output units (hex bytes, base-10 digits, etc.)", "16").addOption(new Option("-i, --in <INPUT_TYPE>", "The input format. If not specified, a new random seed is generated using a secure random number generator.").choices([
1327
- "random",
1328
- "hex",
1329
- "btw",
1330
- "btwm",
1331
- "btwu",
1332
- "bits",
1333
- "cards",
1334
- "dice",
1335
- "base6",
1336
- "base10",
1337
- "ints",
1338
- "bip39",
1339
- "sskr",
1340
- "envelope",
1341
- "seed",
1342
- "multipart"
1343
- ]).default("random")).addOption(new Option("-o, --out <OUTPUT_TYPE>", "The output format.").choices([
1344
- "hex",
1345
- "btw",
1346
- "btwm",
1347
- "btwu",
1348
- "bits",
1349
- "cards",
1350
- "dice",
1351
- "base6",
1352
- "base10",
1353
- "ints",
1354
- "bip39",
1355
- "sskr",
1356
- "envelope",
1357
- "seed",
1358
- "multipart"
1359
- ]).default("hex")).option("--low <LOW>", "The lowest int returned (0-254)", parseLowInt, 0).option("--high <HIGH>", "The highest int returned (1-255), low < high", parseHighInt, 9).option("--name <NAME>", "The name of the seed.").option("--note <NOTE>", "The note associated with the seed.").option("--date <DATE>", "The seed's creation date, in ISO-8601 format. May also be `now`.").option("--max-fragment-len <MAX_FRAG_LEN>", "For `multipart` output, the UR will be segmented into parts with fragments no larger than MAX_FRAG_LEN", "500").option("--additional-parts <NUM_PARTS>", "For `multipart` output, the number of additional parts above the minimum to generate using fountain encoding.", "0").option("-g, --groups <M-of-N>", "Group specifications. May appear more than once. M must be < N", parseGroupSpec, []).option("-t, --group-threshold <THRESHOLD>", "The number of groups that must meet their threshold. Must be <= the number of group specifications.", parseGroupThreshold, 1).addOption(new Option("-s, --sskr-format <SSKR_FORMAT>", "SSKR output format.").choices([
1360
- "envelope",
1361
- "btw",
1362
- "btwm",
1363
- "btwu",
1364
- "ur"
1365
- ]).default("envelope")).option("-d, --deterministic <SEED_STRING>", "Use a deterministic random number generator with the given seed string. Output generated from this seed will be the same every time, so generated seeds are only as secure as the seed string.");
1323
+ program.name("seedtool").description("A tool for generating and transforming cryptographic seeds.\n\nby Wolf McNally and Christopher Allen\n\nReport bugs to ChristopherA@BlockchainCommons.com.\n© 2024 Blockchain Commons.").version(`@bcts/seedtool-cli ${VERSION}`).argument("[INPUT]", "The input to be transformed. If required and not present, it will be read from stdin").option("-c, --count <COUNT>", "The number of output units (hex bytes, base-10 digits, etc.)", "16").addOption(new Option("-i, --in <INPUT_TYPE>", "The input format. If not specified, a new random seed is generated using a secure random number generator").choices([...IN_CHOICES]).argParser(clapChoiceParser("in", "INPUT_TYPE", IN_CHOICES)).default("random")).addOption(new Option("-o, --out <OUTPUT_TYPE>", "The output format").choices([...OUT_CHOICES]).argParser(clapChoiceParser("out", "OUTPUT_TYPE", OUT_CHOICES)).default("hex")).option("--low <LOW>", "The lowest int returned (0-254)", parseLowInt, 0).option("--high <HIGH>", "The highest int returned (1-255), low < high", parseHighInt, 9).option("--name <NAME>", "The name of the seed").option("--note <NOTE>", "The note associated with the seed").option("--date <DATE>", "The seed's creation date, in ISO-8601 format. May also be `now`").option("--max-fragment-len <MAX_FRAG_LEN>", "For `multipart` output, the UR will be segmented into parts with fragments no larger than MAX_FRAG_LEN", "500").option("--additional-parts <NUM_PARTS>", "For `multipart` output, the number of additional parts above the minimum to generate using fountain encoding", "0").option("-g, --groups <M-of-N>", "Group specifications. May appear more than once. M must be < N", parseGroupSpec, []).option("-t, --group-threshold <THRESHOLD>", "The number of groups that must meet their threshold. Must be <= the number of group specifications", parseGroupThreshold, 1).addOption(new Option("-s, --sskr-format <SSKR_FORMAT>", "Output format").choices([...SSKR_FORMAT_CHOICES]).argParser(clapChoiceParser("sskr-format", "SSKR_FORMAT", SSKR_FORMAT_CHOICES)).default("envelope")).option("-d, --deterministic <SEED_STRING>", "Use a deterministic random number generator with the given seed string. Output generated from this seed will be the same every time, so generated seeds are only as secure as the seed string");
1366
1324
  program.parse();
1367
1325
  const options = program.opts();
1368
1326
  const args = program.args;
1369
1327
  const cli = new Cli();
1370
1328
  if (args.length > 0) cli.input = args[0];
1371
- else if (process.stdin.isTTY !== true) cli.input = fs.readFileSync(process.stdin.fd, "utf-8").trim();
1372
1329
  cli.count = parseInt(options.count, 10);
1373
1330
  cli.in = options.in;
1374
1331
  cli.out = options.out;
@@ -1404,10 +1361,11 @@ try {
1404
1361
  main();
1405
1362
  } catch (error) {
1406
1363
  const message = error instanceof Error ? error.message : String(error);
1407
- console.error(message);
1364
+ const prefixed = message.startsWith("Error: ") ? message : `Error: ${message}`;
1365
+ console.error(prefixed);
1408
1366
  process.exit(1);
1409
1367
  }
1410
-
1411
1368
  //#endregion
1412
- export { };
1369
+ export {};
1370
+
1413
1371
  //# sourceMappingURL=main.mjs.map