rudel 0.1.1

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.
Files changed (2) hide show
  1. package/dist/cli.js +3933 -0
  2. package/package.json +28 -0
package/dist/cli.js ADDED
@@ -0,0 +1,3933 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+
4
+ // ../../node_modules/.bun/@stricli+core@1.2.5/node_modules/@stricli/core/dist/index.js
5
+ function checkEnvironmentVariable(process2, varName) {
6
+ const value = process2.env?.[varName];
7
+ return typeof value === "string" && value !== "0";
8
+ }
9
+ var ExitCode = {
10
+ UnknownCommand: -5,
11
+ InvalidArgument: -4,
12
+ ContextLoadError: -3,
13
+ CommandLoadError: -2,
14
+ InternalError: -1,
15
+ Success: 0,
16
+ CommandRunError: 1
17
+ };
18
+ function convertKebabCaseToCamelCase(str) {
19
+ return str.replace(/-./g, (match) => match[1].toUpperCase());
20
+ }
21
+ function convertCamelCaseToKebabCase(name) {
22
+ return Array.from(name).map((char, i) => {
23
+ const upper = char.toUpperCase();
24
+ const lower = char.toLowerCase();
25
+ if (i === 0 || upper !== char || upper === lower) {
26
+ return char;
27
+ }
28
+ return `-${lower}`;
29
+ }).join("");
30
+ }
31
+ function newSparseMatrix(defaultValue) {
32
+ const values = /* @__PURE__ */ new Map;
33
+ return {
34
+ get: (...args) => {
35
+ return values.get(args.join(",")) ?? defaultValue;
36
+ },
37
+ set: (value, ...args) => {
38
+ values.set(args.join(","), value);
39
+ }
40
+ };
41
+ }
42
+ function damerauLevenshtein(a, b, options) {
43
+ const { threshold, weights } = options;
44
+ if (a === b) {
45
+ return 0;
46
+ }
47
+ const lengthDiff = Math.abs(a.length - b.length);
48
+ if (typeof threshold === "number" && lengthDiff > threshold) {
49
+ return Infinity;
50
+ }
51
+ const matrix = newSparseMatrix(Infinity);
52
+ matrix.set(0, -1, -1);
53
+ for (let j = 0;j < b.length; ++j) {
54
+ matrix.set((j + 1) * weights.insertion, -1, j);
55
+ }
56
+ for (let i = 0;i < a.length; ++i) {
57
+ matrix.set((i + 1) * weights.deletion, i, -1);
58
+ }
59
+ let prevRowMinDistance = -Infinity;
60
+ for (let i = 0;i < a.length; ++i) {
61
+ let rowMinDistance = Infinity;
62
+ for (let j = 0;j <= b.length - 1; ++j) {
63
+ const cost = a[i] === b[j] ? 0 : 1;
64
+ const distances = [
65
+ matrix.get(i - 1, j) + weights.deletion,
66
+ matrix.get(i, j - 1) + weights.insertion,
67
+ matrix.get(i - 1, j - 1) + cost * weights.substitution
68
+ ];
69
+ if (a[i] === b[j - 1] && a[i - 1] === b[j]) {
70
+ distances.push(matrix.get(i - 2, j - 2) + cost * weights.transposition);
71
+ }
72
+ const minDistance = Math.min(...distances);
73
+ matrix.set(minDistance, i, j);
74
+ if (minDistance < rowMinDistance) {
75
+ rowMinDistance = minDistance;
76
+ }
77
+ }
78
+ if (rowMinDistance > threshold) {
79
+ if (prevRowMinDistance > threshold) {
80
+ return Infinity;
81
+ }
82
+ prevRowMinDistance = rowMinDistance;
83
+ } else {
84
+ prevRowMinDistance = -Infinity;
85
+ }
86
+ }
87
+ const distance = matrix.get(a.length - 1, b.length - 1);
88
+ if (distance > threshold) {
89
+ return Infinity;
90
+ }
91
+ return distance;
92
+ }
93
+ function compareAlternatives(a, b, target) {
94
+ const cmp = a[1] - b[1];
95
+ if (cmp !== 0) {
96
+ return cmp;
97
+ }
98
+ const aStartsWith = a[0].startsWith(target);
99
+ const bStartsWith = b[0].startsWith(target);
100
+ if (aStartsWith && !bStartsWith) {
101
+ return -1;
102
+ } else if (!aStartsWith && bStartsWith) {
103
+ return 1;
104
+ }
105
+ return a[0].localeCompare(b[0]);
106
+ }
107
+ function filterClosestAlternatives(target, alternatives, options) {
108
+ const validAlternatives = alternatives.map((alt) => [alt, damerauLevenshtein(target, alt, options)]).filter(([, dist]) => dist <= options.threshold);
109
+ const minDistance = Math.min(...validAlternatives.map(([, dist]) => dist));
110
+ return validAlternatives.filter(([, dist]) => dist === minDistance).sort((a, b) => compareAlternatives(a, b, target)).map(([alt]) => alt);
111
+ }
112
+ var InternalError = class extends Error {
113
+ };
114
+ function formatException(exc) {
115
+ if (exc instanceof Error) {
116
+ return exc.stack ?? String(exc);
117
+ }
118
+ return String(exc);
119
+ }
120
+ function maximum(arr1, arr2) {
121
+ const maxValues = [];
122
+ const maxLength = Math.max(arr1.length, arr2.length);
123
+ for (let i = 0;i < maxLength; ++i) {
124
+ maxValues[i] = Math.max(arr1[i], arr2[i]);
125
+ }
126
+ return maxValues;
127
+ }
128
+ function formatRowsWithColumns(cells, separators) {
129
+ if (cells.length === 0) {
130
+ return [];
131
+ }
132
+ const startingLengths = Array(Math.max(...cells.map((cellRow) => cellRow.length))).fill(0, 0);
133
+ const maxLengths = cells.reduce((acc, cellRow) => {
134
+ const lengths = cellRow.map((cell) => cell.length);
135
+ return maximum(acc, lengths);
136
+ }, startingLengths);
137
+ return cells.map((cellRow) => {
138
+ const firstCell = (cellRow[0] ?? "").padEnd(maxLengths[0]);
139
+ return cellRow.slice(1).reduce((parts, str, i, arr) => {
140
+ const paddedStr = arr.length === i + 1 ? str : str.padEnd(maxLengths[i + 1]);
141
+ return [...parts, separators?.[i] ?? " ", paddedStr];
142
+ }, [firstCell]).join("").trimEnd();
143
+ });
144
+ }
145
+ function joinWithGrammar(parts, grammar) {
146
+ if (parts.length <= 1) {
147
+ return parts[0] ?? "";
148
+ }
149
+ if (parts.length === 2) {
150
+ return parts.join(` ${grammar.conjunction} `);
151
+ }
152
+ let allButLast = parts.slice(0, parts.length - 1).join(", ");
153
+ if (grammar.serialComma) {
154
+ allButLast += ",";
155
+ }
156
+ return [allButLast, grammar.conjunction, parts[parts.length - 1]].join(" ");
157
+ }
158
+ function group(array, callback) {
159
+ return array.reduce((groupings, item) => {
160
+ const key = callback(item);
161
+ const groupItems = groupings[key] ?? [];
162
+ groupItems.push(item);
163
+ groupings[key] = groupItems;
164
+ return groupings;
165
+ }, {});
166
+ }
167
+ function groupBy(array, selector) {
168
+ return group(array, (item) => item[selector]);
169
+ }
170
+ async function allSettledOrElse(values) {
171
+ const results = await Promise.allSettled(values);
172
+ const grouped = groupBy(results, "status");
173
+ if (grouped.rejected && grouped.rejected.length > 0) {
174
+ return { status: "rejected", reasons: grouped.rejected.map((result) => result.reason) };
175
+ }
176
+ return { status: "fulfilled", value: grouped.fulfilled?.map((result) => result.value) ?? [] };
177
+ }
178
+ var TRUTHY_VALUES = /* @__PURE__ */ new Set(["true", "t", "yes", "y", "on", "1"]);
179
+ var FALSY_VALUES = /* @__PURE__ */ new Set(["false", "f", "no", "n", "off", "0"]);
180
+ var looseBooleanParser = (input) => {
181
+ const value = input.toLowerCase();
182
+ if (TRUTHY_VALUES.has(value)) {
183
+ return true;
184
+ }
185
+ if (FALSY_VALUES.has(value)) {
186
+ return false;
187
+ }
188
+ throw new SyntaxError(`Cannot convert ${input} to a boolean`);
189
+ };
190
+ var numberParser = (input) => {
191
+ const value = Number(input);
192
+ if (Number.isNaN(value)) {
193
+ throw new SyntaxError(`Cannot convert ${input} to a number`);
194
+ }
195
+ return value;
196
+ };
197
+ var ArgumentScannerError = class extends InternalError {
198
+ _brand;
199
+ };
200
+ function formatMessageForArgumentScannerError(error, formatter) {
201
+ const errorType = error.constructor.name;
202
+ const formatError = formatter[errorType];
203
+ if (formatError) {
204
+ return formatError(error);
205
+ }
206
+ return error.message;
207
+ }
208
+ function resolveAliases(flags, aliases, scannerCaseStyle) {
209
+ return Object.fromEntries(Object.entries(aliases).map(([alias, internalFlagName_]) => {
210
+ const internalFlagName = internalFlagName_;
211
+ const flag = flags[internalFlagName];
212
+ if (!flag) {
213
+ const externalFlagName = asExternal(internalFlagName, scannerCaseStyle);
214
+ throw new FlagNotFoundError(externalFlagName, [], alias);
215
+ }
216
+ return [alias, [internalFlagName, flag]];
217
+ }));
218
+ }
219
+ var FlagNotFoundError = class extends ArgumentScannerError {
220
+ input;
221
+ corrections;
222
+ aliasName;
223
+ constructor(input, corrections, aliasName) {
224
+ let message = `No flag registered for --${input}`;
225
+ if (aliasName) {
226
+ message += ` (aliased from -${aliasName})`;
227
+ } else if (corrections.length > 0) {
228
+ const formattedCorrections = joinWithGrammar(corrections.map((correction) => `--${correction}`), {
229
+ kind: "conjunctive",
230
+ conjunction: "or",
231
+ serialComma: true
232
+ });
233
+ message += `, did you mean ${formattedCorrections}?`;
234
+ }
235
+ super(message);
236
+ this.input = input;
237
+ this.corrections = corrections;
238
+ this.aliasName = aliasName;
239
+ }
240
+ };
241
+ var AliasNotFoundError = class extends ArgumentScannerError {
242
+ input;
243
+ constructor(input) {
244
+ super(`No alias registered for -${input}`);
245
+ this.input = input;
246
+ }
247
+ };
248
+ function getPlaceholder(param, index) {
249
+ if (param.placeholder) {
250
+ return param.placeholder;
251
+ }
252
+ return typeof index === "number" ? `arg${index}` : "args";
253
+ }
254
+ function asExternal(internal, scannerCaseStyle) {
255
+ return scannerCaseStyle === "allow-kebab-for-camel" ? convertCamelCaseToKebabCase(internal) : internal;
256
+ }
257
+ var ArgumentParseError = class extends ArgumentScannerError {
258
+ externalFlagNameOrPlaceholder;
259
+ input;
260
+ exception;
261
+ constructor(externalFlagNameOrPlaceholder, input, exception) {
262
+ super(`Failed to parse "${input}" for ${externalFlagNameOrPlaceholder}: ${exception instanceof Error ? exception.message : String(exception)}`);
263
+ this.externalFlagNameOrPlaceholder = externalFlagNameOrPlaceholder;
264
+ this.input = input;
265
+ this.exception = exception;
266
+ }
267
+ };
268
+ function parseInput(externalFlagNameOrPlaceholder, parameter, input, context) {
269
+ try {
270
+ return parameter.parse.call(context, input);
271
+ } catch (exc) {
272
+ throw new ArgumentParseError(externalFlagNameOrPlaceholder, input, exc);
273
+ }
274
+ }
275
+ var EnumValidationError = class extends ArgumentScannerError {
276
+ externalFlagName;
277
+ input;
278
+ values;
279
+ constructor(externalFlagName, input, values, corrections) {
280
+ let message = `Expected "${input}" to be one of (${values.join("|")})`;
281
+ if (corrections.length > 0) {
282
+ const formattedCorrections = joinWithGrammar(corrections.map((str) => `"${str}"`), {
283
+ kind: "conjunctive",
284
+ conjunction: "or",
285
+ serialComma: true
286
+ });
287
+ message += `, did you mean ${formattedCorrections}?`;
288
+ }
289
+ super(message);
290
+ this.externalFlagName = externalFlagName;
291
+ this.input = input;
292
+ this.values = values;
293
+ }
294
+ };
295
+ var UnsatisfiedFlagError = class extends ArgumentScannerError {
296
+ externalFlagName;
297
+ nextFlagName;
298
+ constructor(externalFlagName, nextFlagName) {
299
+ let message = `Expected input for flag --${externalFlagName}`;
300
+ if (nextFlagName) {
301
+ message += ` but encountered --${nextFlagName} instead`;
302
+ }
303
+ super(message);
304
+ this.externalFlagName = externalFlagName;
305
+ this.nextFlagName = nextFlagName;
306
+ }
307
+ };
308
+ var UnexpectedPositionalError = class extends ArgumentScannerError {
309
+ expectedCount;
310
+ input;
311
+ constructor(expectedCount, input) {
312
+ super(`Too many arguments, expected ${expectedCount} but encountered "${input}"`);
313
+ this.expectedCount = expectedCount;
314
+ this.input = input;
315
+ }
316
+ };
317
+ var UnsatisfiedPositionalError = class extends ArgumentScannerError {
318
+ placeholder;
319
+ limit;
320
+ constructor(placeholder, limit) {
321
+ let message;
322
+ if (limit) {
323
+ message = `Expected at least ${limit[0]} argument(s) for ${placeholder}`;
324
+ if (limit[1] === 0) {
325
+ message += " but found none";
326
+ } else {
327
+ message += ` but only found ${limit[1]}`;
328
+ }
329
+ } else {
330
+ message = `Expected argument for ${placeholder}`;
331
+ }
332
+ super(message);
333
+ this.placeholder = placeholder;
334
+ this.limit = limit;
335
+ }
336
+ };
337
+ function undoNegation(flagName) {
338
+ if (flagName.startsWith("no") && flagName.length > 2) {
339
+ if (flagName[2] === "-") {
340
+ return flagName.slice(4);
341
+ }
342
+ const firstChar = flagName[2];
343
+ const firstUpper = firstChar.toUpperCase();
344
+ if (firstChar !== firstUpper) {
345
+ return;
346
+ }
347
+ const firstLower = firstChar.toLowerCase();
348
+ return firstLower + flagName.slice(3);
349
+ }
350
+ }
351
+ function findInternalFlagMatch(externalFlagName, flags, config) {
352
+ const internalFlagName = externalFlagName;
353
+ let flag = flags[internalFlagName];
354
+ let foundFlagWithNegatedFalse;
355
+ let foundFlagWithNegatedFalseFromKebabConversion = false;
356
+ if (!flag) {
357
+ const internalWithoutNegation = undoNegation(internalFlagName);
358
+ if (internalWithoutNegation) {
359
+ flag = flags[internalWithoutNegation];
360
+ if (flag && flag.kind == "boolean") {
361
+ if (flag.withNegated !== false) {
362
+ return { namedFlag: [internalWithoutNegation, flag], negated: true };
363
+ } else {
364
+ foundFlagWithNegatedFalse = internalWithoutNegation;
365
+ flag = undefined;
366
+ }
367
+ }
368
+ }
369
+ }
370
+ const camelCaseFlagName = convertKebabCaseToCamelCase(externalFlagName);
371
+ if (config.caseStyle === "allow-kebab-for-camel" && !flag) {
372
+ flag = flags[camelCaseFlagName];
373
+ if (flag) {
374
+ return { namedFlag: [camelCaseFlagName, flag] };
375
+ }
376
+ const camelCaseWithoutNegation = undoNegation(camelCaseFlagName);
377
+ if (camelCaseWithoutNegation) {
378
+ flag = flags[camelCaseWithoutNegation];
379
+ if (flag && flag.kind == "boolean") {
380
+ if (flag.withNegated !== false) {
381
+ return { namedFlag: [camelCaseWithoutNegation, flag], negated: true };
382
+ } else {
383
+ foundFlagWithNegatedFalse = camelCaseWithoutNegation;
384
+ foundFlagWithNegatedFalseFromKebabConversion = true;
385
+ flag = undefined;
386
+ }
387
+ }
388
+ }
389
+ }
390
+ if (!flag) {
391
+ if (foundFlagWithNegatedFalse) {
392
+ let correction = foundFlagWithNegatedFalse;
393
+ if (foundFlagWithNegatedFalseFromKebabConversion && externalFlagName.includes("-")) {
394
+ correction = convertCamelCaseToKebabCase(foundFlagWithNegatedFalse);
395
+ }
396
+ throw new FlagNotFoundError(externalFlagName, [correction]);
397
+ }
398
+ if (camelCaseFlagName in flags) {
399
+ throw new FlagNotFoundError(externalFlagName, [camelCaseFlagName]);
400
+ }
401
+ const kebabCaseFlagName = convertCamelCaseToKebabCase(externalFlagName);
402
+ if (kebabCaseFlagName in flags) {
403
+ throw new FlagNotFoundError(externalFlagName, [kebabCaseFlagName]);
404
+ }
405
+ const corrections = filterClosestAlternatives(internalFlagName, Object.keys(flags), config.distanceOptions);
406
+ throw new FlagNotFoundError(externalFlagName, corrections);
407
+ }
408
+ return { namedFlag: [internalFlagName, flag] };
409
+ }
410
+ function isNiladic(namedFlagWithNegation) {
411
+ if (namedFlagWithNegation.namedFlag[1].kind === "boolean" || namedFlagWithNegation.namedFlag[1].kind === "counter") {
412
+ return true;
413
+ }
414
+ return false;
415
+ }
416
+ var FLAG_SHORTHAND_PATTERN = /^-([a-z]+)$/i;
417
+ var FLAG_NAME_PATTERN = /^--([a-z][a-z-.\d_]+)$/i;
418
+ function findFlagsByArgument(arg, flags, resolvedAliases, config) {
419
+ const shorthandMatch = FLAG_SHORTHAND_PATTERN.exec(arg);
420
+ if (shorthandMatch) {
421
+ const batch = shorthandMatch[1];
422
+ return Array.from(batch).map((alias) => {
423
+ const aliasName = alias;
424
+ const namedFlag = resolvedAliases[aliasName];
425
+ if (!namedFlag) {
426
+ throw new AliasNotFoundError(aliasName);
427
+ }
428
+ return { namedFlag };
429
+ });
430
+ }
431
+ const flagNameMatch = FLAG_NAME_PATTERN.exec(arg);
432
+ if (flagNameMatch) {
433
+ const externalFlagName = flagNameMatch[1];
434
+ return [findInternalFlagMatch(externalFlagName, flags, config)];
435
+ }
436
+ return [];
437
+ }
438
+ var FLAG_NAME_VALUE_PATTERN = /^--([a-z][a-z-.\d_]+)=(.+)$/i;
439
+ var ALIAS_VALUE_PATTERN = /^-([a-z])=(.+)$/i;
440
+ var InvalidNegatedFlagSyntaxError = class extends ArgumentScannerError {
441
+ externalFlagName;
442
+ valueText;
443
+ constructor(externalFlagName, valueText) {
444
+ super(`Cannot negate flag --${externalFlagName} and pass "${valueText}" as value`);
445
+ this.externalFlagName = externalFlagName;
446
+ this.valueText = valueText;
447
+ }
448
+ };
449
+ function findFlagByArgumentWithInput(arg, flags, resolvedAliases, config) {
450
+ const flagsNameMatch = FLAG_NAME_VALUE_PATTERN.exec(arg);
451
+ if (flagsNameMatch) {
452
+ const externalFlagName = flagsNameMatch[1];
453
+ const { namedFlag: flagMatch, negated } = findInternalFlagMatch(externalFlagName, flags, config);
454
+ const valueText = flagsNameMatch[2];
455
+ if (negated) {
456
+ throw new InvalidNegatedFlagSyntaxError(externalFlagName, valueText);
457
+ }
458
+ return [flagMatch, valueText];
459
+ }
460
+ const aliasValueMatch = ALIAS_VALUE_PATTERN.exec(arg);
461
+ if (aliasValueMatch) {
462
+ const aliasName = aliasValueMatch[1];
463
+ const namedFlag = resolvedAliases[aliasName];
464
+ if (!namedFlag) {
465
+ throw new AliasNotFoundError(aliasName);
466
+ }
467
+ const valueText = aliasValueMatch[2];
468
+ return [namedFlag, valueText];
469
+ }
470
+ }
471
+ async function parseInputsForFlag(externalFlagName, flag, inputs, config, context) {
472
+ if (!inputs) {
473
+ if ("default" in flag && typeof flag.default !== "undefined") {
474
+ if (flag.kind === "boolean") {
475
+ return flag.default;
476
+ }
477
+ if (flag.kind === "enum") {
478
+ if ("variadic" in flag && flag.variadic && Array.isArray(flag.default)) {
479
+ const defaultArray = flag.default;
480
+ for (const value of defaultArray) {
481
+ if (!flag.values.includes(value)) {
482
+ const corrections = filterClosestAlternatives(value, flag.values, config.distanceOptions);
483
+ throw new EnumValidationError(externalFlagName, value, flag.values, corrections);
484
+ }
485
+ }
486
+ return flag.default;
487
+ }
488
+ return flag.default;
489
+ }
490
+ if ("variadic" in flag && flag.variadic && Array.isArray(flag.default)) {
491
+ const defaultArray = flag.default;
492
+ return Promise.all(defaultArray.map((input2) => parseInput(externalFlagName, flag, input2, context)));
493
+ }
494
+ return parseInput(externalFlagName, flag, flag.default, context);
495
+ }
496
+ if (flag.optional) {
497
+ return;
498
+ }
499
+ if (flag.kind === "boolean") {
500
+ return false;
501
+ } else if (flag.kind === "counter") {
502
+ return 0;
503
+ }
504
+ throw new UnsatisfiedFlagError(externalFlagName);
505
+ }
506
+ if (flag.kind === "counter") {
507
+ return inputs.reduce((total, input2) => {
508
+ try {
509
+ return total + numberParser.call(context, input2);
510
+ } catch (exc) {
511
+ throw new ArgumentParseError(externalFlagName, input2, exc);
512
+ }
513
+ }, 0);
514
+ }
515
+ if ("variadic" in flag && flag.variadic) {
516
+ if (flag.kind === "enum") {
517
+ for (const input2 of inputs) {
518
+ if (!flag.values.includes(input2)) {
519
+ const corrections = filterClosestAlternatives(input2, flag.values, config.distanceOptions);
520
+ throw new EnumValidationError(externalFlagName, input2, flag.values, corrections);
521
+ }
522
+ }
523
+ return inputs;
524
+ }
525
+ return Promise.all(inputs.map((input2) => parseInput(externalFlagName, flag, input2, context)));
526
+ }
527
+ const input = inputs[0];
528
+ if (flag.kind === "boolean") {
529
+ try {
530
+ return looseBooleanParser.call(context, input);
531
+ } catch (exc) {
532
+ throw new ArgumentParseError(externalFlagName, input, exc);
533
+ }
534
+ }
535
+ if (flag.kind === "enum") {
536
+ if (!flag.values.includes(input)) {
537
+ const corrections = filterClosestAlternatives(input, flag.values, config.distanceOptions);
538
+ throw new EnumValidationError(externalFlagName, input, flag.values, corrections);
539
+ }
540
+ return input;
541
+ }
542
+ return parseInput(externalFlagName, flag, input, context);
543
+ }
544
+ var UnexpectedFlagError = class extends ArgumentScannerError {
545
+ externalFlagName;
546
+ previousInput;
547
+ input;
548
+ constructor(externalFlagName, previousInput, input) {
549
+ super(`Too many arguments for --${externalFlagName}, encountered "${input}" after "${previousInput}"`);
550
+ this.externalFlagName = externalFlagName;
551
+ this.previousInput = previousInput;
552
+ this.input = input;
553
+ }
554
+ };
555
+ function isVariadicFlag(flag) {
556
+ if (flag.kind === "counter") {
557
+ return true;
558
+ }
559
+ if ("variadic" in flag) {
560
+ return Boolean(flag.variadic);
561
+ }
562
+ return false;
563
+ }
564
+ function storeInput(flagInputs, scannerCaseStyle, [internalFlagName, flag], input) {
565
+ const inputs = flagInputs.get(internalFlagName) ?? [];
566
+ if (inputs.length > 0 && !isVariadicFlag(flag)) {
567
+ const externalFlagName = asExternal(internalFlagName, scannerCaseStyle);
568
+ throw new UnexpectedFlagError(externalFlagName, inputs[0], input);
569
+ }
570
+ if ("variadic" in flag && typeof flag.variadic === "string") {
571
+ const multipleInputs = input.split(flag.variadic);
572
+ flagInputs.set(internalFlagName, [...inputs, ...multipleInputs]);
573
+ } else {
574
+ flagInputs.set(internalFlagName, [...inputs, input]);
575
+ }
576
+ }
577
+ function isFlagSatisfiedByInputs(flags, flagInputs, key) {
578
+ const inputs = flagInputs.get(key);
579
+ if (inputs) {
580
+ const flag = flags[key];
581
+ if (isVariadicFlag(flag)) {
582
+ return false;
583
+ }
584
+ return true;
585
+ }
586
+ return false;
587
+ }
588
+ function buildArgumentScanner(parameters, config) {
589
+ const { flags = {}, aliases = {}, positional = { kind: "tuple", parameters: [] } } = parameters;
590
+ const resolvedAliases = resolveAliases(flags, aliases, config.caseStyle);
591
+ const positionalInputs = [];
592
+ const flagInputs = /* @__PURE__ */ new Map;
593
+ let positionalIndex = 0;
594
+ let activeFlag;
595
+ let treatInputsAsArguments = false;
596
+ return {
597
+ next: (input) => {
598
+ if (!treatInputsAsArguments && config.allowArgumentEscapeSequence && input === "--") {
599
+ if (activeFlag) {
600
+ if (activeFlag[1].kind === "parsed" && activeFlag[1].inferEmpty) {
601
+ storeInput(flagInputs, config.caseStyle, activeFlag, "");
602
+ activeFlag = undefined;
603
+ } else {
604
+ const externalFlagName = asExternal(activeFlag[0], config.caseStyle);
605
+ throw new UnsatisfiedFlagError(externalFlagName);
606
+ }
607
+ }
608
+ treatInputsAsArguments = true;
609
+ return;
610
+ }
611
+ if (!treatInputsAsArguments) {
612
+ const flagInput = findFlagByArgumentWithInput(input, flags, resolvedAliases, config);
613
+ if (flagInput) {
614
+ if (activeFlag) {
615
+ if (activeFlag[1].kind === "parsed" && activeFlag[1].inferEmpty) {
616
+ storeInput(flagInputs, config.caseStyle, activeFlag, "");
617
+ activeFlag = undefined;
618
+ } else {
619
+ const externalFlagName = asExternal(activeFlag[0], config.caseStyle);
620
+ const nextExternalFlagName = asExternal(flagInput[0][0], config.caseStyle);
621
+ throw new UnsatisfiedFlagError(externalFlagName, nextExternalFlagName);
622
+ }
623
+ }
624
+ storeInput(flagInputs, config.caseStyle, ...flagInput);
625
+ return;
626
+ }
627
+ const nextFlags = findFlagsByArgument(input, flags, resolvedAliases, config);
628
+ if (nextFlags.length > 0) {
629
+ if (activeFlag) {
630
+ if (activeFlag[1].kind === "parsed" && activeFlag[1].inferEmpty) {
631
+ storeInput(flagInputs, config.caseStyle, activeFlag, "");
632
+ activeFlag = undefined;
633
+ } else {
634
+ const externalFlagName = asExternal(activeFlag[0], config.caseStyle);
635
+ const nextFlagName = asExternal(nextFlags[0].namedFlag[0], config.caseStyle);
636
+ throw new UnsatisfiedFlagError(externalFlagName, nextFlagName);
637
+ }
638
+ }
639
+ if (nextFlags.every(isNiladic)) {
640
+ for (const nextFlag of nextFlags) {
641
+ if (nextFlag.namedFlag[1].kind === "boolean") {
642
+ storeInput(flagInputs, config.caseStyle, nextFlag.namedFlag, nextFlag.negated ? "false" : "true");
643
+ } else {
644
+ storeInput(flagInputs, config.caseStyle, nextFlag.namedFlag, "1");
645
+ }
646
+ }
647
+ } else if (nextFlags.length > 1) {
648
+ const nextFlagExpectingArg = nextFlags.find((nextFlag) => !isNiladic(nextFlag));
649
+ const externalFlagName = asExternal(nextFlagExpectingArg.namedFlag[0], config.caseStyle);
650
+ throw new UnsatisfiedFlagError(externalFlagName);
651
+ } else {
652
+ activeFlag = nextFlags[0].namedFlag;
653
+ }
654
+ return;
655
+ }
656
+ }
657
+ if (activeFlag) {
658
+ storeInput(flagInputs, config.caseStyle, activeFlag, input);
659
+ activeFlag = undefined;
660
+ } else {
661
+ if (positional.kind === "tuple") {
662
+ if (positionalIndex >= positional.parameters.length) {
663
+ throw new UnexpectedPositionalError(positional.parameters.length, input);
664
+ }
665
+ } else {
666
+ if (typeof positional.maximum === "number" && positionalIndex >= positional.maximum) {
667
+ throw new UnexpectedPositionalError(positional.maximum, input);
668
+ }
669
+ }
670
+ positionalInputs[positionalIndex] = input;
671
+ ++positionalIndex;
672
+ }
673
+ },
674
+ parseArguments: async (context) => {
675
+ const errors = [];
676
+ let positionalValues_p;
677
+ if (positional.kind === "array") {
678
+ if (typeof positional.minimum === "number" && positionalIndex < positional.minimum) {
679
+ errors.push(new UnsatisfiedPositionalError(getPlaceholder(positional.parameter), [
680
+ positional.minimum,
681
+ positionalIndex
682
+ ]));
683
+ }
684
+ positionalValues_p = allSettledOrElse(positionalInputs.map(async (input, i) => {
685
+ const placeholder = getPlaceholder(positional.parameter, i + 1);
686
+ return parseInput(placeholder, positional.parameter, input, context);
687
+ }));
688
+ } else {
689
+ positionalValues_p = allSettledOrElse(positional.parameters.map(async (param, i) => {
690
+ const placeholder = getPlaceholder(param, i + 1);
691
+ const input = positionalInputs[i];
692
+ if (typeof input !== "string") {
693
+ if (typeof param.default === "string") {
694
+ return parseInput(placeholder, param, param.default, context);
695
+ }
696
+ if (param.optional) {
697
+ return;
698
+ }
699
+ throw new UnsatisfiedPositionalError(placeholder);
700
+ }
701
+ return parseInput(placeholder, param, input, context);
702
+ }));
703
+ }
704
+ if (activeFlag && activeFlag[1].kind === "parsed" && activeFlag[1].inferEmpty) {
705
+ storeInput(flagInputs, config.caseStyle, activeFlag, "");
706
+ activeFlag = undefined;
707
+ }
708
+ const flagEntries_p = allSettledOrElse(Object.entries(flags).map(async (entry) => {
709
+ const [internalFlagName, flag] = entry;
710
+ const externalFlagName = asExternal(internalFlagName, config.caseStyle);
711
+ if (activeFlag && activeFlag[0] === internalFlagName) {
712
+ throw new UnsatisfiedFlagError(externalFlagName);
713
+ }
714
+ const inputs = flagInputs.get(internalFlagName);
715
+ const value = await parseInputsForFlag(externalFlagName, flag, inputs, config, context);
716
+ return [internalFlagName, value];
717
+ }));
718
+ const [positionalValuesResult, flagEntriesResult] = await Promise.all([positionalValues_p, flagEntries_p]);
719
+ if (positionalValuesResult.status === "rejected") {
720
+ for (const reason of positionalValuesResult.reasons) {
721
+ errors.push(reason);
722
+ }
723
+ }
724
+ if (flagEntriesResult.status === "rejected") {
725
+ for (const reason of flagEntriesResult.reasons) {
726
+ errors.push(reason);
727
+ }
728
+ }
729
+ if (errors.length > 0) {
730
+ return { success: false, errors };
731
+ }
732
+ if (positionalValuesResult.status === "rejected") {
733
+ throw new InternalError("Unknown failure while scanning positional arguments");
734
+ }
735
+ if (flagEntriesResult.status === "rejected") {
736
+ throw new InternalError("Unknown failure while scanning flag arguments");
737
+ }
738
+ const parsedFlags = Object.fromEntries(flagEntriesResult.value);
739
+ return { success: true, arguments: [parsedFlags, ...positionalValuesResult.value] };
740
+ },
741
+ proposeCompletions: async ({ partial, completionConfig, text, context, includeVersionFlag }) => {
742
+ if (activeFlag) {
743
+ return proposeFlagCompletionsForPartialInput(activeFlag[1], context, partial);
744
+ }
745
+ const completions = [];
746
+ if (!treatInputsAsArguments) {
747
+ const shorthandMatch = FLAG_SHORTHAND_PATTERN.exec(partial);
748
+ if (completionConfig.includeAliases) {
749
+ if (partial === "" || partial === "-") {
750
+ const incompleteAliases = Object.entries(aliases).filter((entry) => !isFlagSatisfiedByInputs(flags, flagInputs, entry[1]));
751
+ for (const [alias] of incompleteAliases) {
752
+ const flag = resolvedAliases[alias];
753
+ if (flag) {
754
+ completions.push({
755
+ kind: "argument:flag",
756
+ completion: `-${alias}`,
757
+ brief: flag[1].brief
758
+ });
759
+ }
760
+ }
761
+ } else if (shorthandMatch) {
762
+ const partialAliases = Array.from(shorthandMatch[1]);
763
+ if (partialAliases.includes("h")) {
764
+ return [];
765
+ }
766
+ if (includeVersionFlag && partialAliases.includes("v")) {
767
+ return [];
768
+ }
769
+ const flagInputsIncludingPartial = new Map(flagInputs);
770
+ for (const alias of partialAliases) {
771
+ const namedFlag = resolvedAliases[alias];
772
+ if (!namedFlag) {
773
+ throw new AliasNotFoundError(alias);
774
+ }
775
+ storeInput(flagInputsIncludingPartial, config.caseStyle, namedFlag, namedFlag[1].kind === "boolean" ? "true" : "1");
776
+ }
777
+ const lastAlias = partialAliases[partialAliases.length - 1];
778
+ if (lastAlias) {
779
+ const namedFlag = resolvedAliases[lastAlias];
780
+ if (namedFlag) {
781
+ completions.push({
782
+ kind: "argument:flag",
783
+ completion: partial,
784
+ brief: namedFlag[1].brief
785
+ });
786
+ }
787
+ }
788
+ const incompleteAliases = Object.entries(aliases).filter((entry) => !isFlagSatisfiedByInputs(flags, flagInputsIncludingPartial, entry[1]));
789
+ for (const [alias] of incompleteAliases) {
790
+ const flag = resolvedAliases[alias];
791
+ if (flag) {
792
+ completions.push({
793
+ kind: "argument:flag",
794
+ completion: `${partial}${alias}`,
795
+ brief: flag[1].brief
796
+ });
797
+ }
798
+ }
799
+ }
800
+ }
801
+ if (partial === "" || partial === "-" || partial.startsWith("--")) {
802
+ if (config.allowArgumentEscapeSequence) {
803
+ completions.push({
804
+ kind: "argument:flag",
805
+ completion: "--",
806
+ brief: text.briefs.argumentEscapeSequence
807
+ });
808
+ }
809
+ let incompleteFlags = Object.entries(flags).filter(([flagName]) => !isFlagSatisfiedByInputs(flags, flagInputs, flagName));
810
+ if (config.caseStyle === "allow-kebab-for-camel") {
811
+ incompleteFlags = incompleteFlags.map(([flagName, param]) => {
812
+ return [convertCamelCaseToKebabCase(flagName), param];
813
+ });
814
+ }
815
+ const possibleFlags = incompleteFlags.map(([flagName, param]) => [`--${flagName}`, param]).filter(([flagName]) => flagName.startsWith(partial));
816
+ completions.push(...possibleFlags.map(([name, param]) => {
817
+ return {
818
+ kind: "argument:flag",
819
+ completion: name,
820
+ brief: param.brief
821
+ };
822
+ }));
823
+ }
824
+ }
825
+ if (positional.kind === "array") {
826
+ if (positional.parameter.proposeCompletions) {
827
+ if (typeof positional.maximum !== "number" || positionalIndex < positional.maximum) {
828
+ const positionalCompletions = await positional.parameter.proposeCompletions.call(context, partial);
829
+ completions.push(...positionalCompletions.map((value) => {
830
+ return {
831
+ kind: "argument:value",
832
+ completion: value,
833
+ brief: positional.parameter.brief
834
+ };
835
+ }));
836
+ }
837
+ }
838
+ } else {
839
+ const nextPositional = positional.parameters[positionalIndex];
840
+ if (nextPositional?.proposeCompletions) {
841
+ const positionalCompletions = await nextPositional.proposeCompletions.call(context, partial);
842
+ completions.push(...positionalCompletions.map((value) => {
843
+ return {
844
+ kind: "argument:value",
845
+ completion: value,
846
+ brief: nextPositional.brief
847
+ };
848
+ }));
849
+ }
850
+ }
851
+ return completions.filter(({ completion }) => completion.startsWith(partial));
852
+ }
853
+ };
854
+ }
855
+ async function proposeFlagCompletionsForPartialInput(flag, context, partial) {
856
+ if (typeof flag.variadic === "string") {
857
+ if (partial.endsWith(flag.variadic)) {
858
+ return proposeFlagCompletionsForPartialInput(flag, context, "");
859
+ }
860
+ }
861
+ let values;
862
+ if (flag.kind === "enum") {
863
+ values = flag.values;
864
+ } else if (flag.proposeCompletions) {
865
+ values = await flag.proposeCompletions.call(context, partial);
866
+ } else {
867
+ values = [];
868
+ }
869
+ return values.map((value) => {
870
+ return {
871
+ kind: "argument:value",
872
+ completion: value,
873
+ brief: flag.brief
874
+ };
875
+ }).filter(({ completion }) => completion.startsWith(partial));
876
+ }
877
+ function listAllRouteNamesAndAliasesForScan(routeMap, scannerCaseStyle, config) {
878
+ const displayCaseStyle = scannerCaseStyle === "allow-kebab-for-camel" ? "convert-camel-to-kebab" : scannerCaseStyle;
879
+ let entries = routeMap.getAllEntries();
880
+ if (!config.includeHiddenRoutes) {
881
+ entries = entries.filter((entry) => !entry.hidden);
882
+ }
883
+ return entries.flatMap((entry) => {
884
+ const routeName = entry.name[displayCaseStyle];
885
+ if (config.includeAliases) {
886
+ return [routeName, ...entry.aliases];
887
+ }
888
+ return [routeName];
889
+ });
890
+ }
891
+ var text_en = {
892
+ headers: {
893
+ usage: "USAGE",
894
+ aliases: "ALIASES",
895
+ commands: "COMMANDS",
896
+ flags: "FLAGS",
897
+ arguments: "ARGUMENTS"
898
+ },
899
+ keywords: {
900
+ default: "default =",
901
+ separator: "separator ="
902
+ },
903
+ briefs: {
904
+ help: "Print help information and exit",
905
+ helpAll: "Print help information (including hidden commands/flags) and exit",
906
+ version: "Print version information and exit",
907
+ argumentEscapeSequence: "All subsequent inputs should be interpreted as arguments"
908
+ },
909
+ noCommandRegisteredForInput: ({ input, corrections }) => {
910
+ const errorMessage = `No command registered for \`${input}\``;
911
+ if (corrections.length > 0) {
912
+ const formattedCorrections = joinWithGrammar(corrections, {
913
+ kind: "conjunctive",
914
+ conjunction: "or",
915
+ serialComma: true
916
+ });
917
+ return `${errorMessage}, did you mean ${formattedCorrections}?`;
918
+ } else {
919
+ return errorMessage;
920
+ }
921
+ },
922
+ noTextAvailableForLocale: ({ requestedLocale, defaultLocale }) => {
923
+ return `Application does not support "${requestedLocale}" locale, defaulting to "${defaultLocale}"`;
924
+ },
925
+ exceptionWhileParsingArguments: (exc) => {
926
+ if (exc instanceof ArgumentScannerError) {
927
+ return formatMessageForArgumentScannerError(exc, {});
928
+ }
929
+ return `Unable to parse arguments, ${formatException(exc)}`;
930
+ },
931
+ exceptionWhileLoadingCommandFunction: (exc) => {
932
+ return `Unable to load command function, ${formatException(exc)}`;
933
+ },
934
+ exceptionWhileLoadingCommandContext: (exc) => {
935
+ return `Unable to load command context, ${formatException(exc)}`;
936
+ },
937
+ exceptionWhileRunningCommand: (exc) => {
938
+ return `Command failed, ${formatException(exc)}`;
939
+ },
940
+ commandErrorResult: (err) => {
941
+ return err.message;
942
+ },
943
+ currentVersionIsNotLatest: ({ currentVersion, latestVersion, upgradeCommand }) => {
944
+ if (upgradeCommand) {
945
+ return `Latest available version is ${latestVersion} (currently running ${currentVersion}), upgrade with "${upgradeCommand}"`;
946
+ }
947
+ return `Latest available version is ${latestVersion} (currently running ${currentVersion})`;
948
+ }
949
+ };
950
+ function defaultTextLoader(locale) {
951
+ if (locale.startsWith("en")) {
952
+ return text_en;
953
+ }
954
+ }
955
+ function shouldUseAnsiColor(process2, stream, config) {
956
+ return !config.disableAnsiColor && !checkEnvironmentVariable(process2, "STRICLI_NO_COLOR") && (stream.getColorDepth?.(process2.env) ?? 1) >= 4;
957
+ }
958
+ async function runCommand({ loader, parameters }, {
959
+ context,
960
+ inputs,
961
+ scannerConfig,
962
+ errorFormatting,
963
+ documentationConfig,
964
+ determineExitCode
965
+ }) {
966
+ let parsedArguments;
967
+ try {
968
+ const scanner = buildArgumentScanner(parameters, scannerConfig);
969
+ for (const input of inputs) {
970
+ scanner.next(input);
971
+ }
972
+ const result = await scanner.parseArguments(context);
973
+ if (result.success) {
974
+ parsedArguments = result.arguments;
975
+ } else {
976
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, documentationConfig);
977
+ for (const error of result.errors) {
978
+ const errorMessage = errorFormatting.exceptionWhileParsingArguments(error, ansiColor);
979
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[31m${errorMessage}\x1B[39m\x1B[22m
980
+ ` : `${errorMessage}
981
+ `);
982
+ }
983
+ return ExitCode.InvalidArgument;
984
+ }
985
+ } catch (exc) {
986
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, documentationConfig);
987
+ const errorMessage = errorFormatting.exceptionWhileParsingArguments(exc, ansiColor);
988
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[31m${errorMessage}\x1B[39m\x1B[22m
989
+ ` : `${errorMessage}
990
+ `);
991
+ return ExitCode.InvalidArgument;
992
+ }
993
+ let commandFunction;
994
+ try {
995
+ const loaded = await loader();
996
+ if (typeof loaded === "function") {
997
+ commandFunction = loaded;
998
+ } else {
999
+ commandFunction = loaded.default;
1000
+ }
1001
+ } catch (exc) {
1002
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, documentationConfig);
1003
+ const errorMessage = errorFormatting.exceptionWhileLoadingCommandFunction(exc, ansiColor);
1004
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[31m${errorMessage}\x1B[39m\x1B[22m
1005
+ ` : `${errorMessage}
1006
+ `);
1007
+ return ExitCode.CommandLoadError;
1008
+ }
1009
+ try {
1010
+ const result = await commandFunction.call(context, ...parsedArguments);
1011
+ if (result instanceof Error) {
1012
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, documentationConfig);
1013
+ const errorMessage = errorFormatting.commandErrorResult(result, ansiColor);
1014
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[31m${errorMessage}\x1B[39m\x1B[22m
1015
+ ` : `${errorMessage}
1016
+ `);
1017
+ if (determineExitCode) {
1018
+ return determineExitCode(result);
1019
+ }
1020
+ return ExitCode.CommandRunError;
1021
+ }
1022
+ } catch (exc) {
1023
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, documentationConfig);
1024
+ const errorMessage = errorFormatting.exceptionWhileRunningCommand(exc, ansiColor);
1025
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[31m${errorMessage}\x1B[39m\x1B[22m
1026
+ ` : `${errorMessage}
1027
+ `);
1028
+ if (determineExitCode) {
1029
+ return determineExitCode(exc);
1030
+ }
1031
+ return ExitCode.CommandRunError;
1032
+ }
1033
+ return ExitCode.Success;
1034
+ }
1035
+ var RouteMapSymbol = Symbol("RouteMap");
1036
+ var CommandSymbol = Symbol("Command");
1037
+ function buildRouteScanner(root, config, startingPrefix) {
1038
+ const prefix = [...startingPrefix];
1039
+ const unprocessedInputs = [];
1040
+ let parent;
1041
+ let current = root;
1042
+ let target;
1043
+ let rootLevel = true;
1044
+ let helpRequested = false;
1045
+ return {
1046
+ next: (input) => {
1047
+ if (input === "--help" || input === "-h") {
1048
+ helpRequested = true;
1049
+ if (!target) {
1050
+ target = current;
1051
+ }
1052
+ return;
1053
+ } else if (input === "--helpAll" || input === "--help-all" || input === "-H") {
1054
+ helpRequested = "all";
1055
+ if (!target) {
1056
+ target = current;
1057
+ }
1058
+ return;
1059
+ }
1060
+ if (target) {
1061
+ unprocessedInputs.push(input);
1062
+ return;
1063
+ }
1064
+ if (current.kind === CommandSymbol) {
1065
+ target = current;
1066
+ unprocessedInputs.push(input);
1067
+ return;
1068
+ }
1069
+ const camelCaseRouteName = convertKebabCaseToCamelCase(input);
1070
+ let internalRouteName = input;
1071
+ let next = current.getRoutingTargetForInput(internalRouteName);
1072
+ if (config.caseStyle === "allow-kebab-for-camel" && !next) {
1073
+ next = current.getRoutingTargetForInput(camelCaseRouteName);
1074
+ if (next) {
1075
+ internalRouteName = camelCaseRouteName;
1076
+ }
1077
+ }
1078
+ if (!next) {
1079
+ const defaultCommand = current.getDefaultCommand();
1080
+ if (defaultCommand) {
1081
+ rootLevel = false;
1082
+ parent = [current, ""];
1083
+ unprocessedInputs.push(input);
1084
+ current = defaultCommand;
1085
+ return;
1086
+ }
1087
+ return { input, routeMap: current };
1088
+ }
1089
+ rootLevel = false;
1090
+ parent = [current, input];
1091
+ current = next;
1092
+ prefix.push(input);
1093
+ },
1094
+ finish: () => {
1095
+ target = target ?? current;
1096
+ if (target.kind === RouteMapSymbol && !helpRequested) {
1097
+ const defaultCommand = target.getDefaultCommand();
1098
+ if (defaultCommand) {
1099
+ parent = [target, ""];
1100
+ target = defaultCommand;
1101
+ rootLevel = false;
1102
+ }
1103
+ }
1104
+ const aliases = parent ? parent[0].getOtherAliasesForInput(parent[1], config.caseStyle) : { original: [], "convert-camel-to-kebab": [] };
1105
+ return {
1106
+ target,
1107
+ unprocessedInputs,
1108
+ helpRequested,
1109
+ prefix,
1110
+ rootLevel,
1111
+ aliases
1112
+ };
1113
+ }
1114
+ };
1115
+ }
1116
+ async function runApplication({ root, defaultText, config }, rawInputs, context) {
1117
+ let text = defaultText;
1118
+ if (context.locale) {
1119
+ const localeText = config.localization.loadText(context.locale);
1120
+ if (localeText) {
1121
+ text = localeText;
1122
+ } else {
1123
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, config.documentation);
1124
+ const warningMessage = text.noTextAvailableForLocale({
1125
+ requestedLocale: context.locale,
1126
+ defaultLocale: config.localization.defaultLocale,
1127
+ ansiColor
1128
+ });
1129
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[33m${warningMessage}\x1B[39m\x1B[22m
1130
+ ` : `${warningMessage}
1131
+ `);
1132
+ }
1133
+ }
1134
+ if (config.versionInfo?.getLatestVersion && !checkEnvironmentVariable(context.process, "STRICLI_SKIP_VERSION_CHECK")) {
1135
+ let currentVersion;
1136
+ if ("currentVersion" in config.versionInfo) {
1137
+ currentVersion = config.versionInfo.currentVersion;
1138
+ } else {
1139
+ currentVersion = await config.versionInfo.getCurrentVersion.call(context);
1140
+ }
1141
+ const latestVersion = await config.versionInfo.getLatestVersion.call(context, currentVersion);
1142
+ if (latestVersion && currentVersion !== latestVersion) {
1143
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, config.documentation);
1144
+ const warningMessage = text.currentVersionIsNotLatest({
1145
+ currentVersion,
1146
+ latestVersion,
1147
+ upgradeCommand: config.versionInfo.upgradeCommand,
1148
+ ansiColor
1149
+ });
1150
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[33m${warningMessage}\x1B[39m\x1B[22m
1151
+ ` : `${warningMessage}
1152
+ `);
1153
+ }
1154
+ }
1155
+ const inputs = rawInputs.slice();
1156
+ if (config.versionInfo && (inputs[0] === "--version" || inputs[0] === "-v")) {
1157
+ let currentVersion;
1158
+ if ("currentVersion" in config.versionInfo) {
1159
+ currentVersion = config.versionInfo.currentVersion;
1160
+ } else {
1161
+ currentVersion = await config.versionInfo.getCurrentVersion.call(context);
1162
+ }
1163
+ context.process.stdout.write(currentVersion + `
1164
+ `);
1165
+ return ExitCode.Success;
1166
+ }
1167
+ const scanner = buildRouteScanner(root, config.scanner, [config.name]);
1168
+ let error;
1169
+ while (inputs.length > 0 && !error) {
1170
+ const arg = inputs.shift();
1171
+ error = scanner.next(arg);
1172
+ }
1173
+ if (error) {
1174
+ const routeNames = listAllRouteNamesAndAliasesForScan(error.routeMap, config.scanner.caseStyle, config.completion);
1175
+ const corrections = filterClosestAlternatives(error.input, routeNames, config.scanner.distanceOptions).map((str) => `\`${str}\``);
1176
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, config.documentation);
1177
+ const errorMessage = text.noCommandRegisteredForInput({ input: error.input, corrections, ansiColor });
1178
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[31m${errorMessage}\x1B[39m\x1B[22m
1179
+ ` : `${errorMessage}
1180
+ `);
1181
+ return ExitCode.UnknownCommand;
1182
+ }
1183
+ const result = scanner.finish();
1184
+ if (result.helpRequested || result.target.kind === RouteMapSymbol) {
1185
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stdout, config.documentation);
1186
+ context.process.stdout.write(result.target.formatHelp({
1187
+ prefix: result.prefix,
1188
+ includeVersionFlag: Boolean(config.versionInfo) && result.rootLevel,
1189
+ includeArgumentEscapeSequenceFlag: config.scanner.allowArgumentEscapeSequence,
1190
+ includeHelpAllFlag: result.helpRequested === "all" || config.documentation.alwaysShowHelpAllFlag,
1191
+ includeHidden: result.helpRequested === "all",
1192
+ config: config.documentation,
1193
+ aliases: result.aliases[config.documentation.caseStyle],
1194
+ text,
1195
+ ansiColor
1196
+ }));
1197
+ return ExitCode.Success;
1198
+ }
1199
+ let commandContext;
1200
+ if ("forCommand" in context) {
1201
+ try {
1202
+ commandContext = await context.forCommand({ prefix: result.prefix });
1203
+ } catch (exc) {
1204
+ const ansiColor = shouldUseAnsiColor(context.process, context.process.stderr, config.documentation);
1205
+ const errorMessage = text.exceptionWhileLoadingCommandContext(exc, ansiColor);
1206
+ context.process.stderr.write(ansiColor ? `\x1B[1m\x1B[31m${errorMessage}\x1B[39m\x1B[22m` : errorMessage);
1207
+ return ExitCode.ContextLoadError;
1208
+ }
1209
+ } else {
1210
+ commandContext = context;
1211
+ }
1212
+ return runCommand(result.target, {
1213
+ context: commandContext,
1214
+ inputs: result.unprocessedInputs,
1215
+ scannerConfig: config.scanner,
1216
+ documentationConfig: config.documentation,
1217
+ errorFormatting: text,
1218
+ determineExitCode: config.determineExitCode
1219
+ });
1220
+ }
1221
+ function formatForDisplay(flagName, displayCaseStyle) {
1222
+ if (displayCaseStyle === "convert-camel-to-kebab") {
1223
+ return convertCamelCaseToKebabCase(flagName);
1224
+ }
1225
+ return flagName;
1226
+ }
1227
+ function formatAsNegated(flagName, displayCaseStyle) {
1228
+ if (displayCaseStyle === "convert-camel-to-kebab") {
1229
+ return `no-${convertCamelCaseToKebabCase(flagName)}`;
1230
+ }
1231
+ return `no${flagName[0].toUpperCase()}${flagName.slice(1)}`;
1232
+ }
1233
+ function withDefaults(config) {
1234
+ const scannerCaseStyle = config.scanner?.caseStyle ?? "original";
1235
+ let displayCaseStyle;
1236
+ if (config.documentation?.caseStyle) {
1237
+ if (scannerCaseStyle === "original" && config.documentation.caseStyle === "convert-camel-to-kebab") {
1238
+ throw new InternalError("Cannot convert route and flag names on display but scan as original");
1239
+ }
1240
+ displayCaseStyle = config.documentation.caseStyle;
1241
+ } else if (scannerCaseStyle === "allow-kebab-for-camel") {
1242
+ displayCaseStyle = "convert-camel-to-kebab";
1243
+ } else {
1244
+ displayCaseStyle = scannerCaseStyle;
1245
+ }
1246
+ const scannerConfig = {
1247
+ caseStyle: scannerCaseStyle,
1248
+ allowArgumentEscapeSequence: config.scanner?.allowArgumentEscapeSequence ?? false,
1249
+ distanceOptions: config.scanner?.distanceOptions ?? {
1250
+ threshold: 7,
1251
+ weights: {
1252
+ insertion: 1,
1253
+ deletion: 3,
1254
+ substitution: 2,
1255
+ transposition: 0
1256
+ }
1257
+ }
1258
+ };
1259
+ const documentationConfig = {
1260
+ alwaysShowHelpAllFlag: config.documentation?.alwaysShowHelpAllFlag ?? false,
1261
+ useAliasInUsageLine: config.documentation?.useAliasInUsageLine ?? false,
1262
+ onlyRequiredInUsageLine: config.documentation?.onlyRequiredInUsageLine ?? false,
1263
+ caseStyle: displayCaseStyle,
1264
+ disableAnsiColor: config.documentation?.disableAnsiColor ?? false
1265
+ };
1266
+ const completionConfig = {
1267
+ includeAliases: config.completion?.includeAliases ?? documentationConfig.useAliasInUsageLine,
1268
+ includeHiddenRoutes: config.completion?.includeHiddenRoutes ?? false,
1269
+ ...config.completion
1270
+ };
1271
+ return {
1272
+ ...config,
1273
+ scanner: scannerConfig,
1274
+ completion: completionConfig,
1275
+ documentation: documentationConfig,
1276
+ localization: {
1277
+ defaultLocale: "en",
1278
+ loadText: defaultTextLoader,
1279
+ ...config.localization
1280
+ }
1281
+ };
1282
+ }
1283
+ function buildApplication(root, appConfig) {
1284
+ const config = withDefaults(appConfig);
1285
+ if (root.kind === CommandSymbol && config.versionInfo) {
1286
+ if (root.usesFlag("version")) {
1287
+ throw new InternalError("Unable to use command with flag --version as root when version info is supplied");
1288
+ }
1289
+ if (root.usesFlag("v")) {
1290
+ throw new InternalError("Unable to use command with alias -v as root when version info is supplied");
1291
+ }
1292
+ }
1293
+ const defaultText = config.localization.loadText(config.localization.defaultLocale);
1294
+ if (!defaultText) {
1295
+ throw new InternalError(`No text available for the default locale "${config.localization.defaultLocale}"`);
1296
+ }
1297
+ return {
1298
+ root,
1299
+ config,
1300
+ defaultText
1301
+ };
1302
+ }
1303
+ function hasDefault(flag) {
1304
+ return "default" in flag && typeof flag.default !== "undefined";
1305
+ }
1306
+ function isOptionalAtRuntime(flag) {
1307
+ return flag.optional ?? hasDefault(flag);
1308
+ }
1309
+ function wrapRequiredFlag(text) {
1310
+ return `(${text})`;
1311
+ }
1312
+ function wrapOptionalFlag(text) {
1313
+ return `[${text}]`;
1314
+ }
1315
+ function wrapVariadicFlag(text) {
1316
+ return `${text}...`;
1317
+ }
1318
+ function wrapRequiredParameter(text) {
1319
+ return `<${text}>`;
1320
+ }
1321
+ function wrapOptionalParameter(text) {
1322
+ return `[<${text}>]`;
1323
+ }
1324
+ function wrapVariadicParameter(text) {
1325
+ return `<${text}>...`;
1326
+ }
1327
+ function formatUsageLineForParameters(parameters, args) {
1328
+ const flagsUsage = Object.entries(parameters.flags ?? {}).filter(([, flag]) => {
1329
+ if (flag.hidden) {
1330
+ return false;
1331
+ }
1332
+ if (args.config.onlyRequiredInUsageLine && isOptionalAtRuntime(flag)) {
1333
+ return false;
1334
+ }
1335
+ return true;
1336
+ }).map(([name, flag]) => {
1337
+ let displayName = args.config.caseStyle === "convert-camel-to-kebab" ? `--${convertCamelCaseToKebabCase(name)}` : `--${name}`;
1338
+ if (parameters.aliases && args.config.useAliasInUsageLine) {
1339
+ const aliases = Object.entries(parameters.aliases).filter((entry) => entry[1] === name);
1340
+ if (aliases.length === 1 && aliases[0]) {
1341
+ displayName = `-${aliases[0][0]}`;
1342
+ }
1343
+ }
1344
+ if (flag.kind === "boolean") {
1345
+ return [flag, displayName];
1346
+ }
1347
+ if (flag.kind === "enum" && typeof flag.placeholder !== "string") {
1348
+ return [flag, `${displayName} ${flag.values.join("|")}`];
1349
+ }
1350
+ const placeholder = flag.placeholder ?? "value";
1351
+ return [flag, `${displayName} ${placeholder}`];
1352
+ }).map(([flag, usage]) => {
1353
+ if (flag.kind === "parsed" && flag.variadic) {
1354
+ if (isOptionalAtRuntime(flag)) {
1355
+ return wrapVariadicFlag(wrapOptionalFlag(usage));
1356
+ }
1357
+ return wrapVariadicFlag(wrapRequiredFlag(usage));
1358
+ }
1359
+ if (isOptionalAtRuntime(flag)) {
1360
+ return wrapOptionalFlag(usage);
1361
+ }
1362
+ return wrapRequiredFlag(usage);
1363
+ });
1364
+ let positionalUsage = [];
1365
+ const positional = parameters.positional;
1366
+ if (positional) {
1367
+ if (positional.kind === "array") {
1368
+ positionalUsage = [wrapVariadicParameter(positional.parameter.placeholder ?? "args")];
1369
+ } else {
1370
+ let parameters2 = positional.parameters;
1371
+ if (args.config.onlyRequiredInUsageLine) {
1372
+ parameters2 = parameters2.filter((param) => !param.optional && typeof param.default === "undefined");
1373
+ }
1374
+ positionalUsage = parameters2.map((param, i) => {
1375
+ const argName = param.placeholder ?? `arg${i + 1}`;
1376
+ return param.optional || typeof param.default !== "undefined" ? wrapOptionalParameter(argName) : wrapRequiredParameter(argName);
1377
+ });
1378
+ }
1379
+ }
1380
+ return [...args.prefix, ...flagsUsage, ...positionalUsage].join(" ");
1381
+ }
1382
+ function formatDocumentationForFlagParameters(flags, aliases, args) {
1383
+ const { keywords, briefs } = args.text;
1384
+ const visibleFlags = Object.entries(flags).filter(([, flag]) => {
1385
+ if (flag.hidden && !args.includeHidden) {
1386
+ return false;
1387
+ }
1388
+ return true;
1389
+ });
1390
+ const atLeastOneOptional = visibleFlags.some(([, flag]) => isOptionalAtRuntime(flag));
1391
+ const rows = visibleFlags.map(([name, flag]) => {
1392
+ const aliasStrings = Object.entries(aliases).filter((entry) => entry[1] === name).map(([alias]) => `-${alias}`);
1393
+ let flagName = "--" + formatForDisplay(name, args.config.caseStyle);
1394
+ if (flag.kind === "boolean" && flag.default !== false && flag.withNegated !== false) {
1395
+ const negatedFlagName = formatAsNegated(name, args.config.caseStyle);
1396
+ flagName = `${flagName}/--${negatedFlagName}`;
1397
+ }
1398
+ if (isOptionalAtRuntime(flag)) {
1399
+ flagName = `[${flagName}]`;
1400
+ } else if (atLeastOneOptional) {
1401
+ flagName = ` ${flagName}`;
1402
+ }
1403
+ if (flag.kind === "parsed" && flag.variadic) {
1404
+ flagName = `${flagName}...`;
1405
+ }
1406
+ const suffixParts = [];
1407
+ if (flag.kind === "enum") {
1408
+ const choices = flag.values.join("|");
1409
+ suffixParts.push(choices);
1410
+ }
1411
+ if (hasDefault(flag)) {
1412
+ const defaultKeyword = args.ansiColor ? `\x1B[90m${keywords.default}\x1B[39m` : keywords.default;
1413
+ let defaultValue;
1414
+ if (Array.isArray(flag.default)) {
1415
+ if (flag.default.length === 0) {
1416
+ defaultValue = "[]";
1417
+ } else {
1418
+ const separator = "variadic" in flag && typeof flag.variadic === "string" ? flag.variadic : " ";
1419
+ defaultValue = flag.default.join(separator);
1420
+ }
1421
+ } else {
1422
+ defaultValue = flag.default === "" ? `""` : String(flag.default);
1423
+ }
1424
+ suffixParts.push(`${defaultKeyword} ${defaultValue}`);
1425
+ }
1426
+ if ("variadic" in flag && typeof flag.variadic === "string") {
1427
+ const separatorKeyword = args.ansiColor ? `\x1B[90m${keywords.separator}\x1B[39m` : keywords.separator;
1428
+ suffixParts.push(`${separatorKeyword} ${flag.variadic}`);
1429
+ }
1430
+ const suffix = suffixParts.length > 0 ? `[${suffixParts.join(", ")}]` : undefined;
1431
+ return {
1432
+ aliases: aliasStrings.join(" "),
1433
+ flagName,
1434
+ brief: flag.brief,
1435
+ suffix,
1436
+ hidden: flag.hidden
1437
+ };
1438
+ });
1439
+ rows.push({
1440
+ aliases: "-h",
1441
+ flagName: atLeastOneOptional ? " --help" : "--help",
1442
+ brief: briefs.help
1443
+ });
1444
+ if (args.includeHelpAllFlag) {
1445
+ const helpAllFlagName = formatForDisplay("helpAll", args.config.caseStyle);
1446
+ rows.push({
1447
+ aliases: "-H",
1448
+ flagName: atLeastOneOptional ? ` --${helpAllFlagName}` : `--${helpAllFlagName}`,
1449
+ brief: briefs.helpAll,
1450
+ hidden: !args.config.alwaysShowHelpAllFlag
1451
+ });
1452
+ }
1453
+ if (args.includeVersionFlag) {
1454
+ rows.push({
1455
+ aliases: "-v",
1456
+ flagName: atLeastOneOptional ? " --version" : "--version",
1457
+ brief: briefs.version
1458
+ });
1459
+ }
1460
+ if (args.includeArgumentEscapeSequenceFlag) {
1461
+ rows.push({
1462
+ aliases: "",
1463
+ flagName: atLeastOneOptional ? " --" : "--",
1464
+ brief: briefs.argumentEscapeSequence
1465
+ });
1466
+ }
1467
+ return formatRowsWithColumns(rows.map((row) => {
1468
+ if (!args.ansiColor) {
1469
+ return [row.aliases, row.flagName, row.brief, row.suffix ?? ""];
1470
+ }
1471
+ return [
1472
+ row.hidden ? `\x1B[90m${row.aliases}\x1B[39m` : `\x1B[97m${row.aliases}\x1B[39m`,
1473
+ row.hidden ? `\x1B[90m${row.flagName}\x1B[39m` : `\x1B[97m${row.flagName}\x1B[39m`,
1474
+ row.hidden ? `\x1B[90m${row.brief}\x1B[39m` : `\x1B[03m${row.brief}\x1B[23m`,
1475
+ row.suffix ?? ""
1476
+ ];
1477
+ }), [" ", " ", " "]);
1478
+ }
1479
+ function* generateBuiltInFlagUsageLines(args) {
1480
+ yield args.config.useAliasInUsageLine ? "-h" : "--help";
1481
+ if (args.includeHelpAllFlag) {
1482
+ const helpAllFlagName = formatForDisplay("helpAll", args.config.caseStyle);
1483
+ yield args.config.useAliasInUsageLine ? "-H" : `--${helpAllFlagName}`;
1484
+ }
1485
+ if (args.includeVersionFlag) {
1486
+ yield args.config.useAliasInUsageLine ? "-v" : "--version";
1487
+ }
1488
+ }
1489
+ function formatDocumentationForPositionalParameters(positional, args) {
1490
+ if (positional.kind === "array") {
1491
+ const name = positional.parameter.placeholder ?? "args";
1492
+ const argName = args.ansiColor ? `\x1B[97m${name}...\x1B[39m` : `${name}...`;
1493
+ const brief = args.ansiColor ? `\x1B[3m${positional.parameter.brief}\x1B[23m` : positional.parameter.brief;
1494
+ return formatRowsWithColumns([[argName, brief]], [" "]);
1495
+ }
1496
+ const { keywords } = args.text;
1497
+ const atLeastOneOptional = positional.parameters.some((def) => def.optional);
1498
+ return formatRowsWithColumns(positional.parameters.map((def, i) => {
1499
+ let name = def.placeholder ?? `arg${i + 1}`;
1500
+ let suffix;
1501
+ if (def.optional) {
1502
+ name = `[${name}]`;
1503
+ } else if (atLeastOneOptional) {
1504
+ name = ` ${name}`;
1505
+ }
1506
+ if (def.default) {
1507
+ const defaultKeyword = args.ansiColor ? `\x1B[90m${keywords.default}\x1B[39m` : keywords.default;
1508
+ suffix = `[${defaultKeyword} ${def.default}]`;
1509
+ }
1510
+ return [
1511
+ args.ansiColor ? `\x1B[97m${name}\x1B[39m` : name,
1512
+ args.ansiColor ? `\x1B[3m${def.brief}\x1B[23m` : def.brief,
1513
+ suffix ?? ""
1514
+ ];
1515
+ }), [" ", " "]);
1516
+ }
1517
+ function* generateCommandHelpLines(parameters, docs, args) {
1518
+ const { brief, fullDescription, customUsage } = docs;
1519
+ const { headers } = args.text;
1520
+ const prefix = args.prefix.join(" ");
1521
+ yield args.ansiColor ? `\x1B[1m${headers.usage}\x1B[22m` : headers.usage;
1522
+ if (customUsage) {
1523
+ for (const usage of customUsage) {
1524
+ if (typeof usage === "string") {
1525
+ yield ` ${prefix} ${usage}`;
1526
+ } else {
1527
+ const brief2 = args.ansiColor ? `\x1B[3m${usage.brief}\x1B[23m` : usage.brief;
1528
+ yield ` ${prefix} ${usage.input}
1529
+ ${brief2}`;
1530
+ }
1531
+ }
1532
+ } else {
1533
+ yield ` ${formatUsageLineForParameters(parameters, args)}`;
1534
+ }
1535
+ for (const line of generateBuiltInFlagUsageLines(args)) {
1536
+ yield ` ${prefix} ${line}`;
1537
+ }
1538
+ yield "";
1539
+ yield fullDescription ?? brief;
1540
+ if (args.aliases && args.aliases.length > 0) {
1541
+ const aliasPrefix = args.prefix.slice(0, -1).join(" ");
1542
+ yield "";
1543
+ yield args.ansiColor ? `\x1B[1m${headers.aliases}\x1B[22m` : headers.aliases;
1544
+ for (const alias of args.aliases) {
1545
+ yield ` ${aliasPrefix} ${alias}`;
1546
+ }
1547
+ }
1548
+ yield "";
1549
+ yield args.ansiColor ? `\x1B[1m${headers.flags}\x1B[22m` : headers.flags;
1550
+ for (const line of formatDocumentationForFlagParameters(parameters.flags ?? {}, parameters.aliases ?? {}, args)) {
1551
+ yield ` ${line}`;
1552
+ }
1553
+ const positional = parameters.positional ?? { kind: "tuple", parameters: [] };
1554
+ if (positional.kind === "array" || positional.parameters.length > 0) {
1555
+ yield "";
1556
+ yield args.ansiColor ? `\x1B[1m${headers.arguments}\x1B[22m` : headers.arguments;
1557
+ for (const line of formatDocumentationForPositionalParameters(positional, args)) {
1558
+ yield ` ${line}`;
1559
+ }
1560
+ }
1561
+ }
1562
+ function checkForReservedFlags(flags, reserved) {
1563
+ for (const flag of reserved) {
1564
+ if (flag in flags) {
1565
+ throw new InternalError(`Unable to use reserved flag --${flag}`);
1566
+ }
1567
+ }
1568
+ }
1569
+ function checkForReservedAliases(aliases, reserved) {
1570
+ for (const alias of reserved) {
1571
+ if (alias in aliases) {
1572
+ throw new InternalError(`Unable to use reserved alias -${alias}`);
1573
+ }
1574
+ }
1575
+ }
1576
+ function* asNegationFlagNames(flagName) {
1577
+ yield `no-${convertCamelCaseToKebabCase(flagName)}`;
1578
+ yield `no${flagName[0].toUpperCase()}${flagName.slice(1)}`;
1579
+ }
1580
+ function checkForNegationCollisions(flags) {
1581
+ const flagsAllowingNegation = Object.entries(flags).filter(([, flag]) => flag.kind === "boolean" && !flag.optional);
1582
+ for (const [internalFlagName] of flagsAllowingNegation) {
1583
+ for (const negatedFlagName of asNegationFlagNames(internalFlagName)) {
1584
+ if (negatedFlagName in flags) {
1585
+ throw new InternalError(`Unable to allow negation for --${internalFlagName} as it conflicts with --${negatedFlagName}`);
1586
+ }
1587
+ }
1588
+ }
1589
+ }
1590
+ function checkForInvalidVariadicSeparators(flags) {
1591
+ for (const [internalFlagName, flag] of Object.entries(flags)) {
1592
+ if ("variadic" in flag && typeof flag.variadic === "string") {
1593
+ if (flag.variadic.length < 1) {
1594
+ throw new InternalError(`Unable to use "" as variadic separator for --${internalFlagName} as it is empty`);
1595
+ }
1596
+ if (/\s/.test(flag.variadic)) {
1597
+ throw new InternalError(`Unable to use "${flag.variadic}" as variadic separator for --${internalFlagName} as it contains whitespace`);
1598
+ }
1599
+ }
1600
+ }
1601
+ }
1602
+ function buildCommand(builderArgs) {
1603
+ const { flags = {}, aliases = {} } = builderArgs.parameters;
1604
+ checkForReservedFlags(flags, ["help", "helpAll", "help-all"]);
1605
+ checkForReservedAliases(aliases, ["h", "H"]);
1606
+ checkForNegationCollisions(flags);
1607
+ checkForInvalidVariadicSeparators(flags);
1608
+ let loader;
1609
+ if ("func" in builderArgs) {
1610
+ loader = async () => builderArgs.func;
1611
+ } else {
1612
+ loader = builderArgs.loader;
1613
+ }
1614
+ return {
1615
+ kind: CommandSymbol,
1616
+ loader,
1617
+ parameters: builderArgs.parameters,
1618
+ get brief() {
1619
+ return builderArgs.docs.brief;
1620
+ },
1621
+ get fullDescription() {
1622
+ return builderArgs.docs.fullDescription;
1623
+ },
1624
+ formatUsageLine: (args) => {
1625
+ return formatUsageLineForParameters(builderArgs.parameters, args);
1626
+ },
1627
+ formatHelp: (args) => {
1628
+ const lines = [
1629
+ ...generateCommandHelpLines(builderArgs.parameters, builderArgs.docs, args)
1630
+ ];
1631
+ const text = lines.join(`
1632
+ `);
1633
+ return text + `
1634
+ `;
1635
+ },
1636
+ usesFlag: (flagName) => {
1637
+ return Boolean(flagName in flags || flagName in aliases);
1638
+ }
1639
+ };
1640
+ }
1641
+ function* generateRouteMapHelpLines(routes, docs, args) {
1642
+ const { brief, fullDescription, hideRoute } = docs;
1643
+ const { headers } = args.text;
1644
+ yield args.ansiColor ? `\x1B[1m${headers.usage}\x1B[22m` : headers.usage;
1645
+ for (const [name, route] of Object.entries(routes)) {
1646
+ if (!hideRoute || !hideRoute[name] || args.includeHidden) {
1647
+ const externalRouteName = args.config.caseStyle === "convert-camel-to-kebab" ? convertCamelCaseToKebabCase(name) : name;
1648
+ yield ` ${route.formatUsageLine({
1649
+ ...args,
1650
+ prefix: [...args.prefix, externalRouteName]
1651
+ })}`;
1652
+ }
1653
+ }
1654
+ const prefix = args.prefix.join(" ");
1655
+ for (const line of generateBuiltInFlagUsageLines(args)) {
1656
+ yield ` ${prefix} ${line}`;
1657
+ }
1658
+ yield "";
1659
+ yield fullDescription ?? brief;
1660
+ if (args.aliases && args.aliases.length > 0) {
1661
+ const aliasPrefix = args.prefix.slice(0, -1).join(" ");
1662
+ yield "";
1663
+ yield args.ansiColor ? `\x1B[1m${headers.aliases}\x1B[22m` : headers.aliases;
1664
+ for (const alias of args.aliases) {
1665
+ yield ` ${aliasPrefix} ${alias}`;
1666
+ }
1667
+ }
1668
+ yield "";
1669
+ yield args.ansiColor ? `\x1B[1m${headers.flags}\x1B[22m` : headers.flags;
1670
+ for (const line of formatDocumentationForFlagParameters({}, {}, args)) {
1671
+ yield ` ${line}`;
1672
+ }
1673
+ yield "";
1674
+ yield args.ansiColor ? `\x1B[1m${headers.commands}\x1B[22m` : headers.commands;
1675
+ const visibleRoutes = Object.entries(routes).filter(([name]) => !hideRoute || !hideRoute[name] || args.includeHidden);
1676
+ const rows = visibleRoutes.map(([internalRouteName, route]) => {
1677
+ const externalRouteName = formatForDisplay(internalRouteName, args.config.caseStyle);
1678
+ return {
1679
+ routeName: externalRouteName,
1680
+ brief: route.brief,
1681
+ hidden: hideRoute && hideRoute[internalRouteName]
1682
+ };
1683
+ });
1684
+ const formattedRows = formatRowsWithColumns(rows.map((row) => {
1685
+ if (!args.ansiColor) {
1686
+ return [row.routeName, row.brief];
1687
+ }
1688
+ return [
1689
+ row.hidden ? `\x1B[90m${row.routeName}\x1B[39m` : `\x1B[97m${row.routeName}\x1B[39m`,
1690
+ row.hidden ? `\x1B[90m${row.brief}\x1B[39m` : `\x1B[03m${row.brief}\x1B[23m`
1691
+ ];
1692
+ }), [" "]);
1693
+ for (const line of formattedRows) {
1694
+ yield ` ${line}`;
1695
+ }
1696
+ }
1697
+ function buildRouteMap({
1698
+ routes,
1699
+ defaultCommand: defaultCommandRoute,
1700
+ docs,
1701
+ aliases
1702
+ }) {
1703
+ if (Object.entries(routes).length === 0) {
1704
+ throw new InternalError("Route map must contain at least one route");
1705
+ }
1706
+ const activeAliases = aliases ?? {};
1707
+ const aliasesByRoute = /* @__PURE__ */ new Map;
1708
+ for (const [alias, routeName] of Object.entries(activeAliases)) {
1709
+ if (alias in routes) {
1710
+ throw new InternalError(`Cannot use "${alias}" as an alias when a route with that name already exists`);
1711
+ }
1712
+ const routeAliases = aliasesByRoute.get(routeName) ?? [];
1713
+ aliasesByRoute.set(routeName, [...routeAliases, alias]);
1714
+ }
1715
+ const defaultCommand = defaultCommandRoute ? routes[defaultCommandRoute] : undefined;
1716
+ if (defaultCommand && defaultCommand.kind === RouteMapSymbol) {
1717
+ throw new InternalError(`Cannot use "${defaultCommandRoute}" as the default command because it is not a Command`);
1718
+ }
1719
+ const resolveRouteName = (input) => {
1720
+ if (input in activeAliases) {
1721
+ return activeAliases[input];
1722
+ } else if (input in routes) {
1723
+ return input;
1724
+ }
1725
+ };
1726
+ return {
1727
+ kind: RouteMapSymbol,
1728
+ get brief() {
1729
+ return docs.brief;
1730
+ },
1731
+ get fullDescription() {
1732
+ return docs.fullDescription;
1733
+ },
1734
+ formatUsageLine(args) {
1735
+ const routeNames = this.getAllEntries().filter((entry) => !entry.hidden).map((entry) => entry.name[args.config.caseStyle]);
1736
+ return `${args.prefix.join(" ")} ${routeNames.join("|")} ...`;
1737
+ },
1738
+ formatHelp: (config) => {
1739
+ const lines = [...generateRouteMapHelpLines(routes, docs, config)];
1740
+ const text = lines.join(`
1741
+ `);
1742
+ return text + `
1743
+ `;
1744
+ },
1745
+ getDefaultCommand: () => {
1746
+ return defaultCommand;
1747
+ },
1748
+ getOtherAliasesForInput: (input, caseStyle) => {
1749
+ if (defaultCommandRoute) {
1750
+ if (input === defaultCommandRoute) {
1751
+ return {
1752
+ original: [""],
1753
+ "convert-camel-to-kebab": [""]
1754
+ };
1755
+ }
1756
+ if (input === "") {
1757
+ return {
1758
+ original: [defaultCommandRoute],
1759
+ "convert-camel-to-kebab": [defaultCommandRoute]
1760
+ };
1761
+ }
1762
+ }
1763
+ const camelInput = convertKebabCaseToCamelCase(input);
1764
+ let routeName = resolveRouteName(input);
1765
+ if (!routeName && caseStyle === "allow-kebab-for-camel") {
1766
+ routeName = resolveRouteName(camelInput);
1767
+ }
1768
+ if (!routeName) {
1769
+ return {
1770
+ original: [],
1771
+ "convert-camel-to-kebab": []
1772
+ };
1773
+ }
1774
+ const otherAliases = [routeName, ...aliasesByRoute.get(routeName) ?? []].filter((alias) => alias !== input && alias !== camelInput);
1775
+ return {
1776
+ original: otherAliases,
1777
+ "convert-camel-to-kebab": otherAliases.map(convertCamelCaseToKebabCase)
1778
+ };
1779
+ },
1780
+ getRoutingTargetForInput: (input) => {
1781
+ const routeName = input in activeAliases ? activeAliases[input] : input;
1782
+ return routes[routeName];
1783
+ },
1784
+ getAllEntries() {
1785
+ const hiddenRoutes = docs.hideRoute;
1786
+ return Object.entries(routes).map(([originalRouteName, target]) => {
1787
+ return {
1788
+ name: {
1789
+ original: originalRouteName,
1790
+ "convert-camel-to-kebab": convertCamelCaseToKebabCase(originalRouteName)
1791
+ },
1792
+ target,
1793
+ aliases: aliasesByRoute.get(originalRouteName) ?? [],
1794
+ hidden: hiddenRoutes?.[originalRouteName] ?? false
1795
+ };
1796
+ });
1797
+ }
1798
+ };
1799
+ }
1800
+ async function run(app, inputs, context) {
1801
+ const exitCode = await runApplication(app, inputs, context);
1802
+ context.process.exitCode = exitCode;
1803
+ }
1804
+
1805
+ // src/commands/login.ts
1806
+ import { randomBytes } from "crypto";
1807
+
1808
+ // src/lib/credentials.ts
1809
+ import {
1810
+ existsSync,
1811
+ mkdirSync,
1812
+ readFileSync,
1813
+ rmSync,
1814
+ writeFileSync
1815
+ } from "fs";
1816
+ import { join } from "path";
1817
+ function getConfigDir() {
1818
+ return process.env.RUDEL_CONFIG_DIR ?? join(process.env.HOME ?? "~", ".rudel");
1819
+ }
1820
+ function getCredentialsPath() {
1821
+ return join(getConfigDir(), "credentials.json");
1822
+ }
1823
+ function saveCredentials(token, apiBaseUrl) {
1824
+ const dir = getConfigDir();
1825
+ if (!existsSync(dir)) {
1826
+ mkdirSync(dir, { recursive: true, mode: 448 });
1827
+ }
1828
+ const data = { token, apiBaseUrl };
1829
+ writeFileSync(getCredentialsPath(), JSON.stringify(data, null, 2), {
1830
+ mode: 384
1831
+ });
1832
+ }
1833
+ function loadCredentials() {
1834
+ const path = getCredentialsPath();
1835
+ if (!existsSync(path))
1836
+ return null;
1837
+ const content = readFileSync(path, "utf-8");
1838
+ return JSON.parse(content);
1839
+ }
1840
+ function clearCredentials() {
1841
+ const path = getCredentialsPath();
1842
+ if (existsSync(path)) {
1843
+ rmSync(path);
1844
+ }
1845
+ }
1846
+
1847
+ // src/commands/login.ts
1848
+ var DEFAULT_API_BASE = "https://rudel.numia.workers.dev";
1849
+ var DEFAULT_WEB_URL = "https://rudel.numia.workers.dev";
1850
+ var CALLBACK_TIMEOUT_MS = 120000;
1851
+ async function runLogin(flags) {
1852
+ const write = (msg) => process.stdout.write(`${msg}
1853
+ `);
1854
+ const writeError = (msg) => process.stderr.write(`${msg}
1855
+ `);
1856
+ const existing = loadCredentials();
1857
+ if (existing) {
1858
+ write("Already logged in. Run `rudel logout` first to switch accounts.");
1859
+ return;
1860
+ }
1861
+ const state = randomBytes(16).toString("hex");
1862
+ let resolveCallback;
1863
+ let rejectCallback;
1864
+ const tokenPromise = new Promise((resolve, reject) => {
1865
+ resolveCallback = resolve;
1866
+ rejectCallback = reject;
1867
+ });
1868
+ const server = Bun.serve({
1869
+ port: 0,
1870
+ hostname: "127.0.0.1",
1871
+ fetch(request) {
1872
+ const url = new URL(request.url);
1873
+ if (url.pathname !== "/callback") {
1874
+ return new Response("Not found", { status: 404 });
1875
+ }
1876
+ const receivedToken = url.searchParams.get("token");
1877
+ const receivedState = url.searchParams.get("state");
1878
+ if (receivedState !== state) {
1879
+ rejectCallback(new Error("State mismatch \u2014 possible CSRF attack"));
1880
+ return new Response("<html><body><h1>Login failed</h1><p>State mismatch. Please try again.</p></body></html>", { headers: { "Content-Type": "text/html" } });
1881
+ }
1882
+ if (!receivedToken) {
1883
+ rejectCallback(new Error("No token received"));
1884
+ return new Response("<html><body><h1>Login failed</h1><p>No token received.</p></body></html>", { headers: { "Content-Type": "text/html" } });
1885
+ }
1886
+ resolveCallback(receivedToken);
1887
+ return new Response("<html><body><h1>Login successful!</h1><p>You can close this tab and return to the terminal.</p></body></html>", { headers: { "Content-Type": "text/html" } });
1888
+ }
1889
+ });
1890
+ const callbackUrl = `http://127.0.0.1:${server.port}/callback`;
1891
+ const loginUrl = `${flags.webUrl}?cli_callback=${encodeURIComponent(callbackUrl)}&state=${state}`;
1892
+ write("Opening browser for authentication...");
1893
+ write(`If the browser doesn't open, visit: ${loginUrl}`);
1894
+ const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1895
+ Bun.spawn([opener, loginUrl], { stdout: "ignore", stderr: "ignore" });
1896
+ const timeout = setTimeout(() => {
1897
+ rejectCallback(new Error("Login timed out after 120 seconds"));
1898
+ }, CALLBACK_TIMEOUT_MS);
1899
+ let token;
1900
+ try {
1901
+ token = await tokenPromise;
1902
+ } catch (error) {
1903
+ clearTimeout(timeout);
1904
+ server.stop();
1905
+ writeError(`Login failed: ${error instanceof Error ? error.message : String(error)}`);
1906
+ process.exitCode = 1;
1907
+ return;
1908
+ }
1909
+ clearTimeout(timeout);
1910
+ server.stop();
1911
+ write("Validating token...");
1912
+ const meResponse = await fetch(`${flags.apiBase}/rpc/me`, {
1913
+ method: "POST",
1914
+ headers: {
1915
+ "Content-Type": "application/json",
1916
+ Authorization: `Bearer ${token}`
1917
+ },
1918
+ body: JSON.stringify({})
1919
+ });
1920
+ if (!meResponse.ok) {
1921
+ writeError("Login failed: token validation failed");
1922
+ process.exitCode = 1;
1923
+ return;
1924
+ }
1925
+ const body = await meResponse.json();
1926
+ saveCredentials(token, flags.apiBase);
1927
+ write(`Logged in as ${body.json.name} (${body.json.email})`);
1928
+ }
1929
+ var loginCommand = buildCommand({
1930
+ loader: async () => ({ default: runLogin }),
1931
+ parameters: {
1932
+ flags: {
1933
+ apiBase: {
1934
+ kind: "parsed",
1935
+ parse: String,
1936
+ brief: "API server base URL",
1937
+ default: DEFAULT_API_BASE
1938
+ },
1939
+ webUrl: {
1940
+ kind: "parsed",
1941
+ parse: String,
1942
+ brief: "Web app URL for authentication",
1943
+ default: DEFAULT_WEB_URL
1944
+ }
1945
+ }
1946
+ },
1947
+ docs: {
1948
+ brief: "Authenticate with the Rudel API via browser login"
1949
+ }
1950
+ });
1951
+
1952
+ // src/commands/logout.ts
1953
+ async function runLogout() {
1954
+ const write = (msg) => process.stdout.write(`${msg}
1955
+ `);
1956
+ const credentials = loadCredentials();
1957
+ if (!credentials) {
1958
+ write("Not logged in.");
1959
+ return;
1960
+ }
1961
+ clearCredentials();
1962
+ write("Logged out successfully.");
1963
+ }
1964
+ var logoutCommand = buildCommand({
1965
+ loader: async () => ({ default: runLogout }),
1966
+ parameters: {},
1967
+ docs: {
1968
+ brief: "Log out and remove stored credentials"
1969
+ }
1970
+ });
1971
+
1972
+ // src/lib/classifier.ts
1973
+ import { mkdir, unlink } from "fs/promises";
1974
+ import { homedir } from "os";
1975
+ import { join as join2 } from "path";
1976
+
1977
+ // src/lib/types.ts
1978
+ var SESSION_TAGS = [
1979
+ "research",
1980
+ "new_feature",
1981
+ "bug_fix",
1982
+ "refactoring",
1983
+ "documentation",
1984
+ "tests",
1985
+ "other"
1986
+ ];
1987
+ var DEFAULT_ENDPOINT = "https://rudel.numia.workers.dev/rpc";
1988
+
1989
+ // src/lib/classifier.ts
1990
+ var SYSTEM_PROMPT = `You are a session classifier. Analyze the Claude Code session transcript and classify it into exactly ONE of these categories:
1991
+
1992
+ - research: Exploring codebase, understanding code, answering questions about how things work
1993
+ - new_feature: Implementing new functionality or features
1994
+ - bug_fix: Fixing bugs, errors, or unexpected behavior
1995
+ - refactoring: Restructuring existing code without changing functionality
1996
+ - documentation: Writing or updating documentation, comments, READMEs
1997
+ - tests: Writing, updating, or fixing tests
1998
+
1999
+ CRITICAL: Respond with ONLY the tag name. Nothing else. No explanation, no punctuation, no formatting. Just ONE of: research, new_feature, bug_fix, refactoring, documentation, tests`;
2000
+ async function classifySession(content) {
2001
+ const truncatedContent = content.slice(0, 50000);
2002
+ const tempDir = join2(homedir(), ".claude", "temp");
2003
+ const tempFile = join2(tempDir, `classify-${Date.now()}.txt`);
2004
+ try {
2005
+ await mkdir(tempDir, { recursive: true });
2006
+ await Bun.write(tempFile, `Classify this session transcript:
2007
+
2008
+ ${truncatedContent}`);
2009
+ const prompt = `Read and classify the session transcript in this file: ${tempFile}`;
2010
+ const escapedPrompt = prompt.replace(/'/g, "'\\''");
2011
+ const escapedSystemPrompt = SYSTEM_PROMPT.replace(/'/g, "'\\''");
2012
+ const proc = Bun.spawn([
2013
+ "sh",
2014
+ "-c",
2015
+ `echo '${escapedPrompt}' | claude --output-format text --print --model haiku --no-session-persistence --dangerously-skip-permissions --system-prompt '${escapedSystemPrompt}'`
2016
+ ], { stdout: "pipe", stderr: "pipe" });
2017
+ const exitCode = await proc.exited;
2018
+ const stdout = await new Response(proc.stdout).text();
2019
+ if (exitCode !== 0) {
2020
+ return "other";
2021
+ }
2022
+ const output = stdout.trim().toLowerCase();
2023
+ if (SESSION_TAGS.includes(output)) {
2024
+ return output;
2025
+ }
2026
+ for (const tag of SESSION_TAGS) {
2027
+ if (new RegExp(`\\b${tag}\\b`).test(output)) {
2028
+ return tag;
2029
+ }
2030
+ }
2031
+ return "other";
2032
+ } catch {
2033
+ return;
2034
+ } finally {
2035
+ try {
2036
+ await unlink(tempFile);
2037
+ } catch {}
2038
+ }
2039
+ }
2040
+
2041
+ // src/lib/git-info.ts
2042
+ import { join as join3 } from "path";
2043
+ var {$ } = globalThis.Bun;
2044
+ async function getGitInfo(cwd) {
2045
+ const [repository, branch, sha] = await Promise.all([
2046
+ getRepositoryName(cwd),
2047
+ getGitBranch(cwd),
2048
+ getGitSha(cwd)
2049
+ ]);
2050
+ return {
2051
+ repository: repository ?? undefined,
2052
+ branch: branch ?? undefined,
2053
+ sha: sha ?? undefined
2054
+ };
2055
+ }
2056
+ async function getRepositoryName(cwd) {
2057
+ try {
2058
+ const gitRootResult = await $`git -C ${cwd} rev-parse --show-toplevel`.quiet();
2059
+ if (gitRootResult.exitCode !== 0)
2060
+ return null;
2061
+ const gitRoot = gitRootResult.text().trim();
2062
+ const packageJsonPath = join3(gitRoot, "package.json");
2063
+ const packageFile = Bun.file(packageJsonPath);
2064
+ if (await packageFile.exists()) {
2065
+ try {
2066
+ const packageJson = await packageFile.json();
2067
+ if (packageJson.name)
2068
+ return packageJson.name;
2069
+ } catch {}
2070
+ }
2071
+ const remoteResult = await $`git -C ${gitRoot} remote get-url origin`.quiet();
2072
+ if (remoteResult.exitCode === 0) {
2073
+ const remoteUrl = remoteResult.text().trim();
2074
+ const match = remoteUrl.match(/[/:]([^/]+?)(?:\.git)?$/);
2075
+ if (match?.[1])
2076
+ return match[1];
2077
+ }
2078
+ const dirName = gitRoot.split("/").pop();
2079
+ return dirName ?? null;
2080
+ } catch {
2081
+ return null;
2082
+ }
2083
+ }
2084
+ async function getGitBranch(cwd) {
2085
+ try {
2086
+ const result = await $`git -C ${cwd} rev-parse --abbrev-ref HEAD`.quiet();
2087
+ if (result.exitCode !== 0)
2088
+ return null;
2089
+ return result.text().trim();
2090
+ } catch {
2091
+ return null;
2092
+ }
2093
+ }
2094
+ async function getGitSha(cwd) {
2095
+ try {
2096
+ const result = await $`git -C ${cwd} rev-parse HEAD`.quiet();
2097
+ if (result.exitCode !== 0)
2098
+ return null;
2099
+ return result.text().trim();
2100
+ } catch {
2101
+ return null;
2102
+ }
2103
+ }
2104
+
2105
+ // src/lib/session-resolver.ts
2106
+ import { readdir, stat } from "fs/promises";
2107
+ import { homedir as homedir2 } from "os";
2108
+ import { basename, dirname, join as join4 } from "path";
2109
+ var SESSIONS_BASE_DIR = join4(homedir2(), ".claude", "projects");
2110
+ async function resolveSession(input) {
2111
+ const isPath = input.includes("/") || input.endsWith(".jsonl");
2112
+ if (isPath) {
2113
+ return resolveFromPath(input);
2114
+ }
2115
+ return resolveFromId(input);
2116
+ }
2117
+ async function resolveFromPath(filePath) {
2118
+ const filename = basename(filePath);
2119
+ validateNotSubagent(filename);
2120
+ const file = Bun.file(filePath);
2121
+ if (!await file.exists()) {
2122
+ throw new Error(`Session file not found: ${filePath}`);
2123
+ }
2124
+ const sessionId = filename.replace(/\.jsonl$/, "");
2125
+ const sessionDir = dirname(filePath);
2126
+ const parentDir = basename(sessionDir);
2127
+ const projectPath = await decodeProjectPath(parentDir);
2128
+ return { transcriptPath: filePath, projectPath, sessionDir, sessionId };
2129
+ }
2130
+ async function resolveFromId(sessionId) {
2131
+ validateNotSubagent(`${sessionId}.jsonl`);
2132
+ const sessionFileName = `${sessionId}.jsonl`;
2133
+ let projectDirs;
2134
+ try {
2135
+ projectDirs = await readdir(SESSIONS_BASE_DIR);
2136
+ } catch {
2137
+ throw new Error(`Session not found: ${sessionId}`);
2138
+ }
2139
+ for (const projectDir of projectDirs) {
2140
+ const sessionDir = join4(SESSIONS_BASE_DIR, projectDir);
2141
+ try {
2142
+ const files = await readdir(sessionDir);
2143
+ if (files.includes(sessionFileName)) {
2144
+ const transcriptPath = join4(sessionDir, sessionFileName);
2145
+ const projectPath = await decodeProjectPath(projectDir);
2146
+ return {
2147
+ transcriptPath,
2148
+ projectPath,
2149
+ sessionDir,
2150
+ sessionId
2151
+ };
2152
+ }
2153
+ } catch {}
2154
+ }
2155
+ throw new Error(`Session not found: ${sessionId}`);
2156
+ }
2157
+ function validateNotSubagent(filename) {
2158
+ if (filename.startsWith("agent-") && filename.endsWith(".jsonl")) {
2159
+ throw new Error("This is a subagent file, not a main session. Please provide the main session ID or path.");
2160
+ }
2161
+ }
2162
+ async function decodeProjectPath(encodedDir) {
2163
+ const parts = encodedDir.replace(/^-/, "").split("-");
2164
+ async function findPath(partIndex, currentPath) {
2165
+ if (partIndex >= parts.length) {
2166
+ try {
2167
+ await stat(currentPath);
2168
+ return currentPath;
2169
+ } catch {
2170
+ return null;
2171
+ }
2172
+ }
2173
+ for (let endIndex = parts.length;endIndex > partIndex; endIndex--) {
2174
+ const segment = parts.slice(partIndex, endIndex).join("-");
2175
+ const testPath = currentPath ? `${currentPath}/${segment}` : `/${segment}`;
2176
+ try {
2177
+ await stat(testPath);
2178
+ if (endIndex === parts.length) {
2179
+ return testPath;
2180
+ }
2181
+ const result2 = await findPath(endIndex, testPath);
2182
+ if (result2) {
2183
+ return result2;
2184
+ }
2185
+ } catch {}
2186
+ }
2187
+ return null;
2188
+ }
2189
+ const result = await findPath(0, "");
2190
+ if (result) {
2191
+ return result;
2192
+ }
2193
+ return `/${parts.join("/")}`;
2194
+ }
2195
+
2196
+ // src/lib/subagent-reader.ts
2197
+ import { join as join5 } from "path";
2198
+ async function readSubagentFiles(sessionDir, agentIds, sessionId) {
2199
+ const subagents = [];
2200
+ for (const agentId of agentIds) {
2201
+ const possiblePaths = [
2202
+ join5(sessionDir, `agent-${agentId}.jsonl`),
2203
+ ...sessionId ? [join5(sessionDir, sessionId, "subagents", `agent-${agentId}.jsonl`)] : []
2204
+ ];
2205
+ for (const agentPath of possiblePaths) {
2206
+ try {
2207
+ const file = Bun.file(agentPath);
2208
+ if (await file.exists()) {
2209
+ const content = await file.text();
2210
+ subagents.push({ agentId, content });
2211
+ break;
2212
+ }
2213
+ } catch {}
2214
+ }
2215
+ }
2216
+ return subagents;
2217
+ }
2218
+
2219
+ // src/lib/transcript-reader.ts
2220
+ async function readTranscript(transcriptPath) {
2221
+ const maxRetries = 5;
2222
+ const delayMs = 500;
2223
+ for (let attempt = 1;attempt <= maxRetries; attempt++) {
2224
+ try {
2225
+ const file = Bun.file(transcriptPath);
2226
+ if (!await file.exists()) {
2227
+ if (attempt < maxRetries) {
2228
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
2229
+ continue;
2230
+ }
2231
+ throw new Error(`Transcript file not found after ${maxRetries} attempts: ${transcriptPath}`);
2232
+ }
2233
+ return await file.text();
2234
+ } catch (error) {
2235
+ if (attempt < maxRetries) {
2236
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
2237
+ continue;
2238
+ }
2239
+ throw error;
2240
+ }
2241
+ }
2242
+ throw new Error(`Failed to read transcript: ${transcriptPath}`);
2243
+ }
2244
+ function extractAgentIds(sessionContent) {
2245
+ const agentIds = new Set;
2246
+ for (const line of sessionContent.split(`
2247
+ `)) {
2248
+ if (!line.trim())
2249
+ continue;
2250
+ try {
2251
+ const entry = JSON.parse(line);
2252
+ if (entry.toolUseResult?.agentId) {
2253
+ agentIds.add(entry.toolUseResult.agentId);
2254
+ }
2255
+ } catch {}
2256
+ }
2257
+ return Array.from(agentIds);
2258
+ }
2259
+
2260
+ // ../../node_modules/.bun/@orpc+shared@1.13.5/node_modules/@orpc/shared/dist/index.mjs
2261
+ function resolveMaybeOptionalOptions(rest) {
2262
+ return rest[0] ?? {};
2263
+ }
2264
+ function toArray(value) {
2265
+ return Array.isArray(value) ? value : value === undefined || value === null ? [] : [value];
2266
+ }
2267
+ var ORPC_NAME = "orpc";
2268
+ var ORPC_SHARED_PACKAGE_NAME = "@orpc/shared";
2269
+ var ORPC_SHARED_PACKAGE_VERSION = "1.13.5";
2270
+
2271
+ class AbortError extends Error {
2272
+ constructor(...rest) {
2273
+ super(...rest);
2274
+ this.name = "AbortError";
2275
+ }
2276
+ }
2277
+ function once(fn) {
2278
+ let cached;
2279
+ return () => {
2280
+ if (cached) {
2281
+ return cached.result;
2282
+ }
2283
+ const result = fn();
2284
+ cached = { result };
2285
+ return result;
2286
+ };
2287
+ }
2288
+ function sequential(fn) {
2289
+ let lastOperationPromise = Promise.resolve();
2290
+ return (...args) => {
2291
+ return lastOperationPromise = lastOperationPromise.catch(() => {}).then(() => {
2292
+ return fn(...args);
2293
+ });
2294
+ };
2295
+ }
2296
+ var SPAN_ERROR_STATUS = 2;
2297
+ var GLOBAL_OTEL_CONFIG_KEY = `__${ORPC_SHARED_PACKAGE_NAME}@${ORPC_SHARED_PACKAGE_VERSION}/otel/config__`;
2298
+ function getGlobalOtelConfig() {
2299
+ return globalThis[GLOBAL_OTEL_CONFIG_KEY];
2300
+ }
2301
+ function startSpan(name, options = {}, context) {
2302
+ const tracer = getGlobalOtelConfig()?.tracer;
2303
+ return tracer?.startSpan(name, options, context);
2304
+ }
2305
+ function setSpanError(span, error, options = {}) {
2306
+ if (!span) {
2307
+ return;
2308
+ }
2309
+ const exception = toOtelException(error);
2310
+ span.recordException(exception);
2311
+ if (!options.signal?.aborted || options.signal.reason !== error) {
2312
+ span.setStatus({
2313
+ code: SPAN_ERROR_STATUS,
2314
+ message: exception.message
2315
+ });
2316
+ }
2317
+ }
2318
+ function toOtelException(error) {
2319
+ if (error instanceof Error) {
2320
+ const exception = {
2321
+ message: error.message,
2322
+ name: error.name,
2323
+ stack: error.stack
2324
+ };
2325
+ if ("code" in error && (typeof error.code === "string" || typeof error.code === "number")) {
2326
+ exception.code = error.code;
2327
+ }
2328
+ return exception;
2329
+ }
2330
+ return { message: String(error) };
2331
+ }
2332
+ async function runWithSpan({ name, context, ...options }, fn) {
2333
+ const tracer = getGlobalOtelConfig()?.tracer;
2334
+ if (!tracer) {
2335
+ return fn();
2336
+ }
2337
+ const callback = async (span) => {
2338
+ try {
2339
+ return await fn(span);
2340
+ } catch (e) {
2341
+ setSpanError(span, e, options);
2342
+ throw e;
2343
+ } finally {
2344
+ span.end();
2345
+ }
2346
+ };
2347
+ if (context) {
2348
+ return tracer.startActiveSpan(name, options, context, callback);
2349
+ } else {
2350
+ return tracer.startActiveSpan(name, options, callback);
2351
+ }
2352
+ }
2353
+ async function runInSpanContext(span, fn) {
2354
+ const otelConfig = getGlobalOtelConfig();
2355
+ if (!span || !otelConfig) {
2356
+ return fn();
2357
+ }
2358
+ const ctx = otelConfig.trace.setSpan(otelConfig.context.active(), span);
2359
+ return otelConfig.context.with(ctx, fn);
2360
+ }
2361
+ function isAsyncIteratorObject(maybe) {
2362
+ if (!maybe || typeof maybe !== "object") {
2363
+ return false;
2364
+ }
2365
+ return "next" in maybe && typeof maybe.next === "function" && Symbol.asyncIterator in maybe && typeof maybe[Symbol.asyncIterator] === "function";
2366
+ }
2367
+ var fallbackAsyncDisposeSymbol = Symbol.for("asyncDispose");
2368
+ var asyncDisposeSymbol = Symbol.asyncDispose ?? fallbackAsyncDisposeSymbol;
2369
+
2370
+ class AsyncIteratorClass {
2371
+ #isDone = false;
2372
+ #isExecuteComplete = false;
2373
+ #cleanup;
2374
+ #next;
2375
+ constructor(next, cleanup) {
2376
+ this.#cleanup = cleanup;
2377
+ this.#next = sequential(async () => {
2378
+ if (this.#isDone) {
2379
+ return { done: true, value: undefined };
2380
+ }
2381
+ try {
2382
+ const result = await next();
2383
+ if (result.done) {
2384
+ this.#isDone = true;
2385
+ }
2386
+ return result;
2387
+ } catch (err) {
2388
+ this.#isDone = true;
2389
+ throw err;
2390
+ } finally {
2391
+ if (this.#isDone && !this.#isExecuteComplete) {
2392
+ this.#isExecuteComplete = true;
2393
+ await this.#cleanup("next");
2394
+ }
2395
+ }
2396
+ });
2397
+ }
2398
+ next() {
2399
+ return this.#next();
2400
+ }
2401
+ async return(value) {
2402
+ this.#isDone = true;
2403
+ if (!this.#isExecuteComplete) {
2404
+ this.#isExecuteComplete = true;
2405
+ await this.#cleanup("return");
2406
+ }
2407
+ return { done: true, value };
2408
+ }
2409
+ async throw(err) {
2410
+ this.#isDone = true;
2411
+ if (!this.#isExecuteComplete) {
2412
+ this.#isExecuteComplete = true;
2413
+ await this.#cleanup("throw");
2414
+ }
2415
+ throw err;
2416
+ }
2417
+ async[asyncDisposeSymbol]() {
2418
+ this.#isDone = true;
2419
+ if (!this.#isExecuteComplete) {
2420
+ this.#isExecuteComplete = true;
2421
+ await this.#cleanup("dispose");
2422
+ }
2423
+ }
2424
+ [Symbol.asyncIterator]() {
2425
+ return this;
2426
+ }
2427
+ }
2428
+ function asyncIteratorWithSpan({ name, ...options }, iterator) {
2429
+ let span;
2430
+ return new AsyncIteratorClass(async () => {
2431
+ span ??= startSpan(name);
2432
+ try {
2433
+ const result = await runInSpanContext(span, () => iterator.next());
2434
+ span?.addEvent(result.done ? "completed" : "yielded");
2435
+ return result;
2436
+ } catch (err) {
2437
+ setSpanError(span, err, options);
2438
+ throw err;
2439
+ }
2440
+ }, async (reason) => {
2441
+ try {
2442
+ if (reason !== "next") {
2443
+ await runInSpanContext(span, () => iterator.return?.());
2444
+ }
2445
+ } catch (err) {
2446
+ setSpanError(span, err, options);
2447
+ throw err;
2448
+ } finally {
2449
+ span?.end();
2450
+ }
2451
+ });
2452
+ }
2453
+
2454
+ class EventPublisher {
2455
+ #listenersMap = /* @__PURE__ */ new Map;
2456
+ #maxBufferedEvents;
2457
+ constructor(options = {}) {
2458
+ this.#maxBufferedEvents = options.maxBufferedEvents ?? 100;
2459
+ }
2460
+ get size() {
2461
+ return this.#listenersMap.size;
2462
+ }
2463
+ publish(event, payload) {
2464
+ const listeners = this.#listenersMap.get(event);
2465
+ if (!listeners) {
2466
+ return;
2467
+ }
2468
+ for (const listener of listeners) {
2469
+ listener(payload);
2470
+ }
2471
+ }
2472
+ subscribe(event, listenerOrOptions) {
2473
+ if (typeof listenerOrOptions === "function") {
2474
+ let listeners = this.#listenersMap.get(event);
2475
+ if (!listeners) {
2476
+ this.#listenersMap.set(event, listeners = []);
2477
+ }
2478
+ listeners.push(listenerOrOptions);
2479
+ return once(() => {
2480
+ listeners.splice(listeners.indexOf(listenerOrOptions), 1);
2481
+ if (listeners.length === 0) {
2482
+ this.#listenersMap.delete(event);
2483
+ }
2484
+ });
2485
+ }
2486
+ const signal = listenerOrOptions?.signal;
2487
+ const maxBufferedEvents = listenerOrOptions?.maxBufferedEvents ?? this.#maxBufferedEvents;
2488
+ signal?.throwIfAborted();
2489
+ const bufferedEvents = [];
2490
+ const pullResolvers = [];
2491
+ const unsubscribe = this.subscribe(event, (payload) => {
2492
+ const resolver = pullResolvers.shift();
2493
+ if (resolver) {
2494
+ resolver[0]({ done: false, value: payload });
2495
+ } else {
2496
+ bufferedEvents.push(payload);
2497
+ if (bufferedEvents.length > maxBufferedEvents) {
2498
+ bufferedEvents.shift();
2499
+ }
2500
+ }
2501
+ });
2502
+ const abortListener = (event2) => {
2503
+ unsubscribe();
2504
+ pullResolvers.forEach((resolver) => resolver[1](event2.target.reason));
2505
+ pullResolvers.length = 0;
2506
+ bufferedEvents.length = 0;
2507
+ };
2508
+ signal?.addEventListener("abort", abortListener, { once: true });
2509
+ return new AsyncIteratorClass(async () => {
2510
+ if (signal?.aborted) {
2511
+ throw signal.reason;
2512
+ }
2513
+ if (bufferedEvents.length > 0) {
2514
+ return { done: false, value: bufferedEvents.shift() };
2515
+ }
2516
+ return new Promise((resolve, reject) => {
2517
+ pullResolvers.push([resolve, reject]);
2518
+ });
2519
+ }, async () => {
2520
+ unsubscribe();
2521
+ signal?.removeEventListener("abort", abortListener);
2522
+ pullResolvers.forEach((resolver) => resolver[0]({ done: true, value: undefined }));
2523
+ pullResolvers.length = 0;
2524
+ bufferedEvents.length = 0;
2525
+ });
2526
+ }
2527
+ }
2528
+
2529
+ class SequentialIdGenerator {
2530
+ index = BigInt(1);
2531
+ generate() {
2532
+ const id = this.index.toString(36);
2533
+ this.index++;
2534
+ return id;
2535
+ }
2536
+ }
2537
+ function intercept(interceptors, options, main) {
2538
+ const next = (options2, index) => {
2539
+ const interceptor = interceptors[index];
2540
+ if (!interceptor) {
2541
+ return main(options2);
2542
+ }
2543
+ return interceptor({
2544
+ ...options2,
2545
+ next: (newOptions = options2) => next(newOptions, index + 1)
2546
+ });
2547
+ };
2548
+ return next(options, 0);
2549
+ }
2550
+ function parseEmptyableJSON(text) {
2551
+ if (!text) {
2552
+ return;
2553
+ }
2554
+ return JSON.parse(text);
2555
+ }
2556
+ function stringifyJSON(value) {
2557
+ return JSON.stringify(value);
2558
+ }
2559
+ function getConstructor(value) {
2560
+ if (!isTypescriptObject(value)) {
2561
+ return null;
2562
+ }
2563
+ return Object.getPrototypeOf(value)?.constructor;
2564
+ }
2565
+ function isObject(value) {
2566
+ if (!value || typeof value !== "object") {
2567
+ return false;
2568
+ }
2569
+ const proto = Object.getPrototypeOf(value);
2570
+ return proto === Object.prototype || !proto || !proto.constructor;
2571
+ }
2572
+ function isTypescriptObject(value) {
2573
+ return !!value && (typeof value === "object" || typeof value === "function");
2574
+ }
2575
+ function value(value2, ...args) {
2576
+ if (typeof value2 === "function") {
2577
+ return value2(...args);
2578
+ }
2579
+ return value2;
2580
+ }
2581
+ function preventNativeAwait(target) {
2582
+ return new Proxy(target, {
2583
+ get(target2, prop, receiver) {
2584
+ const value2 = Reflect.get(target2, prop, receiver);
2585
+ if (prop !== "then" || typeof value2 !== "function") {
2586
+ return value2;
2587
+ }
2588
+ return new Proxy(value2, {
2589
+ apply(targetFn, thisArg, args) {
2590
+ if (args.length !== 2 || args.some((arg) => !isNativeFunction(arg))) {
2591
+ return Reflect.apply(targetFn, thisArg, args);
2592
+ }
2593
+ let shouldOmit = true;
2594
+ args[0].call(thisArg, preventNativeAwait(new Proxy(target2, {
2595
+ get: (target3, prop2, receiver2) => {
2596
+ if (shouldOmit && prop2 === "then") {
2597
+ shouldOmit = false;
2598
+ return;
2599
+ }
2600
+ return Reflect.get(target3, prop2, receiver2);
2601
+ }
2602
+ })));
2603
+ }
2604
+ });
2605
+ }
2606
+ });
2607
+ }
2608
+ var NATIVE_FUNCTION_REGEX = /^\s*function\s*\(\)\s*\{\s*\[native code\]\s*\}\s*$/;
2609
+ function isNativeFunction(fn) {
2610
+ return typeof fn === "function" && NATIVE_FUNCTION_REGEX.test(fn.toString());
2611
+ }
2612
+ function tryDecodeURIComponent(value2) {
2613
+ try {
2614
+ return decodeURIComponent(value2);
2615
+ } catch {
2616
+ return value2;
2617
+ }
2618
+ }
2619
+ // ../../node_modules/.bun/@orpc+client@1.13.5/node_modules/@orpc/client/dist/shared/client.BF1R3smX.mjs
2620
+ var ORPC_CLIENT_PACKAGE_NAME = "@orpc/client";
2621
+ var ORPC_CLIENT_PACKAGE_VERSION = "1.13.5";
2622
+ var COMMON_ORPC_ERROR_DEFS = {
2623
+ BAD_REQUEST: {
2624
+ status: 400,
2625
+ message: "Bad Request"
2626
+ },
2627
+ UNAUTHORIZED: {
2628
+ status: 401,
2629
+ message: "Unauthorized"
2630
+ },
2631
+ FORBIDDEN: {
2632
+ status: 403,
2633
+ message: "Forbidden"
2634
+ },
2635
+ NOT_FOUND: {
2636
+ status: 404,
2637
+ message: "Not Found"
2638
+ },
2639
+ METHOD_NOT_SUPPORTED: {
2640
+ status: 405,
2641
+ message: "Method Not Supported"
2642
+ },
2643
+ NOT_ACCEPTABLE: {
2644
+ status: 406,
2645
+ message: "Not Acceptable"
2646
+ },
2647
+ TIMEOUT: {
2648
+ status: 408,
2649
+ message: "Request Timeout"
2650
+ },
2651
+ CONFLICT: {
2652
+ status: 409,
2653
+ message: "Conflict"
2654
+ },
2655
+ PRECONDITION_FAILED: {
2656
+ status: 412,
2657
+ message: "Precondition Failed"
2658
+ },
2659
+ PAYLOAD_TOO_LARGE: {
2660
+ status: 413,
2661
+ message: "Payload Too Large"
2662
+ },
2663
+ UNSUPPORTED_MEDIA_TYPE: {
2664
+ status: 415,
2665
+ message: "Unsupported Media Type"
2666
+ },
2667
+ UNPROCESSABLE_CONTENT: {
2668
+ status: 422,
2669
+ message: "Unprocessable Content"
2670
+ },
2671
+ TOO_MANY_REQUESTS: {
2672
+ status: 429,
2673
+ message: "Too Many Requests"
2674
+ },
2675
+ CLIENT_CLOSED_REQUEST: {
2676
+ status: 499,
2677
+ message: "Client Closed Request"
2678
+ },
2679
+ INTERNAL_SERVER_ERROR: {
2680
+ status: 500,
2681
+ message: "Internal Server Error"
2682
+ },
2683
+ NOT_IMPLEMENTED: {
2684
+ status: 501,
2685
+ message: "Not Implemented"
2686
+ },
2687
+ BAD_GATEWAY: {
2688
+ status: 502,
2689
+ message: "Bad Gateway"
2690
+ },
2691
+ SERVICE_UNAVAILABLE: {
2692
+ status: 503,
2693
+ message: "Service Unavailable"
2694
+ },
2695
+ GATEWAY_TIMEOUT: {
2696
+ status: 504,
2697
+ message: "Gateway Timeout"
2698
+ }
2699
+ };
2700
+ function fallbackORPCErrorStatus(code, status) {
2701
+ return status ?? COMMON_ORPC_ERROR_DEFS[code]?.status ?? 500;
2702
+ }
2703
+ function fallbackORPCErrorMessage(code, message) {
2704
+ return message || COMMON_ORPC_ERROR_DEFS[code]?.message || code;
2705
+ }
2706
+ var GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL = Symbol.for(`__${ORPC_CLIENT_PACKAGE_NAME}@${ORPC_CLIENT_PACKAGE_VERSION}/error/ORPC_ERROR_CONSTRUCTORS__`);
2707
+ globalThis[GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL] ??= /* @__PURE__ */ new WeakSet;
2708
+ var globalORPCErrorConstructors = globalThis[GLOBAL_ORPC_ERROR_CONSTRUCTORS_SYMBOL];
2709
+
2710
+ class ORPCError extends Error {
2711
+ defined;
2712
+ code;
2713
+ status;
2714
+ data;
2715
+ constructor(code, ...rest) {
2716
+ const options = resolveMaybeOptionalOptions(rest);
2717
+ if (options.status !== undefined && !isORPCErrorStatus(options.status)) {
2718
+ throw new Error("[ORPCError] Invalid error status code.");
2719
+ }
2720
+ const message = fallbackORPCErrorMessage(code, options.message);
2721
+ super(message, options);
2722
+ this.code = code;
2723
+ this.status = fallbackORPCErrorStatus(code, options.status);
2724
+ this.defined = options.defined ?? false;
2725
+ this.data = options.data;
2726
+ }
2727
+ toJSON() {
2728
+ return {
2729
+ defined: this.defined,
2730
+ code: this.code,
2731
+ status: this.status,
2732
+ message: this.message,
2733
+ data: this.data
2734
+ };
2735
+ }
2736
+ static [Symbol.hasInstance](instance) {
2737
+ if (globalORPCErrorConstructors.has(this)) {
2738
+ const constructor = getConstructor(instance);
2739
+ if (constructor && globalORPCErrorConstructors.has(constructor)) {
2740
+ return true;
2741
+ }
2742
+ }
2743
+ return super[Symbol.hasInstance](instance);
2744
+ }
2745
+ }
2746
+ globalORPCErrorConstructors.add(ORPCError);
2747
+ function toORPCError(error) {
2748
+ return error instanceof ORPCError ? error : new ORPCError("INTERNAL_SERVER_ERROR", {
2749
+ message: "Internal server error",
2750
+ cause: error
2751
+ });
2752
+ }
2753
+ function isORPCErrorStatus(status) {
2754
+ return status < 200 || status >= 400;
2755
+ }
2756
+ function isORPCErrorJson(json) {
2757
+ if (!isObject(json)) {
2758
+ return false;
2759
+ }
2760
+ const validKeys = ["defined", "code", "status", "message", "data"];
2761
+ if (Object.keys(json).some((k) => !validKeys.includes(k))) {
2762
+ return false;
2763
+ }
2764
+ return "defined" in json && typeof json.defined === "boolean" && "code" in json && typeof json.code === "string" && "status" in json && typeof json.status === "number" && isORPCErrorStatus(json.status) && "message" in json && typeof json.message === "string";
2765
+ }
2766
+ function createORPCErrorFromJson(json, options = {}) {
2767
+ return new ORPCError(json.code, {
2768
+ ...options,
2769
+ ...json
2770
+ });
2771
+ }
2772
+ // ../../node_modules/.bun/@orpc+standard-server@1.13.5/node_modules/@orpc/standard-server/dist/index.mjs
2773
+ class EventEncoderError extends TypeError {
2774
+ }
2775
+
2776
+ class EventDecoderError extends TypeError {
2777
+ }
2778
+
2779
+ class ErrorEvent extends Error {
2780
+ data;
2781
+ constructor(options) {
2782
+ super(options?.message ?? "An error event was received", options);
2783
+ this.data = options?.data;
2784
+ }
2785
+ }
2786
+ function decodeEventMessage(encoded) {
2787
+ const lines = encoded.replace(/\n+$/, "").split(/\n/);
2788
+ const message = {
2789
+ data: undefined,
2790
+ event: undefined,
2791
+ id: undefined,
2792
+ retry: undefined,
2793
+ comments: []
2794
+ };
2795
+ for (const line of lines) {
2796
+ const index = line.indexOf(":");
2797
+ const key = index === -1 ? line : line.slice(0, index);
2798
+ const value2 = index === -1 ? "" : line.slice(index + 1).replace(/^\s/, "");
2799
+ if (index === 0) {
2800
+ message.comments.push(value2);
2801
+ } else if (key === "data") {
2802
+ message.data ??= "";
2803
+ message.data += `${value2}
2804
+ `;
2805
+ } else if (key === "event") {
2806
+ message.event = value2;
2807
+ } else if (key === "id") {
2808
+ message.id = value2;
2809
+ } else if (key === "retry") {
2810
+ const maybeInteger = Number.parseInt(value2);
2811
+ if (Number.isInteger(maybeInteger) && maybeInteger >= 0 && maybeInteger.toString() === value2) {
2812
+ message.retry = maybeInteger;
2813
+ }
2814
+ }
2815
+ }
2816
+ message.data = message.data?.replace(/\n$/, "");
2817
+ return message;
2818
+ }
2819
+
2820
+ class EventDecoder {
2821
+ constructor(options = {}) {
2822
+ this.options = options;
2823
+ }
2824
+ incomplete = "";
2825
+ feed(chunk) {
2826
+ this.incomplete += chunk;
2827
+ const lastCompleteIndex = this.incomplete.lastIndexOf(`
2828
+
2829
+ `);
2830
+ if (lastCompleteIndex === -1) {
2831
+ return;
2832
+ }
2833
+ const completes = this.incomplete.slice(0, lastCompleteIndex).split(/\n\n/);
2834
+ this.incomplete = this.incomplete.slice(lastCompleteIndex + 2);
2835
+ for (const encoded of completes) {
2836
+ const message = decodeEventMessage(`${encoded}
2837
+
2838
+ `);
2839
+ if (this.options.onEvent) {
2840
+ this.options.onEvent(message);
2841
+ }
2842
+ }
2843
+ }
2844
+ end() {
2845
+ if (this.incomplete) {
2846
+ throw new EventDecoderError("Event Iterator ended before complete");
2847
+ }
2848
+ }
2849
+ }
2850
+
2851
+ class EventDecoderStream extends TransformStream {
2852
+ constructor() {
2853
+ let decoder;
2854
+ super({
2855
+ start(controller) {
2856
+ decoder = new EventDecoder({
2857
+ onEvent: (event) => {
2858
+ controller.enqueue(event);
2859
+ }
2860
+ });
2861
+ },
2862
+ transform(chunk) {
2863
+ decoder.feed(chunk);
2864
+ },
2865
+ flush() {
2866
+ decoder.end();
2867
+ }
2868
+ });
2869
+ }
2870
+ }
2871
+ function assertEventId(id) {
2872
+ if (id.includes(`
2873
+ `)) {
2874
+ throw new EventEncoderError("Event's id must not contain a newline character");
2875
+ }
2876
+ }
2877
+ function assertEventName(event) {
2878
+ if (event.includes(`
2879
+ `)) {
2880
+ throw new EventEncoderError("Event's event must not contain a newline character");
2881
+ }
2882
+ }
2883
+ function assertEventRetry(retry) {
2884
+ if (!Number.isInteger(retry) || retry < 0) {
2885
+ throw new EventEncoderError("Event's retry must be a integer and >= 0");
2886
+ }
2887
+ }
2888
+ function assertEventComment(comment) {
2889
+ if (comment.includes(`
2890
+ `)) {
2891
+ throw new EventEncoderError("Event's comment must not contain a newline character");
2892
+ }
2893
+ }
2894
+ function encodeEventData(data) {
2895
+ const lines = data?.split(/\n/) ?? [];
2896
+ let output = "";
2897
+ for (const line of lines) {
2898
+ output += `data: ${line}
2899
+ `;
2900
+ }
2901
+ return output;
2902
+ }
2903
+ function encodeEventComments(comments) {
2904
+ let output = "";
2905
+ for (const comment of comments ?? []) {
2906
+ assertEventComment(comment);
2907
+ output += `: ${comment}
2908
+ `;
2909
+ }
2910
+ return output;
2911
+ }
2912
+ function encodeEventMessage(message) {
2913
+ let output = "";
2914
+ output += encodeEventComments(message.comments);
2915
+ if (message.event !== undefined) {
2916
+ assertEventName(message.event);
2917
+ output += `event: ${message.event}
2918
+ `;
2919
+ }
2920
+ if (message.retry !== undefined) {
2921
+ assertEventRetry(message.retry);
2922
+ output += `retry: ${message.retry}
2923
+ `;
2924
+ }
2925
+ if (message.id !== undefined) {
2926
+ assertEventId(message.id);
2927
+ output += `id: ${message.id}
2928
+ `;
2929
+ }
2930
+ output += encodeEventData(message.data);
2931
+ output += `
2932
+ `;
2933
+ return output;
2934
+ }
2935
+ var EVENT_SOURCE_META_SYMBOL = Symbol("ORPC_EVENT_SOURCE_META");
2936
+ function withEventMeta(container, meta) {
2937
+ if (meta.id === undefined && meta.retry === undefined && !meta.comments?.length) {
2938
+ return container;
2939
+ }
2940
+ if (meta.id !== undefined) {
2941
+ assertEventId(meta.id);
2942
+ }
2943
+ if (meta.retry !== undefined) {
2944
+ assertEventRetry(meta.retry);
2945
+ }
2946
+ if (meta.comments !== undefined) {
2947
+ for (const comment of meta.comments) {
2948
+ assertEventComment(comment);
2949
+ }
2950
+ }
2951
+ return new Proxy(container, {
2952
+ get(target, prop, receiver) {
2953
+ if (prop === EVENT_SOURCE_META_SYMBOL) {
2954
+ return meta;
2955
+ }
2956
+ return Reflect.get(target, prop, receiver);
2957
+ }
2958
+ });
2959
+ }
2960
+ function getEventMeta(container) {
2961
+ return isTypescriptObject(container) ? Reflect.get(container, EVENT_SOURCE_META_SYMBOL) : undefined;
2962
+ }
2963
+ function generateContentDisposition(filename) {
2964
+ const escapedFileName = filename.replace(/"/g, "\\\"");
2965
+ const encodedFilenameStar = encodeURIComponent(filename).replace(/['()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`).replace(/%(7C|60|5E)/g, (str, hex) => String.fromCharCode(Number.parseInt(hex, 16)));
2966
+ return `inline; filename="${escapedFileName}"; filename*=utf-8''${encodedFilenameStar}`;
2967
+ }
2968
+ function getFilenameFromContentDisposition(contentDisposition) {
2969
+ const encodedFilenameStarMatch = contentDisposition.match(/filename\*=(UTF-8'')?([^;]*)/i);
2970
+ if (encodedFilenameStarMatch && typeof encodedFilenameStarMatch[2] === "string") {
2971
+ return tryDecodeURIComponent(encodedFilenameStarMatch[2]);
2972
+ }
2973
+ const encodedFilenameMatch = contentDisposition.match(/filename="((?:\\"|[^"])*)"/i);
2974
+ if (encodedFilenameMatch && typeof encodedFilenameMatch[1] === "string") {
2975
+ return encodedFilenameMatch[1].replace(/\\"/g, '"');
2976
+ }
2977
+ }
2978
+ function mergeStandardHeaders(a, b) {
2979
+ const merged = { ...a };
2980
+ for (const key in b) {
2981
+ if (Array.isArray(b[key])) {
2982
+ merged[key] = [...toArray(merged[key]), ...b[key]];
2983
+ } else if (b[key] !== undefined) {
2984
+ if (Array.isArray(merged[key])) {
2985
+ merged[key] = [...merged[key], b[key]];
2986
+ } else if (merged[key] !== undefined) {
2987
+ merged[key] = [merged[key], b[key]];
2988
+ } else {
2989
+ merged[key] = b[key];
2990
+ }
2991
+ }
2992
+ }
2993
+ return merged;
2994
+ }
2995
+
2996
+ // ../../node_modules/.bun/@orpc+client@1.13.5/node_modules/@orpc/client/dist/shared/client.BLtwTQUg.mjs
2997
+ function mapEventIterator(iterator, maps) {
2998
+ const mapError = async (error) => {
2999
+ let mappedError = await maps.error(error);
3000
+ if (mappedError !== error) {
3001
+ const meta = getEventMeta(error);
3002
+ if (meta && isTypescriptObject(mappedError)) {
3003
+ mappedError = withEventMeta(mappedError, meta);
3004
+ }
3005
+ }
3006
+ return mappedError;
3007
+ };
3008
+ return new AsyncIteratorClass(async () => {
3009
+ const { done, value: value2 } = await (async () => {
3010
+ try {
3011
+ return await iterator.next();
3012
+ } catch (error) {
3013
+ throw await mapError(error);
3014
+ }
3015
+ })();
3016
+ let mappedValue = await maps.value(value2, done);
3017
+ if (mappedValue !== value2) {
3018
+ const meta = getEventMeta(value2);
3019
+ if (meta && isTypescriptObject(mappedValue)) {
3020
+ mappedValue = withEventMeta(mappedValue, meta);
3021
+ }
3022
+ }
3023
+ return { done, value: mappedValue };
3024
+ }, async () => {
3025
+ try {
3026
+ await iterator.return?.();
3027
+ } catch (error) {
3028
+ throw await mapError(error);
3029
+ }
3030
+ });
3031
+ }
3032
+ // ../../node_modules/.bun/@orpc+client@1.13.5/node_modules/@orpc/client/dist/index.mjs
3033
+ function resolveFriendlyClientOptions(options) {
3034
+ return {
3035
+ ...options,
3036
+ context: options.context ?? {}
3037
+ };
3038
+ }
3039
+ function createORPCClient(link, options = {}) {
3040
+ const path = options.path ?? [];
3041
+ const procedureClient = async (...[input, options2 = {}]) => {
3042
+ return await link.call(path, input, resolveFriendlyClientOptions(options2));
3043
+ };
3044
+ const recursive = new Proxy(procedureClient, {
3045
+ get(target, key) {
3046
+ if (typeof key !== "string") {
3047
+ return Reflect.get(target, key);
3048
+ }
3049
+ return createORPCClient(link, {
3050
+ ...options,
3051
+ path: [...path, key]
3052
+ });
3053
+ }
3054
+ });
3055
+ return preventNativeAwait(recursive);
3056
+ }
3057
+
3058
+ // ../../node_modules/.bun/@orpc+standard-server-fetch@1.13.5/node_modules/@orpc/standard-server-fetch/dist/index.mjs
3059
+ function toEventIterator(stream, options = {}) {
3060
+ const eventStream = stream?.pipeThrough(new TextDecoderStream).pipeThrough(new EventDecoderStream);
3061
+ const reader = eventStream?.getReader();
3062
+ let span;
3063
+ let isCancelled = false;
3064
+ return new AsyncIteratorClass(async () => {
3065
+ span ??= startSpan("consume_event_iterator_stream");
3066
+ try {
3067
+ while (true) {
3068
+ if (reader === undefined) {
3069
+ return { done: true, value: undefined };
3070
+ }
3071
+ const { done, value: value2 } = await runInSpanContext(span, () => reader.read());
3072
+ if (done) {
3073
+ if (isCancelled) {
3074
+ throw new AbortError("Stream was cancelled");
3075
+ }
3076
+ return { done: true, value: undefined };
3077
+ }
3078
+ switch (value2.event) {
3079
+ case "message": {
3080
+ let message = parseEmptyableJSON(value2.data);
3081
+ if (isTypescriptObject(message)) {
3082
+ message = withEventMeta(message, value2);
3083
+ }
3084
+ span?.addEvent("message");
3085
+ return { done: false, value: message };
3086
+ }
3087
+ case "error": {
3088
+ let error = new ErrorEvent({
3089
+ data: parseEmptyableJSON(value2.data)
3090
+ });
3091
+ error = withEventMeta(error, value2);
3092
+ span?.addEvent("error");
3093
+ throw error;
3094
+ }
3095
+ case "done": {
3096
+ let done2 = parseEmptyableJSON(value2.data);
3097
+ if (isTypescriptObject(done2)) {
3098
+ done2 = withEventMeta(done2, value2);
3099
+ }
3100
+ span?.addEvent("done");
3101
+ return { done: true, value: done2 };
3102
+ }
3103
+ default: {
3104
+ span?.addEvent("maybe_keepalive");
3105
+ }
3106
+ }
3107
+ }
3108
+ } catch (e) {
3109
+ if (!(e instanceof ErrorEvent)) {
3110
+ setSpanError(span, e, options);
3111
+ }
3112
+ throw e;
3113
+ }
3114
+ }, async (reason) => {
3115
+ try {
3116
+ if (reason !== "next") {
3117
+ isCancelled = true;
3118
+ span?.addEvent("cancelled");
3119
+ }
3120
+ await runInSpanContext(span, () => reader?.cancel());
3121
+ } catch (e) {
3122
+ setSpanError(span, e, options);
3123
+ throw e;
3124
+ } finally {
3125
+ span?.end();
3126
+ }
3127
+ });
3128
+ }
3129
+ function toEventStream(iterator, options = {}) {
3130
+ const keepAliveEnabled = options.eventIteratorKeepAliveEnabled ?? true;
3131
+ const keepAliveInterval = options.eventIteratorKeepAliveInterval ?? 5000;
3132
+ const keepAliveComment = options.eventIteratorKeepAliveComment ?? "";
3133
+ const initialCommentEnabled = options.eventIteratorInitialCommentEnabled ?? true;
3134
+ const initialComment = options.eventIteratorInitialComment ?? "";
3135
+ let cancelled = false;
3136
+ let timeout;
3137
+ let span;
3138
+ const stream = new ReadableStream({
3139
+ start(controller) {
3140
+ span = startSpan("stream_event_iterator");
3141
+ if (initialCommentEnabled) {
3142
+ controller.enqueue(encodeEventMessage({
3143
+ comments: [initialComment]
3144
+ }));
3145
+ }
3146
+ },
3147
+ async pull(controller) {
3148
+ try {
3149
+ if (keepAliveEnabled) {
3150
+ timeout = setInterval(() => {
3151
+ controller.enqueue(encodeEventMessage({
3152
+ comments: [keepAliveComment]
3153
+ }));
3154
+ span?.addEvent("keepalive");
3155
+ }, keepAliveInterval);
3156
+ }
3157
+ const value2 = await runInSpanContext(span, () => iterator.next());
3158
+ clearInterval(timeout);
3159
+ if (cancelled) {
3160
+ return;
3161
+ }
3162
+ const meta = getEventMeta(value2.value);
3163
+ if (!value2.done || value2.value !== undefined || meta !== undefined) {
3164
+ const event = value2.done ? "done" : "message";
3165
+ controller.enqueue(encodeEventMessage({
3166
+ ...meta,
3167
+ event,
3168
+ data: stringifyJSON(value2.value)
3169
+ }));
3170
+ span?.addEvent(event);
3171
+ }
3172
+ if (value2.done) {
3173
+ controller.close();
3174
+ span?.end();
3175
+ }
3176
+ } catch (err) {
3177
+ clearInterval(timeout);
3178
+ if (cancelled) {
3179
+ return;
3180
+ }
3181
+ if (err instanceof ErrorEvent) {
3182
+ controller.enqueue(encodeEventMessage({
3183
+ ...getEventMeta(err),
3184
+ event: "error",
3185
+ data: stringifyJSON(err.data)
3186
+ }));
3187
+ span?.addEvent("error");
3188
+ controller.close();
3189
+ } else {
3190
+ setSpanError(span, err);
3191
+ controller.error(err);
3192
+ }
3193
+ span?.end();
3194
+ }
3195
+ },
3196
+ async cancel() {
3197
+ try {
3198
+ cancelled = true;
3199
+ clearInterval(timeout);
3200
+ span?.addEvent("cancelled");
3201
+ await runInSpanContext(span, () => iterator.return?.());
3202
+ } catch (e) {
3203
+ setSpanError(span, e);
3204
+ throw e;
3205
+ } finally {
3206
+ span?.end();
3207
+ }
3208
+ }
3209
+ }).pipeThrough(new TextEncoderStream);
3210
+ return stream;
3211
+ }
3212
+ function toStandardBody(re, options = {}) {
3213
+ return runWithSpan({ name: "parse_standard_body", signal: options.signal }, async () => {
3214
+ const contentDisposition = re.headers.get("content-disposition");
3215
+ if (typeof contentDisposition === "string") {
3216
+ const fileName = getFilenameFromContentDisposition(contentDisposition) ?? "blob";
3217
+ const blob2 = await re.blob();
3218
+ return new File([blob2], fileName, {
3219
+ type: blob2.type
3220
+ });
3221
+ }
3222
+ const contentType = re.headers.get("content-type");
3223
+ if (!contentType || contentType.startsWith("application/json")) {
3224
+ const text = await re.text();
3225
+ return parseEmptyableJSON(text);
3226
+ }
3227
+ if (contentType.startsWith("multipart/form-data")) {
3228
+ return await re.formData();
3229
+ }
3230
+ if (contentType.startsWith("application/x-www-form-urlencoded")) {
3231
+ const text = await re.text();
3232
+ return new URLSearchParams(text);
3233
+ }
3234
+ if (contentType.startsWith("text/event-stream")) {
3235
+ return toEventIterator(re.body, options);
3236
+ }
3237
+ if (contentType.startsWith("text/plain")) {
3238
+ return await re.text();
3239
+ }
3240
+ const blob = await re.blob();
3241
+ return new File([blob], "blob", {
3242
+ type: blob.type
3243
+ });
3244
+ });
3245
+ }
3246
+ function toFetchBody(body, headers, options = {}) {
3247
+ const currentContentDisposition = headers.get("content-disposition");
3248
+ headers.delete("content-type");
3249
+ headers.delete("content-disposition");
3250
+ if (body === undefined) {
3251
+ return;
3252
+ }
3253
+ if (body instanceof Blob) {
3254
+ headers.set("content-type", body.type);
3255
+ headers.set("content-length", body.size.toString());
3256
+ headers.set("content-disposition", currentContentDisposition ?? generateContentDisposition(body instanceof File ? body.name : "blob"));
3257
+ return body;
3258
+ }
3259
+ if (body instanceof FormData) {
3260
+ return body;
3261
+ }
3262
+ if (body instanceof URLSearchParams) {
3263
+ return body;
3264
+ }
3265
+ if (isAsyncIteratorObject(body)) {
3266
+ headers.set("content-type", "text/event-stream");
3267
+ return toEventStream(body, options);
3268
+ }
3269
+ headers.set("content-type", "application/json");
3270
+ return stringifyJSON(body);
3271
+ }
3272
+ function toStandardHeaders(headers, standardHeaders = {}) {
3273
+ headers.forEach((value2, key) => {
3274
+ if (Array.isArray(standardHeaders[key])) {
3275
+ standardHeaders[key].push(value2);
3276
+ } else if (standardHeaders[key] !== undefined) {
3277
+ standardHeaders[key] = [standardHeaders[key], value2];
3278
+ } else {
3279
+ standardHeaders[key] = value2;
3280
+ }
3281
+ });
3282
+ return standardHeaders;
3283
+ }
3284
+ function toFetchHeaders(headers, fetchHeaders = new Headers) {
3285
+ for (const [key, value2] of Object.entries(headers)) {
3286
+ if (Array.isArray(value2)) {
3287
+ for (const v of value2) {
3288
+ fetchHeaders.append(key, v);
3289
+ }
3290
+ } else if (value2 !== undefined) {
3291
+ fetchHeaders.append(key, value2);
3292
+ }
3293
+ }
3294
+ return fetchHeaders;
3295
+ }
3296
+ function toFetchRequest(request, options = {}) {
3297
+ const headers = toFetchHeaders(request.headers);
3298
+ const body = toFetchBody(request.body, headers, options);
3299
+ return new Request(request.url, {
3300
+ signal: request.signal,
3301
+ method: request.method,
3302
+ headers,
3303
+ body
3304
+ });
3305
+ }
3306
+ function toStandardLazyResponse(response, options = {}) {
3307
+ return {
3308
+ body: once(() => toStandardBody(response, options)),
3309
+ status: response.status,
3310
+ get headers() {
3311
+ const headers = toStandardHeaders(response.headers);
3312
+ Object.defineProperty(this, "headers", { value: headers, writable: true });
3313
+ return headers;
3314
+ },
3315
+ set headers(value2) {
3316
+ Object.defineProperty(this, "headers", { value: value2, writable: true });
3317
+ }
3318
+ };
3319
+ }
3320
+
3321
+ // ../../node_modules/.bun/@orpc+client@1.13.5/node_modules/@orpc/client/dist/shared/client.BcDRUyT-.mjs
3322
+ class CompositeStandardLinkPlugin {
3323
+ plugins;
3324
+ constructor(plugins = []) {
3325
+ this.plugins = [...plugins].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
3326
+ }
3327
+ init(options) {
3328
+ for (const plugin of this.plugins) {
3329
+ plugin.init?.(options);
3330
+ }
3331
+ }
3332
+ }
3333
+
3334
+ class StandardLink {
3335
+ constructor(codec, sender, options = {}) {
3336
+ this.codec = codec;
3337
+ this.sender = sender;
3338
+ const plugin = new CompositeStandardLinkPlugin(options.plugins);
3339
+ plugin.init(options);
3340
+ this.interceptors = toArray(options.interceptors);
3341
+ this.clientInterceptors = toArray(options.clientInterceptors);
3342
+ }
3343
+ interceptors;
3344
+ clientInterceptors;
3345
+ call(path, input, options) {
3346
+ return runWithSpan({ name: `${ORPC_NAME}.${path.join("/")}`, signal: options.signal }, (span) => {
3347
+ span?.setAttribute("rpc.system", ORPC_NAME);
3348
+ span?.setAttribute("rpc.method", path.join("."));
3349
+ if (isAsyncIteratorObject(input)) {
3350
+ input = asyncIteratorWithSpan({ name: "consume_event_iterator_input", signal: options.signal }, input);
3351
+ }
3352
+ return intercept(this.interceptors, { ...options, path, input }, async ({ path: path2, input: input2, ...options2 }) => {
3353
+ const otelConfig = getGlobalOtelConfig();
3354
+ let otelContext;
3355
+ const currentSpan = otelConfig?.trace.getActiveSpan() ?? span;
3356
+ if (currentSpan && otelConfig) {
3357
+ otelContext = otelConfig?.trace.setSpan(otelConfig.context.active(), currentSpan);
3358
+ }
3359
+ const request = await runWithSpan({ name: "encode_request", context: otelContext }, () => this.codec.encode(path2, input2, options2));
3360
+ const response = await intercept(this.clientInterceptors, { ...options2, input: input2, path: path2, request }, ({ input: input3, path: path3, request: request2, ...options3 }) => {
3361
+ return runWithSpan({ name: "send_request", signal: options3.signal, context: otelContext }, () => this.sender.call(request2, options3, path3, input3));
3362
+ });
3363
+ const output = await runWithSpan({ name: "decode_response", context: otelContext }, () => this.codec.decode(response, options2, path2, input2));
3364
+ if (isAsyncIteratorObject(output)) {
3365
+ return asyncIteratorWithSpan({ name: "consume_event_iterator_output", signal: options2.signal }, output);
3366
+ }
3367
+ return output;
3368
+ });
3369
+ });
3370
+ }
3371
+ }
3372
+ var STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES = {
3373
+ BIGINT: 0,
3374
+ DATE: 1,
3375
+ NAN: 2,
3376
+ UNDEFINED: 3,
3377
+ URL: 4,
3378
+ REGEXP: 5,
3379
+ SET: 6,
3380
+ MAP: 7
3381
+ };
3382
+
3383
+ class StandardRPCJsonSerializer {
3384
+ customSerializers;
3385
+ constructor(options = {}) {
3386
+ this.customSerializers = options.customJsonSerializers ?? [];
3387
+ if (this.customSerializers.length !== new Set(this.customSerializers.map((custom) => custom.type)).size) {
3388
+ throw new Error("Custom serializer type must be unique.");
3389
+ }
3390
+ }
3391
+ serialize(data, segments = [], meta = [], maps = [], blobs = []) {
3392
+ for (const custom of this.customSerializers) {
3393
+ if (custom.condition(data)) {
3394
+ const result = this.serialize(custom.serialize(data), segments, meta, maps, blobs);
3395
+ meta.push([custom.type, ...segments]);
3396
+ return result;
3397
+ }
3398
+ }
3399
+ if (data instanceof Blob) {
3400
+ maps.push(segments);
3401
+ blobs.push(data);
3402
+ return [data, meta, maps, blobs];
3403
+ }
3404
+ if (typeof data === "bigint") {
3405
+ meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.BIGINT, ...segments]);
3406
+ return [data.toString(), meta, maps, blobs];
3407
+ }
3408
+ if (data instanceof Date) {
3409
+ meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.DATE, ...segments]);
3410
+ if (Number.isNaN(data.getTime())) {
3411
+ return [null, meta, maps, blobs];
3412
+ }
3413
+ return [data.toISOString(), meta, maps, blobs];
3414
+ }
3415
+ if (Number.isNaN(data)) {
3416
+ meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.NAN, ...segments]);
3417
+ return [null, meta, maps, blobs];
3418
+ }
3419
+ if (data instanceof URL) {
3420
+ meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.URL, ...segments]);
3421
+ return [data.toString(), meta, maps, blobs];
3422
+ }
3423
+ if (data instanceof RegExp) {
3424
+ meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.REGEXP, ...segments]);
3425
+ return [data.toString(), meta, maps, blobs];
3426
+ }
3427
+ if (data instanceof Set) {
3428
+ const result = this.serialize(Array.from(data), segments, meta, maps, blobs);
3429
+ meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.SET, ...segments]);
3430
+ return result;
3431
+ }
3432
+ if (data instanceof Map) {
3433
+ const result = this.serialize(Array.from(data.entries()), segments, meta, maps, blobs);
3434
+ meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.MAP, ...segments]);
3435
+ return result;
3436
+ }
3437
+ if (Array.isArray(data)) {
3438
+ const json = data.map((v, i) => {
3439
+ if (v === undefined) {
3440
+ meta.push([STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.UNDEFINED, ...segments, i]);
3441
+ return v;
3442
+ }
3443
+ return this.serialize(v, [...segments, i], meta, maps, blobs)[0];
3444
+ });
3445
+ return [json, meta, maps, blobs];
3446
+ }
3447
+ if (isObject(data)) {
3448
+ const json = {};
3449
+ for (const k in data) {
3450
+ if (k === "toJSON" && typeof data[k] === "function") {
3451
+ continue;
3452
+ }
3453
+ json[k] = this.serialize(data[k], [...segments, k], meta, maps, blobs)[0];
3454
+ }
3455
+ return [json, meta, maps, blobs];
3456
+ }
3457
+ return [data, meta, maps, blobs];
3458
+ }
3459
+ deserialize(json, meta, maps, getBlob) {
3460
+ const ref = { data: json };
3461
+ if (maps && getBlob) {
3462
+ maps.forEach((segments, i) => {
3463
+ let currentRef = ref;
3464
+ let preSegment = "data";
3465
+ segments.forEach((segment) => {
3466
+ currentRef = currentRef[preSegment];
3467
+ preSegment = segment;
3468
+ });
3469
+ currentRef[preSegment] = getBlob(i);
3470
+ });
3471
+ }
3472
+ for (const item of meta) {
3473
+ const type = item[0];
3474
+ let currentRef = ref;
3475
+ let preSegment = "data";
3476
+ for (let i = 1;i < item.length; i++) {
3477
+ currentRef = currentRef[preSegment];
3478
+ preSegment = item[i];
3479
+ }
3480
+ for (const custom of this.customSerializers) {
3481
+ if (custom.type === type) {
3482
+ currentRef[preSegment] = custom.deserialize(currentRef[preSegment]);
3483
+ break;
3484
+ }
3485
+ }
3486
+ switch (type) {
3487
+ case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.BIGINT:
3488
+ currentRef[preSegment] = BigInt(currentRef[preSegment]);
3489
+ break;
3490
+ case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.DATE:
3491
+ currentRef[preSegment] = new Date(currentRef[preSegment] ?? "Invalid Date");
3492
+ break;
3493
+ case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.NAN:
3494
+ currentRef[preSegment] = Number.NaN;
3495
+ break;
3496
+ case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.UNDEFINED:
3497
+ currentRef[preSegment] = undefined;
3498
+ break;
3499
+ case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.URL:
3500
+ currentRef[preSegment] = new URL(currentRef[preSegment]);
3501
+ break;
3502
+ case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.REGEXP: {
3503
+ const [, pattern, flags] = currentRef[preSegment].match(/^\/(.*)\/([a-z]*)$/);
3504
+ currentRef[preSegment] = new RegExp(pattern, flags);
3505
+ break;
3506
+ }
3507
+ case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.SET:
3508
+ currentRef[preSegment] = new Set(currentRef[preSegment]);
3509
+ break;
3510
+ case STANDARD_RPC_JSON_SERIALIZER_BUILT_IN_TYPES.MAP:
3511
+ currentRef[preSegment] = new Map(currentRef[preSegment]);
3512
+ break;
3513
+ }
3514
+ }
3515
+ return ref.data;
3516
+ }
3517
+ }
3518
+ function toHttpPath(path) {
3519
+ return `/${path.map(encodeURIComponent).join("/")}`;
3520
+ }
3521
+ function toStandardHeaders2(headers) {
3522
+ if (typeof headers.forEach === "function") {
3523
+ return toStandardHeaders(headers);
3524
+ }
3525
+ return headers;
3526
+ }
3527
+ function getMalformedResponseErrorCode(status) {
3528
+ return Object.entries(COMMON_ORPC_ERROR_DEFS).find(([, def]) => def.status === status)?.[0] ?? "MALFORMED_ORPC_ERROR_RESPONSE";
3529
+ }
3530
+
3531
+ class StandardRPCLinkCodec {
3532
+ constructor(serializer, options) {
3533
+ this.serializer = serializer;
3534
+ this.baseUrl = options.url;
3535
+ this.maxUrlLength = options.maxUrlLength ?? 2083;
3536
+ this.fallbackMethod = options.fallbackMethod ?? "POST";
3537
+ this.expectedMethod = options.method ?? this.fallbackMethod;
3538
+ this.headers = options.headers ?? {};
3539
+ }
3540
+ baseUrl;
3541
+ maxUrlLength;
3542
+ fallbackMethod;
3543
+ expectedMethod;
3544
+ headers;
3545
+ async encode(path, input, options) {
3546
+ let headers = toStandardHeaders2(await value(this.headers, options, path, input));
3547
+ if (options.lastEventId !== undefined) {
3548
+ headers = mergeStandardHeaders(headers, { "last-event-id": options.lastEventId });
3549
+ }
3550
+ const expectedMethod = await value(this.expectedMethod, options, path, input);
3551
+ const baseUrl = await value(this.baseUrl, options, path, input);
3552
+ const url = new URL(baseUrl);
3553
+ url.pathname = `${url.pathname.replace(/\/$/, "")}${toHttpPath(path)}`;
3554
+ const serialized = this.serializer.serialize(input);
3555
+ if (expectedMethod === "GET" && !(serialized instanceof FormData) && !isAsyncIteratorObject(serialized)) {
3556
+ const maxUrlLength = await value(this.maxUrlLength, options, path, input);
3557
+ const getUrl = new URL(url);
3558
+ getUrl.searchParams.append("data", stringifyJSON(serialized));
3559
+ if (getUrl.toString().length <= maxUrlLength) {
3560
+ return {
3561
+ body: undefined,
3562
+ method: expectedMethod,
3563
+ headers,
3564
+ url: getUrl,
3565
+ signal: options.signal
3566
+ };
3567
+ }
3568
+ }
3569
+ return {
3570
+ url,
3571
+ method: expectedMethod === "GET" ? this.fallbackMethod : expectedMethod,
3572
+ headers,
3573
+ body: serialized,
3574
+ signal: options.signal
3575
+ };
3576
+ }
3577
+ async decode(response) {
3578
+ const isOk = !isORPCErrorStatus(response.status);
3579
+ const deserialized = await (async () => {
3580
+ let isBodyOk = false;
3581
+ try {
3582
+ const body = await response.body();
3583
+ isBodyOk = true;
3584
+ return this.serializer.deserialize(body);
3585
+ } catch (error) {
3586
+ if (!isBodyOk) {
3587
+ throw new Error("Cannot parse response body, please check the response body and content-type.", {
3588
+ cause: error
3589
+ });
3590
+ }
3591
+ throw new Error("Invalid RPC response format.", {
3592
+ cause: error
3593
+ });
3594
+ }
3595
+ })();
3596
+ if (!isOk) {
3597
+ if (isORPCErrorJson(deserialized)) {
3598
+ throw createORPCErrorFromJson(deserialized);
3599
+ }
3600
+ throw new ORPCError(getMalformedResponseErrorCode(response.status), {
3601
+ status: response.status,
3602
+ data: { ...response, body: deserialized }
3603
+ });
3604
+ }
3605
+ return deserialized;
3606
+ }
3607
+ }
3608
+
3609
+ class StandardRPCSerializer {
3610
+ constructor(jsonSerializer) {
3611
+ this.jsonSerializer = jsonSerializer;
3612
+ }
3613
+ serialize(data) {
3614
+ if (isAsyncIteratorObject(data)) {
3615
+ return mapEventIterator(data, {
3616
+ value: async (value2) => this.#serialize(value2, false),
3617
+ error: async (e) => {
3618
+ return new ErrorEvent({
3619
+ data: this.#serialize(toORPCError(e).toJSON(), false),
3620
+ cause: e
3621
+ });
3622
+ }
3623
+ });
3624
+ }
3625
+ return this.#serialize(data, true);
3626
+ }
3627
+ #serialize(data, enableFormData) {
3628
+ const [json, meta_, maps, blobs] = this.jsonSerializer.serialize(data);
3629
+ const meta = meta_.length === 0 ? undefined : meta_;
3630
+ if (!enableFormData || blobs.length === 0) {
3631
+ return {
3632
+ json,
3633
+ meta
3634
+ };
3635
+ }
3636
+ const form = new FormData;
3637
+ form.set("data", stringifyJSON({ json, meta, maps }));
3638
+ blobs.forEach((blob, i) => {
3639
+ form.set(i.toString(), blob);
3640
+ });
3641
+ return form;
3642
+ }
3643
+ deserialize(data) {
3644
+ if (isAsyncIteratorObject(data)) {
3645
+ return mapEventIterator(data, {
3646
+ value: async (value2) => this.#deserialize(value2),
3647
+ error: async (e) => {
3648
+ if (!(e instanceof ErrorEvent)) {
3649
+ return e;
3650
+ }
3651
+ const deserialized = this.#deserialize(e.data);
3652
+ if (isORPCErrorJson(deserialized)) {
3653
+ return createORPCErrorFromJson(deserialized, { cause: e });
3654
+ }
3655
+ return new ErrorEvent({
3656
+ data: deserialized,
3657
+ cause: e
3658
+ });
3659
+ }
3660
+ });
3661
+ }
3662
+ return this.#deserialize(data);
3663
+ }
3664
+ #deserialize(data) {
3665
+ if (data === undefined) {
3666
+ return;
3667
+ }
3668
+ if (!(data instanceof FormData)) {
3669
+ return this.jsonSerializer.deserialize(data.json, data.meta ?? []);
3670
+ }
3671
+ const serialized = JSON.parse(data.get("data"));
3672
+ return this.jsonSerializer.deserialize(serialized.json, serialized.meta ?? [], serialized.maps, (i) => data.get(i.toString()));
3673
+ }
3674
+ }
3675
+
3676
+ class StandardRPCLink extends StandardLink {
3677
+ constructor(linkClient, options) {
3678
+ const jsonSerializer = new StandardRPCJsonSerializer(options);
3679
+ const serializer = new StandardRPCSerializer(jsonSerializer);
3680
+ const linkCodec = new StandardRPCLinkCodec(serializer, options);
3681
+ super(linkCodec, linkClient, options);
3682
+ }
3683
+ }
3684
+
3685
+ // ../../node_modules/.bun/@orpc+client@1.13.5/node_modules/@orpc/client/dist/adapters/fetch/index.mjs
3686
+ class CompositeLinkFetchPlugin extends CompositeStandardLinkPlugin {
3687
+ initRuntimeAdapter(options) {
3688
+ for (const plugin of this.plugins) {
3689
+ plugin.initRuntimeAdapter?.(options);
3690
+ }
3691
+ }
3692
+ }
3693
+
3694
+ class LinkFetchClient {
3695
+ fetch;
3696
+ toFetchRequestOptions;
3697
+ adapterInterceptors;
3698
+ constructor(options) {
3699
+ const plugin = new CompositeLinkFetchPlugin(options.plugins);
3700
+ plugin.initRuntimeAdapter(options);
3701
+ this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
3702
+ this.toFetchRequestOptions = options;
3703
+ this.adapterInterceptors = toArray(options.adapterInterceptors);
3704
+ }
3705
+ async call(standardRequest, options, path, input) {
3706
+ const request = toFetchRequest(standardRequest, this.toFetchRequestOptions);
3707
+ const fetchResponse = await intercept(this.adapterInterceptors, { ...options, request, path, input, init: { redirect: "manual" } }, ({ request: request2, path: path2, input: input2, init, ...options2 }) => this.fetch(request2, init, options2, path2, input2));
3708
+ const lazyResponse = toStandardLazyResponse(fetchResponse, { signal: request.signal });
3709
+ return lazyResponse;
3710
+ }
3711
+ }
3712
+
3713
+ class RPCLink extends StandardRPCLink {
3714
+ constructor(options) {
3715
+ const linkClient = new LinkFetchClient(options);
3716
+ super(linkClient, options);
3717
+ }
3718
+ }
3719
+
3720
+ // src/lib/uploader.ts
3721
+ async function uploadSession(request, config) {
3722
+ const link = new RPCLink({
3723
+ url: config.endpoint,
3724
+ headers: {
3725
+ Authorization: `Bearer ${config.token}`
3726
+ }
3727
+ });
3728
+ const client = createORPCClient(link);
3729
+ try {
3730
+ await client.ingestSession(request);
3731
+ return { success: true, status: 200 };
3732
+ } catch (error) {
3733
+ return { success: false, error: String(error) };
3734
+ }
3735
+ }
3736
+
3737
+ // src/commands/upload.ts
3738
+ async function runUpload(flags, session) {
3739
+ const write = (msg) => {
3740
+ process.stdout.write(`${msg}
3741
+ `);
3742
+ };
3743
+ const writeError = (msg) => {
3744
+ process.stderr.write(`${msg}
3745
+ `);
3746
+ };
3747
+ const credentials = loadCredentials();
3748
+ if (!credentials && !flags.dryRun) {
3749
+ writeError("Error: Not authenticated. Run `rudel login` first.");
3750
+ process.exitCode = 1;
3751
+ return;
3752
+ }
3753
+ write(`Resolving session: ${session}`);
3754
+ let sessionInfo;
3755
+ try {
3756
+ sessionInfo = await resolveSession(session);
3757
+ } catch (error) {
3758
+ writeError(`Error: ${error instanceof Error ? error.message : String(error)}`);
3759
+ process.exitCode = 1;
3760
+ return;
3761
+ }
3762
+ write(`Found session at: ${sessionInfo.transcriptPath}`);
3763
+ write("Reading transcript...");
3764
+ let content;
3765
+ try {
3766
+ content = await readTranscript(sessionInfo.transcriptPath);
3767
+ } catch (error) {
3768
+ writeError(`Error reading transcript: ${error instanceof Error ? error.message : String(error)}`);
3769
+ process.exitCode = 1;
3770
+ return;
3771
+ }
3772
+ write(`Transcript: ${content.length} bytes`);
3773
+ const agentIds = extractAgentIds(content);
3774
+ let subagents = [];
3775
+ if (agentIds.length > 0) {
3776
+ write(`Found ${agentIds.length} subagent(s): ${agentIds.join(", ")}`);
3777
+ subagents = await readSubagentFiles(sessionInfo.sessionDir, agentIds, sessionInfo.sessionId);
3778
+ write(`Read ${subagents.length} subagent file(s): ${subagents.reduce((sum, s) => sum + s.content.length, 0)} bytes total`);
3779
+ }
3780
+ const gitInfo = await getGitInfo(sessionInfo.projectPath);
3781
+ if (gitInfo.repository)
3782
+ write(`Repository: ${gitInfo.repository}`);
3783
+ if (gitInfo.branch)
3784
+ write(`Branch: ${gitInfo.branch}`);
3785
+ let tag = flags.tag;
3786
+ if (!tag && flags.classify) {
3787
+ write("Classifying session...");
3788
+ tag = await classifySession(content) ?? undefined;
3789
+ if (tag)
3790
+ write(`Classified as: ${tag}`);
3791
+ }
3792
+ const request = {
3793
+ sessionId: sessionInfo.sessionId,
3794
+ projectPath: sessionInfo.projectPath,
3795
+ repository: gitInfo.repository,
3796
+ gitBranch: gitInfo.branch,
3797
+ gitSha: gitInfo.sha,
3798
+ tag,
3799
+ content,
3800
+ subagents: subagents.length > 0 ? subagents : undefined
3801
+ };
3802
+ if (flags.dryRun) {
3803
+ const preview = {
3804
+ ...request,
3805
+ content: `[${request.content.length} bytes]`,
3806
+ subagents: request.subagents?.map((s) => ({
3807
+ ...s,
3808
+ content: `[${s.content.length} bytes]`
3809
+ }))
3810
+ };
3811
+ write("Dry run - would upload:");
3812
+ write(JSON.stringify(preview, null, 2));
3813
+ return;
3814
+ }
3815
+ write("Uploading...");
3816
+ const result = await uploadSession(request, {
3817
+ endpoint: flags.endpoint,
3818
+ token: credentials.token
3819
+ });
3820
+ if (result.success) {
3821
+ write("Upload successful!");
3822
+ } else {
3823
+ writeError(`Upload failed: ${result.error}`);
3824
+ process.exitCode = 1;
3825
+ }
3826
+ }
3827
+ var uploadCommand = buildCommand({
3828
+ loader: async () => ({ default: runUpload }),
3829
+ parameters: {
3830
+ positional: {
3831
+ kind: "tuple",
3832
+ parameters: [
3833
+ {
3834
+ brief: "Session ID or path to a session .jsonl file",
3835
+ parse: String,
3836
+ placeholder: "session"
3837
+ }
3838
+ ]
3839
+ },
3840
+ flags: {
3841
+ tag: {
3842
+ kind: "enum",
3843
+ values: [...SESSION_TAGS],
3844
+ brief: "Session tag/category",
3845
+ optional: true
3846
+ },
3847
+ endpoint: {
3848
+ kind: "parsed",
3849
+ parse: String,
3850
+ brief: "Override the upload endpoint URL",
3851
+ default: DEFAULT_ENDPOINT
3852
+ },
3853
+ classify: {
3854
+ kind: "boolean",
3855
+ brief: "Auto-classify session tag using Claude CLI",
3856
+ default: false
3857
+ },
3858
+ dryRun: {
3859
+ kind: "boolean",
3860
+ brief: "Preview what would be uploaded without sending",
3861
+ default: false
3862
+ }
3863
+ },
3864
+ aliases: {
3865
+ t: "tag",
3866
+ c: "classify",
3867
+ n: "dryRun"
3868
+ }
3869
+ },
3870
+ docs: {
3871
+ brief: "Upload a Claude Code session transcript to the backend"
3872
+ }
3873
+ });
3874
+
3875
+ // src/commands/whoami.ts
3876
+ async function runWhoami() {
3877
+ const write = (msg) => process.stdout.write(`${msg}
3878
+ `);
3879
+ const writeError = (msg) => process.stderr.write(`${msg}
3880
+ `);
3881
+ const credentials = loadCredentials();
3882
+ if (!credentials) {
3883
+ write("Not logged in. Run `rudel login` to authenticate.");
3884
+ return;
3885
+ }
3886
+ const response = await fetch(`${credentials.apiBaseUrl}/rpc/me`, {
3887
+ method: "POST",
3888
+ headers: {
3889
+ "Content-Type": "application/json",
3890
+ Authorization: `Bearer ${credentials.token}`
3891
+ },
3892
+ body: JSON.stringify({})
3893
+ });
3894
+ if (!response.ok) {
3895
+ writeError("Session expired or invalid. Run `rudel login` to re-authenticate.");
3896
+ process.exitCode = 1;
3897
+ return;
3898
+ }
3899
+ const body = await response.json();
3900
+ write(`Logged in as ${body.json.name} (${body.json.email})`);
3901
+ }
3902
+ var whoamiCommand = buildCommand({
3903
+ loader: async () => ({ default: runWhoami }),
3904
+ parameters: {},
3905
+ docs: {
3906
+ brief: "Show the currently authenticated user"
3907
+ }
3908
+ });
3909
+
3910
+ // src/app.ts
3911
+ var routes = buildRouteMap({
3912
+ routes: {
3913
+ login: loginCommand,
3914
+ logout: logoutCommand,
3915
+ whoami: whoamiCommand,
3916
+ upload: uploadCommand
3917
+ },
3918
+ docs: {
3919
+ brief: "CLI tools for managing Claude Code sessions"
3920
+ }
3921
+ });
3922
+ var app = buildApplication(routes, {
3923
+ name: "rudel",
3924
+ versionInfo: {
3925
+ currentVersion: "0.1.1"
3926
+ },
3927
+ scanner: {
3928
+ caseStyle: "allow-kebab-for-camel"
3929
+ }
3930
+ });
3931
+
3932
+ // src/bin/cli.ts
3933
+ await run(app, process.argv.slice(2), { process });