@lex-inc/thoughtful 0.0.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.
package/dist/index.js ADDED
@@ -0,0 +1,4513 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ var __create = Object.create;
4
+ var __getProtoOf = Object.getPrototypeOf;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __toESM = (mod, isNodeMode, target) => {
9
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
10
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
+ for (let key of __getOwnPropNames(mod))
12
+ if (!__hasOwnProp.call(to, key))
13
+ __defProp(to, key, {
14
+ get: () => mod[key],
15
+ enumerable: true
16
+ });
17
+ return to;
18
+ };
19
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
20
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
21
+
22
+ // ../../node_modules/commander/lib/error.js
23
+ var require_error = __commonJS((exports) => {
24
+ class CommanderError extends Error {
25
+ constructor(exitCode, code, message) {
26
+ super(message);
27
+ Error.captureStackTrace(this, this.constructor);
28
+ this.name = this.constructor.name;
29
+ this.code = code;
30
+ this.exitCode = exitCode;
31
+ this.nestedError = undefined;
32
+ }
33
+ }
34
+
35
+ class InvalidArgumentError extends CommanderError {
36
+ constructor(message) {
37
+ super(1, "commander.invalidArgument", message);
38
+ Error.captureStackTrace(this, this.constructor);
39
+ this.name = this.constructor.name;
40
+ }
41
+ }
42
+ exports.CommanderError = CommanderError;
43
+ exports.InvalidArgumentError = InvalidArgumentError;
44
+ });
45
+
46
+ // ../../node_modules/commander/lib/argument.js
47
+ var require_argument = __commonJS((exports) => {
48
+ var { InvalidArgumentError } = require_error();
49
+
50
+ class Argument {
51
+ constructor(name, description) {
52
+ this.description = description || "";
53
+ this.variadic = false;
54
+ this.parseArg = undefined;
55
+ this.defaultValue = undefined;
56
+ this.defaultValueDescription = undefined;
57
+ this.argChoices = undefined;
58
+ switch (name[0]) {
59
+ case "<":
60
+ this.required = true;
61
+ this._name = name.slice(1, -1);
62
+ break;
63
+ case "[":
64
+ this.required = false;
65
+ this._name = name.slice(1, -1);
66
+ break;
67
+ default:
68
+ this.required = true;
69
+ this._name = name;
70
+ break;
71
+ }
72
+ if (this._name.length > 3 && this._name.slice(-3) === "...") {
73
+ this.variadic = true;
74
+ this._name = this._name.slice(0, -3);
75
+ }
76
+ }
77
+ name() {
78
+ return this._name;
79
+ }
80
+ _concatValue(value, previous) {
81
+ if (previous === this.defaultValue || !Array.isArray(previous)) {
82
+ return [value];
83
+ }
84
+ return previous.concat(value);
85
+ }
86
+ default(value, description) {
87
+ this.defaultValue = value;
88
+ this.defaultValueDescription = description;
89
+ return this;
90
+ }
91
+ argParser(fn) {
92
+ this.parseArg = fn;
93
+ return this;
94
+ }
95
+ choices(values) {
96
+ this.argChoices = values.slice();
97
+ this.parseArg = (arg, previous) => {
98
+ if (!this.argChoices.includes(arg)) {
99
+ throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
100
+ }
101
+ if (this.variadic) {
102
+ return this._concatValue(arg, previous);
103
+ }
104
+ return arg;
105
+ };
106
+ return this;
107
+ }
108
+ argRequired() {
109
+ this.required = true;
110
+ return this;
111
+ }
112
+ argOptional() {
113
+ this.required = false;
114
+ return this;
115
+ }
116
+ }
117
+ function humanReadableArgName(arg) {
118
+ const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
119
+ return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
120
+ }
121
+ exports.Argument = Argument;
122
+ exports.humanReadableArgName = humanReadableArgName;
123
+ });
124
+
125
+ // ../../node_modules/commander/lib/help.js
126
+ var require_help = __commonJS((exports) => {
127
+ var { humanReadableArgName } = require_argument();
128
+
129
+ class Help {
130
+ constructor() {
131
+ this.helpWidth = undefined;
132
+ this.minWidthToWrap = 40;
133
+ this.sortSubcommands = false;
134
+ this.sortOptions = false;
135
+ this.showGlobalOptions = false;
136
+ }
137
+ prepareContext(contextOptions) {
138
+ this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
139
+ }
140
+ visibleCommands(cmd) {
141
+ const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
142
+ const helpCommand = cmd._getHelpCommand();
143
+ if (helpCommand && !helpCommand._hidden) {
144
+ visibleCommands.push(helpCommand);
145
+ }
146
+ if (this.sortSubcommands) {
147
+ visibleCommands.sort((a, b) => {
148
+ return a.name().localeCompare(b.name());
149
+ });
150
+ }
151
+ return visibleCommands;
152
+ }
153
+ compareOptions(a, b) {
154
+ const getSortKey = (option) => {
155
+ return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
156
+ };
157
+ return getSortKey(a).localeCompare(getSortKey(b));
158
+ }
159
+ visibleOptions(cmd) {
160
+ const visibleOptions = cmd.options.filter((option) => !option.hidden);
161
+ const helpOption = cmd._getHelpOption();
162
+ if (helpOption && !helpOption.hidden) {
163
+ const removeShort = helpOption.short && cmd._findOption(helpOption.short);
164
+ const removeLong = helpOption.long && cmd._findOption(helpOption.long);
165
+ if (!removeShort && !removeLong) {
166
+ visibleOptions.push(helpOption);
167
+ } else if (helpOption.long && !removeLong) {
168
+ visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description));
169
+ } else if (helpOption.short && !removeShort) {
170
+ visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description));
171
+ }
172
+ }
173
+ if (this.sortOptions) {
174
+ visibleOptions.sort(this.compareOptions);
175
+ }
176
+ return visibleOptions;
177
+ }
178
+ visibleGlobalOptions(cmd) {
179
+ if (!this.showGlobalOptions)
180
+ return [];
181
+ const globalOptions = [];
182
+ for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
183
+ const visibleOptions = ancestorCmd.options.filter((option) => !option.hidden);
184
+ globalOptions.push(...visibleOptions);
185
+ }
186
+ if (this.sortOptions) {
187
+ globalOptions.sort(this.compareOptions);
188
+ }
189
+ return globalOptions;
190
+ }
191
+ visibleArguments(cmd) {
192
+ if (cmd._argsDescription) {
193
+ cmd.registeredArguments.forEach((argument) => {
194
+ argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
195
+ });
196
+ }
197
+ if (cmd.registeredArguments.find((argument) => argument.description)) {
198
+ return cmd.registeredArguments;
199
+ }
200
+ return [];
201
+ }
202
+ subcommandTerm(cmd) {
203
+ const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
204
+ return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + (args ? " " + args : "");
205
+ }
206
+ optionTerm(option) {
207
+ return option.flags;
208
+ }
209
+ argumentTerm(argument) {
210
+ return argument.name();
211
+ }
212
+ longestSubcommandTermLength(cmd, helper) {
213
+ return helper.visibleCommands(cmd).reduce((max, command) => {
214
+ return Math.max(max, this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command))));
215
+ }, 0);
216
+ }
217
+ longestOptionTermLength(cmd, helper) {
218
+ return helper.visibleOptions(cmd).reduce((max, option) => {
219
+ return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
220
+ }, 0);
221
+ }
222
+ longestGlobalOptionTermLength(cmd, helper) {
223
+ return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
224
+ return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
225
+ }, 0);
226
+ }
227
+ longestArgumentTermLength(cmd, helper) {
228
+ return helper.visibleArguments(cmd).reduce((max, argument) => {
229
+ return Math.max(max, this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument))));
230
+ }, 0);
231
+ }
232
+ commandUsage(cmd) {
233
+ let cmdName = cmd._name;
234
+ if (cmd._aliases[0]) {
235
+ cmdName = cmdName + "|" + cmd._aliases[0];
236
+ }
237
+ let ancestorCmdNames = "";
238
+ for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
239
+ ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
240
+ }
241
+ return ancestorCmdNames + cmdName + " " + cmd.usage();
242
+ }
243
+ commandDescription(cmd) {
244
+ return cmd.description();
245
+ }
246
+ subcommandDescription(cmd) {
247
+ return cmd.summary() || cmd.description();
248
+ }
249
+ optionDescription(option) {
250
+ const extraInfo = [];
251
+ if (option.argChoices) {
252
+ extraInfo.push(`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
253
+ }
254
+ if (option.defaultValue !== undefined) {
255
+ const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
256
+ if (showDefault) {
257
+ extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
258
+ }
259
+ }
260
+ if (option.presetArg !== undefined && option.optional) {
261
+ extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
262
+ }
263
+ if (option.envVar !== undefined) {
264
+ extraInfo.push(`env: ${option.envVar}`);
265
+ }
266
+ if (extraInfo.length > 0) {
267
+ return `${option.description} (${extraInfo.join(", ")})`;
268
+ }
269
+ return option.description;
270
+ }
271
+ argumentDescription(argument) {
272
+ const extraInfo = [];
273
+ if (argument.argChoices) {
274
+ extraInfo.push(`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
275
+ }
276
+ if (argument.defaultValue !== undefined) {
277
+ extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
278
+ }
279
+ if (extraInfo.length > 0) {
280
+ const extraDescription = `(${extraInfo.join(", ")})`;
281
+ if (argument.description) {
282
+ return `${argument.description} ${extraDescription}`;
283
+ }
284
+ return extraDescription;
285
+ }
286
+ return argument.description;
287
+ }
288
+ formatHelp(cmd, helper) {
289
+ const termWidth = helper.padWidth(cmd, helper);
290
+ const helpWidth = helper.helpWidth ?? 80;
291
+ function callFormatItem(term, description) {
292
+ return helper.formatItem(term, termWidth, description, helper);
293
+ }
294
+ let output = [
295
+ `${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,
296
+ ""
297
+ ];
298
+ const commandDescription = helper.commandDescription(cmd);
299
+ if (commandDescription.length > 0) {
300
+ output = output.concat([
301
+ helper.boxWrap(helper.styleCommandDescription(commandDescription), helpWidth),
302
+ ""
303
+ ]);
304
+ }
305
+ const argumentList = helper.visibleArguments(cmd).map((argument) => {
306
+ return callFormatItem(helper.styleArgumentTerm(helper.argumentTerm(argument)), helper.styleArgumentDescription(helper.argumentDescription(argument)));
307
+ });
308
+ if (argumentList.length > 0) {
309
+ output = output.concat([
310
+ helper.styleTitle("Arguments:"),
311
+ ...argumentList,
312
+ ""
313
+ ]);
314
+ }
315
+ const optionList = helper.visibleOptions(cmd).map((option) => {
316
+ return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
317
+ });
318
+ if (optionList.length > 0) {
319
+ output = output.concat([
320
+ helper.styleTitle("Options:"),
321
+ ...optionList,
322
+ ""
323
+ ]);
324
+ }
325
+ if (helper.showGlobalOptions) {
326
+ const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
327
+ return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
328
+ });
329
+ if (globalOptionList.length > 0) {
330
+ output = output.concat([
331
+ helper.styleTitle("Global Options:"),
332
+ ...globalOptionList,
333
+ ""
334
+ ]);
335
+ }
336
+ }
337
+ const commandList = helper.visibleCommands(cmd).map((cmd2) => {
338
+ return callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(cmd2)), helper.styleSubcommandDescription(helper.subcommandDescription(cmd2)));
339
+ });
340
+ if (commandList.length > 0) {
341
+ output = output.concat([
342
+ helper.styleTitle("Commands:"),
343
+ ...commandList,
344
+ ""
345
+ ]);
346
+ }
347
+ return output.join(`
348
+ `);
349
+ }
350
+ displayWidth(str) {
351
+ return stripColor(str).length;
352
+ }
353
+ styleTitle(str) {
354
+ return str;
355
+ }
356
+ styleUsage(str) {
357
+ return str.split(" ").map((word) => {
358
+ if (word === "[options]")
359
+ return this.styleOptionText(word);
360
+ if (word === "[command]")
361
+ return this.styleSubcommandText(word);
362
+ if (word[0] === "[" || word[0] === "<")
363
+ return this.styleArgumentText(word);
364
+ return this.styleCommandText(word);
365
+ }).join(" ");
366
+ }
367
+ styleCommandDescription(str) {
368
+ return this.styleDescriptionText(str);
369
+ }
370
+ styleOptionDescription(str) {
371
+ return this.styleDescriptionText(str);
372
+ }
373
+ styleSubcommandDescription(str) {
374
+ return this.styleDescriptionText(str);
375
+ }
376
+ styleArgumentDescription(str) {
377
+ return this.styleDescriptionText(str);
378
+ }
379
+ styleDescriptionText(str) {
380
+ return str;
381
+ }
382
+ styleOptionTerm(str) {
383
+ return this.styleOptionText(str);
384
+ }
385
+ styleSubcommandTerm(str) {
386
+ return str.split(" ").map((word) => {
387
+ if (word === "[options]")
388
+ return this.styleOptionText(word);
389
+ if (word[0] === "[" || word[0] === "<")
390
+ return this.styleArgumentText(word);
391
+ return this.styleSubcommandText(word);
392
+ }).join(" ");
393
+ }
394
+ styleArgumentTerm(str) {
395
+ return this.styleArgumentText(str);
396
+ }
397
+ styleOptionText(str) {
398
+ return str;
399
+ }
400
+ styleArgumentText(str) {
401
+ return str;
402
+ }
403
+ styleSubcommandText(str) {
404
+ return str;
405
+ }
406
+ styleCommandText(str) {
407
+ return str;
408
+ }
409
+ padWidth(cmd, helper) {
410
+ return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper));
411
+ }
412
+ preformatted(str) {
413
+ return /\n[^\S\r\n]/.test(str);
414
+ }
415
+ formatItem(term, termWidth, description, helper) {
416
+ const itemIndent = 2;
417
+ const itemIndentStr = " ".repeat(itemIndent);
418
+ if (!description)
419
+ return itemIndentStr + term;
420
+ const paddedTerm = term.padEnd(termWidth + term.length - helper.displayWidth(term));
421
+ const spacerWidth = 2;
422
+ const helpWidth = this.helpWidth ?? 80;
423
+ const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent;
424
+ let formattedDescription;
425
+ if (remainingWidth < this.minWidthToWrap || helper.preformatted(description)) {
426
+ formattedDescription = description;
427
+ } else {
428
+ const wrappedDescription = helper.boxWrap(description, remainingWidth);
429
+ formattedDescription = wrappedDescription.replace(/\n/g, `
430
+ ` + " ".repeat(termWidth + spacerWidth));
431
+ }
432
+ return itemIndentStr + paddedTerm + " ".repeat(spacerWidth) + formattedDescription.replace(/\n/g, `
433
+ ${itemIndentStr}`);
434
+ }
435
+ boxWrap(str, width) {
436
+ if (width < this.minWidthToWrap)
437
+ return str;
438
+ const rawLines = str.split(/\r\n|\n/);
439
+ const chunkPattern = /[\s]*[^\s]+/g;
440
+ const wrappedLines = [];
441
+ rawLines.forEach((line) => {
442
+ const chunks = line.match(chunkPattern);
443
+ if (chunks === null) {
444
+ wrappedLines.push("");
445
+ return;
446
+ }
447
+ let sumChunks = [chunks.shift()];
448
+ let sumWidth = this.displayWidth(sumChunks[0]);
449
+ chunks.forEach((chunk) => {
450
+ const visibleWidth = this.displayWidth(chunk);
451
+ if (sumWidth + visibleWidth <= width) {
452
+ sumChunks.push(chunk);
453
+ sumWidth += visibleWidth;
454
+ return;
455
+ }
456
+ wrappedLines.push(sumChunks.join(""));
457
+ const nextChunk = chunk.trimStart();
458
+ sumChunks = [nextChunk];
459
+ sumWidth = this.displayWidth(nextChunk);
460
+ });
461
+ wrappedLines.push(sumChunks.join(""));
462
+ });
463
+ return wrappedLines.join(`
464
+ `);
465
+ }
466
+ }
467
+ function stripColor(str) {
468
+ const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
469
+ return str.replace(sgrPattern, "");
470
+ }
471
+ exports.Help = Help;
472
+ exports.stripColor = stripColor;
473
+ });
474
+
475
+ // ../../node_modules/commander/lib/option.js
476
+ var require_option = __commonJS((exports) => {
477
+ var { InvalidArgumentError } = require_error();
478
+
479
+ class Option {
480
+ constructor(flags, description) {
481
+ this.flags = flags;
482
+ this.description = description || "";
483
+ this.required = flags.includes("<");
484
+ this.optional = flags.includes("[");
485
+ this.variadic = /\w\.\.\.[>\]]$/.test(flags);
486
+ this.mandatory = false;
487
+ const optionFlags = splitOptionFlags(flags);
488
+ this.short = optionFlags.shortFlag;
489
+ this.long = optionFlags.longFlag;
490
+ this.negate = false;
491
+ if (this.long) {
492
+ this.negate = this.long.startsWith("--no-");
493
+ }
494
+ this.defaultValue = undefined;
495
+ this.defaultValueDescription = undefined;
496
+ this.presetArg = undefined;
497
+ this.envVar = undefined;
498
+ this.parseArg = undefined;
499
+ this.hidden = false;
500
+ this.argChoices = undefined;
501
+ this.conflictsWith = [];
502
+ this.implied = undefined;
503
+ }
504
+ default(value, description) {
505
+ this.defaultValue = value;
506
+ this.defaultValueDescription = description;
507
+ return this;
508
+ }
509
+ preset(arg) {
510
+ this.presetArg = arg;
511
+ return this;
512
+ }
513
+ conflicts(names) {
514
+ this.conflictsWith = this.conflictsWith.concat(names);
515
+ return this;
516
+ }
517
+ implies(impliedOptionValues) {
518
+ let newImplied = impliedOptionValues;
519
+ if (typeof impliedOptionValues === "string") {
520
+ newImplied = { [impliedOptionValues]: true };
521
+ }
522
+ this.implied = Object.assign(this.implied || {}, newImplied);
523
+ return this;
524
+ }
525
+ env(name) {
526
+ this.envVar = name;
527
+ return this;
528
+ }
529
+ argParser(fn) {
530
+ this.parseArg = fn;
531
+ return this;
532
+ }
533
+ makeOptionMandatory(mandatory = true) {
534
+ this.mandatory = !!mandatory;
535
+ return this;
536
+ }
537
+ hideHelp(hide = true) {
538
+ this.hidden = !!hide;
539
+ return this;
540
+ }
541
+ _concatValue(value, previous) {
542
+ if (previous === this.defaultValue || !Array.isArray(previous)) {
543
+ return [value];
544
+ }
545
+ return previous.concat(value);
546
+ }
547
+ choices(values) {
548
+ this.argChoices = values.slice();
549
+ this.parseArg = (arg, previous) => {
550
+ if (!this.argChoices.includes(arg)) {
551
+ throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
552
+ }
553
+ if (this.variadic) {
554
+ return this._concatValue(arg, previous);
555
+ }
556
+ return arg;
557
+ };
558
+ return this;
559
+ }
560
+ name() {
561
+ if (this.long) {
562
+ return this.long.replace(/^--/, "");
563
+ }
564
+ return this.short.replace(/^-/, "");
565
+ }
566
+ attributeName() {
567
+ if (this.negate) {
568
+ return camelcase(this.name().replace(/^no-/, ""));
569
+ }
570
+ return camelcase(this.name());
571
+ }
572
+ is(arg) {
573
+ return this.short === arg || this.long === arg;
574
+ }
575
+ isBoolean() {
576
+ return !this.required && !this.optional && !this.negate;
577
+ }
578
+ }
579
+
580
+ class DualOptions {
581
+ constructor(options) {
582
+ this.positiveOptions = new Map;
583
+ this.negativeOptions = new Map;
584
+ this.dualOptions = new Set;
585
+ options.forEach((option) => {
586
+ if (option.negate) {
587
+ this.negativeOptions.set(option.attributeName(), option);
588
+ } else {
589
+ this.positiveOptions.set(option.attributeName(), option);
590
+ }
591
+ });
592
+ this.negativeOptions.forEach((value, key) => {
593
+ if (this.positiveOptions.has(key)) {
594
+ this.dualOptions.add(key);
595
+ }
596
+ });
597
+ }
598
+ valueFromOption(value, option) {
599
+ const optionKey = option.attributeName();
600
+ if (!this.dualOptions.has(optionKey))
601
+ return true;
602
+ const preset = this.negativeOptions.get(optionKey).presetArg;
603
+ const negativeValue = preset !== undefined ? preset : false;
604
+ return option.negate === (negativeValue === value);
605
+ }
606
+ }
607
+ function camelcase(str) {
608
+ return str.split("-").reduce((str2, word) => {
609
+ return str2 + word[0].toUpperCase() + word.slice(1);
610
+ });
611
+ }
612
+ function splitOptionFlags(flags) {
613
+ let shortFlag;
614
+ let longFlag;
615
+ const shortFlagExp = /^-[^-]$/;
616
+ const longFlagExp = /^--[^-]/;
617
+ const flagParts = flags.split(/[ |,]+/).concat("guard");
618
+ if (shortFlagExp.test(flagParts[0]))
619
+ shortFlag = flagParts.shift();
620
+ if (longFlagExp.test(flagParts[0]))
621
+ longFlag = flagParts.shift();
622
+ if (!shortFlag && shortFlagExp.test(flagParts[0]))
623
+ shortFlag = flagParts.shift();
624
+ if (!shortFlag && longFlagExp.test(flagParts[0])) {
625
+ shortFlag = longFlag;
626
+ longFlag = flagParts.shift();
627
+ }
628
+ if (flagParts[0].startsWith("-")) {
629
+ const unsupportedFlag = flagParts[0];
630
+ const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;
631
+ if (/^-[^-][^-]/.test(unsupportedFlag))
632
+ throw new Error(`${baseError}
633
+ - a short flag is a single dash and a single character
634
+ - either use a single dash and a single character (for a short flag)
635
+ - or use a double dash for a long option (and can have two, like '--ws, --workspace')`);
636
+ if (shortFlagExp.test(unsupportedFlag))
637
+ throw new Error(`${baseError}
638
+ - too many short flags`);
639
+ if (longFlagExp.test(unsupportedFlag))
640
+ throw new Error(`${baseError}
641
+ - too many long flags`);
642
+ throw new Error(`${baseError}
643
+ - unrecognised flag format`);
644
+ }
645
+ if (shortFlag === undefined && longFlag === undefined)
646
+ throw new Error(`option creation failed due to no flags found in '${flags}'.`);
647
+ return { shortFlag, longFlag };
648
+ }
649
+ exports.Option = Option;
650
+ exports.DualOptions = DualOptions;
651
+ });
652
+
653
+ // ../../node_modules/commander/lib/suggestSimilar.js
654
+ var require_suggestSimilar = __commonJS((exports) => {
655
+ var maxDistance = 3;
656
+ function editDistance(a, b) {
657
+ if (Math.abs(a.length - b.length) > maxDistance)
658
+ return Math.max(a.length, b.length);
659
+ const d = [];
660
+ for (let i = 0;i <= a.length; i++) {
661
+ d[i] = [i];
662
+ }
663
+ for (let j = 0;j <= b.length; j++) {
664
+ d[0][j] = j;
665
+ }
666
+ for (let j = 1;j <= b.length; j++) {
667
+ for (let i = 1;i <= a.length; i++) {
668
+ let cost = 1;
669
+ if (a[i - 1] === b[j - 1]) {
670
+ cost = 0;
671
+ } else {
672
+ cost = 1;
673
+ }
674
+ d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
675
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
676
+ d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
677
+ }
678
+ }
679
+ }
680
+ return d[a.length][b.length];
681
+ }
682
+ function suggestSimilar(word, candidates) {
683
+ if (!candidates || candidates.length === 0)
684
+ return "";
685
+ candidates = Array.from(new Set(candidates));
686
+ const searchingOptions = word.startsWith("--");
687
+ if (searchingOptions) {
688
+ word = word.slice(2);
689
+ candidates = candidates.map((candidate) => candidate.slice(2));
690
+ }
691
+ let similar = [];
692
+ let bestDistance = maxDistance;
693
+ const minSimilarity = 0.4;
694
+ candidates.forEach((candidate) => {
695
+ if (candidate.length <= 1)
696
+ return;
697
+ const distance = editDistance(word, candidate);
698
+ const length = Math.max(word.length, candidate.length);
699
+ const similarity = (length - distance) / length;
700
+ if (similarity > minSimilarity) {
701
+ if (distance < bestDistance) {
702
+ bestDistance = distance;
703
+ similar = [candidate];
704
+ } else if (distance === bestDistance) {
705
+ similar.push(candidate);
706
+ }
707
+ }
708
+ });
709
+ similar.sort((a, b) => a.localeCompare(b));
710
+ if (searchingOptions) {
711
+ similar = similar.map((candidate) => `--${candidate}`);
712
+ }
713
+ if (similar.length > 1) {
714
+ return `
715
+ (Did you mean one of ${similar.join(", ")}?)`;
716
+ }
717
+ if (similar.length === 1) {
718
+ return `
719
+ (Did you mean ${similar[0]}?)`;
720
+ }
721
+ return "";
722
+ }
723
+ exports.suggestSimilar = suggestSimilar;
724
+ });
725
+
726
+ // ../../node_modules/commander/lib/command.js
727
+ var require_command = __commonJS((exports) => {
728
+ var EventEmitter = __require("node:events").EventEmitter;
729
+ var childProcess = __require("node:child_process");
730
+ var path = __require("node:path");
731
+ var fs = __require("node:fs");
732
+ var process2 = __require("node:process");
733
+ var { Argument, humanReadableArgName } = require_argument();
734
+ var { CommanderError } = require_error();
735
+ var { Help, stripColor } = require_help();
736
+ var { Option, DualOptions } = require_option();
737
+ var { suggestSimilar } = require_suggestSimilar();
738
+
739
+ class Command extends EventEmitter {
740
+ constructor(name) {
741
+ super();
742
+ this.commands = [];
743
+ this.options = [];
744
+ this.parent = null;
745
+ this._allowUnknownOption = false;
746
+ this._allowExcessArguments = false;
747
+ this.registeredArguments = [];
748
+ this._args = this.registeredArguments;
749
+ this.args = [];
750
+ this.rawArgs = [];
751
+ this.processedArgs = [];
752
+ this._scriptPath = null;
753
+ this._name = name || "";
754
+ this._optionValues = {};
755
+ this._optionValueSources = {};
756
+ this._storeOptionsAsProperties = false;
757
+ this._actionHandler = null;
758
+ this._executableHandler = false;
759
+ this._executableFile = null;
760
+ this._executableDir = null;
761
+ this._defaultCommandName = null;
762
+ this._exitCallback = null;
763
+ this._aliases = [];
764
+ this._combineFlagAndOptionalValue = true;
765
+ this._description = "";
766
+ this._summary = "";
767
+ this._argsDescription = undefined;
768
+ this._enablePositionalOptions = false;
769
+ this._passThroughOptions = false;
770
+ this._lifeCycleHooks = {};
771
+ this._showHelpAfterError = false;
772
+ this._showSuggestionAfterError = true;
773
+ this._savedState = null;
774
+ this._outputConfiguration = {
775
+ writeOut: (str) => process2.stdout.write(str),
776
+ writeErr: (str) => process2.stderr.write(str),
777
+ outputError: (str, write) => write(str),
778
+ getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : undefined,
779
+ getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : undefined,
780
+ getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
781
+ getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
782
+ stripColor: (str) => stripColor(str)
783
+ };
784
+ this._hidden = false;
785
+ this._helpOption = undefined;
786
+ this._addImplicitHelpCommand = undefined;
787
+ this._helpCommand = undefined;
788
+ this._helpConfiguration = {};
789
+ }
790
+ copyInheritedSettings(sourceCommand) {
791
+ this._outputConfiguration = sourceCommand._outputConfiguration;
792
+ this._helpOption = sourceCommand._helpOption;
793
+ this._helpCommand = sourceCommand._helpCommand;
794
+ this._helpConfiguration = sourceCommand._helpConfiguration;
795
+ this._exitCallback = sourceCommand._exitCallback;
796
+ this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
797
+ this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
798
+ this._allowExcessArguments = sourceCommand._allowExcessArguments;
799
+ this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
800
+ this._showHelpAfterError = sourceCommand._showHelpAfterError;
801
+ this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
802
+ return this;
803
+ }
804
+ _getCommandAndAncestors() {
805
+ const result = [];
806
+ for (let command = this;command; command = command.parent) {
807
+ result.push(command);
808
+ }
809
+ return result;
810
+ }
811
+ command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
812
+ let desc = actionOptsOrExecDesc;
813
+ let opts = execOpts;
814
+ if (typeof desc === "object" && desc !== null) {
815
+ opts = desc;
816
+ desc = null;
817
+ }
818
+ opts = opts || {};
819
+ const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);
820
+ const cmd = this.createCommand(name);
821
+ if (desc) {
822
+ cmd.description(desc);
823
+ cmd._executableHandler = true;
824
+ }
825
+ if (opts.isDefault)
826
+ this._defaultCommandName = cmd._name;
827
+ cmd._hidden = !!(opts.noHelp || opts.hidden);
828
+ cmd._executableFile = opts.executableFile || null;
829
+ if (args)
830
+ cmd.arguments(args);
831
+ this._registerCommand(cmd);
832
+ cmd.parent = this;
833
+ cmd.copyInheritedSettings(this);
834
+ if (desc)
835
+ return this;
836
+ return cmd;
837
+ }
838
+ createCommand(name) {
839
+ return new Command(name);
840
+ }
841
+ createHelp() {
842
+ return Object.assign(new Help, this.configureHelp());
843
+ }
844
+ configureHelp(configuration) {
845
+ if (configuration === undefined)
846
+ return this._helpConfiguration;
847
+ this._helpConfiguration = configuration;
848
+ return this;
849
+ }
850
+ configureOutput(configuration) {
851
+ if (configuration === undefined)
852
+ return this._outputConfiguration;
853
+ Object.assign(this._outputConfiguration, configuration);
854
+ return this;
855
+ }
856
+ showHelpAfterError(displayHelp = true) {
857
+ if (typeof displayHelp !== "string")
858
+ displayHelp = !!displayHelp;
859
+ this._showHelpAfterError = displayHelp;
860
+ return this;
861
+ }
862
+ showSuggestionAfterError(displaySuggestion = true) {
863
+ this._showSuggestionAfterError = !!displaySuggestion;
864
+ return this;
865
+ }
866
+ addCommand(cmd, opts) {
867
+ if (!cmd._name) {
868
+ throw new Error(`Command passed to .addCommand() must have a name
869
+ - specify the name in Command constructor or using .name()`);
870
+ }
871
+ opts = opts || {};
872
+ if (opts.isDefault)
873
+ this._defaultCommandName = cmd._name;
874
+ if (opts.noHelp || opts.hidden)
875
+ cmd._hidden = true;
876
+ this._registerCommand(cmd);
877
+ cmd.parent = this;
878
+ cmd._checkForBrokenPassThrough();
879
+ return this;
880
+ }
881
+ createArgument(name, description) {
882
+ return new Argument(name, description);
883
+ }
884
+ argument(name, description, fn, defaultValue) {
885
+ const argument = this.createArgument(name, description);
886
+ if (typeof fn === "function") {
887
+ argument.default(defaultValue).argParser(fn);
888
+ } else {
889
+ argument.default(fn);
890
+ }
891
+ this.addArgument(argument);
892
+ return this;
893
+ }
894
+ arguments(names) {
895
+ names.trim().split(/ +/).forEach((detail) => {
896
+ this.argument(detail);
897
+ });
898
+ return this;
899
+ }
900
+ addArgument(argument) {
901
+ const previousArgument = this.registeredArguments.slice(-1)[0];
902
+ if (previousArgument && previousArgument.variadic) {
903
+ throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);
904
+ }
905
+ if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) {
906
+ throw new Error(`a default value for a required argument is never used: '${argument.name()}'`);
907
+ }
908
+ this.registeredArguments.push(argument);
909
+ return this;
910
+ }
911
+ helpCommand(enableOrNameAndArgs, description) {
912
+ if (typeof enableOrNameAndArgs === "boolean") {
913
+ this._addImplicitHelpCommand = enableOrNameAndArgs;
914
+ return this;
915
+ }
916
+ enableOrNameAndArgs = enableOrNameAndArgs ?? "help [command]";
917
+ const [, helpName, helpArgs] = enableOrNameAndArgs.match(/([^ ]+) *(.*)/);
918
+ const helpDescription = description ?? "display help for command";
919
+ const helpCommand = this.createCommand(helpName);
920
+ helpCommand.helpOption(false);
921
+ if (helpArgs)
922
+ helpCommand.arguments(helpArgs);
923
+ if (helpDescription)
924
+ helpCommand.description(helpDescription);
925
+ this._addImplicitHelpCommand = true;
926
+ this._helpCommand = helpCommand;
927
+ return this;
928
+ }
929
+ addHelpCommand(helpCommand, deprecatedDescription) {
930
+ if (typeof helpCommand !== "object") {
931
+ this.helpCommand(helpCommand, deprecatedDescription);
932
+ return this;
933
+ }
934
+ this._addImplicitHelpCommand = true;
935
+ this._helpCommand = helpCommand;
936
+ return this;
937
+ }
938
+ _getHelpCommand() {
939
+ const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand("help"));
940
+ if (hasImplicitHelpCommand) {
941
+ if (this._helpCommand === undefined) {
942
+ this.helpCommand(undefined, undefined);
943
+ }
944
+ return this._helpCommand;
945
+ }
946
+ return null;
947
+ }
948
+ hook(event, listener) {
949
+ const allowedValues = ["preSubcommand", "preAction", "postAction"];
950
+ if (!allowedValues.includes(event)) {
951
+ throw new Error(`Unexpected value for event passed to hook : '${event}'.
952
+ Expecting one of '${allowedValues.join("', '")}'`);
953
+ }
954
+ if (this._lifeCycleHooks[event]) {
955
+ this._lifeCycleHooks[event].push(listener);
956
+ } else {
957
+ this._lifeCycleHooks[event] = [listener];
958
+ }
959
+ return this;
960
+ }
961
+ exitOverride(fn) {
962
+ if (fn) {
963
+ this._exitCallback = fn;
964
+ } else {
965
+ this._exitCallback = (err) => {
966
+ if (err.code !== "commander.executeSubCommandAsync") {
967
+ throw err;
968
+ } else {}
969
+ };
970
+ }
971
+ return this;
972
+ }
973
+ _exit(exitCode, code, message) {
974
+ if (this._exitCallback) {
975
+ this._exitCallback(new CommanderError(exitCode, code, message));
976
+ }
977
+ process2.exit(exitCode);
978
+ }
979
+ action(fn) {
980
+ const listener = (args) => {
981
+ const expectedArgsCount = this.registeredArguments.length;
982
+ const actionArgs = args.slice(0, expectedArgsCount);
983
+ if (this._storeOptionsAsProperties) {
984
+ actionArgs[expectedArgsCount] = this;
985
+ } else {
986
+ actionArgs[expectedArgsCount] = this.opts();
987
+ }
988
+ actionArgs.push(this);
989
+ return fn.apply(this, actionArgs);
990
+ };
991
+ this._actionHandler = listener;
992
+ return this;
993
+ }
994
+ createOption(flags, description) {
995
+ return new Option(flags, description);
996
+ }
997
+ _callParseArg(target, value, previous, invalidArgumentMessage) {
998
+ try {
999
+ return target.parseArg(value, previous);
1000
+ } catch (err) {
1001
+ if (err.code === "commander.invalidArgument") {
1002
+ const message = `${invalidArgumentMessage} ${err.message}`;
1003
+ this.error(message, { exitCode: err.exitCode, code: err.code });
1004
+ }
1005
+ throw err;
1006
+ }
1007
+ }
1008
+ _registerOption(option) {
1009
+ const matchingOption = option.short && this._findOption(option.short) || option.long && this._findOption(option.long);
1010
+ if (matchingOption) {
1011
+ const matchingFlag = option.long && this._findOption(option.long) ? option.long : option.short;
1012
+ throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
1013
+ - already used by option '${matchingOption.flags}'`);
1014
+ }
1015
+ this.options.push(option);
1016
+ }
1017
+ _registerCommand(command) {
1018
+ const knownBy = (cmd) => {
1019
+ return [cmd.name()].concat(cmd.aliases());
1020
+ };
1021
+ const alreadyUsed = knownBy(command).find((name) => this._findCommand(name));
1022
+ if (alreadyUsed) {
1023
+ const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
1024
+ const newCmd = knownBy(command).join("|");
1025
+ throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`);
1026
+ }
1027
+ this.commands.push(command);
1028
+ }
1029
+ addOption(option) {
1030
+ this._registerOption(option);
1031
+ const oname = option.name();
1032
+ const name = option.attributeName();
1033
+ if (option.negate) {
1034
+ const positiveLongFlag = option.long.replace(/^--no-/, "--");
1035
+ if (!this._findOption(positiveLongFlag)) {
1036
+ this.setOptionValueWithSource(name, option.defaultValue === undefined ? true : option.defaultValue, "default");
1037
+ }
1038
+ } else if (option.defaultValue !== undefined) {
1039
+ this.setOptionValueWithSource(name, option.defaultValue, "default");
1040
+ }
1041
+ const handleOptionValue = (val, invalidValueMessage, valueSource) => {
1042
+ if (val == null && option.presetArg !== undefined) {
1043
+ val = option.presetArg;
1044
+ }
1045
+ const oldValue = this.getOptionValue(name);
1046
+ if (val !== null && option.parseArg) {
1047
+ val = this._callParseArg(option, val, oldValue, invalidValueMessage);
1048
+ } else if (val !== null && option.variadic) {
1049
+ val = option._concatValue(val, oldValue);
1050
+ }
1051
+ if (val == null) {
1052
+ if (option.negate) {
1053
+ val = false;
1054
+ } else if (option.isBoolean() || option.optional) {
1055
+ val = true;
1056
+ } else {
1057
+ val = "";
1058
+ }
1059
+ }
1060
+ this.setOptionValueWithSource(name, val, valueSource);
1061
+ };
1062
+ this.on("option:" + oname, (val) => {
1063
+ const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`;
1064
+ handleOptionValue(val, invalidValueMessage, "cli");
1065
+ });
1066
+ if (option.envVar) {
1067
+ this.on("optionEnv:" + oname, (val) => {
1068
+ const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;
1069
+ handleOptionValue(val, invalidValueMessage, "env");
1070
+ });
1071
+ }
1072
+ return this;
1073
+ }
1074
+ _optionEx(config, flags, description, fn, defaultValue) {
1075
+ if (typeof flags === "object" && flags instanceof Option) {
1076
+ throw new Error("To add an Option object use addOption() instead of option() or requiredOption()");
1077
+ }
1078
+ const option = this.createOption(flags, description);
1079
+ option.makeOptionMandatory(!!config.mandatory);
1080
+ if (typeof fn === "function") {
1081
+ option.default(defaultValue).argParser(fn);
1082
+ } else if (fn instanceof RegExp) {
1083
+ const regex = fn;
1084
+ fn = (val, def) => {
1085
+ const m = regex.exec(val);
1086
+ return m ? m[0] : def;
1087
+ };
1088
+ option.default(defaultValue).argParser(fn);
1089
+ } else {
1090
+ option.default(fn);
1091
+ }
1092
+ return this.addOption(option);
1093
+ }
1094
+ option(flags, description, parseArg, defaultValue) {
1095
+ return this._optionEx({}, flags, description, parseArg, defaultValue);
1096
+ }
1097
+ requiredOption(flags, description, parseArg, defaultValue) {
1098
+ return this._optionEx({ mandatory: true }, flags, description, parseArg, defaultValue);
1099
+ }
1100
+ combineFlagAndOptionalValue(combine = true) {
1101
+ this._combineFlagAndOptionalValue = !!combine;
1102
+ return this;
1103
+ }
1104
+ allowUnknownOption(allowUnknown = true) {
1105
+ this._allowUnknownOption = !!allowUnknown;
1106
+ return this;
1107
+ }
1108
+ allowExcessArguments(allowExcess = true) {
1109
+ this._allowExcessArguments = !!allowExcess;
1110
+ return this;
1111
+ }
1112
+ enablePositionalOptions(positional = true) {
1113
+ this._enablePositionalOptions = !!positional;
1114
+ return this;
1115
+ }
1116
+ passThroughOptions(passThrough = true) {
1117
+ this._passThroughOptions = !!passThrough;
1118
+ this._checkForBrokenPassThrough();
1119
+ return this;
1120
+ }
1121
+ _checkForBrokenPassThrough() {
1122
+ if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
1123
+ throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`);
1124
+ }
1125
+ }
1126
+ storeOptionsAsProperties(storeAsProperties = true) {
1127
+ if (this.options.length) {
1128
+ throw new Error("call .storeOptionsAsProperties() before adding options");
1129
+ }
1130
+ if (Object.keys(this._optionValues).length) {
1131
+ throw new Error("call .storeOptionsAsProperties() before setting option values");
1132
+ }
1133
+ this._storeOptionsAsProperties = !!storeAsProperties;
1134
+ return this;
1135
+ }
1136
+ getOptionValue(key) {
1137
+ if (this._storeOptionsAsProperties) {
1138
+ return this[key];
1139
+ }
1140
+ return this._optionValues[key];
1141
+ }
1142
+ setOptionValue(key, value) {
1143
+ return this.setOptionValueWithSource(key, value, undefined);
1144
+ }
1145
+ setOptionValueWithSource(key, value, source) {
1146
+ if (this._storeOptionsAsProperties) {
1147
+ this[key] = value;
1148
+ } else {
1149
+ this._optionValues[key] = value;
1150
+ }
1151
+ this._optionValueSources[key] = source;
1152
+ return this;
1153
+ }
1154
+ getOptionValueSource(key) {
1155
+ return this._optionValueSources[key];
1156
+ }
1157
+ getOptionValueSourceWithGlobals(key) {
1158
+ let source;
1159
+ this._getCommandAndAncestors().forEach((cmd) => {
1160
+ if (cmd.getOptionValueSource(key) !== undefined) {
1161
+ source = cmd.getOptionValueSource(key);
1162
+ }
1163
+ });
1164
+ return source;
1165
+ }
1166
+ _prepareUserArgs(argv, parseOptions) {
1167
+ if (argv !== undefined && !Array.isArray(argv)) {
1168
+ throw new Error("first parameter to parse must be array or undefined");
1169
+ }
1170
+ parseOptions = parseOptions || {};
1171
+ if (argv === undefined && parseOptions.from === undefined) {
1172
+ if (process2.versions?.electron) {
1173
+ parseOptions.from = "electron";
1174
+ }
1175
+ const execArgv = process2.execArgv ?? [];
1176
+ if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
1177
+ parseOptions.from = "eval";
1178
+ }
1179
+ }
1180
+ if (argv === undefined) {
1181
+ argv = process2.argv;
1182
+ }
1183
+ this.rawArgs = argv.slice();
1184
+ let userArgs;
1185
+ switch (parseOptions.from) {
1186
+ case undefined:
1187
+ case "node":
1188
+ this._scriptPath = argv[1];
1189
+ userArgs = argv.slice(2);
1190
+ break;
1191
+ case "electron":
1192
+ if (process2.defaultApp) {
1193
+ this._scriptPath = argv[1];
1194
+ userArgs = argv.slice(2);
1195
+ } else {
1196
+ userArgs = argv.slice(1);
1197
+ }
1198
+ break;
1199
+ case "user":
1200
+ userArgs = argv.slice(0);
1201
+ break;
1202
+ case "eval":
1203
+ userArgs = argv.slice(1);
1204
+ break;
1205
+ default:
1206
+ throw new Error(`unexpected parse option { from: '${parseOptions.from}' }`);
1207
+ }
1208
+ if (!this._name && this._scriptPath)
1209
+ this.nameFromFilename(this._scriptPath);
1210
+ this._name = this._name || "program";
1211
+ return userArgs;
1212
+ }
1213
+ parse(argv, parseOptions) {
1214
+ this._prepareForParse();
1215
+ const userArgs = this._prepareUserArgs(argv, parseOptions);
1216
+ this._parseCommand([], userArgs);
1217
+ return this;
1218
+ }
1219
+ async parseAsync(argv, parseOptions) {
1220
+ this._prepareForParse();
1221
+ const userArgs = this._prepareUserArgs(argv, parseOptions);
1222
+ await this._parseCommand([], userArgs);
1223
+ return this;
1224
+ }
1225
+ _prepareForParse() {
1226
+ if (this._savedState === null) {
1227
+ this.saveStateBeforeParse();
1228
+ } else {
1229
+ this.restoreStateBeforeParse();
1230
+ }
1231
+ }
1232
+ saveStateBeforeParse() {
1233
+ this._savedState = {
1234
+ _name: this._name,
1235
+ _optionValues: { ...this._optionValues },
1236
+ _optionValueSources: { ...this._optionValueSources }
1237
+ };
1238
+ }
1239
+ restoreStateBeforeParse() {
1240
+ if (this._storeOptionsAsProperties)
1241
+ throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
1242
+ - either make a new Command for each call to parse, or stop storing options as properties`);
1243
+ this._name = this._savedState._name;
1244
+ this._scriptPath = null;
1245
+ this.rawArgs = [];
1246
+ this._optionValues = { ...this._savedState._optionValues };
1247
+ this._optionValueSources = { ...this._savedState._optionValueSources };
1248
+ this.args = [];
1249
+ this.processedArgs = [];
1250
+ }
1251
+ _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
1252
+ if (fs.existsSync(executableFile))
1253
+ return;
1254
+ const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
1255
+ const executableMissing = `'${executableFile}' does not exist
1256
+ - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
1257
+ - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
1258
+ - ${executableDirMessage}`;
1259
+ throw new Error(executableMissing);
1260
+ }
1261
+ _executeSubCommand(subcommand, args) {
1262
+ args = args.slice();
1263
+ let launchWithNode = false;
1264
+ const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1265
+ function findFile(baseDir, baseName) {
1266
+ const localBin = path.resolve(baseDir, baseName);
1267
+ if (fs.existsSync(localBin))
1268
+ return localBin;
1269
+ if (sourceExt.includes(path.extname(baseName)))
1270
+ return;
1271
+ const foundExt = sourceExt.find((ext) => fs.existsSync(`${localBin}${ext}`));
1272
+ if (foundExt)
1273
+ return `${localBin}${foundExt}`;
1274
+ return;
1275
+ }
1276
+ this._checkForMissingMandatoryOptions();
1277
+ this._checkForConflictingOptions();
1278
+ let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
1279
+ let executableDir = this._executableDir || "";
1280
+ if (this._scriptPath) {
1281
+ let resolvedScriptPath;
1282
+ try {
1283
+ resolvedScriptPath = fs.realpathSync(this._scriptPath);
1284
+ } catch {
1285
+ resolvedScriptPath = this._scriptPath;
1286
+ }
1287
+ executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir);
1288
+ }
1289
+ if (executableDir) {
1290
+ let localFile = findFile(executableDir, executableFile);
1291
+ if (!localFile && !subcommand._executableFile && this._scriptPath) {
1292
+ const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath));
1293
+ if (legacyName !== this._name) {
1294
+ localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
1295
+ }
1296
+ }
1297
+ executableFile = localFile || executableFile;
1298
+ }
1299
+ launchWithNode = sourceExt.includes(path.extname(executableFile));
1300
+ let proc;
1301
+ if (process2.platform !== "win32") {
1302
+ if (launchWithNode) {
1303
+ args.unshift(executableFile);
1304
+ args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1305
+ proc = childProcess.spawn(process2.argv[0], args, { stdio: "inherit" });
1306
+ } else {
1307
+ proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
1308
+ }
1309
+ } else {
1310
+ this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
1311
+ args.unshift(executableFile);
1312
+ args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1313
+ proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
1314
+ }
1315
+ if (!proc.killed) {
1316
+ const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
1317
+ signals.forEach((signal) => {
1318
+ process2.on(signal, () => {
1319
+ if (proc.killed === false && proc.exitCode === null) {
1320
+ proc.kill(signal);
1321
+ }
1322
+ });
1323
+ });
1324
+ }
1325
+ const exitCallback = this._exitCallback;
1326
+ proc.on("close", (code) => {
1327
+ code = code ?? 1;
1328
+ if (!exitCallback) {
1329
+ process2.exit(code);
1330
+ } else {
1331
+ exitCallback(new CommanderError(code, "commander.executeSubCommandAsync", "(close)"));
1332
+ }
1333
+ });
1334
+ proc.on("error", (err) => {
1335
+ if (err.code === "ENOENT") {
1336
+ this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
1337
+ } else if (err.code === "EACCES") {
1338
+ throw new Error(`'${executableFile}' not executable`);
1339
+ }
1340
+ if (!exitCallback) {
1341
+ process2.exit(1);
1342
+ } else {
1343
+ const wrappedError = new CommanderError(1, "commander.executeSubCommandAsync", "(error)");
1344
+ wrappedError.nestedError = err;
1345
+ exitCallback(wrappedError);
1346
+ }
1347
+ });
1348
+ this.runningCommand = proc;
1349
+ }
1350
+ _dispatchSubcommand(commandName, operands, unknown) {
1351
+ const subCommand = this._findCommand(commandName);
1352
+ if (!subCommand)
1353
+ this.help({ error: true });
1354
+ subCommand._prepareForParse();
1355
+ let promiseChain;
1356
+ promiseChain = this._chainOrCallSubCommandHook(promiseChain, subCommand, "preSubcommand");
1357
+ promiseChain = this._chainOrCall(promiseChain, () => {
1358
+ if (subCommand._executableHandler) {
1359
+ this._executeSubCommand(subCommand, operands.concat(unknown));
1360
+ } else {
1361
+ return subCommand._parseCommand(operands, unknown);
1362
+ }
1363
+ });
1364
+ return promiseChain;
1365
+ }
1366
+ _dispatchHelpCommand(subcommandName) {
1367
+ if (!subcommandName) {
1368
+ this.help();
1369
+ }
1370
+ const subCommand = this._findCommand(subcommandName);
1371
+ if (subCommand && !subCommand._executableHandler) {
1372
+ subCommand.help();
1373
+ }
1374
+ return this._dispatchSubcommand(subcommandName, [], [this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? "--help"]);
1375
+ }
1376
+ _checkNumberOfArguments() {
1377
+ this.registeredArguments.forEach((arg, i) => {
1378
+ if (arg.required && this.args[i] == null) {
1379
+ this.missingArgument(arg.name());
1380
+ }
1381
+ });
1382
+ if (this.registeredArguments.length > 0 && this.registeredArguments[this.registeredArguments.length - 1].variadic) {
1383
+ return;
1384
+ }
1385
+ if (this.args.length > this.registeredArguments.length) {
1386
+ this._excessArguments(this.args);
1387
+ }
1388
+ }
1389
+ _processArguments() {
1390
+ const myParseArg = (argument, value, previous) => {
1391
+ let parsedValue = value;
1392
+ if (value !== null && argument.parseArg) {
1393
+ const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
1394
+ parsedValue = this._callParseArg(argument, value, previous, invalidValueMessage);
1395
+ }
1396
+ return parsedValue;
1397
+ };
1398
+ this._checkNumberOfArguments();
1399
+ const processedArgs = [];
1400
+ this.registeredArguments.forEach((declaredArg, index) => {
1401
+ let value = declaredArg.defaultValue;
1402
+ if (declaredArg.variadic) {
1403
+ if (index < this.args.length) {
1404
+ value = this.args.slice(index);
1405
+ if (declaredArg.parseArg) {
1406
+ value = value.reduce((processed, v) => {
1407
+ return myParseArg(declaredArg, v, processed);
1408
+ }, declaredArg.defaultValue);
1409
+ }
1410
+ } else if (value === undefined) {
1411
+ value = [];
1412
+ }
1413
+ } else if (index < this.args.length) {
1414
+ value = this.args[index];
1415
+ if (declaredArg.parseArg) {
1416
+ value = myParseArg(declaredArg, value, declaredArg.defaultValue);
1417
+ }
1418
+ }
1419
+ processedArgs[index] = value;
1420
+ });
1421
+ this.processedArgs = processedArgs;
1422
+ }
1423
+ _chainOrCall(promise, fn) {
1424
+ if (promise && promise.then && typeof promise.then === "function") {
1425
+ return promise.then(() => fn());
1426
+ }
1427
+ return fn();
1428
+ }
1429
+ _chainOrCallHooks(promise, event) {
1430
+ let result = promise;
1431
+ const hooks = [];
1432
+ this._getCommandAndAncestors().reverse().filter((cmd) => cmd._lifeCycleHooks[event] !== undefined).forEach((hookedCommand) => {
1433
+ hookedCommand._lifeCycleHooks[event].forEach((callback) => {
1434
+ hooks.push({ hookedCommand, callback });
1435
+ });
1436
+ });
1437
+ if (event === "postAction") {
1438
+ hooks.reverse();
1439
+ }
1440
+ hooks.forEach((hookDetail) => {
1441
+ result = this._chainOrCall(result, () => {
1442
+ return hookDetail.callback(hookDetail.hookedCommand, this);
1443
+ });
1444
+ });
1445
+ return result;
1446
+ }
1447
+ _chainOrCallSubCommandHook(promise, subCommand, event) {
1448
+ let result = promise;
1449
+ if (this._lifeCycleHooks[event] !== undefined) {
1450
+ this._lifeCycleHooks[event].forEach((hook) => {
1451
+ result = this._chainOrCall(result, () => {
1452
+ return hook(this, subCommand);
1453
+ });
1454
+ });
1455
+ }
1456
+ return result;
1457
+ }
1458
+ _parseCommand(operands, unknown) {
1459
+ const parsed = this.parseOptions(unknown);
1460
+ this._parseOptionsEnv();
1461
+ this._parseOptionsImplied();
1462
+ operands = operands.concat(parsed.operands);
1463
+ unknown = parsed.unknown;
1464
+ this.args = operands.concat(unknown);
1465
+ if (operands && this._findCommand(operands[0])) {
1466
+ return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
1467
+ }
1468
+ if (this._getHelpCommand() && operands[0] === this._getHelpCommand().name()) {
1469
+ return this._dispatchHelpCommand(operands[1]);
1470
+ }
1471
+ if (this._defaultCommandName) {
1472
+ this._outputHelpIfRequested(unknown);
1473
+ return this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
1474
+ }
1475
+ if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
1476
+ this.help({ error: true });
1477
+ }
1478
+ this._outputHelpIfRequested(parsed.unknown);
1479
+ this._checkForMissingMandatoryOptions();
1480
+ this._checkForConflictingOptions();
1481
+ const checkForUnknownOptions = () => {
1482
+ if (parsed.unknown.length > 0) {
1483
+ this.unknownOption(parsed.unknown[0]);
1484
+ }
1485
+ };
1486
+ const commandEvent = `command:${this.name()}`;
1487
+ if (this._actionHandler) {
1488
+ checkForUnknownOptions();
1489
+ this._processArguments();
1490
+ let promiseChain;
1491
+ promiseChain = this._chainOrCallHooks(promiseChain, "preAction");
1492
+ promiseChain = this._chainOrCall(promiseChain, () => this._actionHandler(this.processedArgs));
1493
+ if (this.parent) {
1494
+ promiseChain = this._chainOrCall(promiseChain, () => {
1495
+ this.parent.emit(commandEvent, operands, unknown);
1496
+ });
1497
+ }
1498
+ promiseChain = this._chainOrCallHooks(promiseChain, "postAction");
1499
+ return promiseChain;
1500
+ }
1501
+ if (this.parent && this.parent.listenerCount(commandEvent)) {
1502
+ checkForUnknownOptions();
1503
+ this._processArguments();
1504
+ this.parent.emit(commandEvent, operands, unknown);
1505
+ } else if (operands.length) {
1506
+ if (this._findCommand("*")) {
1507
+ return this._dispatchSubcommand("*", operands, unknown);
1508
+ }
1509
+ if (this.listenerCount("command:*")) {
1510
+ this.emit("command:*", operands, unknown);
1511
+ } else if (this.commands.length) {
1512
+ this.unknownCommand();
1513
+ } else {
1514
+ checkForUnknownOptions();
1515
+ this._processArguments();
1516
+ }
1517
+ } else if (this.commands.length) {
1518
+ checkForUnknownOptions();
1519
+ this.help({ error: true });
1520
+ } else {
1521
+ checkForUnknownOptions();
1522
+ this._processArguments();
1523
+ }
1524
+ }
1525
+ _findCommand(name) {
1526
+ if (!name)
1527
+ return;
1528
+ return this.commands.find((cmd) => cmd._name === name || cmd._aliases.includes(name));
1529
+ }
1530
+ _findOption(arg) {
1531
+ return this.options.find((option) => option.is(arg));
1532
+ }
1533
+ _checkForMissingMandatoryOptions() {
1534
+ this._getCommandAndAncestors().forEach((cmd) => {
1535
+ cmd.options.forEach((anOption) => {
1536
+ if (anOption.mandatory && cmd.getOptionValue(anOption.attributeName()) === undefined) {
1537
+ cmd.missingMandatoryOptionValue(anOption);
1538
+ }
1539
+ });
1540
+ });
1541
+ }
1542
+ _checkForConflictingLocalOptions() {
1543
+ const definedNonDefaultOptions = this.options.filter((option) => {
1544
+ const optionKey = option.attributeName();
1545
+ if (this.getOptionValue(optionKey) === undefined) {
1546
+ return false;
1547
+ }
1548
+ return this.getOptionValueSource(optionKey) !== "default";
1549
+ });
1550
+ const optionsWithConflicting = definedNonDefaultOptions.filter((option) => option.conflictsWith.length > 0);
1551
+ optionsWithConflicting.forEach((option) => {
1552
+ const conflictingAndDefined = definedNonDefaultOptions.find((defined) => option.conflictsWith.includes(defined.attributeName()));
1553
+ if (conflictingAndDefined) {
1554
+ this._conflictingOption(option, conflictingAndDefined);
1555
+ }
1556
+ });
1557
+ }
1558
+ _checkForConflictingOptions() {
1559
+ this._getCommandAndAncestors().forEach((cmd) => {
1560
+ cmd._checkForConflictingLocalOptions();
1561
+ });
1562
+ }
1563
+ parseOptions(argv) {
1564
+ const operands = [];
1565
+ const unknown = [];
1566
+ let dest = operands;
1567
+ const args = argv.slice();
1568
+ function maybeOption(arg) {
1569
+ return arg.length > 1 && arg[0] === "-";
1570
+ }
1571
+ let activeVariadicOption = null;
1572
+ while (args.length) {
1573
+ const arg = args.shift();
1574
+ if (arg === "--") {
1575
+ if (dest === unknown)
1576
+ dest.push(arg);
1577
+ dest.push(...args);
1578
+ break;
1579
+ }
1580
+ if (activeVariadicOption && !maybeOption(arg)) {
1581
+ this.emit(`option:${activeVariadicOption.name()}`, arg);
1582
+ continue;
1583
+ }
1584
+ activeVariadicOption = null;
1585
+ if (maybeOption(arg)) {
1586
+ const option = this._findOption(arg);
1587
+ if (option) {
1588
+ if (option.required) {
1589
+ const value = args.shift();
1590
+ if (value === undefined)
1591
+ this.optionMissingArgument(option);
1592
+ this.emit(`option:${option.name()}`, value);
1593
+ } else if (option.optional) {
1594
+ let value = null;
1595
+ if (args.length > 0 && !maybeOption(args[0])) {
1596
+ value = args.shift();
1597
+ }
1598
+ this.emit(`option:${option.name()}`, value);
1599
+ } else {
1600
+ this.emit(`option:${option.name()}`);
1601
+ }
1602
+ activeVariadicOption = option.variadic ? option : null;
1603
+ continue;
1604
+ }
1605
+ }
1606
+ if (arg.length > 2 && arg[0] === "-" && arg[1] !== "-") {
1607
+ const option = this._findOption(`-${arg[1]}`);
1608
+ if (option) {
1609
+ if (option.required || option.optional && this._combineFlagAndOptionalValue) {
1610
+ this.emit(`option:${option.name()}`, arg.slice(2));
1611
+ } else {
1612
+ this.emit(`option:${option.name()}`);
1613
+ args.unshift(`-${arg.slice(2)}`);
1614
+ }
1615
+ continue;
1616
+ }
1617
+ }
1618
+ if (/^--[^=]+=/.test(arg)) {
1619
+ const index = arg.indexOf("=");
1620
+ const option = this._findOption(arg.slice(0, index));
1621
+ if (option && (option.required || option.optional)) {
1622
+ this.emit(`option:${option.name()}`, arg.slice(index + 1));
1623
+ continue;
1624
+ }
1625
+ }
1626
+ if (maybeOption(arg)) {
1627
+ dest = unknown;
1628
+ }
1629
+ if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
1630
+ if (this._findCommand(arg)) {
1631
+ operands.push(arg);
1632
+ if (args.length > 0)
1633
+ unknown.push(...args);
1634
+ break;
1635
+ } else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
1636
+ operands.push(arg);
1637
+ if (args.length > 0)
1638
+ operands.push(...args);
1639
+ break;
1640
+ } else if (this._defaultCommandName) {
1641
+ unknown.push(arg);
1642
+ if (args.length > 0)
1643
+ unknown.push(...args);
1644
+ break;
1645
+ }
1646
+ }
1647
+ if (this._passThroughOptions) {
1648
+ dest.push(arg);
1649
+ if (args.length > 0)
1650
+ dest.push(...args);
1651
+ break;
1652
+ }
1653
+ dest.push(arg);
1654
+ }
1655
+ return { operands, unknown };
1656
+ }
1657
+ opts() {
1658
+ if (this._storeOptionsAsProperties) {
1659
+ const result = {};
1660
+ const len = this.options.length;
1661
+ for (let i = 0;i < len; i++) {
1662
+ const key = this.options[i].attributeName();
1663
+ result[key] = key === this._versionOptionName ? this._version : this[key];
1664
+ }
1665
+ return result;
1666
+ }
1667
+ return this._optionValues;
1668
+ }
1669
+ optsWithGlobals() {
1670
+ return this._getCommandAndAncestors().reduce((combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()), {});
1671
+ }
1672
+ error(message, errorOptions) {
1673
+ this._outputConfiguration.outputError(`${message}
1674
+ `, this._outputConfiguration.writeErr);
1675
+ if (typeof this._showHelpAfterError === "string") {
1676
+ this._outputConfiguration.writeErr(`${this._showHelpAfterError}
1677
+ `);
1678
+ } else if (this._showHelpAfterError) {
1679
+ this._outputConfiguration.writeErr(`
1680
+ `);
1681
+ this.outputHelp({ error: true });
1682
+ }
1683
+ const config = errorOptions || {};
1684
+ const exitCode = config.exitCode || 1;
1685
+ const code = config.code || "commander.error";
1686
+ this._exit(exitCode, code, message);
1687
+ }
1688
+ _parseOptionsEnv() {
1689
+ this.options.forEach((option) => {
1690
+ if (option.envVar && option.envVar in process2.env) {
1691
+ const optionKey = option.attributeName();
1692
+ if (this.getOptionValue(optionKey) === undefined || ["default", "config", "env"].includes(this.getOptionValueSource(optionKey))) {
1693
+ if (option.required || option.optional) {
1694
+ this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
1695
+ } else {
1696
+ this.emit(`optionEnv:${option.name()}`);
1697
+ }
1698
+ }
1699
+ }
1700
+ });
1701
+ }
1702
+ _parseOptionsImplied() {
1703
+ const dualHelper = new DualOptions(this.options);
1704
+ const hasCustomOptionValue = (optionKey) => {
1705
+ return this.getOptionValue(optionKey) !== undefined && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
1706
+ };
1707
+ this.options.filter((option) => option.implied !== undefined && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(this.getOptionValue(option.attributeName()), option)).forEach((option) => {
1708
+ Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
1709
+ this.setOptionValueWithSource(impliedKey, option.implied[impliedKey], "implied");
1710
+ });
1711
+ });
1712
+ }
1713
+ missingArgument(name) {
1714
+ const message = `error: missing required argument '${name}'`;
1715
+ this.error(message, { code: "commander.missingArgument" });
1716
+ }
1717
+ optionMissingArgument(option) {
1718
+ const message = `error: option '${option.flags}' argument missing`;
1719
+ this.error(message, { code: "commander.optionMissingArgument" });
1720
+ }
1721
+ missingMandatoryOptionValue(option) {
1722
+ const message = `error: required option '${option.flags}' not specified`;
1723
+ this.error(message, { code: "commander.missingMandatoryOptionValue" });
1724
+ }
1725
+ _conflictingOption(option, conflictingOption) {
1726
+ const findBestOptionFromValue = (option2) => {
1727
+ const optionKey = option2.attributeName();
1728
+ const optionValue = this.getOptionValue(optionKey);
1729
+ const negativeOption = this.options.find((target) => target.negate && optionKey === target.attributeName());
1730
+ const positiveOption = this.options.find((target) => !target.negate && optionKey === target.attributeName());
1731
+ if (negativeOption && (negativeOption.presetArg === undefined && optionValue === false || negativeOption.presetArg !== undefined && optionValue === negativeOption.presetArg)) {
1732
+ return negativeOption;
1733
+ }
1734
+ return positiveOption || option2;
1735
+ };
1736
+ const getErrorMessage = (option2) => {
1737
+ const bestOption = findBestOptionFromValue(option2);
1738
+ const optionKey = bestOption.attributeName();
1739
+ const source = this.getOptionValueSource(optionKey);
1740
+ if (source === "env") {
1741
+ return `environment variable '${bestOption.envVar}'`;
1742
+ }
1743
+ return `option '${bestOption.flags}'`;
1744
+ };
1745
+ const message = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
1746
+ this.error(message, { code: "commander.conflictingOption" });
1747
+ }
1748
+ unknownOption(flag) {
1749
+ if (this._allowUnknownOption)
1750
+ return;
1751
+ let suggestion = "";
1752
+ if (flag.startsWith("--") && this._showSuggestionAfterError) {
1753
+ let candidateFlags = [];
1754
+ let command = this;
1755
+ do {
1756
+ const moreFlags = command.createHelp().visibleOptions(command).filter((option) => option.long).map((option) => option.long);
1757
+ candidateFlags = candidateFlags.concat(moreFlags);
1758
+ command = command.parent;
1759
+ } while (command && !command._enablePositionalOptions);
1760
+ suggestion = suggestSimilar(flag, candidateFlags);
1761
+ }
1762
+ const message = `error: unknown option '${flag}'${suggestion}`;
1763
+ this.error(message, { code: "commander.unknownOption" });
1764
+ }
1765
+ _excessArguments(receivedArgs) {
1766
+ if (this._allowExcessArguments)
1767
+ return;
1768
+ const expected = this.registeredArguments.length;
1769
+ const s = expected === 1 ? "" : "s";
1770
+ const forSubcommand = this.parent ? ` for '${this.name()}'` : "";
1771
+ const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
1772
+ this.error(message, { code: "commander.excessArguments" });
1773
+ }
1774
+ unknownCommand() {
1775
+ const unknownName = this.args[0];
1776
+ let suggestion = "";
1777
+ if (this._showSuggestionAfterError) {
1778
+ const candidateNames = [];
1779
+ this.createHelp().visibleCommands(this).forEach((command) => {
1780
+ candidateNames.push(command.name());
1781
+ if (command.alias())
1782
+ candidateNames.push(command.alias());
1783
+ });
1784
+ suggestion = suggestSimilar(unknownName, candidateNames);
1785
+ }
1786
+ const message = `error: unknown command '${unknownName}'${suggestion}`;
1787
+ this.error(message, { code: "commander.unknownCommand" });
1788
+ }
1789
+ version(str, flags, description) {
1790
+ if (str === undefined)
1791
+ return this._version;
1792
+ this._version = str;
1793
+ flags = flags || "-V, --version";
1794
+ description = description || "output the version number";
1795
+ const versionOption = this.createOption(flags, description);
1796
+ this._versionOptionName = versionOption.attributeName();
1797
+ this._registerOption(versionOption);
1798
+ this.on("option:" + versionOption.name(), () => {
1799
+ this._outputConfiguration.writeOut(`${str}
1800
+ `);
1801
+ this._exit(0, "commander.version", str);
1802
+ });
1803
+ return this;
1804
+ }
1805
+ description(str, argsDescription) {
1806
+ if (str === undefined && argsDescription === undefined)
1807
+ return this._description;
1808
+ this._description = str;
1809
+ if (argsDescription) {
1810
+ this._argsDescription = argsDescription;
1811
+ }
1812
+ return this;
1813
+ }
1814
+ summary(str) {
1815
+ if (str === undefined)
1816
+ return this._summary;
1817
+ this._summary = str;
1818
+ return this;
1819
+ }
1820
+ alias(alias) {
1821
+ if (alias === undefined)
1822
+ return this._aliases[0];
1823
+ let command = this;
1824
+ if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
1825
+ command = this.commands[this.commands.length - 1];
1826
+ }
1827
+ if (alias === command._name)
1828
+ throw new Error("Command alias can't be the same as its name");
1829
+ const matchingCommand = this.parent?._findCommand(alias);
1830
+ if (matchingCommand) {
1831
+ const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
1832
+ throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`);
1833
+ }
1834
+ command._aliases.push(alias);
1835
+ return this;
1836
+ }
1837
+ aliases(aliases) {
1838
+ if (aliases === undefined)
1839
+ return this._aliases;
1840
+ aliases.forEach((alias) => this.alias(alias));
1841
+ return this;
1842
+ }
1843
+ usage(str) {
1844
+ if (str === undefined) {
1845
+ if (this._usage)
1846
+ return this._usage;
1847
+ const args = this.registeredArguments.map((arg) => {
1848
+ return humanReadableArgName(arg);
1849
+ });
1850
+ return [].concat(this.options.length || this._helpOption !== null ? "[options]" : [], this.commands.length ? "[command]" : [], this.registeredArguments.length ? args : []).join(" ");
1851
+ }
1852
+ this._usage = str;
1853
+ return this;
1854
+ }
1855
+ name(str) {
1856
+ if (str === undefined)
1857
+ return this._name;
1858
+ this._name = str;
1859
+ return this;
1860
+ }
1861
+ nameFromFilename(filename) {
1862
+ this._name = path.basename(filename, path.extname(filename));
1863
+ return this;
1864
+ }
1865
+ executableDir(path2) {
1866
+ if (path2 === undefined)
1867
+ return this._executableDir;
1868
+ this._executableDir = path2;
1869
+ return this;
1870
+ }
1871
+ helpInformation(contextOptions) {
1872
+ const helper = this.createHelp();
1873
+ const context = this._getOutputContext(contextOptions);
1874
+ helper.prepareContext({
1875
+ error: context.error,
1876
+ helpWidth: context.helpWidth,
1877
+ outputHasColors: context.hasColors
1878
+ });
1879
+ const text = helper.formatHelp(this, helper);
1880
+ if (context.hasColors)
1881
+ return text;
1882
+ return this._outputConfiguration.stripColor(text);
1883
+ }
1884
+ _getOutputContext(contextOptions) {
1885
+ contextOptions = contextOptions || {};
1886
+ const error = !!contextOptions.error;
1887
+ let baseWrite;
1888
+ let hasColors;
1889
+ let helpWidth;
1890
+ if (error) {
1891
+ baseWrite = (str) => this._outputConfiguration.writeErr(str);
1892
+ hasColors = this._outputConfiguration.getErrHasColors();
1893
+ helpWidth = this._outputConfiguration.getErrHelpWidth();
1894
+ } else {
1895
+ baseWrite = (str) => this._outputConfiguration.writeOut(str);
1896
+ hasColors = this._outputConfiguration.getOutHasColors();
1897
+ helpWidth = this._outputConfiguration.getOutHelpWidth();
1898
+ }
1899
+ const write = (str) => {
1900
+ if (!hasColors)
1901
+ str = this._outputConfiguration.stripColor(str);
1902
+ return baseWrite(str);
1903
+ };
1904
+ return { error, write, hasColors, helpWidth };
1905
+ }
1906
+ outputHelp(contextOptions) {
1907
+ let deprecatedCallback;
1908
+ if (typeof contextOptions === "function") {
1909
+ deprecatedCallback = contextOptions;
1910
+ contextOptions = undefined;
1911
+ }
1912
+ const outputContext = this._getOutputContext(contextOptions);
1913
+ const eventContext = {
1914
+ error: outputContext.error,
1915
+ write: outputContext.write,
1916
+ command: this
1917
+ };
1918
+ this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
1919
+ this.emit("beforeHelp", eventContext);
1920
+ let helpInformation = this.helpInformation({ error: outputContext.error });
1921
+ if (deprecatedCallback) {
1922
+ helpInformation = deprecatedCallback(helpInformation);
1923
+ if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
1924
+ throw new Error("outputHelp callback must return a string or a Buffer");
1925
+ }
1926
+ }
1927
+ outputContext.write(helpInformation);
1928
+ if (this._getHelpOption()?.long) {
1929
+ this.emit(this._getHelpOption().long);
1930
+ }
1931
+ this.emit("afterHelp", eventContext);
1932
+ this._getCommandAndAncestors().forEach((command) => command.emit("afterAllHelp", eventContext));
1933
+ }
1934
+ helpOption(flags, description) {
1935
+ if (typeof flags === "boolean") {
1936
+ if (flags) {
1937
+ this._helpOption = this._helpOption ?? undefined;
1938
+ } else {
1939
+ this._helpOption = null;
1940
+ }
1941
+ return this;
1942
+ }
1943
+ flags = flags ?? "-h, --help";
1944
+ description = description ?? "display help for command";
1945
+ this._helpOption = this.createOption(flags, description);
1946
+ return this;
1947
+ }
1948
+ _getHelpOption() {
1949
+ if (this._helpOption === undefined) {
1950
+ this.helpOption(undefined, undefined);
1951
+ }
1952
+ return this._helpOption;
1953
+ }
1954
+ addHelpOption(option) {
1955
+ this._helpOption = option;
1956
+ return this;
1957
+ }
1958
+ help(contextOptions) {
1959
+ this.outputHelp(contextOptions);
1960
+ let exitCode = Number(process2.exitCode ?? 0);
1961
+ if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
1962
+ exitCode = 1;
1963
+ }
1964
+ this._exit(exitCode, "commander.help", "(outputHelp)");
1965
+ }
1966
+ addHelpText(position, text) {
1967
+ const allowedValues = ["beforeAll", "before", "after", "afterAll"];
1968
+ if (!allowedValues.includes(position)) {
1969
+ throw new Error(`Unexpected value for position to addHelpText.
1970
+ Expecting one of '${allowedValues.join("', '")}'`);
1971
+ }
1972
+ const helpEvent = `${position}Help`;
1973
+ this.on(helpEvent, (context) => {
1974
+ let helpStr;
1975
+ if (typeof text === "function") {
1976
+ helpStr = text({ error: context.error, command: context.command });
1977
+ } else {
1978
+ helpStr = text;
1979
+ }
1980
+ if (helpStr) {
1981
+ context.write(`${helpStr}
1982
+ `);
1983
+ }
1984
+ });
1985
+ return this;
1986
+ }
1987
+ _outputHelpIfRequested(args) {
1988
+ const helpOption = this._getHelpOption();
1989
+ const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
1990
+ if (helpRequested) {
1991
+ this.outputHelp();
1992
+ this._exit(0, "commander.helpDisplayed", "(outputHelp)");
1993
+ }
1994
+ }
1995
+ }
1996
+ function incrementNodeInspectorPort(args) {
1997
+ return args.map((arg) => {
1998
+ if (!arg.startsWith("--inspect")) {
1999
+ return arg;
2000
+ }
2001
+ let debugOption;
2002
+ let debugHost = "127.0.0.1";
2003
+ let debugPort = "9229";
2004
+ let match;
2005
+ if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
2006
+ debugOption = match[1];
2007
+ } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
2008
+ debugOption = match[1];
2009
+ if (/^\d+$/.test(match[3])) {
2010
+ debugPort = match[3];
2011
+ } else {
2012
+ debugHost = match[3];
2013
+ }
2014
+ } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
2015
+ debugOption = match[1];
2016
+ debugHost = match[3];
2017
+ debugPort = match[4];
2018
+ }
2019
+ if (debugOption && debugPort !== "0") {
2020
+ return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
2021
+ }
2022
+ return arg;
2023
+ });
2024
+ }
2025
+ function useColor() {
2026
+ if (process2.env.NO_COLOR || process2.env.FORCE_COLOR === "0" || process2.env.FORCE_COLOR === "false")
2027
+ return false;
2028
+ if (process2.env.FORCE_COLOR || process2.env.CLICOLOR_FORCE !== undefined)
2029
+ return true;
2030
+ return;
2031
+ }
2032
+ exports.Command = Command;
2033
+ exports.useColor = useColor;
2034
+ });
2035
+
2036
+ // ../../node_modules/commander/index.js
2037
+ var require_commander = __commonJS((exports) => {
2038
+ var { Argument } = require_argument();
2039
+ var { Command } = require_command();
2040
+ var { CommanderError, InvalidArgumentError } = require_error();
2041
+ var { Help } = require_help();
2042
+ var { Option } = require_option();
2043
+ exports.program = new Command;
2044
+ exports.createCommand = (name) => new Command(name);
2045
+ exports.createOption = (flags, description) => new Option(flags, description);
2046
+ exports.createArgument = (name, description) => new Argument(name, description);
2047
+ exports.Command = Command;
2048
+ exports.Option = Option;
2049
+ exports.Argument = Argument;
2050
+ exports.Help = Help;
2051
+ exports.CommanderError = CommanderError;
2052
+ exports.InvalidArgumentError = InvalidArgumentError;
2053
+ exports.InvalidOptionArgumentError = InvalidArgumentError;
2054
+ });
2055
+
2056
+ // ../../node_modules/commander/esm.mjs
2057
+ var import__ = __toESM(require_commander(), 1);
2058
+ var {
2059
+ program,
2060
+ createCommand,
2061
+ createArgument,
2062
+ createOption,
2063
+ CommanderError,
2064
+ InvalidArgumentError,
2065
+ InvalidOptionArgumentError,
2066
+ Command,
2067
+ Argument,
2068
+ Option,
2069
+ Help
2070
+ } = import__.default;
2071
+
2072
+ // src/index.ts
2073
+ import { readFileSync } from "node:fs";
2074
+ import { fileURLToPath } from "node:url";
2075
+ import { dirname, join } from "node:path";
2076
+
2077
+ // src/config.ts
2078
+ import fs from "node:fs";
2079
+ import os from "node:os";
2080
+ import path from "node:path";
2081
+ var ENV_API_URL = process.env.THOUGHTFUL_API_URL;
2082
+ var ENV_NO_COLOR = process.env.THOUGHTFUL_NO_COLOR === "1" || process.env.THOUGHTFUL_NO_COLOR === "true";
2083
+ var ENV_DEBUG = process.env.THOUGHTFUL_DEBUG === "1" || process.env.THOUGHTFUL_DEBUG === "true";
2084
+ var PRODUCTION_API_URL = "https://www.thoughtful.app";
2085
+ var DEVELOPMENT_API_URL = "http://localhost:3000";
2086
+ var environmentOverride = null;
2087
+ function setEnvironmentOverride(env) {
2088
+ environmentOverride = env;
2089
+ }
2090
+ function getDefaultApiUrl() {
2091
+ if (environmentOverride === "dev") {
2092
+ return DEVELOPMENT_API_URL;
2093
+ }
2094
+ if (environmentOverride === "prod") {
2095
+ return PRODUCTION_API_URL;
2096
+ }
2097
+ if (ENV_API_URL) {
2098
+ return ENV_API_URL;
2099
+ }
2100
+ return PRODUCTION_API_URL;
2101
+ }
2102
+ function getXdgConfigHome() {
2103
+ return process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
2104
+ }
2105
+ var LEGACY_CONFIG_DIR = path.join(os.homedir(), ".thoughtful");
2106
+ var LEGACY_CONFIG_FILE = path.join(LEGACY_CONFIG_DIR, "config.json");
2107
+ var CONFIG_DIR = path.join(getXdgConfigHome(), "thoughtful");
2108
+ var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
2109
+ var env = {
2110
+ noColor: ENV_NO_COLOR,
2111
+ debug: ENV_DEBUG
2112
+ };
2113
+ function migrateLegacyConfig() {
2114
+ if (fs.existsSync(CONFIG_FILE)) {
2115
+ return;
2116
+ }
2117
+ if (fs.existsSync(LEGACY_CONFIG_FILE)) {
2118
+ try {
2119
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
2120
+ fs.copyFileSync(LEGACY_CONFIG_FILE, CONFIG_FILE);
2121
+ fs.chmodSync(CONFIG_FILE, 384);
2122
+ if (env.debug) {
2123
+ console.error(`[DEBUG] Migrated config from ${LEGACY_CONFIG_FILE} to ${CONFIG_FILE}`);
2124
+ }
2125
+ } catch (error) {
2126
+ if (env.debug) {
2127
+ console.error(`[DEBUG] Failed to migrate legacy config: ${error}`);
2128
+ }
2129
+ }
2130
+ }
2131
+ }
2132
+ function ensureConfigDir() {
2133
+ migrateLegacyConfig();
2134
+ if (!fs.existsSync(CONFIG_DIR)) {
2135
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
2136
+ }
2137
+ }
2138
+ function loadConfig() {
2139
+ ensureConfigDir();
2140
+ if (!fs.existsSync(CONFIG_FILE)) {
2141
+ return {
2142
+ apiUrl: getDefaultApiUrl()
2143
+ };
2144
+ }
2145
+ try {
2146
+ const content = fs.readFileSync(CONFIG_FILE, "utf-8");
2147
+ const fileConfig = JSON.parse(content);
2148
+ const config = {
2149
+ apiUrl: PRODUCTION_API_URL,
2150
+ ...fileConfig
2151
+ };
2152
+ if (environmentOverride || ENV_API_URL) {
2153
+ config.apiUrl = getDefaultApiUrl();
2154
+ }
2155
+ return config;
2156
+ } catch {
2157
+ return {
2158
+ apiUrl: getDefaultApiUrl()
2159
+ };
2160
+ }
2161
+ }
2162
+ function saveConfig(config) {
2163
+ ensureConfigDir();
2164
+ let fileApiUrl;
2165
+ if (fs.existsSync(CONFIG_FILE)) {
2166
+ try {
2167
+ const content = fs.readFileSync(CONFIG_FILE, "utf-8");
2168
+ const fileConfig = JSON.parse(content);
2169
+ fileApiUrl = fileConfig.apiUrl;
2170
+ } catch {}
2171
+ }
2172
+ const configToSave = { ...config };
2173
+ if ((environmentOverride || ENV_API_URL) && fileApiUrl) {
2174
+ const overrideUrl = getDefaultApiUrl();
2175
+ if (config.apiUrl === overrideUrl) {
2176
+ configToSave.apiUrl = fileApiUrl;
2177
+ }
2178
+ }
2179
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(configToSave, null, 2), {
2180
+ mode: 384
2181
+ });
2182
+ }
2183
+ function updateConfig(updates) {
2184
+ const config = loadConfig();
2185
+ const newConfig = { ...config, ...updates };
2186
+ saveConfig(newConfig);
2187
+ return newConfig;
2188
+ }
2189
+ function clearAuth() {
2190
+ const config = loadConfig();
2191
+ const newConfig = {
2192
+ apiUrl: config.apiUrl
2193
+ };
2194
+ saveConfig(newConfig);
2195
+ }
2196
+ function isLoggedIn() {
2197
+ const config = loadConfig();
2198
+ return Boolean(config.accessToken);
2199
+ }
2200
+
2201
+ // ../../node_modules/chalk/source/vendor/ansi-styles/index.js
2202
+ var ANSI_BACKGROUND_OFFSET = 10;
2203
+ var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
2204
+ var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
2205
+ var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
2206
+ var styles = {
2207
+ modifier: {
2208
+ reset: [0, 0],
2209
+ bold: [1, 22],
2210
+ dim: [2, 22],
2211
+ italic: [3, 23],
2212
+ underline: [4, 24],
2213
+ overline: [53, 55],
2214
+ inverse: [7, 27],
2215
+ hidden: [8, 28],
2216
+ strikethrough: [9, 29]
2217
+ },
2218
+ color: {
2219
+ black: [30, 39],
2220
+ red: [31, 39],
2221
+ green: [32, 39],
2222
+ yellow: [33, 39],
2223
+ blue: [34, 39],
2224
+ magenta: [35, 39],
2225
+ cyan: [36, 39],
2226
+ white: [37, 39],
2227
+ blackBright: [90, 39],
2228
+ gray: [90, 39],
2229
+ grey: [90, 39],
2230
+ redBright: [91, 39],
2231
+ greenBright: [92, 39],
2232
+ yellowBright: [93, 39],
2233
+ blueBright: [94, 39],
2234
+ magentaBright: [95, 39],
2235
+ cyanBright: [96, 39],
2236
+ whiteBright: [97, 39]
2237
+ },
2238
+ bgColor: {
2239
+ bgBlack: [40, 49],
2240
+ bgRed: [41, 49],
2241
+ bgGreen: [42, 49],
2242
+ bgYellow: [43, 49],
2243
+ bgBlue: [44, 49],
2244
+ bgMagenta: [45, 49],
2245
+ bgCyan: [46, 49],
2246
+ bgWhite: [47, 49],
2247
+ bgBlackBright: [100, 49],
2248
+ bgGray: [100, 49],
2249
+ bgGrey: [100, 49],
2250
+ bgRedBright: [101, 49],
2251
+ bgGreenBright: [102, 49],
2252
+ bgYellowBright: [103, 49],
2253
+ bgBlueBright: [104, 49],
2254
+ bgMagentaBright: [105, 49],
2255
+ bgCyanBright: [106, 49],
2256
+ bgWhiteBright: [107, 49]
2257
+ }
2258
+ };
2259
+ var modifierNames = Object.keys(styles.modifier);
2260
+ var foregroundColorNames = Object.keys(styles.color);
2261
+ var backgroundColorNames = Object.keys(styles.bgColor);
2262
+ var colorNames = [...foregroundColorNames, ...backgroundColorNames];
2263
+ function assembleStyles() {
2264
+ const codes = new Map;
2265
+ for (const [groupName, group] of Object.entries(styles)) {
2266
+ for (const [styleName, style] of Object.entries(group)) {
2267
+ styles[styleName] = {
2268
+ open: `\x1B[${style[0]}m`,
2269
+ close: `\x1B[${style[1]}m`
2270
+ };
2271
+ group[styleName] = styles[styleName];
2272
+ codes.set(style[0], style[1]);
2273
+ }
2274
+ Object.defineProperty(styles, groupName, {
2275
+ value: group,
2276
+ enumerable: false
2277
+ });
2278
+ }
2279
+ Object.defineProperty(styles, "codes", {
2280
+ value: codes,
2281
+ enumerable: false
2282
+ });
2283
+ styles.color.close = "\x1B[39m";
2284
+ styles.bgColor.close = "\x1B[49m";
2285
+ styles.color.ansi = wrapAnsi16();
2286
+ styles.color.ansi256 = wrapAnsi256();
2287
+ styles.color.ansi16m = wrapAnsi16m();
2288
+ styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
2289
+ styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
2290
+ styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
2291
+ Object.defineProperties(styles, {
2292
+ rgbToAnsi256: {
2293
+ value(red, green, blue) {
2294
+ if (red === green && green === blue) {
2295
+ if (red < 8) {
2296
+ return 16;
2297
+ }
2298
+ if (red > 248) {
2299
+ return 231;
2300
+ }
2301
+ return Math.round((red - 8) / 247 * 24) + 232;
2302
+ }
2303
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
2304
+ },
2305
+ enumerable: false
2306
+ },
2307
+ hexToRgb: {
2308
+ value(hex) {
2309
+ const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
2310
+ if (!matches) {
2311
+ return [0, 0, 0];
2312
+ }
2313
+ let [colorString] = matches;
2314
+ if (colorString.length === 3) {
2315
+ colorString = [...colorString].map((character) => character + character).join("");
2316
+ }
2317
+ const integer = Number.parseInt(colorString, 16);
2318
+ return [
2319
+ integer >> 16 & 255,
2320
+ integer >> 8 & 255,
2321
+ integer & 255
2322
+ ];
2323
+ },
2324
+ enumerable: false
2325
+ },
2326
+ hexToAnsi256: {
2327
+ value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
2328
+ enumerable: false
2329
+ },
2330
+ ansi256ToAnsi: {
2331
+ value(code) {
2332
+ if (code < 8) {
2333
+ return 30 + code;
2334
+ }
2335
+ if (code < 16) {
2336
+ return 90 + (code - 8);
2337
+ }
2338
+ let red;
2339
+ let green;
2340
+ let blue;
2341
+ if (code >= 232) {
2342
+ red = ((code - 232) * 10 + 8) / 255;
2343
+ green = red;
2344
+ blue = red;
2345
+ } else {
2346
+ code -= 16;
2347
+ const remainder = code % 36;
2348
+ red = Math.floor(code / 36) / 5;
2349
+ green = Math.floor(remainder / 6) / 5;
2350
+ blue = remainder % 6 / 5;
2351
+ }
2352
+ const value = Math.max(red, green, blue) * 2;
2353
+ if (value === 0) {
2354
+ return 30;
2355
+ }
2356
+ let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
2357
+ if (value === 2) {
2358
+ result += 60;
2359
+ }
2360
+ return result;
2361
+ },
2362
+ enumerable: false
2363
+ },
2364
+ rgbToAnsi: {
2365
+ value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
2366
+ enumerable: false
2367
+ },
2368
+ hexToAnsi: {
2369
+ value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
2370
+ enumerable: false
2371
+ }
2372
+ });
2373
+ return styles;
2374
+ }
2375
+ var ansiStyles = assembleStyles();
2376
+ var ansi_styles_default = ansiStyles;
2377
+
2378
+ // ../../node_modules/chalk/source/vendor/supports-color/index.js
2379
+ import process2 from "node:process";
2380
+ import os2 from "node:os";
2381
+ import tty from "node:tty";
2382
+ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
2383
+ const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
2384
+ const position = argv.indexOf(prefix + flag);
2385
+ const terminatorPosition = argv.indexOf("--");
2386
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
2387
+ }
2388
+ var { env: env2 } = process2;
2389
+ var flagForceColor;
2390
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
2391
+ flagForceColor = 0;
2392
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
2393
+ flagForceColor = 1;
2394
+ }
2395
+ function envForceColor() {
2396
+ if ("FORCE_COLOR" in env2) {
2397
+ if (env2.FORCE_COLOR === "true") {
2398
+ return 1;
2399
+ }
2400
+ if (env2.FORCE_COLOR === "false") {
2401
+ return 0;
2402
+ }
2403
+ return env2.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env2.FORCE_COLOR, 10), 3);
2404
+ }
2405
+ }
2406
+ function translateLevel(level) {
2407
+ if (level === 0) {
2408
+ return false;
2409
+ }
2410
+ return {
2411
+ level,
2412
+ hasBasic: true,
2413
+ has256: level >= 2,
2414
+ has16m: level >= 3
2415
+ };
2416
+ }
2417
+ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
2418
+ const noFlagForceColor = envForceColor();
2419
+ if (noFlagForceColor !== undefined) {
2420
+ flagForceColor = noFlagForceColor;
2421
+ }
2422
+ const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
2423
+ if (forceColor === 0) {
2424
+ return 0;
2425
+ }
2426
+ if (sniffFlags) {
2427
+ if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
2428
+ return 3;
2429
+ }
2430
+ if (hasFlag("color=256")) {
2431
+ return 2;
2432
+ }
2433
+ }
2434
+ if ("TF_BUILD" in env2 && "AGENT_NAME" in env2) {
2435
+ return 1;
2436
+ }
2437
+ if (haveStream && !streamIsTTY && forceColor === undefined) {
2438
+ return 0;
2439
+ }
2440
+ const min = forceColor || 0;
2441
+ if (env2.TERM === "dumb") {
2442
+ return min;
2443
+ }
2444
+ if (process2.platform === "win32") {
2445
+ const osRelease = os2.release().split(".");
2446
+ if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
2447
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
2448
+ }
2449
+ return 1;
2450
+ }
2451
+ if ("CI" in env2) {
2452
+ if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => (key in env2))) {
2453
+ return 3;
2454
+ }
2455
+ if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => (sign in env2)) || env2.CI_NAME === "codeship") {
2456
+ return 1;
2457
+ }
2458
+ return min;
2459
+ }
2460
+ if ("TEAMCITY_VERSION" in env2) {
2461
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env2.TEAMCITY_VERSION) ? 1 : 0;
2462
+ }
2463
+ if (env2.COLORTERM === "truecolor") {
2464
+ return 3;
2465
+ }
2466
+ if (env2.TERM === "xterm-kitty") {
2467
+ return 3;
2468
+ }
2469
+ if (env2.TERM === "xterm-ghostty") {
2470
+ return 3;
2471
+ }
2472
+ if (env2.TERM === "wezterm") {
2473
+ return 3;
2474
+ }
2475
+ if ("TERM_PROGRAM" in env2) {
2476
+ const version = Number.parseInt((env2.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
2477
+ switch (env2.TERM_PROGRAM) {
2478
+ case "iTerm.app": {
2479
+ return version >= 3 ? 3 : 2;
2480
+ }
2481
+ case "Apple_Terminal": {
2482
+ return 2;
2483
+ }
2484
+ }
2485
+ }
2486
+ if (/-256(color)?$/i.test(env2.TERM)) {
2487
+ return 2;
2488
+ }
2489
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env2.TERM)) {
2490
+ return 1;
2491
+ }
2492
+ if ("COLORTERM" in env2) {
2493
+ return 1;
2494
+ }
2495
+ return min;
2496
+ }
2497
+ function createSupportsColor(stream, options = {}) {
2498
+ const level = _supportsColor(stream, {
2499
+ streamIsTTY: stream && stream.isTTY,
2500
+ ...options
2501
+ });
2502
+ return translateLevel(level);
2503
+ }
2504
+ var supportsColor = {
2505
+ stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
2506
+ stderr: createSupportsColor({ isTTY: tty.isatty(2) })
2507
+ };
2508
+ var supports_color_default = supportsColor;
2509
+
2510
+ // ../../node_modules/chalk/source/utilities.js
2511
+ function stringReplaceAll(string, substring, replacer) {
2512
+ let index = string.indexOf(substring);
2513
+ if (index === -1) {
2514
+ return string;
2515
+ }
2516
+ const substringLength = substring.length;
2517
+ let endIndex = 0;
2518
+ let returnValue = "";
2519
+ do {
2520
+ returnValue += string.slice(endIndex, index) + substring + replacer;
2521
+ endIndex = index + substringLength;
2522
+ index = string.indexOf(substring, endIndex);
2523
+ } while (index !== -1);
2524
+ returnValue += string.slice(endIndex);
2525
+ return returnValue;
2526
+ }
2527
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
2528
+ let endIndex = 0;
2529
+ let returnValue = "";
2530
+ do {
2531
+ const gotCR = string[index - 1] === "\r";
2532
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? `\r
2533
+ ` : `
2534
+ `) + postfix;
2535
+ endIndex = index + 1;
2536
+ index = string.indexOf(`
2537
+ `, endIndex);
2538
+ } while (index !== -1);
2539
+ returnValue += string.slice(endIndex);
2540
+ return returnValue;
2541
+ }
2542
+
2543
+ // ../../node_modules/chalk/source/index.js
2544
+ var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
2545
+ var GENERATOR = Symbol("GENERATOR");
2546
+ var STYLER = Symbol("STYLER");
2547
+ var IS_EMPTY = Symbol("IS_EMPTY");
2548
+ var levelMapping = [
2549
+ "ansi",
2550
+ "ansi",
2551
+ "ansi256",
2552
+ "ansi16m"
2553
+ ];
2554
+ var styles2 = Object.create(null);
2555
+ var applyOptions = (object, options = {}) => {
2556
+ if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
2557
+ throw new Error("The `level` option should be an integer from 0 to 3");
2558
+ }
2559
+ const colorLevel = stdoutColor ? stdoutColor.level : 0;
2560
+ object.level = options.level === undefined ? colorLevel : options.level;
2561
+ };
2562
+ var chalkFactory = (options) => {
2563
+ const chalk = (...strings) => strings.join(" ");
2564
+ applyOptions(chalk, options);
2565
+ Object.setPrototypeOf(chalk, createChalk.prototype);
2566
+ return chalk;
2567
+ };
2568
+ function createChalk(options) {
2569
+ return chalkFactory(options);
2570
+ }
2571
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
2572
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
2573
+ styles2[styleName] = {
2574
+ get() {
2575
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
2576
+ Object.defineProperty(this, styleName, { value: builder });
2577
+ return builder;
2578
+ }
2579
+ };
2580
+ }
2581
+ styles2.visible = {
2582
+ get() {
2583
+ const builder = createBuilder(this, this[STYLER], true);
2584
+ Object.defineProperty(this, "visible", { value: builder });
2585
+ return builder;
2586
+ }
2587
+ };
2588
+ var getModelAnsi = (model, level, type, ...arguments_) => {
2589
+ if (model === "rgb") {
2590
+ if (level === "ansi16m") {
2591
+ return ansi_styles_default[type].ansi16m(...arguments_);
2592
+ }
2593
+ if (level === "ansi256") {
2594
+ return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
2595
+ }
2596
+ return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
2597
+ }
2598
+ if (model === "hex") {
2599
+ return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
2600
+ }
2601
+ return ansi_styles_default[type][model](...arguments_);
2602
+ };
2603
+ var usedModels = ["rgb", "hex", "ansi256"];
2604
+ for (const model of usedModels) {
2605
+ styles2[model] = {
2606
+ get() {
2607
+ const { level } = this;
2608
+ return function(...arguments_) {
2609
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
2610
+ return createBuilder(this, styler, this[IS_EMPTY]);
2611
+ };
2612
+ }
2613
+ };
2614
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
2615
+ styles2[bgModel] = {
2616
+ get() {
2617
+ const { level } = this;
2618
+ return function(...arguments_) {
2619
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
2620
+ return createBuilder(this, styler, this[IS_EMPTY]);
2621
+ };
2622
+ }
2623
+ };
2624
+ }
2625
+ var proto = Object.defineProperties(() => {}, {
2626
+ ...styles2,
2627
+ level: {
2628
+ enumerable: true,
2629
+ get() {
2630
+ return this[GENERATOR].level;
2631
+ },
2632
+ set(level) {
2633
+ this[GENERATOR].level = level;
2634
+ }
2635
+ }
2636
+ });
2637
+ var createStyler = (open, close, parent) => {
2638
+ let openAll;
2639
+ let closeAll;
2640
+ if (parent === undefined) {
2641
+ openAll = open;
2642
+ closeAll = close;
2643
+ } else {
2644
+ openAll = parent.openAll + open;
2645
+ closeAll = close + parent.closeAll;
2646
+ }
2647
+ return {
2648
+ open,
2649
+ close,
2650
+ openAll,
2651
+ closeAll,
2652
+ parent
2653
+ };
2654
+ };
2655
+ var createBuilder = (self, _styler, _isEmpty) => {
2656
+ const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
2657
+ Object.setPrototypeOf(builder, proto);
2658
+ builder[GENERATOR] = self;
2659
+ builder[STYLER] = _styler;
2660
+ builder[IS_EMPTY] = _isEmpty;
2661
+ return builder;
2662
+ };
2663
+ var applyStyle = (self, string) => {
2664
+ if (self.level <= 0 || !string) {
2665
+ return self[IS_EMPTY] ? "" : string;
2666
+ }
2667
+ let styler = self[STYLER];
2668
+ if (styler === undefined) {
2669
+ return string;
2670
+ }
2671
+ const { openAll, closeAll } = styler;
2672
+ if (string.includes("\x1B")) {
2673
+ while (styler !== undefined) {
2674
+ string = stringReplaceAll(string, styler.close, styler.open);
2675
+ styler = styler.parent;
2676
+ }
2677
+ }
2678
+ const lfIndex = string.indexOf(`
2679
+ `);
2680
+ if (lfIndex !== -1) {
2681
+ string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
2682
+ }
2683
+ return openAll + string + closeAll;
2684
+ };
2685
+ Object.defineProperties(createChalk.prototype, styles2);
2686
+ var chalk = createChalk();
2687
+ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
2688
+ var source_default = chalk;
2689
+
2690
+ // src/output.ts
2691
+ var globalOptions = {};
2692
+ function setGlobalOptions(options) {
2693
+ globalOptions = { ...options };
2694
+ }
2695
+ function isTTY() {
2696
+ return Boolean(process.stdout.isTTY && process.stdin.isTTY);
2697
+ }
2698
+ function shouldDisableColors() {
2699
+ if (process.env.NO_COLOR !== undefined) {
2700
+ return true;
2701
+ }
2702
+ if (process.env.THOUGHTFUL_NO_COLOR === "1" || process.env.THOUGHTFUL_NO_COLOR === "true") {
2703
+ return true;
2704
+ }
2705
+ if (process.env.TERM === "dumb") {
2706
+ return true;
2707
+ }
2708
+ if (!isTTY()) {
2709
+ return true;
2710
+ }
2711
+ if (globalOptions.noColor) {
2712
+ return true;
2713
+ }
2714
+ if (globalOptions.json) {
2715
+ return true;
2716
+ }
2717
+ return false;
2718
+ }
2719
+ var c = {
2720
+ blue: (text) => shouldDisableColors() ? text : source_default.blue(text),
2721
+ green: (text) => shouldDisableColors() ? text : source_default.green(text),
2722
+ yellow: (text) => shouldDisableColors() ? text : source_default.yellow(text),
2723
+ red: (text) => shouldDisableColors() ? text : source_default.red(text),
2724
+ gray: (text) => shouldDisableColors() ? text : source_default.gray(text),
2725
+ white: (text) => shouldDisableColors() ? text : source_default.white(text),
2726
+ cyan: (text) => shouldDisableColors() ? text : source_default.cyan(text)
2727
+ };
2728
+ function isQuiet() {
2729
+ return Boolean(globalOptions.quiet);
2730
+ }
2731
+ function isJson() {
2732
+ return Boolean(globalOptions.json);
2733
+ }
2734
+ function log(message) {
2735
+ if (!isQuiet() && !isJson()) {
2736
+ console.log(message);
2737
+ }
2738
+ }
2739
+ function logError(message) {
2740
+ if (!isJson()) {
2741
+ console.error(message);
2742
+ }
2743
+ }
2744
+ function outputJson(data) {
2745
+ console.log(JSON.stringify(data));
2746
+ }
2747
+ function isNoInput() {
2748
+ return Boolean(globalOptions.noInput);
2749
+ }
2750
+
2751
+ // src/client.ts
2752
+ class ApiError extends Error {
2753
+ status;
2754
+ statusText;
2755
+ body;
2756
+ constructor(status, statusText, body) {
2757
+ super(`API Error: ${status} ${statusText}`);
2758
+ this.status = status;
2759
+ this.statusText = statusText;
2760
+ this.body = body;
2761
+ this.name = "ApiError";
2762
+ }
2763
+ isValidationError() {
2764
+ return this.status === 400 || this.status === 422;
2765
+ }
2766
+ isOperationalError() {
2767
+ return this.status >= 500 || this.status === 401 || this.status === 403;
2768
+ }
2769
+ }
2770
+
2771
+ class ValidationError extends Error {
2772
+ constructor(message) {
2773
+ super(message);
2774
+ this.name = "ValidationError";
2775
+ }
2776
+ }
2777
+
2778
+ class ThoughtfulClient {
2779
+ config;
2780
+ constructor() {
2781
+ this.config = loadConfig();
2782
+ }
2783
+ async refreshTokens() {
2784
+ const refreshToken = this.config.refreshToken;
2785
+ if (!refreshToken) {
2786
+ return false;
2787
+ }
2788
+ try {
2789
+ const res = await fetch(`${this.config.apiUrl}/api/auth/mobile/refresh`, {
2790
+ method: "POST",
2791
+ headers: {
2792
+ "Content-Type": "application/json"
2793
+ },
2794
+ body: JSON.stringify({ refreshToken })
2795
+ });
2796
+ if (!res.ok) {
2797
+ return false;
2798
+ }
2799
+ const data = await res.json();
2800
+ const expiresAt = new Date(Date.now() + 55 * 60 * 1000);
2801
+ this.config = updateConfig({
2802
+ accessToken: data.accessToken,
2803
+ refreshToken: data.refreshToken,
2804
+ tokenExpiresAt: expiresAt.toISOString()
2805
+ });
2806
+ return true;
2807
+ } catch {
2808
+ return false;
2809
+ }
2810
+ }
2811
+ async ensureValidToken() {
2812
+ if (!this.config.accessToken) {
2813
+ throw new Error("Not logged in. Run 'thoughtful login' first.");
2814
+ }
2815
+ if (this.config.tokenExpiresAt) {
2816
+ const expiresAt = new Date(this.config.tokenExpiresAt);
2817
+ const now = new Date;
2818
+ if (expiresAt <= now) {
2819
+ const refreshed = await this.refreshTokens();
2820
+ if (!refreshed) {
2821
+ clearAuth();
2822
+ throw new Error("Session expired. Please run 'thoughtful login' again.");
2823
+ }
2824
+ }
2825
+ }
2826
+ }
2827
+ async request(path2, options) {
2828
+ const { skipAuth, ...fetchOptions } = options ?? {};
2829
+ if (!skipAuth) {
2830
+ await this.ensureValidToken();
2831
+ }
2832
+ const headers = {
2833
+ "Content-Type": "application/json",
2834
+ ...fetchOptions.headers
2835
+ };
2836
+ if (!skipAuth && this.config.accessToken) {
2837
+ headers["Authorization"] = `Bearer ${this.config.accessToken}`;
2838
+ }
2839
+ const res = await fetch(`${this.config.apiUrl}${path2}`, {
2840
+ ...fetchOptions,
2841
+ headers
2842
+ });
2843
+ if (!res.ok) {
2844
+ if (res.status === 401 && !skipAuth) {
2845
+ const refreshed = await this.refreshTokens();
2846
+ if (refreshed) {
2847
+ headers["Authorization"] = `Bearer ${this.config.accessToken}`;
2848
+ const retryRes = await fetch(`${this.config.apiUrl}${path2}`, {
2849
+ ...fetchOptions,
2850
+ headers
2851
+ });
2852
+ if (retryRes.ok) {
2853
+ return retryRes.json();
2854
+ }
2855
+ }
2856
+ clearAuth();
2857
+ throw new Error("Session expired. Please run 'thoughtful login' again.");
2858
+ }
2859
+ let body;
2860
+ const text2 = await res.text();
2861
+ try {
2862
+ body = JSON.parse(text2);
2863
+ } catch {
2864
+ body = text2;
2865
+ }
2866
+ throw new ApiError(res.status, res.statusText, body);
2867
+ }
2868
+ const text = await res.text();
2869
+ if (!text) {
2870
+ return {};
2871
+ }
2872
+ return JSON.parse(text);
2873
+ }
2874
+ async sendVerificationCode(email) {
2875
+ return this.request("/api/auth/mobile/send-code", {
2876
+ method: "POST",
2877
+ body: JSON.stringify({ email }),
2878
+ skipAuth: true
2879
+ });
2880
+ }
2881
+ async verifyCode(email, code) {
2882
+ return this.request("/api/auth/mobile/verify-code", {
2883
+ method: "POST",
2884
+ body: JSON.stringify({ email, code }),
2885
+ skipAuth: true
2886
+ });
2887
+ }
2888
+ async getMembershipsAndWorkspaces() {
2889
+ return this.request("/api/mobile/memberships-workspaces");
2890
+ }
2891
+ async setMembership(membershipId) {
2892
+ return this.request("/api/mobile/set-membership", {
2893
+ method: "POST",
2894
+ body: JSON.stringify({ membershipId })
2895
+ });
2896
+ }
2897
+ async setWorkspace(workspaceId) {
2898
+ return this.request("/api/mobile/set-workspace", {
2899
+ method: "POST",
2900
+ body: JSON.stringify({ workspaceId })
2901
+ });
2902
+ }
2903
+ async getPages() {
2904
+ return this.request("/api/cli/pages");
2905
+ }
2906
+ async getPage(slug) {
2907
+ return this.request(`/api/cli/pages/${encodeURIComponent(slug)}`);
2908
+ }
2909
+ async createPage(data) {
2910
+ return this.request("/api/cli/pages", {
2911
+ method: "POST",
2912
+ body: JSON.stringify(data)
2913
+ });
2914
+ }
2915
+ async updatePage(slug, data) {
2916
+ return this.request(`/api/cli/pages/${encodeURIComponent(slug)}`, {
2917
+ method: "PATCH",
2918
+ body: JSON.stringify(data)
2919
+ });
2920
+ }
2921
+ async deletePage(slug) {
2922
+ return this.request(`/api/cli/pages/${encodeURIComponent(slug)}`, {
2923
+ method: "DELETE"
2924
+ });
2925
+ }
2926
+ async searchPages(query) {
2927
+ return this.request(`/api/cli/pages/search?q=${encodeURIComponent(query)}`);
2928
+ }
2929
+ async getThreads() {
2930
+ return this.request("/api/cli/threads");
2931
+ }
2932
+ async createThread(message) {
2933
+ return this.request("/api/cli/threads", {
2934
+ method: "POST",
2935
+ body: JSON.stringify({ message })
2936
+ });
2937
+ }
2938
+ async getThreadMessages(threadId) {
2939
+ return this.request(`/api/cli/threads/${encodeURIComponent(threadId)}/messages`);
2940
+ }
2941
+ async sendThreadMessage(threadId, message) {
2942
+ return this.request(`/api/cli/threads/${encodeURIComponent(threadId)}/messages`, {
2943
+ method: "POST",
2944
+ body: JSON.stringify({ message })
2945
+ });
2946
+ }
2947
+ async sendMessageWithResponse(threadId, message) {
2948
+ return this.request(`/api/cli/threads/${encodeURIComponent(threadId)}/respond`, {
2949
+ method: "POST",
2950
+ body: JSON.stringify({ message })
2951
+ });
2952
+ }
2953
+ async createWorkspace(name) {
2954
+ return this.request("/api/cli/workspaces", {
2955
+ method: "POST",
2956
+ body: JSON.stringify({ name })
2957
+ });
2958
+ }
2959
+ }
2960
+ function createClient() {
2961
+ return new ThoughtfulClient;
2962
+ }
2963
+ function handleApiError(error) {
2964
+ let exitCode = 1;
2965
+ const json = isJson();
2966
+ if (error instanceof ApiError) {
2967
+ if (error.isValidationError()) {
2968
+ exitCode = 2;
2969
+ }
2970
+ if (json) {
2971
+ outputJson({
2972
+ error: true,
2973
+ status: error.status,
2974
+ message: error.message,
2975
+ details: error.body
2976
+ });
2977
+ } else {
2978
+ logError(c.red(`Error: ${error.message}`));
2979
+ if (error.body && typeof error.body === "object" && "error" in error.body) {
2980
+ logError(c.gray(error.body.error));
2981
+ }
2982
+ }
2983
+ } else if (error instanceof ValidationError) {
2984
+ exitCode = 2;
2985
+ if (json) {
2986
+ outputJson({ error: true, message: error.message });
2987
+ } else {
2988
+ logError(c.red(`Error: ${error.message}`));
2989
+ }
2990
+ } else if (error instanceof Error) {
2991
+ if (json) {
2992
+ outputJson({ error: true, message: error.message });
2993
+ } else {
2994
+ logError(c.red(`Error: ${error.message}`));
2995
+ }
2996
+ } else {
2997
+ if (json) {
2998
+ outputJson({ error: true, message: "Unknown error" });
2999
+ } else {
3000
+ logError(c.red("An unknown error occurred"));
3001
+ }
3002
+ }
3003
+ process.exit(exitCode);
3004
+ }
3005
+
3006
+ // src/prompt.ts
3007
+ import readline from "node:readline";
3008
+ function prompt(question, options = {}) {
3009
+ const { secure = false, required = false } = options;
3010
+ if (isNoInput()) {
3011
+ const error = new Error(`Interactive input is disabled (--no-input flag set). ${required ? "This input is required." : ""}`);
3012
+ return Promise.reject(error);
3013
+ }
3014
+ if (!isTTY()) {
3015
+ const error = new Error(`Cannot prompt for input: stdin is not a TTY. ${required ? "This input is required." : ""}`);
3016
+ return Promise.reject(error);
3017
+ }
3018
+ return new Promise((resolve, reject) => {
3019
+ const rl = readline.createInterface({
3020
+ input: process.stdin,
3021
+ output: process.stdout
3022
+ });
3023
+ if (secure) {
3024
+ process.stdout.write(question);
3025
+ const stdin = process.stdin;
3026
+ const originalSetRawMode = stdin.setRawMode?.bind(stdin);
3027
+ if (originalSetRawMode) {
3028
+ originalSetRawMode(true);
3029
+ }
3030
+ stdin.resume();
3031
+ stdin.setEncoding("utf8");
3032
+ let input = "";
3033
+ const onData = (char) => {
3034
+ const c2 = char.toString();
3035
+ switch (c2) {
3036
+ case `
3037
+ `:
3038
+ case "\r":
3039
+ case "\x04":
3040
+ stdin.pause();
3041
+ stdin.removeListener("data", onData);
3042
+ if (originalSetRawMode) {
3043
+ originalSetRawMode(false);
3044
+ }
3045
+ rl.close();
3046
+ process.stdout.write(`
3047
+ `);
3048
+ resolve(input.trim());
3049
+ break;
3050
+ case "\x03":
3051
+ stdin.pause();
3052
+ stdin.removeListener("data", onData);
3053
+ if (originalSetRawMode) {
3054
+ originalSetRawMode(false);
3055
+ }
3056
+ rl.close();
3057
+ process.stdout.write(`
3058
+ `);
3059
+ reject(new Error("User cancelled input (Ctrl+C)"));
3060
+ break;
3061
+ case "":
3062
+ case "\b":
3063
+ if (input.length > 0) {
3064
+ input = input.slice(0, -1);
3065
+ process.stdout.write("\b \b");
3066
+ }
3067
+ break;
3068
+ default:
3069
+ if (c2.charCodeAt(0) >= 32 && c2.charCodeAt(0) < 127) {
3070
+ input += c2;
3071
+ process.stdout.write("*");
3072
+ }
3073
+ break;
3074
+ }
3075
+ };
3076
+ stdin.on("data", onData);
3077
+ } else {
3078
+ rl.question(question, (answer) => {
3079
+ rl.close();
3080
+ resolve(answer.trim());
3081
+ });
3082
+ }
3083
+ });
3084
+ }
3085
+ async function confirm(question, options = {}) {
3086
+ const { defaultValue = false } = options;
3087
+ if (isNoInput()) {
3088
+ throw new Error("Interactive confirmation is disabled (--no-input flag set)");
3089
+ }
3090
+ if (!isTTY()) {
3091
+ throw new Error("Cannot prompt for confirmation: stdin is not a TTY");
3092
+ }
3093
+ const suffix = defaultValue ? " (Y/n) " : " (y/N) ";
3094
+ const answer = await prompt(question + suffix);
3095
+ if (!answer) {
3096
+ return defaultValue;
3097
+ }
3098
+ const normalized = answer.toLowerCase();
3099
+ return normalized === "y" || normalized === "yes";
3100
+ }
3101
+
3102
+ // src/commands/auth.ts
3103
+ function registerAuthCommands(program2) {
3104
+ program2.command("login").description("Log in to Thoughtful").option("--email <email>", "Email address for login (skips email prompt)").option("--code <code>", "Verification code (skips code prompt, requires --email)").addHelpText("after", `
3105
+ Examples:
3106
+ $ thoughtful login
3107
+ Email: alice@example.com
3108
+ Enter code: ******
3109
+
3110
+ $ thoughtful login --email alice@example.com --code 123456
3111
+ Successfully logged in as alice@example.com
3112
+
3113
+ $ thoughtful login --json
3114
+ {"success":true,"user":{...},"workspace":{...}}
3115
+
3116
+ $ thoughtful login --no-input --email alice@example.com --code 123456
3117
+ Successfully logged in as alice@example.com
3118
+ `).action(async (options) => {
3119
+ try {
3120
+ if (isLoggedIn()) {
3121
+ const config = loadConfig();
3122
+ if (isJson()) {
3123
+ outputJson({
3124
+ success: false,
3125
+ message: "Already logged in",
3126
+ email: config.user?.email
3127
+ });
3128
+ } else {
3129
+ log(c.yellow(`Already logged in as ${config.user?.email}. Use 'thoughtful logout' first to log in as a different user.`));
3130
+ }
3131
+ return;
3132
+ }
3133
+ const client = createClient();
3134
+ if (!isJson()) {
3135
+ log(c.blue("Thoughtful CLI Login"));
3136
+ log("");
3137
+ }
3138
+ let email = options.email;
3139
+ if (!email) {
3140
+ try {
3141
+ email = await prompt("Email: ", { required: true });
3142
+ } catch (error) {
3143
+ if (error instanceof Error) {
3144
+ throw new ValidationError(`Email is required. ${error.message} Provide --email flag for non-interactive mode.`);
3145
+ }
3146
+ throw error;
3147
+ }
3148
+ }
3149
+ if (!email) {
3150
+ throw new ValidationError("Email is required");
3151
+ }
3152
+ let code = options.code;
3153
+ if (!code) {
3154
+ if (!isJson()) {
3155
+ log(c.gray("Sending verification code..."));
3156
+ }
3157
+ await client.sendVerificationCode(email);
3158
+ if (!isJson()) {
3159
+ log(c.green("Verification code sent! Check your email."));
3160
+ log("");
3161
+ }
3162
+ try {
3163
+ code = await prompt("Enter code: ", { secure: true, required: true });
3164
+ } catch (error) {
3165
+ if (error instanceof Error) {
3166
+ throw new ValidationError(`Verification code is required. ${error.message} Provide --code flag for non-interactive mode.`);
3167
+ }
3168
+ throw error;
3169
+ }
3170
+ }
3171
+ if (!code) {
3172
+ throw new ValidationError("Verification code is required");
3173
+ }
3174
+ const result = await client.verifyCode(email, code);
3175
+ const expiresAt = new Date(Date.now() + 55 * 60 * 1000);
3176
+ updateConfig({
3177
+ accessToken: result.accessToken,
3178
+ refreshToken: result.refreshToken,
3179
+ tokenExpiresAt: expiresAt.toISOString(),
3180
+ activeOrgId: result.workspace.organizationId,
3181
+ activeWorkspaceId: result.workspace.id,
3182
+ user: {
3183
+ id: result.user.id,
3184
+ email: result.user.email,
3185
+ displayName: result.user.displayName
3186
+ }
3187
+ });
3188
+ if (isJson()) {
3189
+ outputJson({
3190
+ success: true,
3191
+ user: {
3192
+ id: result.user.id,
3193
+ email: result.user.email,
3194
+ displayName: result.user.displayName
3195
+ },
3196
+ workspace: {
3197
+ id: result.workspace.id,
3198
+ name: result.workspace.name
3199
+ }
3200
+ });
3201
+ } else {
3202
+ log("");
3203
+ log(c.green(`Successfully logged in as ${result.user.email}`));
3204
+ log(c.gray(`Workspace: ${result.workspace.name}`));
3205
+ }
3206
+ } catch (error) {
3207
+ handleApiError(error);
3208
+ }
3209
+ });
3210
+ program2.command("logout").description("Log out from Thoughtful").addHelpText("after", `
3211
+ Examples:
3212
+ $ thoughtful logout
3213
+ Successfully logged out
3214
+
3215
+ $ thoughtful logout --json
3216
+ {"success":true}
3217
+ `).action(() => {
3218
+ if (!isLoggedIn()) {
3219
+ if (isJson()) {
3220
+ outputJson({ success: true, message: "Not logged in" });
3221
+ } else {
3222
+ log(c.yellow("Not logged in"));
3223
+ }
3224
+ return;
3225
+ }
3226
+ clearAuth();
3227
+ if (isJson()) {
3228
+ outputJson({ success: true });
3229
+ } else {
3230
+ log(c.green("Successfully logged out"));
3231
+ }
3232
+ });
3233
+ program2.command("whoami").description("Show current user and workspace").addHelpText("after", `
3234
+ Examples:
3235
+ $ thoughtful whoami
3236
+ Current Session
3237
+ User: alice@example.com
3238
+ Name: Alice Smith
3239
+ Organization: Acme Corp
3240
+ Workspace: Engineering
3241
+
3242
+ $ thoughtful whoami --json
3243
+ {"user":{...},"organization":{...},"workspace":{...}}
3244
+ `).action(async () => {
3245
+ try {
3246
+ if (!isLoggedIn()) {
3247
+ if (isJson()) {
3248
+ outputJson({ error: true, message: "Not logged in" });
3249
+ } else {
3250
+ log(c.yellow("Not logged in. Run 'thoughtful login' first."));
3251
+ }
3252
+ process.exit(1);
3253
+ }
3254
+ const config = loadConfig();
3255
+ const client = createClient();
3256
+ const data = await client.getMembershipsAndWorkspaces();
3257
+ const activeMembership = data.memberships.find((m) => m.id === data.activeMembershipId);
3258
+ const activeWorkspace = data.workspaces.find((w) => w.id === data.activeWorkspaceId);
3259
+ if (isJson()) {
3260
+ outputJson({
3261
+ user: config.user,
3262
+ organization: activeMembership ? {
3263
+ id: activeMembership.organizationId,
3264
+ name: activeMembership.organizationName,
3265
+ domain: activeMembership.organizationDomain
3266
+ } : null,
3267
+ workspace: activeWorkspace ? {
3268
+ id: activeWorkspace.id,
3269
+ name: activeWorkspace.name
3270
+ } : null
3271
+ });
3272
+ } else {
3273
+ log(c.blue("Current Session"));
3274
+ log("");
3275
+ log(` ${c.gray("User:")} ${config.user?.email}`);
3276
+ if (config.user?.displayName) {
3277
+ log(` ${c.gray("Name:")} ${config.user.displayName}`);
3278
+ }
3279
+ if (activeMembership) {
3280
+ log(` ${c.gray("Organization:")} ${activeMembership.organizationName}`);
3281
+ }
3282
+ if (activeWorkspace) {
3283
+ log(` ${c.gray("Workspace:")} ${activeWorkspace.name}`);
3284
+ }
3285
+ }
3286
+ } catch (error) {
3287
+ handleApiError(error);
3288
+ }
3289
+ });
3290
+ }
3291
+
3292
+ // src/commands/orgs.ts
3293
+ function registerOrgsCommands(program2) {
3294
+ const orgs = program2.command("orgs").description("Manage organizations").addHelpText("after", `
3295
+ Examples:
3296
+ $ thoughtful orgs list
3297
+ $ thoughtful orgs switch org_abc123
3298
+ $ thoughtful orgs list --json | jq '.organizations[] | select(.active)'
3299
+ `);
3300
+ orgs.command("list").description("List organizations you belong to").option("--json", "Output as JSON").addHelpText("after", `
3301
+ Examples:
3302
+ $ thoughtful orgs list
3303
+ Organizations
3304
+ * Acme Corp (acme.com)
3305
+ ID: org_abc123
3306
+ Consulting Inc
3307
+ ID: org_xyz789
3308
+
3309
+ $ thoughtful orgs list --json
3310
+ {"organizations":[{"id":"org_abc123","name":"Acme Corp","domain":"acme.com","active":true},...]}
3311
+ `).action(async (options) => {
3312
+ const json = options.json;
3313
+ try {
3314
+ if (!isLoggedIn()) {
3315
+ if (json) {
3316
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3317
+ } else {
3318
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3319
+ }
3320
+ process.exit(1);
3321
+ }
3322
+ const client = createClient();
3323
+ const data = await client.getMembershipsAndWorkspaces();
3324
+ if (json) {
3325
+ console.log(JSON.stringify({
3326
+ organizations: data.memberships.map((m) => ({
3327
+ id: m.organizationId,
3328
+ name: m.organizationName,
3329
+ domain: m.organizationDomain,
3330
+ active: m.id === data.activeMembershipId
3331
+ }))
3332
+ }));
3333
+ } else {
3334
+ console.log(source_default.blue("Organizations"));
3335
+ console.log();
3336
+ if (data.memberships.length === 0) {
3337
+ console.log(source_default.gray(" No organizations found"));
3338
+ return;
3339
+ }
3340
+ for (const m of data.memberships) {
3341
+ const isActive = m.id === data.activeMembershipId;
3342
+ const marker = isActive ? source_default.green("*") : " ";
3343
+ const name = isActive ? source_default.white(m.organizationName) : source_default.gray(m.organizationName);
3344
+ const domain = m.organizationDomain ? source_default.gray(` (${m.organizationDomain})`) : "";
3345
+ console.log(` ${marker} ${name}${domain}`);
3346
+ console.log(source_default.gray(` ID: ${m.organizationId}`));
3347
+ }
3348
+ console.log();
3349
+ console.log(source_default.gray("* = active organization"));
3350
+ }
3351
+ } catch (error) {
3352
+ handleApiError(error);
3353
+ }
3354
+ });
3355
+ orgs.command("switch <org-id>").description("Switch to a different organization").option("--json", "Output as JSON").addHelpText("after", `
3356
+ Examples:
3357
+ $ thoughtful orgs switch org_abc123
3358
+ Switched to organization: Acme Corp
3359
+ Workspace: Engineering
3360
+
3361
+ $ thoughtful orgs switch org_abc123 --json
3362
+ {"success":true,"organization":{...},"workspace":{...}}
3363
+ `).action(async (orgId, options) => {
3364
+ const json = options.json;
3365
+ try {
3366
+ if (!isLoggedIn()) {
3367
+ if (json) {
3368
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3369
+ } else {
3370
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3371
+ }
3372
+ process.exit(1);
3373
+ }
3374
+ const client = createClient();
3375
+ const data = await client.getMembershipsAndWorkspaces();
3376
+ const membership = data.memberships.find((m) => m.organizationId === orgId);
3377
+ if (!membership) {
3378
+ const availableList = data.memberships.map((m) => `${m.organizationName} (${m.organizationId})`).join(", ");
3379
+ const message = json ? `Organization '${orgId}' not found` : `Organization '${orgId}' not found. Available organizations: ${availableList}`;
3380
+ throw new ValidationError(message);
3381
+ }
3382
+ const result = await client.setMembership(membership.id);
3383
+ const expiresAt = new Date(Date.now() + 55 * 60 * 1000);
3384
+ updateConfig({
3385
+ accessToken: result.accessToken,
3386
+ refreshToken: result.refreshToken,
3387
+ tokenExpiresAt: expiresAt.toISOString(),
3388
+ activeOrgId: membership.organizationId,
3389
+ activeWorkspaceId: result.workspace.id
3390
+ });
3391
+ if (json) {
3392
+ console.log(JSON.stringify({
3393
+ success: true,
3394
+ organization: {
3395
+ id: membership.organizationId,
3396
+ name: membership.organizationName
3397
+ },
3398
+ workspace: {
3399
+ id: result.workspace.id,
3400
+ name: result.workspace.name
3401
+ }
3402
+ }));
3403
+ } else {
3404
+ console.log(source_default.green(`Switched to organization: ${membership.organizationName}`));
3405
+ console.log(source_default.gray(`Workspace: ${result.workspace.name}`));
3406
+ }
3407
+ } catch (error) {
3408
+ handleApiError(error);
3409
+ }
3410
+ });
3411
+ }
3412
+
3413
+ // src/commands/workspaces.ts
3414
+ function registerWorkspacesCommands(program2) {
3415
+ const workspaces = program2.command("workspaces").description("Manage workspaces").addHelpText("after", `
3416
+ Examples:
3417
+ $ thoughtful workspaces list
3418
+ $ thoughtful workspaces create "New Project Team"
3419
+ $ thoughtful workspaces switch ws_abc123
3420
+ $ thoughtful workspaces list --json | jq '.workspaces[] | select(.active)'
3421
+ `);
3422
+ workspaces.command("list").description("List workspaces in current organization").option("--json", "Output as JSON").addHelpText("after", `
3423
+ Examples:
3424
+ $ thoughtful workspaces list
3425
+ Workspaces
3426
+ * Engineering
3427
+ Product development workspace
3428
+ ID: ws_abc123
3429
+ Marketing
3430
+ Marketing team workspace
3431
+ ID: ws_xyz789
3432
+
3433
+ $ thoughtful workspaces list --json
3434
+ {"workspaces":[{"id":"ws_abc123","name":"Engineering","description":"Product development workspace","active":true},...]}
3435
+ `).action(async (options) => {
3436
+ const json = options.json;
3437
+ try {
3438
+ if (!isLoggedIn()) {
3439
+ if (json) {
3440
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3441
+ } else {
3442
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3443
+ }
3444
+ process.exit(1);
3445
+ }
3446
+ const client = createClient();
3447
+ const data = await client.getMembershipsAndWorkspaces();
3448
+ if (json) {
3449
+ console.log(JSON.stringify({
3450
+ workspaces: data.workspaces.map((w) => ({
3451
+ id: w.id,
3452
+ name: w.name,
3453
+ description: w.description,
3454
+ active: w.id === data.activeWorkspaceId
3455
+ }))
3456
+ }));
3457
+ } else {
3458
+ console.log(source_default.blue("Workspaces"));
3459
+ console.log();
3460
+ if (data.workspaces.length === 0) {
3461
+ console.log(source_default.gray(" No workspaces found"));
3462
+ return;
3463
+ }
3464
+ for (const w of data.workspaces) {
3465
+ const isActive = w.id === data.activeWorkspaceId;
3466
+ const marker = isActive ? source_default.green("*") : " ";
3467
+ const name = isActive ? source_default.white(w.name) : source_default.gray(w.name);
3468
+ console.log(` ${marker} ${name}`);
3469
+ if (w.description) {
3470
+ console.log(source_default.gray(` ${w.description}`));
3471
+ }
3472
+ console.log(source_default.gray(` ID: ${w.id}`));
3473
+ }
3474
+ console.log();
3475
+ console.log(source_default.gray("* = active workspace"));
3476
+ }
3477
+ } catch (error) {
3478
+ handleApiError(error);
3479
+ }
3480
+ });
3481
+ workspaces.command("switch <workspace-id>").description("Switch to a different workspace").option("--json", "Output as JSON").addHelpText("after", `
3482
+ Examples:
3483
+ $ thoughtful workspaces switch ws_abc123
3484
+ Switched to workspace: Engineering
3485
+
3486
+ $ thoughtful workspaces switch ws_abc123 --json
3487
+ {"success":true,"workspace":{"id":"ws_abc123","name":"Engineering"}}
3488
+ `).action(async (workspaceId, options) => {
3489
+ const json = options.json;
3490
+ try {
3491
+ if (!isLoggedIn()) {
3492
+ if (json) {
3493
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3494
+ } else {
3495
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3496
+ }
3497
+ process.exit(1);
3498
+ }
3499
+ const client = createClient();
3500
+ const data = await client.getMembershipsAndWorkspaces();
3501
+ const workspace = data.workspaces.find((w) => w.id === workspaceId);
3502
+ if (!workspace) {
3503
+ const availableList = data.workspaces.map((w) => `${w.name} (${w.id})`).join(", ");
3504
+ const message = json ? `Workspace '${workspaceId}' not found` : `Workspace '${workspaceId}' not found. Available workspaces: ${availableList}`;
3505
+ throw new ValidationError(message);
3506
+ }
3507
+ const result = await client.setWorkspace(workspaceId);
3508
+ const expiresAt = new Date(Date.now() + 55 * 60 * 1000);
3509
+ updateConfig({
3510
+ accessToken: result.accessToken,
3511
+ refreshToken: result.refreshToken,
3512
+ tokenExpiresAt: expiresAt.toISOString(),
3513
+ activeWorkspaceId: workspaceId
3514
+ });
3515
+ if (json) {
3516
+ console.log(JSON.stringify({
3517
+ success: true,
3518
+ workspace: {
3519
+ id: workspace.id,
3520
+ name: workspace.name
3521
+ }
3522
+ }));
3523
+ } else {
3524
+ console.log(source_default.green(`Switched to workspace: ${workspace.name}`));
3525
+ }
3526
+ } catch (error) {
3527
+ handleApiError(error);
3528
+ }
3529
+ });
3530
+ workspaces.command("create <name>").description("Create a new workspace").option("--json", "Output as JSON").addHelpText("after", `
3531
+ Examples:
3532
+ $ thoughtful workspaces create "New Project Team"
3533
+ Created workspace: New Project Team
3534
+ ID: ws_newid123
3535
+ Switched to the new workspace.
3536
+
3537
+ $ thoughtful workspaces create "Sales Team" --json
3538
+ {"success":true,"workspace":{"id":"ws_newid123","name":"Sales Team"}}
3539
+ `).action(async (name, options) => {
3540
+ const json = options.json;
3541
+ try {
3542
+ if (!isLoggedIn()) {
3543
+ if (json) {
3544
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3545
+ } else {
3546
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3547
+ }
3548
+ process.exit(1);
3549
+ }
3550
+ const client = createClient();
3551
+ const result = await client.createWorkspace(name);
3552
+ const expiresAt = new Date(Date.now() + 55 * 60 * 1000);
3553
+ updateConfig({
3554
+ accessToken: result.accessToken,
3555
+ refreshToken: result.refreshToken,
3556
+ tokenExpiresAt: expiresAt.toISOString(),
3557
+ activeWorkspaceId: result.workspace.id
3558
+ });
3559
+ if (json) {
3560
+ console.log(JSON.stringify({
3561
+ success: true,
3562
+ workspace: {
3563
+ id: result.workspace.id,
3564
+ name: result.workspace.name
3565
+ }
3566
+ }));
3567
+ } else {
3568
+ console.log(source_default.green(`Created workspace: ${result.workspace.name}`));
3569
+ console.log(source_default.gray(`ID: ${result.workspace.id}`));
3570
+ console.log(source_default.gray("Switched to the new workspace."));
3571
+ }
3572
+ } catch (error) {
3573
+ handleApiError(error);
3574
+ }
3575
+ });
3576
+ }
3577
+
3578
+ // src/commands/pages.ts
3579
+ function buildTree(pages) {
3580
+ const nodeMap = new Map;
3581
+ const roots = [];
3582
+ for (const page of pages) {
3583
+ nodeMap.set(page.id, { ...page, children: [] });
3584
+ }
3585
+ for (const page of pages) {
3586
+ const node = nodeMap.get(page.id);
3587
+ if (page.parentId) {
3588
+ const parent = nodeMap.get(page.parentId);
3589
+ if (parent) {
3590
+ parent.children.push(node);
3591
+ } else {
3592
+ roots.push(node);
3593
+ }
3594
+ } else {
3595
+ roots.push(node);
3596
+ }
3597
+ }
3598
+ return roots;
3599
+ }
3600
+ function printTree(nodes, prefix = "", isLast = true) {
3601
+ for (let i = 0;i < nodes.length; i++) {
3602
+ const node = nodes[i];
3603
+ const isLastNode = i === nodes.length - 1;
3604
+ const connector = prefix === "" ? "" : isLastNode ? "└─ " : "├─ ";
3605
+ const status = node.status ? source_default.gray(` [${node.status}]`) : "";
3606
+ const owner = node.ownerName ? source_default.gray(` @${node.ownerName}`) : "";
3607
+ console.log(`${prefix}${connector}${source_default.white(node.title)}${status}${owner}`);
3608
+ console.log(`${prefix}${isLastNode ? " " : "│ "}${source_default.gray(node.slug)}`);
3609
+ if (node.children.length > 0) {
3610
+ const newPrefix = prefix + (isLastNode ? " " : "│ ");
3611
+ printTree(node.children, newPrefix, isLastNode);
3612
+ }
3613
+ }
3614
+ }
3615
+ function registerPagesCommands(program2) {
3616
+ const pages = program2.command("pages").description("Manage pages").addHelpText("after", `
3617
+ Examples:
3618
+ $ thoughtful pages list
3619
+ $ thoughtful pages create "New Feature" --parent roadmap
3620
+ $ thoughtful pages get roadmap
3621
+ $ thoughtful pages search "quarterly goals"
3622
+ $ thoughtful pages update roadmap --status completed
3623
+ $ thoughtful pages delete old-draft --yes
3624
+ `);
3625
+ pages.command("list").description("List all pages").option("--flat", "Show flat list instead of tree").option("--json", "Output as JSON").addHelpText("after", `
3626
+ Examples:
3627
+ $ thoughtful pages list
3628
+ Pages
3629
+ └─ Roadmap
3630
+ roadmap
3631
+ ├─ Q1 Goals [active] @alice
3632
+ q1-goals
3633
+ └─ Q2 Goals [draft]
3634
+ q2-goals
3635
+
3636
+ $ thoughtful pages list --flat
3637
+ Pages
3638
+ Roadmap
3639
+ roadmap
3640
+ Q1 Goals [active] @alice
3641
+ q1-goals
3642
+
3643
+ $ thoughtful pages list --json
3644
+ {"pages":[{"id":"pg_123","slug":"roadmap","title":"Roadmap",...},...]}
3645
+ `).action(async (options) => {
3646
+ const json = options.json;
3647
+ const flat = options.flat;
3648
+ try {
3649
+ if (!isLoggedIn()) {
3650
+ if (json) {
3651
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3652
+ } else {
3653
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3654
+ }
3655
+ process.exit(1);
3656
+ }
3657
+ const client = createClient();
3658
+ const data = await client.getPages();
3659
+ if (json) {
3660
+ console.log(JSON.stringify(data));
3661
+ return;
3662
+ }
3663
+ if (data.pages.length === 0) {
3664
+ console.log(source_default.gray("No pages found"));
3665
+ return;
3666
+ }
3667
+ console.log(source_default.blue("Pages"));
3668
+ console.log();
3669
+ if (flat) {
3670
+ for (const page of data.pages) {
3671
+ const status = page.status ? source_default.gray(` [${page.status}]`) : "";
3672
+ const owner = page.ownerName ? source_default.gray(` @${page.ownerName}`) : "";
3673
+ console.log(` ${source_default.white(page.title)}${status}${owner}`);
3674
+ console.log(` ${source_default.gray(page.slug)}`);
3675
+ console.log();
3676
+ }
3677
+ } else {
3678
+ const tree = buildTree(data.pages);
3679
+ printTree(tree);
3680
+ }
3681
+ } catch (error) {
3682
+ handleApiError(error);
3683
+ }
3684
+ });
3685
+ pages.command("get <slug>").description("Get page details").option("--json", "Output as JSON").addHelpText("after", `
3686
+ Examples:
3687
+ $ thoughtful pages get roadmap
3688
+ Roadmap
3689
+ Slug: roadmap
3690
+ ID: pg_abc123
3691
+ Status: active
3692
+ Owner: Alice Smith
3693
+ Created: 1/15/2025, 10:30:00 AM
3694
+ Updated: 1/18/2025, 3:45:00 PM
3695
+
3696
+ $ thoughtful pages get roadmap --json
3697
+ {"page":{"id":"pg_abc123","slug":"roadmap","title":"Roadmap",...}}
3698
+ `).action(async (slug, options) => {
3699
+ const json = options.json;
3700
+ try {
3701
+ if (!isLoggedIn()) {
3702
+ if (json) {
3703
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3704
+ } else {
3705
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3706
+ }
3707
+ process.exit(1);
3708
+ }
3709
+ const client = createClient();
3710
+ const data = await client.getPage(slug);
3711
+ if (json) {
3712
+ console.log(JSON.stringify(data));
3713
+ return;
3714
+ }
3715
+ const page = data.page;
3716
+ console.log(source_default.blue(page.title));
3717
+ console.log();
3718
+ console.log(` ${source_default.gray("Slug:")} ${page.slug}`);
3719
+ console.log(` ${source_default.gray("ID:")} ${page.id}`);
3720
+ if (page.status) {
3721
+ console.log(` ${source_default.gray("Status:")} ${page.status}`);
3722
+ }
3723
+ if (page.ownerName) {
3724
+ console.log(` ${source_default.gray("Owner:")} ${page.ownerName}`);
3725
+ }
3726
+ if (page.parentSlug) {
3727
+ console.log(` ${source_default.gray("Parent:")} ${page.parentSlug}`);
3728
+ }
3729
+ console.log(` ${source_default.gray("Created:")} ${new Date(page.createdAt).toLocaleString()}`);
3730
+ console.log(` ${source_default.gray("Updated:")} ${new Date(page.updatedAt).toLocaleString()}`);
3731
+ if (page.description) {
3732
+ console.log();
3733
+ console.log(source_default.gray("Description:"));
3734
+ console.log(page.description);
3735
+ }
3736
+ } catch (error) {
3737
+ handleApiError(error);
3738
+ }
3739
+ });
3740
+ pages.command("create [title]").description("Create a new page (use '-' to read title from stdin)").option("--parent <slug>", "Parent page slug").option("--owner <email>", "Owner email").option("--status <status>", "Page status").option("--json", "Output as JSON").addHelpText("after", `
3741
+ Examples:
3742
+ $ thoughtful pages create "Q3 Goals"
3743
+ Created page: Q3 Goals
3744
+ Slug: q3-goals
3745
+
3746
+ $ thoughtful pages create "Q3 Goals" --parent roadmap --owner alice@example.com --status draft
3747
+ Created page: Q3 Goals
3748
+ Slug: q3-goals
3749
+
3750
+ $ echo "Project Plan" | thoughtful pages create -
3751
+ Created page: Project Plan
3752
+ Slug: project-plan
3753
+
3754
+ $ thoughtful pages create "Project Plan" --json
3755
+ {"success":true,"page":{"id":"pg_new123","slug":"project-plan","title":"Project Plan"}}
3756
+ `).action(async (titleArg, options) => {
3757
+ const json = options.json;
3758
+ try {
3759
+ if (!isLoggedIn()) {
3760
+ if (json) {
3761
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3762
+ } else {
3763
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3764
+ }
3765
+ process.exit(1);
3766
+ }
3767
+ let title;
3768
+ if (titleArg === "-" || !titleArg && !process.stdin.isTTY) {
3769
+ const chunks = [];
3770
+ for await (const chunk of process.stdin) {
3771
+ chunks.push(chunk);
3772
+ }
3773
+ title = Buffer.concat(chunks).toString("utf-8").trim();
3774
+ if (!title) {
3775
+ throw new ValidationError("No title provided via stdin");
3776
+ }
3777
+ } else if (titleArg) {
3778
+ title = titleArg;
3779
+ } else {
3780
+ throw new ValidationError("Title is required. Use '-' to read from stdin.");
3781
+ }
3782
+ const client = createClient();
3783
+ const data = await client.createPage({
3784
+ title,
3785
+ parentSlug: options.parent,
3786
+ ownerEmail: options.owner,
3787
+ status: options.status
3788
+ });
3789
+ if (json) {
3790
+ console.log(JSON.stringify({ success: true, page: data.page }));
3791
+ } else {
3792
+ console.log(source_default.green(`Created page: ${data.page.title}`));
3793
+ console.log(source_default.gray(`Slug: ${data.page.slug}`));
3794
+ }
3795
+ } catch (error) {
3796
+ handleApiError(error);
3797
+ }
3798
+ });
3799
+ pages.command("update <slug>").description("Update a page").option("--title <title>", "New title").option("--status <status>", "New status").option("--owner <email>", "New owner email").option("--dry-run", "Show what would be updated without making changes").option("--json", "Output as JSON").addHelpText("after", `
3800
+ Examples:
3801
+ $ thoughtful pages update roadmap --status completed
3802
+ Updated page: Roadmap
3803
+
3804
+ $ thoughtful pages update q1-goals --title "Q1 2025 Goals" --owner bob@example.com
3805
+ Updated page: Q1 2025 Goals
3806
+
3807
+ $ thoughtful pages update roadmap --status active --dry-run
3808
+ Dry run mode - no changes will be made
3809
+ Page: roadmap
3810
+ Updates:
3811
+ status: active
3812
+
3813
+ $ thoughtful pages update roadmap --status active --json
3814
+ {"success":true,"page":{"id":"pg_abc123","slug":"roadmap","title":"Roadmap","status":"active"}}
3815
+ `).action(async (slug, options) => {
3816
+ const json = options.json;
3817
+ const dryRun = options.dryRun;
3818
+ try {
3819
+ if (!isLoggedIn()) {
3820
+ if (json) {
3821
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3822
+ } else {
3823
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3824
+ }
3825
+ process.exit(1);
3826
+ }
3827
+ const updates = {};
3828
+ if (options.title)
3829
+ updates.title = options.title;
3830
+ if (options.status)
3831
+ updates.status = options.status;
3832
+ if (options.owner)
3833
+ updates.ownerEmail = options.owner;
3834
+ if (Object.keys(updates).length === 0) {
3835
+ throw new ValidationError("No updates specified. Use --title, --status, or --owner");
3836
+ }
3837
+ if (dryRun) {
3838
+ if (json) {
3839
+ console.log(JSON.stringify({
3840
+ dryRun: true,
3841
+ slug,
3842
+ updates,
3843
+ message: "No changes made (dry run)"
3844
+ }));
3845
+ } else {
3846
+ console.log(source_default.blue("Dry run mode - no changes will be made"));
3847
+ console.log();
3848
+ console.log(source_default.gray(`Page: ${slug}`));
3849
+ console.log(source_default.gray("Updates:"));
3850
+ for (const [key, value] of Object.entries(updates)) {
3851
+ console.log(` ${source_default.gray(`${key}:`)} ${value}`);
3852
+ }
3853
+ }
3854
+ return;
3855
+ }
3856
+ const client = createClient();
3857
+ const data = await client.updatePage(slug, updates);
3858
+ if (json) {
3859
+ console.log(JSON.stringify({ success: true, page: data.page }));
3860
+ } else {
3861
+ console.log(source_default.green(`Updated page: ${data.page.title}`));
3862
+ }
3863
+ } catch (error) {
3864
+ handleApiError(error);
3865
+ }
3866
+ });
3867
+ pages.command("delete <slug>").description("Delete a page").option("-y, --yes", "Skip confirmation").option("--dry-run", "Show what would be deleted without making changes").option("--json", "Output as JSON").addHelpText("after", `
3868
+ Examples:
3869
+ $ thoughtful pages delete old-draft
3870
+ Are you sure you want to delete 'old-draft'? (y/N) y
3871
+ Deleted page: old-draft
3872
+
3873
+ $ thoughtful pages delete old-draft --yes
3874
+ Deleted page: old-draft
3875
+
3876
+ $ thoughtful pages delete old-draft --dry-run
3877
+ Dry run mode - no changes will be made
3878
+ Would delete page: old-draft
3879
+
3880
+ $ thoughtful pages delete old-draft --yes --json
3881
+ {"success":true}
3882
+ `).action(async (slug, options) => {
3883
+ const json = options.json;
3884
+ const skipConfirm = options.yes;
3885
+ const dryRun = options.dryRun;
3886
+ try {
3887
+ if (!isLoggedIn()) {
3888
+ if (json) {
3889
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3890
+ } else {
3891
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3892
+ }
3893
+ process.exit(1);
3894
+ }
3895
+ if (dryRun) {
3896
+ if (json) {
3897
+ console.log(JSON.stringify({
3898
+ dryRun: true,
3899
+ slug,
3900
+ message: "No changes made (dry run)"
3901
+ }));
3902
+ } else {
3903
+ console.log(source_default.blue("Dry run mode - no changes will be made"));
3904
+ console.log();
3905
+ console.log(source_default.gray(`Would delete page: ${slug}`));
3906
+ }
3907
+ return;
3908
+ }
3909
+ if (!skipConfirm && !json) {
3910
+ try {
3911
+ const shouldDelete = await confirm(`Are you sure you want to delete '${slug}'?`, { defaultValue: false });
3912
+ if (!shouldDelete) {
3913
+ console.log(source_default.yellow("Cancelled"));
3914
+ return;
3915
+ }
3916
+ } catch (error) {
3917
+ if (error instanceof Error) {
3918
+ throw new ValidationError(`Cannot confirm deletion. ${error.message} Use --yes flag to skip confirmation.`);
3919
+ }
3920
+ throw error;
3921
+ }
3922
+ }
3923
+ const client = createClient();
3924
+ await client.deletePage(slug);
3925
+ if (json) {
3926
+ console.log(JSON.stringify({ success: true }));
3927
+ } else {
3928
+ console.log(source_default.green(`Deleted page: ${slug}`));
3929
+ }
3930
+ } catch (error) {
3931
+ handleApiError(error);
3932
+ }
3933
+ });
3934
+ pages.command("search <query>").description("Search pages").option("--json", "Output as JSON").addHelpText("after", `
3935
+ Examples:
3936
+ $ thoughtful pages search "quarterly goals"
3937
+ Search results for 'quarterly goals'
3938
+ Q1 Goals [active]
3939
+ q1-goals
3940
+ Planning and objectives for Q1 2025
3941
+
3942
+ Q2 Goals [draft]
3943
+ q2-goals
3944
+
3945
+ $ thoughtful pages search "roadmap" --json
3946
+ {"pages":[{"id":"pg_123","slug":"roadmap","title":"Roadmap",...},...]}
3947
+ `).action(async (query, options) => {
3948
+ const json = options.json;
3949
+ try {
3950
+ if (!isLoggedIn()) {
3951
+ if (json) {
3952
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
3953
+ } else {
3954
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
3955
+ }
3956
+ process.exit(1);
3957
+ }
3958
+ const client = createClient();
3959
+ const data = await client.searchPages(query);
3960
+ if (json) {
3961
+ console.log(JSON.stringify(data));
3962
+ return;
3963
+ }
3964
+ if (data.pages.length === 0) {
3965
+ console.log(source_default.gray(`No pages found matching '${query}'`));
3966
+ return;
3967
+ }
3968
+ console.log(source_default.blue(`Search results for '${query}'`));
3969
+ console.log();
3970
+ for (const page of data.pages) {
3971
+ const status = page.status ? source_default.gray(` [${page.status}]`) : "";
3972
+ console.log(` ${source_default.white(page.title)}${status}`);
3973
+ console.log(` ${source_default.gray(page.slug)}`);
3974
+ if (page.description) {
3975
+ const desc = page.description.length > 100 ? page.description.slice(0, 100) + "..." : page.description;
3976
+ console.log(` ${source_default.gray(desc)}`);
3977
+ }
3978
+ console.log();
3979
+ }
3980
+ } catch (error) {
3981
+ handleApiError(error);
3982
+ }
3983
+ });
3984
+ }
3985
+
3986
+ // src/commands/chat.ts
3987
+ function registerChatCommands(program2) {
3988
+ const threads = program2.command("threads").description("Manage chat threads").addHelpText("after", `
3989
+ Examples:
3990
+ $ thoughtful threads list
3991
+ $ thoughtful threads new "What's the status of project X?"
3992
+ $ thoughtful threads show thread_abc123
3993
+ $ thoughtful threads send thread_abc123 "Can you provide more details?"
3994
+ `);
3995
+ threads.command("list").description("List recent chat threads").option("--json", "Output as JSON").addHelpText("after", `
3996
+ Examples:
3997
+ $ thoughtful threads list
3998
+ Chat Threads
3999
+ Project Status Discussion
4000
+ ID: thread_abc123
4001
+ Last activity: 1/18/2025
4002
+
4003
+ Weekly Planning
4004
+ ID: thread_xyz789
4005
+ Last activity: 1/15/2025
4006
+
4007
+ $ thoughtful threads list --json
4008
+ {"threads":[{"providerThreadId":"thread_abc123","title":"Project Status Discussion",...},...]}
4009
+ `).action(async (options) => {
4010
+ const json = options.json;
4011
+ try {
4012
+ if (!isLoggedIn()) {
4013
+ if (json) {
4014
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
4015
+ } else {
4016
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
4017
+ }
4018
+ process.exit(1);
4019
+ }
4020
+ const client = createClient();
4021
+ const data = await client.getThreads();
4022
+ if (json) {
4023
+ console.log(JSON.stringify(data));
4024
+ return;
4025
+ }
4026
+ if (data.threads.length === 0) {
4027
+ console.log(source_default.gray("No chat threads found"));
4028
+ return;
4029
+ }
4030
+ console.log(source_default.blue("Chat Threads"));
4031
+ console.log();
4032
+ for (const thread of data.threads) {
4033
+ const title = thread.title || source_default.gray("(untitled)");
4034
+ const date = thread.lastMessageAt ? new Date(thread.lastMessageAt).toLocaleDateString() : new Date(thread.createdAt).toLocaleDateString();
4035
+ console.log(` ${source_default.white(title)}`);
4036
+ console.log(` ${source_default.gray(`ID: ${thread.providerThreadId}`)}`);
4037
+ console.log(` ${source_default.gray(`Last activity: ${date}`)}`);
4038
+ console.log();
4039
+ }
4040
+ } catch (error) {
4041
+ handleApiError(error);
4042
+ }
4043
+ });
4044
+ threads.command("new [message]").description("Start a new chat thread").option("--json", "Output as JSON").option("--no-ai", "Don't trigger AI response").addHelpText("after", `
4045
+ Examples:
4046
+ $ thoughtful threads new
4047
+ Created new chat thread
4048
+ Thread ID: thread_abc123
4049
+
4050
+ $ thoughtful threads new "What's the status of project X?"
4051
+ Created new chat thread
4052
+ Thread ID: thread_abc123
4053
+
4054
+ AI Response:
4055
+ Based on the latest updates...
4056
+
4057
+ $ thoughtful threads new "What are our Q1 goals?" --json
4058
+ {"success":true,"thread":{"providerThreadId":"thread_abc123"},"aiResponse":{...}}
4059
+
4060
+ $ thoughtful threads new "Hello" --no-ai
4061
+ Created new chat thread
4062
+ Thread ID: thread_abc123
4063
+ Sent initial message
4064
+ `).action(async (message, options) => {
4065
+ const json = options.json;
4066
+ const triggerAi = options.ai !== false;
4067
+ try {
4068
+ if (!isLoggedIn()) {
4069
+ if (json) {
4070
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
4071
+ } else {
4072
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
4073
+ }
4074
+ process.exit(1);
4075
+ }
4076
+ const client = createClient();
4077
+ if (message && triggerAi) {
4078
+ const threadData = await client.createThread();
4079
+ const threadId = threadData.thread.providerThreadId;
4080
+ if (json) {
4081
+ console.log(JSON.stringify({ success: true, thread: { providerThreadId: threadId } }));
4082
+ } else {
4083
+ console.log(source_default.green("Created new chat thread"));
4084
+ console.log(source_default.gray(`Thread ID: ${threadId}`));
4085
+ console.log();
4086
+ }
4087
+ const response = await client.sendMessageWithResponse(threadId, message);
4088
+ if (json) {
4089
+ console.log(JSON.stringify({ success: true, ...response }));
4090
+ } else {
4091
+ console.log(source_default.bold("AI Response:"));
4092
+ console.log(response.aiResponse.content);
4093
+ }
4094
+ } else {
4095
+ const data = await client.createThread(message);
4096
+ if (json) {
4097
+ console.log(JSON.stringify({ success: true, ...data }));
4098
+ } else {
4099
+ console.log(source_default.green("Created new chat thread"));
4100
+ console.log(source_default.gray(`Thread ID: ${data.thread.providerThreadId}`));
4101
+ if (message) {
4102
+ console.log(source_default.gray("Sent initial message"));
4103
+ }
4104
+ }
4105
+ }
4106
+ } catch (error) {
4107
+ handleApiError(error);
4108
+ }
4109
+ });
4110
+ threads.command("show <thread-id>").description("Show messages in a thread").option("--json", "Output as JSON").addHelpText("after", `
4111
+ Examples:
4112
+ $ thoughtful threads show thread_abc123
4113
+ Thread thread_abc123
4114
+
4115
+ You (1/18/2025, 10:30:00 AM)
4116
+ What's the status of project X?
4117
+
4118
+ Assistant (1/18/2025, 10:30:15 AM)
4119
+ Project X is currently in the testing phase...
4120
+
4121
+ $ thoughtful threads show thread_abc123 --json
4122
+ {"messages":[{"role":"user","content":"What's the status of project X?",...},...]}
4123
+ `).action(async (threadId, options) => {
4124
+ const json = options.json;
4125
+ try {
4126
+ if (!isLoggedIn()) {
4127
+ if (json) {
4128
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
4129
+ } else {
4130
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
4131
+ }
4132
+ process.exit(1);
4133
+ }
4134
+ const client = createClient();
4135
+ const data = await client.getThreadMessages(threadId);
4136
+ if (json) {
4137
+ console.log(JSON.stringify(data));
4138
+ return;
4139
+ }
4140
+ if (data.messages.length === 0) {
4141
+ console.log(source_default.gray("No messages in this thread"));
4142
+ return;
4143
+ }
4144
+ console.log(source_default.blue(`Thread ${threadId}`));
4145
+ console.log();
4146
+ for (const msg of data.messages) {
4147
+ const roleColor = msg.role === "user" ? source_default.cyan : source_default.green;
4148
+ const roleLabel = msg.role === "user" ? "You" : "Assistant";
4149
+ const date = new Date(msg.createdAt).toLocaleString();
4150
+ console.log(`${roleColor(roleLabel)} ${source_default.gray(`(${date})`)}`);
4151
+ console.log(msg.content);
4152
+ console.log();
4153
+ }
4154
+ } catch (error) {
4155
+ handleApiError(error);
4156
+ }
4157
+ });
4158
+ threads.command("send <thread-id> [message...]").description("Send a message to a thread and get AI response (use '-' to read from stdin)").option("--json", "Output as JSON").option("--no-ai", "Don't trigger AI response").addHelpText("after", `
4159
+ Examples:
4160
+ $ thoughtful threads send thread_abc123 "Can you provide more details?"
4161
+ Sent message
4162
+
4163
+ AI Response:
4164
+ Sure! Here are the details...
4165
+
4166
+ $ thoughtful threads send thread_abc123 What is the next milestone?
4167
+ Sent message
4168
+
4169
+ AI Response:
4170
+ The next milestone is scheduled for...
4171
+
4172
+ $ echo "What are the blockers?" | thoughtful threads send thread_abc123 -
4173
+ Sent message
4174
+
4175
+ AI Response:
4176
+ Currently, the main blockers are...
4177
+
4178
+ $ thoughtful threads send thread_abc123 "Update please" --json
4179
+ {"success":true,"userMessage":{...},"aiResponse":{...}}
4180
+
4181
+ $ thoughtful threads send thread_abc123 "Just a note" --no-ai
4182
+ Message sent
4183
+ `).action(async (threadId, messageParts, options) => {
4184
+ const json = options.json;
4185
+ const triggerAi = options.ai !== false;
4186
+ try {
4187
+ if (!isLoggedIn()) {
4188
+ if (json) {
4189
+ console.log(JSON.stringify({ error: true, message: "Not logged in" }));
4190
+ } else {
4191
+ console.log(source_default.yellow("Not logged in. Run 'thoughtful login' first."));
4192
+ }
4193
+ process.exit(1);
4194
+ }
4195
+ let message;
4196
+ if (messageParts.length === 1 && messageParts[0] === "-" || messageParts.length === 0 && !process.stdin.isTTY) {
4197
+ const chunks = [];
4198
+ for await (const chunk of process.stdin) {
4199
+ chunks.push(chunk);
4200
+ }
4201
+ message = Buffer.concat(chunks).toString("utf-8").trim();
4202
+ if (!message) {
4203
+ throw new ValidationError("No message provided via stdin");
4204
+ }
4205
+ } else if (messageParts.length > 0) {
4206
+ message = messageParts.join(" ");
4207
+ } else {
4208
+ throw new ValidationError("Message is required. Use '-' to read from stdin.");
4209
+ }
4210
+ const client = createClient();
4211
+ if (triggerAi) {
4212
+ const data = await client.sendMessageWithResponse(threadId, message);
4213
+ if (json) {
4214
+ console.log(JSON.stringify({ success: true, ...data }));
4215
+ } else {
4216
+ console.log(source_default.gray("Sent message"));
4217
+ console.log();
4218
+ console.log(source_default.bold("AI Response:"));
4219
+ console.log(data.aiResponse.content);
4220
+ }
4221
+ } else {
4222
+ const data = await client.sendThreadMessage(threadId, message);
4223
+ if (json) {
4224
+ console.log(JSON.stringify({ success: true, message: data.message }));
4225
+ } else {
4226
+ console.log(source_default.green("Message sent"));
4227
+ }
4228
+ }
4229
+ } catch (error) {
4230
+ handleApiError(error);
4231
+ }
4232
+ });
4233
+ }
4234
+
4235
+ // src/commands/completion.ts
4236
+ var bashCompletion = `
4237
+ # Bash completion for thoughtful CLI
4238
+ # Add this to your ~/.bashrc or ~/.bash_profile:
4239
+ # eval "$(thoughtful completion bash)"
4240
+
4241
+ _thoughtful_completion() {
4242
+ local cur prev opts
4243
+ COMPREPLY=()
4244
+ cur="\${COMP_WORDS[COMP_CWORD]}"
4245
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
4246
+
4247
+ # Top-level commands
4248
+ if [ \${COMP_CWORD} -eq 1 ]; then
4249
+ opts="login logout whoami orgs workspaces pages threads completion help"
4250
+ COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
4251
+ return 0
4252
+ fi
4253
+
4254
+ # Subcommands
4255
+ case "\${COMP_WORDS[1]}" in
4256
+ orgs)
4257
+ if [ \${COMP_CWORD} -eq 2 ]; then
4258
+ opts="list switch"
4259
+ COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
4260
+ fi
4261
+ ;;
4262
+ workspaces)
4263
+ if [ \${COMP_CWORD} -eq 2 ]; then
4264
+ opts="list switch create"
4265
+ COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
4266
+ fi
4267
+ ;;
4268
+ pages)
4269
+ if [ \${COMP_CWORD} -eq 2 ]; then
4270
+ opts="list get create update delete search"
4271
+ COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
4272
+ fi
4273
+ ;;
4274
+ threads)
4275
+ if [ \${COMP_CWORD} -eq 2 ]; then
4276
+ opts="list new show send"
4277
+ COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
4278
+ fi
4279
+ ;;
4280
+ completion)
4281
+ if [ \${COMP_CWORD} -eq 2 ]; then
4282
+ opts="bash zsh fish"
4283
+ COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
4284
+ fi
4285
+ ;;
4286
+ esac
4287
+
4288
+ # Options
4289
+ case "\${prev}" in
4290
+ --parent|--owner|--status|--title)
4291
+ # No completion for these
4292
+ return 0
4293
+ ;;
4294
+ *)
4295
+ # Suggest flags
4296
+ if [[ \${cur} == -* ]]; then
4297
+ opts="--json --help --flat --yes"
4298
+ COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
4299
+ fi
4300
+ ;;
4301
+ esac
4302
+ }
4303
+
4304
+ complete -F _thoughtful_completion thoughtful
4305
+ `;
4306
+ var zshCompletion = `
4307
+ # Zsh completion for thoughtful CLI
4308
+ # Add this to your ~/.zshrc:
4309
+ # eval "$(thoughtful completion zsh)"
4310
+
4311
+ #compdef thoughtful
4312
+
4313
+ _thoughtful() {
4314
+ local line state
4315
+
4316
+ _arguments -C \\
4317
+ "1: :->cmds" \\
4318
+ "*::arg:->args"
4319
+
4320
+ case "$state" in
4321
+ cmds)
4322
+ _values "thoughtful commands" \\
4323
+ "login[Log in to Thoughtful]" \\
4324
+ "logout[Log out]" \\
4325
+ "whoami[Show current user info]" \\
4326
+ "orgs[Manage organizations]" \\
4327
+ "workspaces[Manage workspaces]" \\
4328
+ "pages[Manage pages]" \\
4329
+ "threads[Manage chat threads]" \\
4330
+ "completion[Generate shell completion scripts]" \\
4331
+ "help[Display help information]"
4332
+ ;;
4333
+ args)
4334
+ case $line[1] in
4335
+ orgs)
4336
+ _values "orgs commands" \\
4337
+ "list[List organizations]" \\
4338
+ "switch[Switch to a different organization]"
4339
+ ;;
4340
+ workspaces)
4341
+ _values "workspaces commands" \\
4342
+ "list[List workspaces]" \\
4343
+ "switch[Switch to a different workspace]" \\
4344
+ "create[Create a new workspace]"
4345
+ ;;
4346
+ pages)
4347
+ _values "pages commands" \\
4348
+ "list[List all pages]" \\
4349
+ "get[Get page details]" \\
4350
+ "create[Create a new page]" \\
4351
+ "update[Update a page]" \\
4352
+ "delete[Delete a page]" \\
4353
+ "search[Search pages]"
4354
+ ;;
4355
+ threads)
4356
+ _values "threads commands" \\
4357
+ "list[List recent chat threads]" \\
4358
+ "new[Start a new chat thread]" \\
4359
+ "show[Show messages in a thread]" \\
4360
+ "send[Send a message to a thread]"
4361
+ ;;
4362
+ completion)
4363
+ _values "completion shells" \\
4364
+ "bash[Generate bash completion script]" \\
4365
+ "zsh[Generate zsh completion script]" \\
4366
+ "fish[Generate fish completion script]"
4367
+ ;;
4368
+ esac
4369
+ ;;
4370
+ esac
4371
+ }
4372
+
4373
+ _thoughtful
4374
+ `;
4375
+ var fishCompletion = `
4376
+ # Fish completion for thoughtful CLI
4377
+ # Add this to your ~/.config/fish/completions/thoughtful.fish:
4378
+ # thoughtful completion fish > ~/.config/fish/completions/thoughtful.fish
4379
+
4380
+ # Remove old completions
4381
+ complete -c thoughtful -e
4382
+
4383
+ # Top-level commands
4384
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "login" -d "Log in to Thoughtful"
4385
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "logout" -d "Log out"
4386
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "whoami" -d "Show current user info"
4387
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "orgs" -d "Manage organizations"
4388
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "workspaces" -d "Manage workspaces"
4389
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "pages" -d "Manage pages"
4390
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "threads" -d "Manage chat threads"
4391
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "completion" -d "Generate shell completion scripts"
4392
+ complete -c thoughtful -f -n "__fish_use_subcommand" -a "help" -d "Display help information"
4393
+
4394
+ # orgs subcommands
4395
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from orgs; and not __fish_seen_subcommand_from list switch" -a "list" -d "List organizations"
4396
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from orgs; and not __fish_seen_subcommand_from list switch" -a "switch" -d "Switch to a different organization"
4397
+
4398
+ # workspaces subcommands
4399
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from workspaces; and not __fish_seen_subcommand_from list switch create" -a "list" -d "List workspaces"
4400
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from workspaces; and not __fish_seen_subcommand_from list switch create" -a "switch" -d "Switch to a different workspace"
4401
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from workspaces; and not __fish_seen_subcommand_from list switch create" -a "create" -d "Create a new workspace"
4402
+
4403
+ # pages subcommands
4404
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from pages; and not __fish_seen_subcommand_from list get create update delete search" -a "list" -d "List all pages"
4405
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from pages; and not __fish_seen_subcommand_from list get create update delete search" -a "get" -d "Get page details"
4406
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from pages; and not __fish_seen_subcommand_from list get create update delete search" -a "create" -d "Create a new page"
4407
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from pages; and not __fish_seen_subcommand_from list get create update delete search" -a "update" -d "Update a page"
4408
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from pages; and not __fish_seen_subcommand_from list get create update delete search" -a "delete" -d "Delete a page"
4409
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from pages; and not __fish_seen_subcommand_from list get create update delete search" -a "search" -d "Search pages"
4410
+
4411
+ # threads subcommands
4412
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from threads; and not __fish_seen_subcommand_from list new show send" -a "list" -d "List recent chat threads"
4413
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from threads; and not __fish_seen_subcommand_from list new show send" -a "new" -d "Start a new chat thread"
4414
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from threads; and not __fish_seen_subcommand_from list new show send" -a "show" -d "Show messages in a thread"
4415
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from threads; and not __fish_seen_subcommand_from list new show send" -a "send" -d "Send a message to a thread"
4416
+
4417
+ # completion subcommands
4418
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish" -a "bash" -d "Generate bash completion script"
4419
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish" -a "zsh" -d "Generate zsh completion script"
4420
+ complete -c thoughtful -f -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish" -a "fish" -d "Generate fish completion script"
4421
+
4422
+ # Global options
4423
+ complete -c thoughtful -l json -d "Output as JSON"
4424
+ complete -c thoughtful -l help -d "Display help"
4425
+ complete -c thoughtful -l flat -d "Show flat list instead of tree"
4426
+ complete -c thoughtful -l yes -s y -d "Skip confirmation"
4427
+ complete -c thoughtful -l parent -d "Parent page slug"
4428
+ complete -c thoughtful -l owner -d "Owner email"
4429
+ complete -c thoughtful -l status -d "Page status"
4430
+ complete -c thoughtful -l title -d "Page title"
4431
+ `;
4432
+ function registerCompletionCommand(program2) {
4433
+ const completion = program2.command("completion").description("Generate shell completion scripts");
4434
+ completion.command("bash").description("Generate bash completion script").action(() => {
4435
+ console.log(bashCompletion);
4436
+ });
4437
+ completion.command("zsh").description("Generate zsh completion script").action(() => {
4438
+ console.log(zshCompletion);
4439
+ });
4440
+ completion.command("fish").description("Generate fish completion script").action(() => {
4441
+ console.log(fishCompletion);
4442
+ });
4443
+ completion.action(() => {
4444
+ console.log(source_default.blue("Shell Completion Installation"));
4445
+ console.log();
4446
+ console.log("Generate completion scripts for your shell:");
4447
+ console.log();
4448
+ console.log(source_default.cyan("Bash:"));
4449
+ console.log(" Add to ~/.bashrc:");
4450
+ console.log(source_default.gray(' eval "$(thoughtful completion bash)"'));
4451
+ console.log();
4452
+ console.log(source_default.cyan("Zsh:"));
4453
+ console.log(" Add to ~/.zshrc:");
4454
+ console.log(source_default.gray(' eval "$(thoughtful completion zsh)"'));
4455
+ console.log();
4456
+ console.log(source_default.cyan("Fish:"));
4457
+ console.log(" Save to completions directory:");
4458
+ console.log(source_default.gray(" thoughtful completion fish > ~/.config/fish/completions/thoughtful.fish"));
4459
+ console.log();
4460
+ console.log("After adding the completion script, restart your shell or source the config file.");
4461
+ });
4462
+ }
4463
+
4464
+ // src/index.ts
4465
+ var __filename2 = fileURLToPath(import.meta.url);
4466
+ var __dirname2 = dirname(__filename2);
4467
+ var packageJsonPath = join(__dirname2, "..", "package.json");
4468
+ var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
4469
+ var version = packageJson.version;
4470
+ var program2 = new Command;
4471
+ program2.name("thoughtful").description("CLI for interacting with your Thoughtful workspace").version(version).option("--json", "Output as JSON").option("--no-color", "Disable colored output").option("-q, --quiet", "Suppress non-essential output").option("-v, --verbose", "Show verbose output").option("--no-input", "Disable interactive prompts (requires all inputs via flags)").option("--dev", "Use development API (http://localhost:3000)").option("--prod", "Use production API (https://www.thoughtful.app)").hook("preAction", (thisCommand) => {
4472
+ const opts = thisCommand.opts();
4473
+ if (opts.dev && opts.prod) {
4474
+ console.error("Error: Cannot specify both --dev and --prod flags");
4475
+ process.exit(1);
4476
+ }
4477
+ if (opts.dev) {
4478
+ setEnvironmentOverride("dev");
4479
+ } else if (opts.prod) {
4480
+ setEnvironmentOverride("prod");
4481
+ }
4482
+ setGlobalOptions({
4483
+ json: opts.json,
4484
+ noColor: opts.color === false,
4485
+ quiet: opts.quiet,
4486
+ verbose: opts.verbose,
4487
+ noInput: opts.input === false
4488
+ });
4489
+ }).addHelpText("after", `
4490
+ Examples:
4491
+ $ thoughtful login
4492
+ $ thoughtful whoami
4493
+
4494
+ $ thoughtful pages list
4495
+ $ thoughtful pages create "Project Plan" --parent roadmap --owner alice@example.com
4496
+ $ thoughtful pages search "quarterly goals"
4497
+
4498
+ $ thoughtful orgs list
4499
+ $ thoughtful workspaces switch ws_abc123
4500
+
4501
+ $ thoughtful threads new "What's the status of project X?"
4502
+ $ thoughtful threads list --json | jq '.threads[0]'
4503
+
4504
+ For more help on a specific command, run:
4505
+ $ thoughtful <command> --help
4506
+ `);
4507
+ registerAuthCommands(program2);
4508
+ registerOrgsCommands(program2);
4509
+ registerWorkspacesCommands(program2);
4510
+ registerPagesCommands(program2);
4511
+ registerChatCommands(program2);
4512
+ registerCompletionCommand(program2);
4513
+ program2.parse();