@drakulavich/oura-cli 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/index.js +1636 -3028
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,2209 +1,22 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- var __create = Object.create;
4
- var __getProtoOf = Object.getPrototypeOf;
5
3
  var __defProp = Object.defineProperty;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- function __accessProp(key) {
9
- return this[key];
10
- }
11
- var __toESMCache_node;
12
- var __toESMCache_esm;
13
- var __toESM = (mod, isNodeMode, target) => {
14
- var canCache = mod != null && typeof mod === "object";
15
- if (canCache) {
16
- var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
- var cached = cache.get(mod);
18
- if (cached)
19
- return cached;
20
- }
21
- target = mod != null ? __create(__getProtoOf(mod)) : {};
22
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
23
- for (let key of __getOwnPropNames(mod))
24
- if (!__hasOwnProp.call(to, key))
25
- __defProp(to, key, {
26
- get: __accessProp.bind(mod, key),
27
- enumerable: true
28
- });
29
- if (canCache)
30
- cache.set(mod, to);
31
- return to;
32
- };
33
- var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
- var __require = import.meta.require;
35
-
36
- // node_modules/commander/lib/error.js
37
- var require_error = __commonJS((exports) => {
38
- class CommanderError extends Error {
39
- constructor(exitCode, code, message) {
40
- super(message);
41
- Error.captureStackTrace(this, this.constructor);
42
- this.name = this.constructor.name;
43
- this.code = code;
44
- this.exitCode = exitCode;
45
- this.nestedError = undefined;
46
- }
47
- }
48
-
49
- class InvalidArgumentError extends CommanderError {
50
- constructor(message) {
51
- super(1, "commander.invalidArgument", message);
52
- Error.captureStackTrace(this, this.constructor);
53
- this.name = this.constructor.name;
54
- }
55
- }
56
- exports.CommanderError = CommanderError;
57
- exports.InvalidArgumentError = InvalidArgumentError;
58
- });
59
-
60
- // node_modules/commander/lib/argument.js
61
- var require_argument = __commonJS((exports) => {
62
- var { InvalidArgumentError } = require_error();
63
-
64
- class Argument {
65
- constructor(name, description) {
66
- this.description = description || "";
67
- this.variadic = false;
68
- this.parseArg = undefined;
69
- this.defaultValue = undefined;
70
- this.defaultValueDescription = undefined;
71
- this.argChoices = undefined;
72
- switch (name[0]) {
73
- case "<":
74
- this.required = true;
75
- this._name = name.slice(1, -1);
76
- break;
77
- case "[":
78
- this.required = false;
79
- this._name = name.slice(1, -1);
80
- break;
81
- default:
82
- this.required = true;
83
- this._name = name;
84
- break;
85
- }
86
- if (this._name.endsWith("...")) {
87
- this.variadic = true;
88
- this._name = this._name.slice(0, -3);
89
- }
90
- }
91
- name() {
92
- return this._name;
93
- }
94
- _collectValue(value, previous) {
95
- if (previous === this.defaultValue || !Array.isArray(previous)) {
96
- return [value];
97
- }
98
- previous.push(value);
99
- return previous;
100
- }
101
- default(value, description) {
102
- this.defaultValue = value;
103
- this.defaultValueDescription = description;
104
- return this;
105
- }
106
- argParser(fn) {
107
- this.parseArg = fn;
108
- return this;
109
- }
110
- choices(values) {
111
- this.argChoices = values.slice();
112
- this.parseArg = (arg, previous) => {
113
- if (!this.argChoices.includes(arg)) {
114
- throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
115
- }
116
- if (this.variadic) {
117
- return this._collectValue(arg, previous);
118
- }
119
- return arg;
120
- };
121
- return this;
122
- }
123
- argRequired() {
124
- this.required = true;
125
- return this;
126
- }
127
- argOptional() {
128
- this.required = false;
129
- return this;
130
- }
131
- }
132
- function humanReadableArgName(arg) {
133
- const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
134
- return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
135
- }
136
- exports.Argument = Argument;
137
- exports.humanReadableArgName = humanReadableArgName;
138
- });
139
-
140
- // node_modules/commander/lib/help.js
141
- var require_help = __commonJS((exports) => {
142
- var { humanReadableArgName } = require_argument();
143
-
144
- class Help {
145
- constructor() {
146
- this.helpWidth = undefined;
147
- this.minWidthToWrap = 40;
148
- this.sortSubcommands = false;
149
- this.sortOptions = false;
150
- this.showGlobalOptions = false;
151
- }
152
- prepareContext(contextOptions) {
153
- this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
154
- }
155
- visibleCommands(cmd) {
156
- const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
157
- const helpCommand = cmd._getHelpCommand();
158
- if (helpCommand && !helpCommand._hidden) {
159
- visibleCommands.push(helpCommand);
160
- }
161
- if (this.sortSubcommands) {
162
- visibleCommands.sort((a, b) => {
163
- return a.name().localeCompare(b.name());
164
- });
165
- }
166
- return visibleCommands;
167
- }
168
- compareOptions(a, b) {
169
- const getSortKey = (option) => {
170
- return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
171
- };
172
- return getSortKey(a).localeCompare(getSortKey(b));
173
- }
174
- visibleOptions(cmd) {
175
- const visibleOptions = cmd.options.filter((option) => !option.hidden);
176
- const helpOption = cmd._getHelpOption();
177
- if (helpOption && !helpOption.hidden) {
178
- const removeShort = helpOption.short && cmd._findOption(helpOption.short);
179
- const removeLong = helpOption.long && cmd._findOption(helpOption.long);
180
- if (!removeShort && !removeLong) {
181
- visibleOptions.push(helpOption);
182
- } else if (helpOption.long && !removeLong) {
183
- visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description));
184
- } else if (helpOption.short && !removeShort) {
185
- visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description));
186
- }
187
- }
188
- if (this.sortOptions) {
189
- visibleOptions.sort(this.compareOptions);
190
- }
191
- return visibleOptions;
192
- }
193
- visibleGlobalOptions(cmd) {
194
- if (!this.showGlobalOptions)
195
- return [];
196
- const globalOptions = [];
197
- for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
198
- const visibleOptions = ancestorCmd.options.filter((option) => !option.hidden);
199
- globalOptions.push(...visibleOptions);
200
- }
201
- if (this.sortOptions) {
202
- globalOptions.sort(this.compareOptions);
203
- }
204
- return globalOptions;
205
- }
206
- visibleArguments(cmd) {
207
- if (cmd._argsDescription) {
208
- cmd.registeredArguments.forEach((argument) => {
209
- argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
210
- });
211
- }
212
- if (cmd.registeredArguments.find((argument) => argument.description)) {
213
- return cmd.registeredArguments;
214
- }
215
- return [];
216
- }
217
- subcommandTerm(cmd) {
218
- const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
219
- return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + (args ? " " + args : "");
220
- }
221
- optionTerm(option) {
222
- return option.flags;
223
- }
224
- argumentTerm(argument) {
225
- return argument.name();
226
- }
227
- longestSubcommandTermLength(cmd, helper) {
228
- return helper.visibleCommands(cmd).reduce((max, command) => {
229
- return Math.max(max, this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command))));
230
- }, 0);
231
- }
232
- longestOptionTermLength(cmd, helper) {
233
- return helper.visibleOptions(cmd).reduce((max, option) => {
234
- return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
235
- }, 0);
236
- }
237
- longestGlobalOptionTermLength(cmd, helper) {
238
- return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
239
- return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
240
- }, 0);
241
- }
242
- longestArgumentTermLength(cmd, helper) {
243
- return helper.visibleArguments(cmd).reduce((max, argument) => {
244
- return Math.max(max, this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument))));
245
- }, 0);
246
- }
247
- commandUsage(cmd) {
248
- let cmdName = cmd._name;
249
- if (cmd._aliases[0]) {
250
- cmdName = cmdName + "|" + cmd._aliases[0];
251
- }
252
- let ancestorCmdNames = "";
253
- for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
254
- ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
255
- }
256
- return ancestorCmdNames + cmdName + " " + cmd.usage();
257
- }
258
- commandDescription(cmd) {
259
- return cmd.description();
260
- }
261
- subcommandDescription(cmd) {
262
- return cmd.summary() || cmd.description();
263
- }
264
- optionDescription(option) {
265
- const extraInfo = [];
266
- if (option.argChoices) {
267
- extraInfo.push(`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
268
- }
269
- if (option.defaultValue !== undefined) {
270
- const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
271
- if (showDefault) {
272
- extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
273
- }
274
- }
275
- if (option.presetArg !== undefined && option.optional) {
276
- extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
277
- }
278
- if (option.envVar !== undefined) {
279
- extraInfo.push(`env: ${option.envVar}`);
280
- }
281
- if (extraInfo.length > 0) {
282
- const extraDescription = `(${extraInfo.join(", ")})`;
283
- if (option.description) {
284
- return `${option.description} ${extraDescription}`;
285
- }
286
- return extraDescription;
287
- }
288
- return option.description;
289
- }
290
- argumentDescription(argument) {
291
- const extraInfo = [];
292
- if (argument.argChoices) {
293
- extraInfo.push(`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
294
- }
295
- if (argument.defaultValue !== undefined) {
296
- extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
297
- }
298
- if (extraInfo.length > 0) {
299
- const extraDescription = `(${extraInfo.join(", ")})`;
300
- if (argument.description) {
301
- return `${argument.description} ${extraDescription}`;
302
- }
303
- return extraDescription;
304
- }
305
- return argument.description;
306
- }
307
- formatItemList(heading, items, helper) {
308
- if (items.length === 0)
309
- return [];
310
- return [helper.styleTitle(heading), ...items, ""];
311
- }
312
- groupItems(unsortedItems, visibleItems, getGroup) {
313
- const result = new Map;
314
- unsortedItems.forEach((item) => {
315
- const group = getGroup(item);
316
- if (!result.has(group))
317
- result.set(group, []);
318
- });
319
- visibleItems.forEach((item) => {
320
- const group = getGroup(item);
321
- if (!result.has(group)) {
322
- result.set(group, []);
323
- }
324
- result.get(group).push(item);
325
- });
326
- return result;
327
- }
328
- formatHelp(cmd, helper) {
329
- const termWidth = helper.padWidth(cmd, helper);
330
- const helpWidth = helper.helpWidth ?? 80;
331
- function callFormatItem(term, description) {
332
- return helper.formatItem(term, termWidth, description, helper);
333
- }
334
- let output = [
335
- `${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,
336
- ""
337
- ];
338
- const commandDescription = helper.commandDescription(cmd);
339
- if (commandDescription.length > 0) {
340
- output = output.concat([
341
- helper.boxWrap(helper.styleCommandDescription(commandDescription), helpWidth),
342
- ""
343
- ]);
344
- }
345
- const argumentList = helper.visibleArguments(cmd).map((argument) => {
346
- return callFormatItem(helper.styleArgumentTerm(helper.argumentTerm(argument)), helper.styleArgumentDescription(helper.argumentDescription(argument)));
347
- });
348
- output = output.concat(this.formatItemList("Arguments:", argumentList, helper));
349
- const optionGroups = this.groupItems(cmd.options, helper.visibleOptions(cmd), (option) => option.helpGroupHeading ?? "Options:");
350
- optionGroups.forEach((options, group) => {
351
- const optionList = options.map((option) => {
352
- return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
353
- });
354
- output = output.concat(this.formatItemList(group, optionList, helper));
355
- });
356
- if (helper.showGlobalOptions) {
357
- const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
358
- return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
359
- });
360
- output = output.concat(this.formatItemList("Global Options:", globalOptionList, helper));
361
- }
362
- const commandGroups = this.groupItems(cmd.commands, helper.visibleCommands(cmd), (sub) => sub.helpGroup() || "Commands:");
363
- commandGroups.forEach((commands, group) => {
364
- const commandList = commands.map((sub) => {
365
- return callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(sub)), helper.styleSubcommandDescription(helper.subcommandDescription(sub)));
366
- });
367
- output = output.concat(this.formatItemList(group, commandList, helper));
368
- });
369
- return output.join(`
370
- `);
371
- }
372
- displayWidth(str) {
373
- return stripColor(str).length;
374
- }
375
- styleTitle(str) {
376
- return str;
377
- }
378
- styleUsage(str) {
379
- return str.split(" ").map((word) => {
380
- if (word === "[options]")
381
- return this.styleOptionText(word);
382
- if (word === "[command]")
383
- return this.styleSubcommandText(word);
384
- if (word[0] === "[" || word[0] === "<")
385
- return this.styleArgumentText(word);
386
- return this.styleCommandText(word);
387
- }).join(" ");
388
- }
389
- styleCommandDescription(str) {
390
- return this.styleDescriptionText(str);
391
- }
392
- styleOptionDescription(str) {
393
- return this.styleDescriptionText(str);
394
- }
395
- styleSubcommandDescription(str) {
396
- return this.styleDescriptionText(str);
397
- }
398
- styleArgumentDescription(str) {
399
- return this.styleDescriptionText(str);
400
- }
401
- styleDescriptionText(str) {
402
- return str;
403
- }
404
- styleOptionTerm(str) {
405
- return this.styleOptionText(str);
406
- }
407
- styleSubcommandTerm(str) {
408
- return str.split(" ").map((word) => {
409
- if (word === "[options]")
410
- return this.styleOptionText(word);
411
- if (word[0] === "[" || word[0] === "<")
412
- return this.styleArgumentText(word);
413
- return this.styleSubcommandText(word);
414
- }).join(" ");
415
- }
416
- styleArgumentTerm(str) {
417
- return this.styleArgumentText(str);
418
- }
419
- styleOptionText(str) {
420
- return str;
421
- }
422
- styleArgumentText(str) {
423
- return str;
424
- }
425
- styleSubcommandText(str) {
426
- return str;
427
- }
428
- styleCommandText(str) {
429
- return str;
430
- }
431
- padWidth(cmd, helper) {
432
- return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper));
433
- }
434
- preformatted(str) {
435
- return /\n[^\S\r\n]/.test(str);
436
- }
437
- formatItem(term, termWidth, description, helper) {
438
- const itemIndent = 2;
439
- const itemIndentStr = " ".repeat(itemIndent);
440
- if (!description)
441
- return itemIndentStr + term;
442
- const paddedTerm = term.padEnd(termWidth + term.length - helper.displayWidth(term));
443
- const spacerWidth = 2;
444
- const helpWidth = this.helpWidth ?? 80;
445
- const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent;
446
- let formattedDescription;
447
- if (remainingWidth < this.minWidthToWrap || helper.preformatted(description)) {
448
- formattedDescription = description;
449
- } else {
450
- const wrappedDescription = helper.boxWrap(description, remainingWidth);
451
- formattedDescription = wrappedDescription.replace(/\n/g, `
452
- ` + " ".repeat(termWidth + spacerWidth));
453
- }
454
- return itemIndentStr + paddedTerm + " ".repeat(spacerWidth) + formattedDescription.replace(/\n/g, `
455
- ${itemIndentStr}`);
456
- }
457
- boxWrap(str, width) {
458
- if (width < this.minWidthToWrap)
459
- return str;
460
- const rawLines = str.split(/\r\n|\n/);
461
- const chunkPattern = /[\s]*[^\s]+/g;
462
- const wrappedLines = [];
463
- rawLines.forEach((line) => {
464
- const chunks = line.match(chunkPattern);
465
- if (chunks === null) {
466
- wrappedLines.push("");
467
- return;
468
- }
469
- let sumChunks = [chunks.shift()];
470
- let sumWidth = this.displayWidth(sumChunks[0]);
471
- chunks.forEach((chunk) => {
472
- const visibleWidth = this.displayWidth(chunk);
473
- if (sumWidth + visibleWidth <= width) {
474
- sumChunks.push(chunk);
475
- sumWidth += visibleWidth;
476
- return;
477
- }
478
- wrappedLines.push(sumChunks.join(""));
479
- const nextChunk = chunk.trimStart();
480
- sumChunks = [nextChunk];
481
- sumWidth = this.displayWidth(nextChunk);
482
- });
483
- wrappedLines.push(sumChunks.join(""));
484
- });
485
- return wrappedLines.join(`
486
- `);
487
- }
488
- }
489
- function stripColor(str) {
490
- const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
491
- return str.replace(sgrPattern, "");
492
- }
493
- exports.Help = Help;
494
- exports.stripColor = stripColor;
495
- });
496
-
497
- // node_modules/commander/lib/option.js
498
- var require_option = __commonJS((exports) => {
499
- var { InvalidArgumentError } = require_error();
500
-
501
- class Option {
502
- constructor(flags, description) {
503
- this.flags = flags;
504
- this.description = description || "";
505
- this.required = flags.includes("<");
506
- this.optional = flags.includes("[");
507
- this.variadic = /\w\.\.\.[>\]]$/.test(flags);
508
- this.mandatory = false;
509
- const optionFlags = splitOptionFlags(flags);
510
- this.short = optionFlags.shortFlag;
511
- this.long = optionFlags.longFlag;
512
- this.negate = false;
513
- if (this.long) {
514
- this.negate = this.long.startsWith("--no-");
515
- }
516
- this.defaultValue = undefined;
517
- this.defaultValueDescription = undefined;
518
- this.presetArg = undefined;
519
- this.envVar = undefined;
520
- this.parseArg = undefined;
521
- this.hidden = false;
522
- this.argChoices = undefined;
523
- this.conflictsWith = [];
524
- this.implied = undefined;
525
- this.helpGroupHeading = undefined;
526
- }
527
- default(value, description) {
528
- this.defaultValue = value;
529
- this.defaultValueDescription = description;
530
- return this;
531
- }
532
- preset(arg) {
533
- this.presetArg = arg;
534
- return this;
535
- }
536
- conflicts(names) {
537
- this.conflictsWith = this.conflictsWith.concat(names);
538
- return this;
539
- }
540
- implies(impliedOptionValues) {
541
- let newImplied = impliedOptionValues;
542
- if (typeof impliedOptionValues === "string") {
543
- newImplied = { [impliedOptionValues]: true };
544
- }
545
- this.implied = Object.assign(this.implied || {}, newImplied);
546
- return this;
547
- }
548
- env(name) {
549
- this.envVar = name;
550
- return this;
551
- }
552
- argParser(fn) {
553
- this.parseArg = fn;
554
- return this;
555
- }
556
- makeOptionMandatory(mandatory = true) {
557
- this.mandatory = !!mandatory;
558
- return this;
559
- }
560
- hideHelp(hide = true) {
561
- this.hidden = !!hide;
562
- return this;
563
- }
564
- _collectValue(value, previous) {
565
- if (previous === this.defaultValue || !Array.isArray(previous)) {
566
- return [value];
567
- }
568
- previous.push(value);
569
- return previous;
570
- }
571
- choices(values) {
572
- this.argChoices = values.slice();
573
- this.parseArg = (arg, previous) => {
574
- if (!this.argChoices.includes(arg)) {
575
- throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
576
- }
577
- if (this.variadic) {
578
- return this._collectValue(arg, previous);
579
- }
580
- return arg;
581
- };
582
- return this;
583
- }
584
- name() {
585
- if (this.long) {
586
- return this.long.replace(/^--/, "");
587
- }
588
- return this.short.replace(/^-/, "");
589
- }
590
- attributeName() {
591
- if (this.negate) {
592
- return camelcase(this.name().replace(/^no-/, ""));
593
- }
594
- return camelcase(this.name());
595
- }
596
- helpGroup(heading) {
597
- this.helpGroupHeading = heading;
598
- return this;
599
- }
600
- is(arg) {
601
- return this.short === arg || this.long === arg;
602
- }
603
- isBoolean() {
604
- return !this.required && !this.optional && !this.negate;
605
- }
606
- }
607
-
608
- class DualOptions {
609
- constructor(options) {
610
- this.positiveOptions = new Map;
611
- this.negativeOptions = new Map;
612
- this.dualOptions = new Set;
613
- options.forEach((option) => {
614
- if (option.negate) {
615
- this.negativeOptions.set(option.attributeName(), option);
616
- } else {
617
- this.positiveOptions.set(option.attributeName(), option);
618
- }
619
- });
620
- this.negativeOptions.forEach((value, key) => {
621
- if (this.positiveOptions.has(key)) {
622
- this.dualOptions.add(key);
623
- }
624
- });
625
- }
626
- valueFromOption(value, option) {
627
- const optionKey = option.attributeName();
628
- if (!this.dualOptions.has(optionKey))
629
- return true;
630
- const preset = this.negativeOptions.get(optionKey).presetArg;
631
- const negativeValue = preset !== undefined ? preset : false;
632
- return option.negate === (negativeValue === value);
633
- }
634
- }
635
- function camelcase(str) {
636
- return str.split("-").reduce((str2, word) => {
637
- return str2 + word[0].toUpperCase() + word.slice(1);
638
- });
639
- }
640
- function splitOptionFlags(flags) {
641
- let shortFlag;
642
- let longFlag;
643
- const shortFlagExp = /^-[^-]$/;
644
- const longFlagExp = /^--[^-]/;
645
- const flagParts = flags.split(/[ |,]+/).concat("guard");
646
- if (shortFlagExp.test(flagParts[0]))
647
- shortFlag = flagParts.shift();
648
- if (longFlagExp.test(flagParts[0]))
649
- longFlag = flagParts.shift();
650
- if (!shortFlag && shortFlagExp.test(flagParts[0]))
651
- shortFlag = flagParts.shift();
652
- if (!shortFlag && longFlagExp.test(flagParts[0])) {
653
- shortFlag = longFlag;
654
- longFlag = flagParts.shift();
655
- }
656
- if (flagParts[0].startsWith("-")) {
657
- const unsupportedFlag = flagParts[0];
658
- const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;
659
- if (/^-[^-][^-]/.test(unsupportedFlag))
660
- throw new Error(`${baseError}
661
- - a short flag is a single dash and a single character
662
- - either use a single dash and a single character (for a short flag)
663
- - or use a double dash for a long option (and can have two, like '--ws, --workspace')`);
664
- if (shortFlagExp.test(unsupportedFlag))
665
- throw new Error(`${baseError}
666
- - too many short flags`);
667
- if (longFlagExp.test(unsupportedFlag))
668
- throw new Error(`${baseError}
669
- - too many long flags`);
670
- throw new Error(`${baseError}
671
- - unrecognised flag format`);
672
- }
673
- if (shortFlag === undefined && longFlag === undefined)
674
- throw new Error(`option creation failed due to no flags found in '${flags}'.`);
675
- return { shortFlag, longFlag };
676
- }
677
- exports.Option = Option;
678
- exports.DualOptions = DualOptions;
679
- });
680
-
681
- // node_modules/commander/lib/suggestSimilar.js
682
- var require_suggestSimilar = __commonJS((exports) => {
683
- var maxDistance = 3;
684
- function editDistance(a, b) {
685
- if (Math.abs(a.length - b.length) > maxDistance)
686
- return Math.max(a.length, b.length);
687
- const d = [];
688
- for (let i = 0;i <= a.length; i++) {
689
- d[i] = [i];
690
- }
691
- for (let j = 0;j <= b.length; j++) {
692
- d[0][j] = j;
693
- }
694
- for (let j = 1;j <= b.length; j++) {
695
- for (let i = 1;i <= a.length; i++) {
696
- let cost = 1;
697
- if (a[i - 1] === b[j - 1]) {
698
- cost = 0;
699
- } else {
700
- cost = 1;
701
- }
702
- d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
703
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
704
- d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
705
- }
706
- }
707
- }
708
- return d[a.length][b.length];
709
- }
710
- function suggestSimilar(word, candidates) {
711
- if (!candidates || candidates.length === 0)
712
- return "";
713
- candidates = Array.from(new Set(candidates));
714
- const searchingOptions = word.startsWith("--");
715
- if (searchingOptions) {
716
- word = word.slice(2);
717
- candidates = candidates.map((candidate) => candidate.slice(2));
718
- }
719
- let similar = [];
720
- let bestDistance = maxDistance;
721
- const minSimilarity = 0.4;
722
- candidates.forEach((candidate) => {
723
- if (candidate.length <= 1)
724
- return;
725
- const distance = editDistance(word, candidate);
726
- const length = Math.max(word.length, candidate.length);
727
- const similarity = (length - distance) / length;
728
- if (similarity > minSimilarity) {
729
- if (distance < bestDistance) {
730
- bestDistance = distance;
731
- similar = [candidate];
732
- } else if (distance === bestDistance) {
733
- similar.push(candidate);
734
- }
735
- }
736
- });
737
- similar.sort((a, b) => a.localeCompare(b));
738
- if (searchingOptions) {
739
- similar = similar.map((candidate) => `--${candidate}`);
740
- }
741
- if (similar.length > 1) {
742
- return `
743
- (Did you mean one of ${similar.join(", ")}?)`;
744
- }
745
- if (similar.length === 1) {
746
- return `
747
- (Did you mean ${similar[0]}?)`;
748
- }
749
- return "";
750
- }
751
- exports.suggestSimilar = suggestSimilar;
752
- });
753
-
754
- // node_modules/commander/lib/command.js
755
- var require_command = __commonJS((exports) => {
756
- var EventEmitter = __require("events").EventEmitter;
757
- var childProcess = __require("child_process");
758
- var path = __require("path");
759
- var fs = __require("fs");
760
- var process2 = __require("process");
761
- var { Argument, humanReadableArgName } = require_argument();
762
- var { CommanderError } = require_error();
763
- var { Help, stripColor } = require_help();
764
- var { Option, DualOptions } = require_option();
765
- var { suggestSimilar } = require_suggestSimilar();
766
-
767
- class Command extends EventEmitter {
768
- constructor(name) {
769
- super();
770
- this.commands = [];
771
- this.options = [];
772
- this.parent = null;
773
- this._allowUnknownOption = false;
774
- this._allowExcessArguments = false;
775
- this.registeredArguments = [];
776
- this._args = this.registeredArguments;
777
- this.args = [];
778
- this.rawArgs = [];
779
- this.processedArgs = [];
780
- this._scriptPath = null;
781
- this._name = name || "";
782
- this._optionValues = {};
783
- this._optionValueSources = {};
784
- this._storeOptionsAsProperties = false;
785
- this._actionHandler = null;
786
- this._executableHandler = false;
787
- this._executableFile = null;
788
- this._executableDir = null;
789
- this._defaultCommandName = null;
790
- this._exitCallback = null;
791
- this._aliases = [];
792
- this._combineFlagAndOptionalValue = true;
793
- this._description = "";
794
- this._summary = "";
795
- this._argsDescription = undefined;
796
- this._enablePositionalOptions = false;
797
- this._passThroughOptions = false;
798
- this._lifeCycleHooks = {};
799
- this._showHelpAfterError = false;
800
- this._showSuggestionAfterError = true;
801
- this._savedState = null;
802
- this._outputConfiguration = {
803
- writeOut: (str) => process2.stdout.write(str),
804
- writeErr: (str) => process2.stderr.write(str),
805
- outputError: (str, write) => write(str),
806
- getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : undefined,
807
- getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : undefined,
808
- getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
809
- getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
810
- stripColor: (str) => stripColor(str)
811
- };
812
- this._hidden = false;
813
- this._helpOption = undefined;
814
- this._addImplicitHelpCommand = undefined;
815
- this._helpCommand = undefined;
816
- this._helpConfiguration = {};
817
- this._helpGroupHeading = undefined;
818
- this._defaultCommandGroup = undefined;
819
- this._defaultOptionGroup = undefined;
820
- }
821
- copyInheritedSettings(sourceCommand) {
822
- this._outputConfiguration = sourceCommand._outputConfiguration;
823
- this._helpOption = sourceCommand._helpOption;
824
- this._helpCommand = sourceCommand._helpCommand;
825
- this._helpConfiguration = sourceCommand._helpConfiguration;
826
- this._exitCallback = sourceCommand._exitCallback;
827
- this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
828
- this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
829
- this._allowExcessArguments = sourceCommand._allowExcessArguments;
830
- this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
831
- this._showHelpAfterError = sourceCommand._showHelpAfterError;
832
- this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
833
- return this;
834
- }
835
- _getCommandAndAncestors() {
836
- const result = [];
837
- for (let command = this;command; command = command.parent) {
838
- result.push(command);
839
- }
840
- return result;
841
- }
842
- command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
843
- let desc = actionOptsOrExecDesc;
844
- let opts = execOpts;
845
- if (typeof desc === "object" && desc !== null) {
846
- opts = desc;
847
- desc = null;
848
- }
849
- opts = opts || {};
850
- const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);
851
- const cmd = this.createCommand(name);
852
- if (desc) {
853
- cmd.description(desc);
854
- cmd._executableHandler = true;
855
- }
856
- if (opts.isDefault)
857
- this._defaultCommandName = cmd._name;
858
- cmd._hidden = !!(opts.noHelp || opts.hidden);
859
- cmd._executableFile = opts.executableFile || null;
860
- if (args)
861
- cmd.arguments(args);
862
- this._registerCommand(cmd);
863
- cmd.parent = this;
864
- cmd.copyInheritedSettings(this);
865
- if (desc)
866
- return this;
867
- return cmd;
868
- }
869
- createCommand(name) {
870
- return new Command(name);
871
- }
872
- createHelp() {
873
- return Object.assign(new Help, this.configureHelp());
874
- }
875
- configureHelp(configuration) {
876
- if (configuration === undefined)
877
- return this._helpConfiguration;
878
- this._helpConfiguration = configuration;
879
- return this;
880
- }
881
- configureOutput(configuration) {
882
- if (configuration === undefined)
883
- return this._outputConfiguration;
884
- this._outputConfiguration = {
885
- ...this._outputConfiguration,
886
- ...configuration
887
- };
888
- return this;
889
- }
890
- showHelpAfterError(displayHelp = true) {
891
- if (typeof displayHelp !== "string")
892
- displayHelp = !!displayHelp;
893
- this._showHelpAfterError = displayHelp;
894
- return this;
895
- }
896
- showSuggestionAfterError(displaySuggestion = true) {
897
- this._showSuggestionAfterError = !!displaySuggestion;
898
- return this;
899
- }
900
- addCommand(cmd, opts) {
901
- if (!cmd._name) {
902
- throw new Error(`Command passed to .addCommand() must have a name
903
- - specify the name in Command constructor or using .name()`);
904
- }
905
- opts = opts || {};
906
- if (opts.isDefault)
907
- this._defaultCommandName = cmd._name;
908
- if (opts.noHelp || opts.hidden)
909
- cmd._hidden = true;
910
- this._registerCommand(cmd);
911
- cmd.parent = this;
912
- cmd._checkForBrokenPassThrough();
913
- return this;
914
- }
915
- createArgument(name, description) {
916
- return new Argument(name, description);
917
- }
918
- argument(name, description, parseArg, defaultValue) {
919
- const argument = this.createArgument(name, description);
920
- if (typeof parseArg === "function") {
921
- argument.default(defaultValue).argParser(parseArg);
922
- } else {
923
- argument.default(parseArg);
924
- }
925
- this.addArgument(argument);
926
- return this;
927
- }
928
- arguments(names) {
929
- names.trim().split(/ +/).forEach((detail) => {
930
- this.argument(detail);
931
- });
932
- return this;
933
- }
934
- addArgument(argument) {
935
- const previousArgument = this.registeredArguments.slice(-1)[0];
936
- if (previousArgument?.variadic) {
937
- throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);
938
- }
939
- if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) {
940
- throw new Error(`a default value for a required argument is never used: '${argument.name()}'`);
941
- }
942
- this.registeredArguments.push(argument);
943
- return this;
944
- }
945
- helpCommand(enableOrNameAndArgs, description) {
946
- if (typeof enableOrNameAndArgs === "boolean") {
947
- this._addImplicitHelpCommand = enableOrNameAndArgs;
948
- if (enableOrNameAndArgs && this._defaultCommandGroup) {
949
- this._initCommandGroup(this._getHelpCommand());
950
- }
951
- return this;
952
- }
953
- const nameAndArgs = enableOrNameAndArgs ?? "help [command]";
954
- const [, helpName, helpArgs] = nameAndArgs.match(/([^ ]+) *(.*)/);
955
- const helpDescription = description ?? "display help for command";
956
- const helpCommand = this.createCommand(helpName);
957
- helpCommand.helpOption(false);
958
- if (helpArgs)
959
- helpCommand.arguments(helpArgs);
960
- if (helpDescription)
961
- helpCommand.description(helpDescription);
962
- this._addImplicitHelpCommand = true;
963
- this._helpCommand = helpCommand;
964
- if (enableOrNameAndArgs || description)
965
- this._initCommandGroup(helpCommand);
966
- return this;
967
- }
968
- addHelpCommand(helpCommand, deprecatedDescription) {
969
- if (typeof helpCommand !== "object") {
970
- this.helpCommand(helpCommand, deprecatedDescription);
971
- return this;
972
- }
973
- this._addImplicitHelpCommand = true;
974
- this._helpCommand = helpCommand;
975
- this._initCommandGroup(helpCommand);
976
- return this;
977
- }
978
- _getHelpCommand() {
979
- const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand("help"));
980
- if (hasImplicitHelpCommand) {
981
- if (this._helpCommand === undefined) {
982
- this.helpCommand(undefined, undefined);
983
- }
984
- return this._helpCommand;
985
- }
986
- return null;
987
- }
988
- hook(event, listener) {
989
- const allowedValues = ["preSubcommand", "preAction", "postAction"];
990
- if (!allowedValues.includes(event)) {
991
- throw new Error(`Unexpected value for event passed to hook : '${event}'.
992
- Expecting one of '${allowedValues.join("', '")}'`);
993
- }
994
- if (this._lifeCycleHooks[event]) {
995
- this._lifeCycleHooks[event].push(listener);
996
- } else {
997
- this._lifeCycleHooks[event] = [listener];
998
- }
999
- return this;
1000
- }
1001
- exitOverride(fn) {
1002
- if (fn) {
1003
- this._exitCallback = fn;
1004
- } else {
1005
- this._exitCallback = (err) => {
1006
- if (err.code !== "commander.executeSubCommandAsync") {
1007
- throw err;
1008
- }
1009
- };
1010
- }
1011
- return this;
1012
- }
1013
- _exit(exitCode, code, message) {
1014
- if (this._exitCallback) {
1015
- this._exitCallback(new CommanderError(exitCode, code, message));
1016
- }
1017
- process2.exit(exitCode);
1018
- }
1019
- action(fn) {
1020
- const listener = (args) => {
1021
- const expectedArgsCount = this.registeredArguments.length;
1022
- const actionArgs = args.slice(0, expectedArgsCount);
1023
- if (this._storeOptionsAsProperties) {
1024
- actionArgs[expectedArgsCount] = this;
1025
- } else {
1026
- actionArgs[expectedArgsCount] = this.opts();
1027
- }
1028
- actionArgs.push(this);
1029
- return fn.apply(this, actionArgs);
1030
- };
1031
- this._actionHandler = listener;
1032
- return this;
1033
- }
1034
- createOption(flags, description) {
1035
- return new Option(flags, description);
1036
- }
1037
- _callParseArg(target, value, previous, invalidArgumentMessage) {
1038
- try {
1039
- return target.parseArg(value, previous);
1040
- } catch (err) {
1041
- if (err.code === "commander.invalidArgument") {
1042
- const message = `${invalidArgumentMessage} ${err.message}`;
1043
- this.error(message, { exitCode: err.exitCode, code: err.code });
1044
- }
1045
- throw err;
1046
- }
1047
- }
1048
- _registerOption(option) {
1049
- const matchingOption = option.short && this._findOption(option.short) || option.long && this._findOption(option.long);
1050
- if (matchingOption) {
1051
- const matchingFlag = option.long && this._findOption(option.long) ? option.long : option.short;
1052
- throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
1053
- - already used by option '${matchingOption.flags}'`);
1054
- }
1055
- this._initOptionGroup(option);
1056
- this.options.push(option);
1057
- }
1058
- _registerCommand(command) {
1059
- const knownBy = (cmd) => {
1060
- return [cmd.name()].concat(cmd.aliases());
1061
- };
1062
- const alreadyUsed = knownBy(command).find((name) => this._findCommand(name));
1063
- if (alreadyUsed) {
1064
- const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
1065
- const newCmd = knownBy(command).join("|");
1066
- throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`);
1067
- }
1068
- this._initCommandGroup(command);
1069
- this.commands.push(command);
1070
- }
1071
- addOption(option) {
1072
- this._registerOption(option);
1073
- const oname = option.name();
1074
- const name = option.attributeName();
1075
- if (option.negate) {
1076
- const positiveLongFlag = option.long.replace(/^--no-/, "--");
1077
- if (!this._findOption(positiveLongFlag)) {
1078
- this.setOptionValueWithSource(name, option.defaultValue === undefined ? true : option.defaultValue, "default");
1079
- }
1080
- } else if (option.defaultValue !== undefined) {
1081
- this.setOptionValueWithSource(name, option.defaultValue, "default");
1082
- }
1083
- const handleOptionValue = (val, invalidValueMessage, valueSource) => {
1084
- if (val == null && option.presetArg !== undefined) {
1085
- val = option.presetArg;
1086
- }
1087
- const oldValue = this.getOptionValue(name);
1088
- if (val !== null && option.parseArg) {
1089
- val = this._callParseArg(option, val, oldValue, invalidValueMessage);
1090
- } else if (val !== null && option.variadic) {
1091
- val = option._collectValue(val, oldValue);
1092
- }
1093
- if (val == null) {
1094
- if (option.negate) {
1095
- val = false;
1096
- } else if (option.isBoolean() || option.optional) {
1097
- val = true;
1098
- } else {
1099
- val = "";
1100
- }
1101
- }
1102
- this.setOptionValueWithSource(name, val, valueSource);
1103
- };
1104
- this.on("option:" + oname, (val) => {
1105
- const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`;
1106
- handleOptionValue(val, invalidValueMessage, "cli");
1107
- });
1108
- if (option.envVar) {
1109
- this.on("optionEnv:" + oname, (val) => {
1110
- const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;
1111
- handleOptionValue(val, invalidValueMessage, "env");
1112
- });
1113
- }
1114
- return this;
1115
- }
1116
- _optionEx(config, flags, description, fn, defaultValue) {
1117
- if (typeof flags === "object" && flags instanceof Option) {
1118
- throw new Error("To add an Option object use addOption() instead of option() or requiredOption()");
1119
- }
1120
- const option = this.createOption(flags, description);
1121
- option.makeOptionMandatory(!!config.mandatory);
1122
- if (typeof fn === "function") {
1123
- option.default(defaultValue).argParser(fn);
1124
- } else if (fn instanceof RegExp) {
1125
- const regex = fn;
1126
- fn = (val, def) => {
1127
- const m = regex.exec(val);
1128
- return m ? m[0] : def;
1129
- };
1130
- option.default(defaultValue).argParser(fn);
1131
- } else {
1132
- option.default(fn);
1133
- }
1134
- return this.addOption(option);
1135
- }
1136
- option(flags, description, parseArg, defaultValue) {
1137
- return this._optionEx({}, flags, description, parseArg, defaultValue);
1138
- }
1139
- requiredOption(flags, description, parseArg, defaultValue) {
1140
- return this._optionEx({ mandatory: true }, flags, description, parseArg, defaultValue);
1141
- }
1142
- combineFlagAndOptionalValue(combine = true) {
1143
- this._combineFlagAndOptionalValue = !!combine;
1144
- return this;
1145
- }
1146
- allowUnknownOption(allowUnknown = true) {
1147
- this._allowUnknownOption = !!allowUnknown;
1148
- return this;
1149
- }
1150
- allowExcessArguments(allowExcess = true) {
1151
- this._allowExcessArguments = !!allowExcess;
1152
- return this;
1153
- }
1154
- enablePositionalOptions(positional = true) {
1155
- this._enablePositionalOptions = !!positional;
1156
- return this;
1157
- }
1158
- passThroughOptions(passThrough = true) {
1159
- this._passThroughOptions = !!passThrough;
1160
- this._checkForBrokenPassThrough();
1161
- return this;
1162
- }
1163
- _checkForBrokenPassThrough() {
1164
- if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
1165
- throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`);
1166
- }
1167
- }
1168
- storeOptionsAsProperties(storeAsProperties = true) {
1169
- if (this.options.length) {
1170
- throw new Error("call .storeOptionsAsProperties() before adding options");
1171
- }
1172
- if (Object.keys(this._optionValues).length) {
1173
- throw new Error("call .storeOptionsAsProperties() before setting option values");
1174
- }
1175
- this._storeOptionsAsProperties = !!storeAsProperties;
1176
- return this;
1177
- }
1178
- getOptionValue(key) {
1179
- if (this._storeOptionsAsProperties) {
1180
- return this[key];
1181
- }
1182
- return this._optionValues[key];
1183
- }
1184
- setOptionValue(key, value) {
1185
- return this.setOptionValueWithSource(key, value, undefined);
1186
- }
1187
- setOptionValueWithSource(key, value, source) {
1188
- if (this._storeOptionsAsProperties) {
1189
- this[key] = value;
1190
- } else {
1191
- this._optionValues[key] = value;
1192
- }
1193
- this._optionValueSources[key] = source;
1194
- return this;
1195
- }
1196
- getOptionValueSource(key) {
1197
- return this._optionValueSources[key];
1198
- }
1199
- getOptionValueSourceWithGlobals(key) {
1200
- let source;
1201
- this._getCommandAndAncestors().forEach((cmd) => {
1202
- if (cmd.getOptionValueSource(key) !== undefined) {
1203
- source = cmd.getOptionValueSource(key);
1204
- }
1205
- });
1206
- return source;
1207
- }
1208
- _prepareUserArgs(argv, parseOptions) {
1209
- if (argv !== undefined && !Array.isArray(argv)) {
1210
- throw new Error("first parameter to parse must be array or undefined");
1211
- }
1212
- parseOptions = parseOptions || {};
1213
- if (argv === undefined && parseOptions.from === undefined) {
1214
- if (process2.versions?.electron) {
1215
- parseOptions.from = "electron";
1216
- }
1217
- const execArgv = process2.execArgv ?? [];
1218
- if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
1219
- parseOptions.from = "eval";
1220
- }
1221
- }
1222
- if (argv === undefined) {
1223
- argv = process2.argv;
1224
- }
1225
- this.rawArgs = argv.slice();
1226
- let userArgs;
1227
- switch (parseOptions.from) {
1228
- case undefined:
1229
- case "node":
1230
- this._scriptPath = argv[1];
1231
- userArgs = argv.slice(2);
1232
- break;
1233
- case "electron":
1234
- if (process2.defaultApp) {
1235
- this._scriptPath = argv[1];
1236
- userArgs = argv.slice(2);
1237
- } else {
1238
- userArgs = argv.slice(1);
1239
- }
1240
- break;
1241
- case "user":
1242
- userArgs = argv.slice(0);
1243
- break;
1244
- case "eval":
1245
- userArgs = argv.slice(1);
1246
- break;
1247
- default:
1248
- throw new Error(`unexpected parse option { from: '${parseOptions.from}' }`);
1249
- }
1250
- if (!this._name && this._scriptPath)
1251
- this.nameFromFilename(this._scriptPath);
1252
- this._name = this._name || "program";
1253
- return userArgs;
1254
- }
1255
- parse(argv, parseOptions) {
1256
- this._prepareForParse();
1257
- const userArgs = this._prepareUserArgs(argv, parseOptions);
1258
- this._parseCommand([], userArgs);
1259
- return this;
1260
- }
1261
- async parseAsync(argv, parseOptions) {
1262
- this._prepareForParse();
1263
- const userArgs = this._prepareUserArgs(argv, parseOptions);
1264
- await this._parseCommand([], userArgs);
1265
- return this;
1266
- }
1267
- _prepareForParse() {
1268
- if (this._savedState === null) {
1269
- this.saveStateBeforeParse();
1270
- } else {
1271
- this.restoreStateBeforeParse();
1272
- }
1273
- }
1274
- saveStateBeforeParse() {
1275
- this._savedState = {
1276
- _name: this._name,
1277
- _optionValues: { ...this._optionValues },
1278
- _optionValueSources: { ...this._optionValueSources }
1279
- };
1280
- }
1281
- restoreStateBeforeParse() {
1282
- if (this._storeOptionsAsProperties)
1283
- throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
1284
- - either make a new Command for each call to parse, or stop storing options as properties`);
1285
- this._name = this._savedState._name;
1286
- this._scriptPath = null;
1287
- this.rawArgs = [];
1288
- this._optionValues = { ...this._savedState._optionValues };
1289
- this._optionValueSources = { ...this._savedState._optionValueSources };
1290
- this.args = [];
1291
- this.processedArgs = [];
1292
- }
1293
- _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
1294
- if (fs.existsSync(executableFile))
1295
- return;
1296
- 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";
1297
- const executableMissing = `'${executableFile}' does not exist
1298
- - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
1299
- - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
1300
- - ${executableDirMessage}`;
1301
- throw new Error(executableMissing);
1302
- }
1303
- _executeSubCommand(subcommand, args) {
1304
- args = args.slice();
1305
- let launchWithNode = false;
1306
- const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1307
- function findFile(baseDir, baseName) {
1308
- const localBin = path.resolve(baseDir, baseName);
1309
- if (fs.existsSync(localBin))
1310
- return localBin;
1311
- if (sourceExt.includes(path.extname(baseName)))
1312
- return;
1313
- const foundExt = sourceExt.find((ext) => fs.existsSync(`${localBin}${ext}`));
1314
- if (foundExt)
1315
- return `${localBin}${foundExt}`;
1316
- return;
1317
- }
1318
- this._checkForMissingMandatoryOptions();
1319
- this._checkForConflictingOptions();
1320
- let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
1321
- let executableDir = this._executableDir || "";
1322
- if (this._scriptPath) {
1323
- let resolvedScriptPath;
1324
- try {
1325
- resolvedScriptPath = fs.realpathSync(this._scriptPath);
1326
- } catch {
1327
- resolvedScriptPath = this._scriptPath;
1328
- }
1329
- executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir);
1330
- }
1331
- if (executableDir) {
1332
- let localFile = findFile(executableDir, executableFile);
1333
- if (!localFile && !subcommand._executableFile && this._scriptPath) {
1334
- const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath));
1335
- if (legacyName !== this._name) {
1336
- localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
1337
- }
1338
- }
1339
- executableFile = localFile || executableFile;
1340
- }
1341
- launchWithNode = sourceExt.includes(path.extname(executableFile));
1342
- let proc;
1343
- if (process2.platform !== "win32") {
1344
- if (launchWithNode) {
1345
- args.unshift(executableFile);
1346
- args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1347
- proc = childProcess.spawn(process2.argv[0], args, { stdio: "inherit" });
1348
- } else {
1349
- proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
1350
- }
1351
- } else {
1352
- this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
1353
- args.unshift(executableFile);
1354
- args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1355
- proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
1356
- }
1357
- if (!proc.killed) {
1358
- const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
1359
- signals.forEach((signal) => {
1360
- process2.on(signal, () => {
1361
- if (proc.killed === false && proc.exitCode === null) {
1362
- proc.kill(signal);
1363
- }
1364
- });
1365
- });
1366
- }
1367
- const exitCallback = this._exitCallback;
1368
- proc.on("close", (code) => {
1369
- code = code ?? 1;
1370
- if (!exitCallback) {
1371
- process2.exit(code);
1372
- } else {
1373
- exitCallback(new CommanderError(code, "commander.executeSubCommandAsync", "(close)"));
1374
- }
1375
- });
1376
- proc.on("error", (err) => {
1377
- if (err.code === "ENOENT") {
1378
- this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
1379
- } else if (err.code === "EACCES") {
1380
- throw new Error(`'${executableFile}' not executable`);
1381
- }
1382
- if (!exitCallback) {
1383
- process2.exit(1);
1384
- } else {
1385
- const wrappedError = new CommanderError(1, "commander.executeSubCommandAsync", "(error)");
1386
- wrappedError.nestedError = err;
1387
- exitCallback(wrappedError);
1388
- }
1389
- });
1390
- this.runningCommand = proc;
1391
- }
1392
- _dispatchSubcommand(commandName, operands, unknown) {
1393
- const subCommand = this._findCommand(commandName);
1394
- if (!subCommand)
1395
- this.help({ error: true });
1396
- subCommand._prepareForParse();
1397
- let promiseChain;
1398
- promiseChain = this._chainOrCallSubCommandHook(promiseChain, subCommand, "preSubcommand");
1399
- promiseChain = this._chainOrCall(promiseChain, () => {
1400
- if (subCommand._executableHandler) {
1401
- this._executeSubCommand(subCommand, operands.concat(unknown));
1402
- } else {
1403
- return subCommand._parseCommand(operands, unknown);
1404
- }
1405
- });
1406
- return promiseChain;
1407
- }
1408
- _dispatchHelpCommand(subcommandName) {
1409
- if (!subcommandName) {
1410
- this.help();
1411
- }
1412
- const subCommand = this._findCommand(subcommandName);
1413
- if (subCommand && !subCommand._executableHandler) {
1414
- subCommand.help();
1415
- }
1416
- return this._dispatchSubcommand(subcommandName, [], [this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? "--help"]);
1417
- }
1418
- _checkNumberOfArguments() {
1419
- this.registeredArguments.forEach((arg, i) => {
1420
- if (arg.required && this.args[i] == null) {
1421
- this.missingArgument(arg.name());
1422
- }
1423
- });
1424
- if (this.registeredArguments.length > 0 && this.registeredArguments[this.registeredArguments.length - 1].variadic) {
1425
- return;
1426
- }
1427
- if (this.args.length > this.registeredArguments.length) {
1428
- this._excessArguments(this.args);
1429
- }
1430
- }
1431
- _processArguments() {
1432
- const myParseArg = (argument, value, previous) => {
1433
- let parsedValue = value;
1434
- if (value !== null && argument.parseArg) {
1435
- const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
1436
- parsedValue = this._callParseArg(argument, value, previous, invalidValueMessage);
1437
- }
1438
- return parsedValue;
1439
- };
1440
- this._checkNumberOfArguments();
1441
- const processedArgs = [];
1442
- this.registeredArguments.forEach((declaredArg, index) => {
1443
- let value = declaredArg.defaultValue;
1444
- if (declaredArg.variadic) {
1445
- if (index < this.args.length) {
1446
- value = this.args.slice(index);
1447
- if (declaredArg.parseArg) {
1448
- value = value.reduce((processed, v) => {
1449
- return myParseArg(declaredArg, v, processed);
1450
- }, declaredArg.defaultValue);
1451
- }
1452
- } else if (value === undefined) {
1453
- value = [];
1454
- }
1455
- } else if (index < this.args.length) {
1456
- value = this.args[index];
1457
- if (declaredArg.parseArg) {
1458
- value = myParseArg(declaredArg, value, declaredArg.defaultValue);
1459
- }
1460
- }
1461
- processedArgs[index] = value;
1462
- });
1463
- this.processedArgs = processedArgs;
1464
- }
1465
- _chainOrCall(promise, fn) {
1466
- if (promise?.then && typeof promise.then === "function") {
1467
- return promise.then(() => fn());
1468
- }
1469
- return fn();
1470
- }
1471
- _chainOrCallHooks(promise, event) {
1472
- let result = promise;
1473
- const hooks = [];
1474
- this._getCommandAndAncestors().reverse().filter((cmd) => cmd._lifeCycleHooks[event] !== undefined).forEach((hookedCommand) => {
1475
- hookedCommand._lifeCycleHooks[event].forEach((callback) => {
1476
- hooks.push({ hookedCommand, callback });
1477
- });
1478
- });
1479
- if (event === "postAction") {
1480
- hooks.reverse();
1481
- }
1482
- hooks.forEach((hookDetail) => {
1483
- result = this._chainOrCall(result, () => {
1484
- return hookDetail.callback(hookDetail.hookedCommand, this);
1485
- });
1486
- });
1487
- return result;
1488
- }
1489
- _chainOrCallSubCommandHook(promise, subCommand, event) {
1490
- let result = promise;
1491
- if (this._lifeCycleHooks[event] !== undefined) {
1492
- this._lifeCycleHooks[event].forEach((hook) => {
1493
- result = this._chainOrCall(result, () => {
1494
- return hook(this, subCommand);
1495
- });
1496
- });
1497
- }
1498
- return result;
1499
- }
1500
- _parseCommand(operands, unknown) {
1501
- const parsed = this.parseOptions(unknown);
1502
- this._parseOptionsEnv();
1503
- this._parseOptionsImplied();
1504
- operands = operands.concat(parsed.operands);
1505
- unknown = parsed.unknown;
1506
- this.args = operands.concat(unknown);
1507
- if (operands && this._findCommand(operands[0])) {
1508
- return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
1509
- }
1510
- if (this._getHelpCommand() && operands[0] === this._getHelpCommand().name()) {
1511
- return this._dispatchHelpCommand(operands[1]);
1512
- }
1513
- if (this._defaultCommandName) {
1514
- this._outputHelpIfRequested(unknown);
1515
- return this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
1516
- }
1517
- if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
1518
- this.help({ error: true });
1519
- }
1520
- this._outputHelpIfRequested(parsed.unknown);
1521
- this._checkForMissingMandatoryOptions();
1522
- this._checkForConflictingOptions();
1523
- const checkForUnknownOptions = () => {
1524
- if (parsed.unknown.length > 0) {
1525
- this.unknownOption(parsed.unknown[0]);
1526
- }
1527
- };
1528
- const commandEvent = `command:${this.name()}`;
1529
- if (this._actionHandler) {
1530
- checkForUnknownOptions();
1531
- this._processArguments();
1532
- let promiseChain;
1533
- promiseChain = this._chainOrCallHooks(promiseChain, "preAction");
1534
- promiseChain = this._chainOrCall(promiseChain, () => this._actionHandler(this.processedArgs));
1535
- if (this.parent) {
1536
- promiseChain = this._chainOrCall(promiseChain, () => {
1537
- this.parent.emit(commandEvent, operands, unknown);
1538
- });
1539
- }
1540
- promiseChain = this._chainOrCallHooks(promiseChain, "postAction");
1541
- return promiseChain;
1542
- }
1543
- if (this.parent?.listenerCount(commandEvent)) {
1544
- checkForUnknownOptions();
1545
- this._processArguments();
1546
- this.parent.emit(commandEvent, operands, unknown);
1547
- } else if (operands.length) {
1548
- if (this._findCommand("*")) {
1549
- return this._dispatchSubcommand("*", operands, unknown);
1550
- }
1551
- if (this.listenerCount("command:*")) {
1552
- this.emit("command:*", operands, unknown);
1553
- } else if (this.commands.length) {
1554
- this.unknownCommand();
1555
- } else {
1556
- checkForUnknownOptions();
1557
- this._processArguments();
1558
- }
1559
- } else if (this.commands.length) {
1560
- checkForUnknownOptions();
1561
- this.help({ error: true });
1562
- } else {
1563
- checkForUnknownOptions();
1564
- this._processArguments();
1565
- }
1566
- }
1567
- _findCommand(name) {
1568
- if (!name)
1569
- return;
1570
- return this.commands.find((cmd) => cmd._name === name || cmd._aliases.includes(name));
1571
- }
1572
- _findOption(arg) {
1573
- return this.options.find((option) => option.is(arg));
1574
- }
1575
- _checkForMissingMandatoryOptions() {
1576
- this._getCommandAndAncestors().forEach((cmd) => {
1577
- cmd.options.forEach((anOption) => {
1578
- if (anOption.mandatory && cmd.getOptionValue(anOption.attributeName()) === undefined) {
1579
- cmd.missingMandatoryOptionValue(anOption);
1580
- }
1581
- });
1582
- });
1583
- }
1584
- _checkForConflictingLocalOptions() {
1585
- const definedNonDefaultOptions = this.options.filter((option) => {
1586
- const optionKey = option.attributeName();
1587
- if (this.getOptionValue(optionKey) === undefined) {
1588
- return false;
1589
- }
1590
- return this.getOptionValueSource(optionKey) !== "default";
1591
- });
1592
- const optionsWithConflicting = definedNonDefaultOptions.filter((option) => option.conflictsWith.length > 0);
1593
- optionsWithConflicting.forEach((option) => {
1594
- const conflictingAndDefined = definedNonDefaultOptions.find((defined) => option.conflictsWith.includes(defined.attributeName()));
1595
- if (conflictingAndDefined) {
1596
- this._conflictingOption(option, conflictingAndDefined);
1597
- }
1598
- });
1599
- }
1600
- _checkForConflictingOptions() {
1601
- this._getCommandAndAncestors().forEach((cmd) => {
1602
- cmd._checkForConflictingLocalOptions();
1603
- });
1604
- }
1605
- parseOptions(args) {
1606
- const operands = [];
1607
- const unknown = [];
1608
- let dest = operands;
1609
- function maybeOption(arg) {
1610
- return arg.length > 1 && arg[0] === "-";
1611
- }
1612
- const negativeNumberArg = (arg) => {
1613
- if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg))
1614
- return false;
1615
- return !this._getCommandAndAncestors().some((cmd) => cmd.options.map((opt) => opt.short).some((short) => /^-\d$/.test(short)));
1616
- };
1617
- let activeVariadicOption = null;
1618
- let activeGroup = null;
1619
- let i = 0;
1620
- while (i < args.length || activeGroup) {
1621
- const arg = activeGroup ?? args[i++];
1622
- activeGroup = null;
1623
- if (arg === "--") {
1624
- if (dest === unknown)
1625
- dest.push(arg);
1626
- dest.push(...args.slice(i));
1627
- break;
1628
- }
1629
- if (activeVariadicOption && (!maybeOption(arg) || negativeNumberArg(arg))) {
1630
- this.emit(`option:${activeVariadicOption.name()}`, arg);
1631
- continue;
1632
- }
1633
- activeVariadicOption = null;
1634
- if (maybeOption(arg)) {
1635
- const option = this._findOption(arg);
1636
- if (option) {
1637
- if (option.required) {
1638
- const value = args[i++];
1639
- if (value === undefined)
1640
- this.optionMissingArgument(option);
1641
- this.emit(`option:${option.name()}`, value);
1642
- } else if (option.optional) {
1643
- let value = null;
1644
- if (i < args.length && (!maybeOption(args[i]) || negativeNumberArg(args[i]))) {
1645
- value = args[i++];
1646
- }
1647
- this.emit(`option:${option.name()}`, value);
1648
- } else {
1649
- this.emit(`option:${option.name()}`);
1650
- }
1651
- activeVariadicOption = option.variadic ? option : null;
1652
- continue;
1653
- }
1654
- }
1655
- if (arg.length > 2 && arg[0] === "-" && arg[1] !== "-") {
1656
- const option = this._findOption(`-${arg[1]}`);
1657
- if (option) {
1658
- if (option.required || option.optional && this._combineFlagAndOptionalValue) {
1659
- this.emit(`option:${option.name()}`, arg.slice(2));
1660
- } else {
1661
- this.emit(`option:${option.name()}`);
1662
- activeGroup = `-${arg.slice(2)}`;
1663
- }
1664
- continue;
1665
- }
1666
- }
1667
- if (/^--[^=]+=/.test(arg)) {
1668
- const index = arg.indexOf("=");
1669
- const option = this._findOption(arg.slice(0, index));
1670
- if (option && (option.required || option.optional)) {
1671
- this.emit(`option:${option.name()}`, arg.slice(index + 1));
1672
- continue;
1673
- }
1674
- }
1675
- if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
1676
- dest = unknown;
1677
- }
1678
- if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
1679
- if (this._findCommand(arg)) {
1680
- operands.push(arg);
1681
- unknown.push(...args.slice(i));
1682
- break;
1683
- } else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
1684
- operands.push(arg, ...args.slice(i));
1685
- break;
1686
- } else if (this._defaultCommandName) {
1687
- unknown.push(arg, ...args.slice(i));
1688
- break;
1689
- }
1690
- }
1691
- if (this._passThroughOptions) {
1692
- dest.push(arg, ...args.slice(i));
1693
- break;
1694
- }
1695
- dest.push(arg);
1696
- }
1697
- return { operands, unknown };
1698
- }
1699
- opts() {
1700
- if (this._storeOptionsAsProperties) {
1701
- const result = {};
1702
- const len = this.options.length;
1703
- for (let i = 0;i < len; i++) {
1704
- const key = this.options[i].attributeName();
1705
- result[key] = key === this._versionOptionName ? this._version : this[key];
1706
- }
1707
- return result;
1708
- }
1709
- return this._optionValues;
1710
- }
1711
- optsWithGlobals() {
1712
- return this._getCommandAndAncestors().reduce((combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()), {});
1713
- }
1714
- error(message, errorOptions) {
1715
- this._outputConfiguration.outputError(`${message}
1716
- `, this._outputConfiguration.writeErr);
1717
- if (typeof this._showHelpAfterError === "string") {
1718
- this._outputConfiguration.writeErr(`${this._showHelpAfterError}
1719
- `);
1720
- } else if (this._showHelpAfterError) {
1721
- this._outputConfiguration.writeErr(`
1722
- `);
1723
- this.outputHelp({ error: true });
1724
- }
1725
- const config = errorOptions || {};
1726
- const exitCode = config.exitCode || 1;
1727
- const code = config.code || "commander.error";
1728
- this._exit(exitCode, code, message);
1729
- }
1730
- _parseOptionsEnv() {
1731
- this.options.forEach((option) => {
1732
- if (option.envVar && option.envVar in process2.env) {
1733
- const optionKey = option.attributeName();
1734
- if (this.getOptionValue(optionKey) === undefined || ["default", "config", "env"].includes(this.getOptionValueSource(optionKey))) {
1735
- if (option.required || option.optional) {
1736
- this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
1737
- } else {
1738
- this.emit(`optionEnv:${option.name()}`);
1739
- }
1740
- }
1741
- }
1742
- });
1743
- }
1744
- _parseOptionsImplied() {
1745
- const dualHelper = new DualOptions(this.options);
1746
- const hasCustomOptionValue = (optionKey) => {
1747
- return this.getOptionValue(optionKey) !== undefined && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
1748
- };
1749
- this.options.filter((option) => option.implied !== undefined && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(this.getOptionValue(option.attributeName()), option)).forEach((option) => {
1750
- Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
1751
- this.setOptionValueWithSource(impliedKey, option.implied[impliedKey], "implied");
1752
- });
1753
- });
1754
- }
1755
- missingArgument(name) {
1756
- const message = `error: missing required argument '${name}'`;
1757
- this.error(message, { code: "commander.missingArgument" });
1758
- }
1759
- optionMissingArgument(option) {
1760
- const message = `error: option '${option.flags}' argument missing`;
1761
- this.error(message, { code: "commander.optionMissingArgument" });
1762
- }
1763
- missingMandatoryOptionValue(option) {
1764
- const message = `error: required option '${option.flags}' not specified`;
1765
- this.error(message, { code: "commander.missingMandatoryOptionValue" });
1766
- }
1767
- _conflictingOption(option, conflictingOption) {
1768
- const findBestOptionFromValue = (option2) => {
1769
- const optionKey = option2.attributeName();
1770
- const optionValue = this.getOptionValue(optionKey);
1771
- const negativeOption = this.options.find((target) => target.negate && optionKey === target.attributeName());
1772
- const positiveOption = this.options.find((target) => !target.negate && optionKey === target.attributeName());
1773
- if (negativeOption && (negativeOption.presetArg === undefined && optionValue === false || negativeOption.presetArg !== undefined && optionValue === negativeOption.presetArg)) {
1774
- return negativeOption;
1775
- }
1776
- return positiveOption || option2;
1777
- };
1778
- const getErrorMessage = (option2) => {
1779
- const bestOption = findBestOptionFromValue(option2);
1780
- const optionKey = bestOption.attributeName();
1781
- const source = this.getOptionValueSource(optionKey);
1782
- if (source === "env") {
1783
- return `environment variable '${bestOption.envVar}'`;
1784
- }
1785
- return `option '${bestOption.flags}'`;
1786
- };
1787
- const message = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
1788
- this.error(message, { code: "commander.conflictingOption" });
1789
- }
1790
- unknownOption(flag) {
1791
- if (this._allowUnknownOption)
1792
- return;
1793
- let suggestion = "";
1794
- if (flag.startsWith("--") && this._showSuggestionAfterError) {
1795
- let candidateFlags = [];
1796
- let command = this;
1797
- do {
1798
- const moreFlags = command.createHelp().visibleOptions(command).filter((option) => option.long).map((option) => option.long);
1799
- candidateFlags = candidateFlags.concat(moreFlags);
1800
- command = command.parent;
1801
- } while (command && !command._enablePositionalOptions);
1802
- suggestion = suggestSimilar(flag, candidateFlags);
1803
- }
1804
- const message = `error: unknown option '${flag}'${suggestion}`;
1805
- this.error(message, { code: "commander.unknownOption" });
1806
- }
1807
- _excessArguments(receivedArgs) {
1808
- if (this._allowExcessArguments)
1809
- return;
1810
- const expected = this.registeredArguments.length;
1811
- const s = expected === 1 ? "" : "s";
1812
- const forSubcommand = this.parent ? ` for '${this.name()}'` : "";
1813
- const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
1814
- this.error(message, { code: "commander.excessArguments" });
1815
- }
1816
- unknownCommand() {
1817
- const unknownName = this.args[0];
1818
- let suggestion = "";
1819
- if (this._showSuggestionAfterError) {
1820
- const candidateNames = [];
1821
- this.createHelp().visibleCommands(this).forEach((command) => {
1822
- candidateNames.push(command.name());
1823
- if (command.alias())
1824
- candidateNames.push(command.alias());
1825
- });
1826
- suggestion = suggestSimilar(unknownName, candidateNames);
1827
- }
1828
- const message = `error: unknown command '${unknownName}'${suggestion}`;
1829
- this.error(message, { code: "commander.unknownCommand" });
1830
- }
1831
- version(str, flags, description) {
1832
- if (str === undefined)
1833
- return this._version;
1834
- this._version = str;
1835
- flags = flags || "-V, --version";
1836
- description = description || "output the version number";
1837
- const versionOption = this.createOption(flags, description);
1838
- this._versionOptionName = versionOption.attributeName();
1839
- this._registerOption(versionOption);
1840
- this.on("option:" + versionOption.name(), () => {
1841
- this._outputConfiguration.writeOut(`${str}
1842
- `);
1843
- this._exit(0, "commander.version", str);
1844
- });
1845
- return this;
1846
- }
1847
- description(str, argsDescription) {
1848
- if (str === undefined && argsDescription === undefined)
1849
- return this._description;
1850
- this._description = str;
1851
- if (argsDescription) {
1852
- this._argsDescription = argsDescription;
1853
- }
1854
- return this;
1855
- }
1856
- summary(str) {
1857
- if (str === undefined)
1858
- return this._summary;
1859
- this._summary = str;
1860
- return this;
1861
- }
1862
- alias(alias) {
1863
- if (alias === undefined)
1864
- return this._aliases[0];
1865
- let command = this;
1866
- if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
1867
- command = this.commands[this.commands.length - 1];
1868
- }
1869
- if (alias === command._name)
1870
- throw new Error("Command alias can't be the same as its name");
1871
- const matchingCommand = this.parent?._findCommand(alias);
1872
- if (matchingCommand) {
1873
- const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
1874
- throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`);
1875
- }
1876
- command._aliases.push(alias);
1877
- return this;
1878
- }
1879
- aliases(aliases) {
1880
- if (aliases === undefined)
1881
- return this._aliases;
1882
- aliases.forEach((alias) => this.alias(alias));
1883
- return this;
1884
- }
1885
- usage(str) {
1886
- if (str === undefined) {
1887
- if (this._usage)
1888
- return this._usage;
1889
- const args = this.registeredArguments.map((arg) => {
1890
- return humanReadableArgName(arg);
1891
- });
1892
- return [].concat(this.options.length || this._helpOption !== null ? "[options]" : [], this.commands.length ? "[command]" : [], this.registeredArguments.length ? args : []).join(" ");
1893
- }
1894
- this._usage = str;
1895
- return this;
1896
- }
1897
- name(str) {
1898
- if (str === undefined)
1899
- return this._name;
1900
- this._name = str;
1901
- return this;
1902
- }
1903
- helpGroup(heading) {
1904
- if (heading === undefined)
1905
- return this._helpGroupHeading ?? "";
1906
- this._helpGroupHeading = heading;
1907
- return this;
1908
- }
1909
- commandsGroup(heading) {
1910
- if (heading === undefined)
1911
- return this._defaultCommandGroup ?? "";
1912
- this._defaultCommandGroup = heading;
1913
- return this;
1914
- }
1915
- optionsGroup(heading) {
1916
- if (heading === undefined)
1917
- return this._defaultOptionGroup ?? "";
1918
- this._defaultOptionGroup = heading;
1919
- return this;
1920
- }
1921
- _initOptionGroup(option) {
1922
- if (this._defaultOptionGroup && !option.helpGroupHeading)
1923
- option.helpGroup(this._defaultOptionGroup);
1924
- }
1925
- _initCommandGroup(cmd) {
1926
- if (this._defaultCommandGroup && !cmd.helpGroup())
1927
- cmd.helpGroup(this._defaultCommandGroup);
1928
- }
1929
- nameFromFilename(filename) {
1930
- this._name = path.basename(filename, path.extname(filename));
1931
- return this;
1932
- }
1933
- executableDir(path2) {
1934
- if (path2 === undefined)
1935
- return this._executableDir;
1936
- this._executableDir = path2;
1937
- return this;
1938
- }
1939
- helpInformation(contextOptions) {
1940
- const helper = this.createHelp();
1941
- const context = this._getOutputContext(contextOptions);
1942
- helper.prepareContext({
1943
- error: context.error,
1944
- helpWidth: context.helpWidth,
1945
- outputHasColors: context.hasColors
1946
- });
1947
- const text = helper.formatHelp(this, helper);
1948
- if (context.hasColors)
1949
- return text;
1950
- return this._outputConfiguration.stripColor(text);
1951
- }
1952
- _getOutputContext(contextOptions) {
1953
- contextOptions = contextOptions || {};
1954
- const error = !!contextOptions.error;
1955
- let baseWrite;
1956
- let hasColors;
1957
- let helpWidth;
1958
- if (error) {
1959
- baseWrite = (str) => this._outputConfiguration.writeErr(str);
1960
- hasColors = this._outputConfiguration.getErrHasColors();
1961
- helpWidth = this._outputConfiguration.getErrHelpWidth();
1962
- } else {
1963
- baseWrite = (str) => this._outputConfiguration.writeOut(str);
1964
- hasColors = this._outputConfiguration.getOutHasColors();
1965
- helpWidth = this._outputConfiguration.getOutHelpWidth();
1966
- }
1967
- const write = (str) => {
1968
- if (!hasColors)
1969
- str = this._outputConfiguration.stripColor(str);
1970
- return baseWrite(str);
1971
- };
1972
- return { error, write, hasColors, helpWidth };
1973
- }
1974
- outputHelp(contextOptions) {
1975
- let deprecatedCallback;
1976
- if (typeof contextOptions === "function") {
1977
- deprecatedCallback = contextOptions;
1978
- contextOptions = undefined;
1979
- }
1980
- const outputContext = this._getOutputContext(contextOptions);
1981
- const eventContext = {
1982
- error: outputContext.error,
1983
- write: outputContext.write,
1984
- command: this
1985
- };
1986
- this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
1987
- this.emit("beforeHelp", eventContext);
1988
- let helpInformation = this.helpInformation({ error: outputContext.error });
1989
- if (deprecatedCallback) {
1990
- helpInformation = deprecatedCallback(helpInformation);
1991
- if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
1992
- throw new Error("outputHelp callback must return a string or a Buffer");
1993
- }
1994
- }
1995
- outputContext.write(helpInformation);
1996
- if (this._getHelpOption()?.long) {
1997
- this.emit(this._getHelpOption().long);
1998
- }
1999
- this.emit("afterHelp", eventContext);
2000
- this._getCommandAndAncestors().forEach((command) => command.emit("afterAllHelp", eventContext));
2001
- }
2002
- helpOption(flags, description) {
2003
- if (typeof flags === "boolean") {
2004
- if (flags) {
2005
- if (this._helpOption === null)
2006
- this._helpOption = undefined;
2007
- if (this._defaultOptionGroup) {
2008
- this._initOptionGroup(this._getHelpOption());
2009
- }
2010
- } else {
2011
- this._helpOption = null;
2012
- }
2013
- return this;
2014
- }
2015
- this._helpOption = this.createOption(flags ?? "-h, --help", description ?? "display help for command");
2016
- if (flags || description)
2017
- this._initOptionGroup(this._helpOption);
2018
- return this;
2019
- }
2020
- _getHelpOption() {
2021
- if (this._helpOption === undefined) {
2022
- this.helpOption(undefined, undefined);
2023
- }
2024
- return this._helpOption;
2025
- }
2026
- addHelpOption(option) {
2027
- this._helpOption = option;
2028
- this._initOptionGroup(option);
2029
- return this;
2030
- }
2031
- help(contextOptions) {
2032
- this.outputHelp(contextOptions);
2033
- let exitCode = Number(process2.exitCode ?? 0);
2034
- if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
2035
- exitCode = 1;
2036
- }
2037
- this._exit(exitCode, "commander.help", "(outputHelp)");
2038
- }
2039
- addHelpText(position, text) {
2040
- const allowedValues = ["beforeAll", "before", "after", "afterAll"];
2041
- if (!allowedValues.includes(position)) {
2042
- throw new Error(`Unexpected value for position to addHelpText.
2043
- Expecting one of '${allowedValues.join("', '")}'`);
2044
- }
2045
- const helpEvent = `${position}Help`;
2046
- this.on(helpEvent, (context) => {
2047
- let helpStr;
2048
- if (typeof text === "function") {
2049
- helpStr = text({ error: context.error, command: context.command });
2050
- } else {
2051
- helpStr = text;
2052
- }
2053
- if (helpStr) {
2054
- context.write(`${helpStr}
2055
- `);
2056
- }
2057
- });
2058
- return this;
2059
- }
2060
- _outputHelpIfRequested(args) {
2061
- const helpOption = this._getHelpOption();
2062
- const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
2063
- if (helpRequested) {
2064
- this.outputHelp();
2065
- this._exit(0, "commander.helpDisplayed", "(outputHelp)");
2066
- }
2067
- }
2068
- }
2069
- function incrementNodeInspectorPort(args) {
2070
- return args.map((arg) => {
2071
- if (!arg.startsWith("--inspect")) {
2072
- return arg;
2073
- }
2074
- let debugOption;
2075
- let debugHost = "127.0.0.1";
2076
- let debugPort = "9229";
2077
- let match;
2078
- if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
2079
- debugOption = match[1];
2080
- } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
2081
- debugOption = match[1];
2082
- if (/^\d+$/.test(match[3])) {
2083
- debugPort = match[3];
2084
- } else {
2085
- debugHost = match[3];
2086
- }
2087
- } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
2088
- debugOption = match[1];
2089
- debugHost = match[3];
2090
- debugPort = match[4];
2091
- }
2092
- if (debugOption && debugPort !== "0") {
2093
- return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
2094
- }
2095
- return arg;
4
+ var __returnValue = (v) => v;
5
+ function __exportSetter(name, newValue) {
6
+ this[name] = __returnValue.bind(null, newValue);
7
+ }
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, {
11
+ get: all[name],
12
+ enumerable: true,
13
+ configurable: true,
14
+ set: __exportSetter.bind(all, name)
2096
15
  });
2097
- }
2098
- function useColor() {
2099
- if (process2.env.NO_COLOR || process2.env.FORCE_COLOR === "0" || process2.env.FORCE_COLOR === "false")
2100
- return false;
2101
- if (process2.env.FORCE_COLOR || process2.env.CLICOLOR_FORCE !== undefined)
2102
- return true;
2103
- return;
2104
- }
2105
- exports.Command = Command;
2106
- exports.useColor = useColor;
2107
- });
2108
-
2109
- // node_modules/commander/index.js
2110
- var require_commander = __commonJS((exports) => {
2111
- var { Argument } = require_argument();
2112
- var { Command } = require_command();
2113
- var { CommanderError, InvalidArgumentError } = require_error();
2114
- var { Help } = require_help();
2115
- var { Option } = require_option();
2116
- exports.program = new Command;
2117
- exports.createCommand = (name) => new Command(name);
2118
- exports.createOption = (flags, description) => new Option(flags, description);
2119
- exports.createArgument = (name, description) => new Argument(name, description);
2120
- exports.Command = Command;
2121
- exports.Option = Option;
2122
- exports.Argument = Argument;
2123
- exports.Help = Help;
2124
- exports.CommanderError = CommanderError;
2125
- exports.InvalidArgumentError = InvalidArgumentError;
2126
- exports.InvalidOptionArgumentError = InvalidArgumentError;
2127
- });
2128
-
2129
- // node_modules/commander/esm.mjs
2130
- var import__ = __toESM(require_commander(), 1);
2131
- var {
2132
- program,
2133
- createCommand,
2134
- createArgument,
2135
- createOption,
2136
- CommanderError,
2137
- InvalidArgumentError,
2138
- InvalidOptionArgumentError,
2139
- Command,
2140
- Argument,
2141
- Option,
2142
- Help
2143
- } = import__.default;
16
+ };
17
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
2144
18
 
2145
19
  // node_modules/chalk/source/vendor/ansi-styles/index.js
2146
- var ANSI_BACKGROUND_OFFSET = 10;
2147
- var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
2148
- var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
2149
- var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
2150
- var styles = {
2151
- modifier: {
2152
- reset: [0, 0],
2153
- bold: [1, 22],
2154
- dim: [2, 22],
2155
- italic: [3, 23],
2156
- underline: [4, 24],
2157
- overline: [53, 55],
2158
- inverse: [7, 27],
2159
- hidden: [8, 28],
2160
- strikethrough: [9, 29]
2161
- },
2162
- color: {
2163
- black: [30, 39],
2164
- red: [31, 39],
2165
- green: [32, 39],
2166
- yellow: [33, 39],
2167
- blue: [34, 39],
2168
- magenta: [35, 39],
2169
- cyan: [36, 39],
2170
- white: [37, 39],
2171
- blackBright: [90, 39],
2172
- gray: [90, 39],
2173
- grey: [90, 39],
2174
- redBright: [91, 39],
2175
- greenBright: [92, 39],
2176
- yellowBright: [93, 39],
2177
- blueBright: [94, 39],
2178
- magentaBright: [95, 39],
2179
- cyanBright: [96, 39],
2180
- whiteBright: [97, 39]
2181
- },
2182
- bgColor: {
2183
- bgBlack: [40, 49],
2184
- bgRed: [41, 49],
2185
- bgGreen: [42, 49],
2186
- bgYellow: [43, 49],
2187
- bgBlue: [44, 49],
2188
- bgMagenta: [45, 49],
2189
- bgCyan: [46, 49],
2190
- bgWhite: [47, 49],
2191
- bgBlackBright: [100, 49],
2192
- bgGray: [100, 49],
2193
- bgGrey: [100, 49],
2194
- bgRedBright: [101, 49],
2195
- bgGreenBright: [102, 49],
2196
- bgYellowBright: [103, 49],
2197
- bgBlueBright: [104, 49],
2198
- bgMagentaBright: [105, 49],
2199
- bgCyanBright: [106, 49],
2200
- bgWhiteBright: [107, 49]
2201
- }
2202
- };
2203
- var modifierNames = Object.keys(styles.modifier);
2204
- var foregroundColorNames = Object.keys(styles.color);
2205
- var backgroundColorNames = Object.keys(styles.bgColor);
2206
- var colorNames = [...foregroundColorNames, ...backgroundColorNames];
2207
20
  function assembleStyles() {
2208
21
  const codes = new Map;
2209
22
  for (const [groupName, group] of Object.entries(styles)) {
@@ -2316,8 +129,68 @@ function assembleStyles() {
2316
129
  });
2317
130
  return styles;
2318
131
  }
2319
- var ansiStyles = assembleStyles();
2320
- var ansi_styles_default = ansiStyles;
132
+ var ANSI_BACKGROUND_OFFSET = 10, wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`, wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`, styles, modifierNames, foregroundColorNames, backgroundColorNames, colorNames, ansiStyles, ansi_styles_default;
133
+ var init_ansi_styles = __esm(() => {
134
+ styles = {
135
+ modifier: {
136
+ reset: [0, 0],
137
+ bold: [1, 22],
138
+ dim: [2, 22],
139
+ italic: [3, 23],
140
+ underline: [4, 24],
141
+ overline: [53, 55],
142
+ inverse: [7, 27],
143
+ hidden: [8, 28],
144
+ strikethrough: [9, 29]
145
+ },
146
+ color: {
147
+ black: [30, 39],
148
+ red: [31, 39],
149
+ green: [32, 39],
150
+ yellow: [33, 39],
151
+ blue: [34, 39],
152
+ magenta: [35, 39],
153
+ cyan: [36, 39],
154
+ white: [37, 39],
155
+ blackBright: [90, 39],
156
+ gray: [90, 39],
157
+ grey: [90, 39],
158
+ redBright: [91, 39],
159
+ greenBright: [92, 39],
160
+ yellowBright: [93, 39],
161
+ blueBright: [94, 39],
162
+ magentaBright: [95, 39],
163
+ cyanBright: [96, 39],
164
+ whiteBright: [97, 39]
165
+ },
166
+ bgColor: {
167
+ bgBlack: [40, 49],
168
+ bgRed: [41, 49],
169
+ bgGreen: [42, 49],
170
+ bgYellow: [43, 49],
171
+ bgBlue: [44, 49],
172
+ bgMagenta: [45, 49],
173
+ bgCyan: [46, 49],
174
+ bgWhite: [47, 49],
175
+ bgBlackBright: [100, 49],
176
+ bgGray: [100, 49],
177
+ bgGrey: [100, 49],
178
+ bgRedBright: [101, 49],
179
+ bgGreenBright: [102, 49],
180
+ bgYellowBright: [103, 49],
181
+ bgBlueBright: [104, 49],
182
+ bgMagentaBright: [105, 49],
183
+ bgCyanBright: [106, 49],
184
+ bgWhiteBright: [107, 49]
185
+ }
186
+ };
187
+ modifierNames = Object.keys(styles.modifier);
188
+ foregroundColorNames = Object.keys(styles.color);
189
+ backgroundColorNames = Object.keys(styles.bgColor);
190
+ colorNames = [...foregroundColorNames, ...backgroundColorNames];
191
+ ansiStyles = assembleStyles();
192
+ ansi_styles_default = ansiStyles;
193
+ });
2321
194
 
2322
195
  // node_modules/chalk/source/vendor/supports-color/index.js
2323
196
  import process2 from "process";
@@ -2329,13 +202,6 @@ function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.
2329
202
  const terminatorPosition = argv.indexOf("--");
2330
203
  return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
2331
204
  }
2332
- var { env } = process2;
2333
- var flagForceColor;
2334
- if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
2335
- flagForceColor = 0;
2336
- } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
2337
- flagForceColor = 1;
2338
- }
2339
205
  function envForceColor() {
2340
206
  if ("FORCE_COLOR" in env) {
2341
207
  if (env.FORCE_COLOR === "true") {
@@ -2445,11 +311,20 @@ function createSupportsColor(stream, options = {}) {
2445
311
  });
2446
312
  return translateLevel(level);
2447
313
  }
2448
- var supportsColor = {
2449
- stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
2450
- stderr: createSupportsColor({ isTTY: tty.isatty(2) })
2451
- };
2452
- var supports_color_default = supportsColor;
314
+ var env, flagForceColor, supportsColor, supports_color_default;
315
+ var init_supports_color = __esm(() => {
316
+ ({ env } = process2);
317
+ if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
318
+ flagForceColor = 0;
319
+ } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
320
+ flagForceColor = 1;
321
+ }
322
+ supportsColor = {
323
+ stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
324
+ stderr: createSupportsColor({ isTTY: tty.isatty(2) })
325
+ };
326
+ supports_color_default = supportsColor;
327
+ });
2453
328
 
2454
329
  // node_modules/chalk/source/utilities.js
2455
330
  function stringReplaceAll(string, substring, replacer) {
@@ -2485,51 +360,43 @@ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
2485
360
  }
2486
361
 
2487
362
  // node_modules/chalk/source/index.js
2488
- var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
2489
- var GENERATOR = Symbol("GENERATOR");
2490
- var STYLER = Symbol("STYLER");
2491
- var IS_EMPTY = Symbol("IS_EMPTY");
2492
- var levelMapping = [
2493
- "ansi",
2494
- "ansi",
2495
- "ansi256",
2496
- "ansi16m"
2497
- ];
2498
- var styles2 = Object.create(null);
2499
- var applyOptions = (object, options = {}) => {
363
+ var exports_source = {};
364
+ __export(exports_source, {
365
+ supportsColorStderr: () => stderrColor,
366
+ supportsColor: () => stdoutColor,
367
+ modifiers: () => modifierNames,
368
+ modifierNames: () => modifierNames,
369
+ foregroundColors: () => foregroundColorNames,
370
+ foregroundColorNames: () => foregroundColorNames,
371
+ default: () => source_default,
372
+ colors: () => colorNames,
373
+ colorNames: () => colorNames,
374
+ chalkStderr: () => chalkStderr,
375
+ backgroundColors: () => backgroundColorNames,
376
+ backgroundColorNames: () => backgroundColorNames,
377
+ Chalk: () => Chalk
378
+ });
379
+
380
+ class Chalk {
381
+ constructor(options) {
382
+ return chalkFactory(options);
383
+ }
384
+ }
385
+ function createChalk(options) {
386
+ return chalkFactory(options);
387
+ }
388
+ var stdoutColor, stderrColor, GENERATOR, STYLER, IS_EMPTY, levelMapping, styles2, applyOptions = (object, options = {}) => {
2500
389
  if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
2501
390
  throw new Error("The `level` option should be an integer from 0 to 3");
2502
391
  }
2503
392
  const colorLevel = stdoutColor ? stdoutColor.level : 0;
2504
393
  object.level = options.level === undefined ? colorLevel : options.level;
2505
- };
2506
- var chalkFactory = (options) => {
394
+ }, chalkFactory = (options) => {
2507
395
  const chalk = (...strings) => strings.join(" ");
2508
396
  applyOptions(chalk, options);
2509
397
  Object.setPrototypeOf(chalk, createChalk.prototype);
2510
398
  return chalk;
2511
- };
2512
- function createChalk(options) {
2513
- return chalkFactory(options);
2514
- }
2515
- Object.setPrototypeOf(createChalk.prototype, Function.prototype);
2516
- for (const [styleName, style] of Object.entries(ansi_styles_default)) {
2517
- styles2[styleName] = {
2518
- get() {
2519
- const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
2520
- Object.defineProperty(this, styleName, { value: builder });
2521
- return builder;
2522
- }
2523
- };
2524
- }
2525
- styles2.visible = {
2526
- get() {
2527
- const builder = createBuilder(this, this[STYLER], true);
2528
- Object.defineProperty(this, "visible", { value: builder });
2529
- return builder;
2530
- }
2531
- };
2532
- var getModelAnsi = (model, level, type, ...arguments_) => {
399
+ }, getModelAnsi = (model, level, type, ...arguments_) => {
2533
400
  if (model === "rgb") {
2534
401
  if (level === "ansi16m") {
2535
402
  return ansi_styles_default[type].ansi16m(...arguments_);
@@ -2543,42 +410,7 @@ var getModelAnsi = (model, level, type, ...arguments_) => {
2543
410
  return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
2544
411
  }
2545
412
  return ansi_styles_default[type][model](...arguments_);
2546
- };
2547
- var usedModels = ["rgb", "hex", "ansi256"];
2548
- for (const model of usedModels) {
2549
- styles2[model] = {
2550
- get() {
2551
- const { level } = this;
2552
- return function(...arguments_) {
2553
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
2554
- return createBuilder(this, styler, this[IS_EMPTY]);
2555
- };
2556
- }
2557
- };
2558
- const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
2559
- styles2[bgModel] = {
2560
- get() {
2561
- const { level } = this;
2562
- return function(...arguments_) {
2563
- const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
2564
- return createBuilder(this, styler, this[IS_EMPTY]);
2565
- };
2566
- }
2567
- };
2568
- }
2569
- var proto = Object.defineProperties(() => {}, {
2570
- ...styles2,
2571
- level: {
2572
- enumerable: true,
2573
- get() {
2574
- return this[GENERATOR].level;
2575
- },
2576
- set(level) {
2577
- this[GENERATOR].level = level;
2578
- }
2579
- }
2580
- });
2581
- var createStyler = (open, close, parent) => {
413
+ }, usedModels, proto, createStyler = (open, close, parent) => {
2582
414
  let openAll;
2583
415
  let closeAll;
2584
416
  if (parent === undefined) {
@@ -2595,16 +427,14 @@ var createStyler = (open, close, parent) => {
2595
427
  closeAll,
2596
428
  parent
2597
429
  };
2598
- };
2599
- var createBuilder = (self, _styler, _isEmpty) => {
430
+ }, createBuilder = (self, _styler, _isEmpty) => {
2600
431
  const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
2601
432
  Object.setPrototypeOf(builder, proto);
2602
433
  builder[GENERATOR] = self;
2603
434
  builder[STYLER] = _styler;
2604
435
  builder[IS_EMPTY] = _isEmpty;
2605
436
  return builder;
2606
- };
2607
- var applyStyle = (self, string) => {
437
+ }, applyStyle = (self, string) => {
2608
438
  if (self.level <= 0 || !string) {
2609
439
  return self[IS_EMPTY] ? "" : string;
2610
440
  }
@@ -2625,203 +455,873 @@ var applyStyle = (self, string) => {
2625
455
  string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
2626
456
  }
2627
457
  return openAll + string + closeAll;
2628
- };
2629
- Object.defineProperties(createChalk.prototype, styles2);
2630
- var chalk = createChalk();
2631
- var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
2632
- var source_default = chalk;
458
+ }, chalk, chalkStderr, source_default;
459
+ var init_source = __esm(() => {
460
+ init_ansi_styles();
461
+ init_supports_color();
462
+ init_ansi_styles();
463
+ ({ stdout: stdoutColor, stderr: stderrColor } = supports_color_default);
464
+ GENERATOR = Symbol("GENERATOR");
465
+ STYLER = Symbol("STYLER");
466
+ IS_EMPTY = Symbol("IS_EMPTY");
467
+ levelMapping = [
468
+ "ansi",
469
+ "ansi",
470
+ "ansi256",
471
+ "ansi16m"
472
+ ];
473
+ styles2 = Object.create(null);
474
+ Object.setPrototypeOf(createChalk.prototype, Function.prototype);
475
+ for (const [styleName, style] of Object.entries(ansi_styles_default)) {
476
+ styles2[styleName] = {
477
+ get() {
478
+ const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
479
+ Object.defineProperty(this, styleName, { value: builder });
480
+ return builder;
481
+ }
482
+ };
483
+ }
484
+ styles2.visible = {
485
+ get() {
486
+ const builder = createBuilder(this, this[STYLER], true);
487
+ Object.defineProperty(this, "visible", { value: builder });
488
+ return builder;
489
+ }
490
+ };
491
+ usedModels = ["rgb", "hex", "ansi256"];
492
+ for (const model of usedModels) {
493
+ styles2[model] = {
494
+ get() {
495
+ const { level } = this;
496
+ return function(...arguments_) {
497
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
498
+ return createBuilder(this, styler, this[IS_EMPTY]);
499
+ };
500
+ }
501
+ };
502
+ const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
503
+ styles2[bgModel] = {
504
+ get() {
505
+ const { level } = this;
506
+ return function(...arguments_) {
507
+ const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
508
+ return createBuilder(this, styler, this[IS_EMPTY]);
509
+ };
510
+ }
511
+ };
512
+ }
513
+ proto = Object.defineProperties(() => {}, {
514
+ ...styles2,
515
+ level: {
516
+ enumerable: true,
517
+ get() {
518
+ return this[GENERATOR].level;
519
+ },
520
+ set(level) {
521
+ this[GENERATOR].level = level;
522
+ }
523
+ }
524
+ });
525
+ Object.defineProperties(createChalk.prototype, styles2);
526
+ chalk = createChalk();
527
+ chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
528
+ source_default = chalk;
529
+ });
2633
530
 
2634
- // src/api/client.ts
2635
- import { readFileSync } from "fs";
2636
- import { resolve } from "path";
2637
- import { homedir } from "os";
531
+ // src/index.ts
532
+ init_source();
2638
533
 
2639
- // src/lib/errors.ts
2640
- class CliError extends Error {
534
+ // node_modules/citty/dist/_chunks/libs/scule.mjs
535
+ var NUMBER_CHAR_RE = /\d/;
536
+ var STR_SPLITTERS = [
537
+ "-",
538
+ "_",
539
+ "/",
540
+ "."
541
+ ];
542
+ function isUppercase(char = "") {
543
+ if (NUMBER_CHAR_RE.test(char))
544
+ return;
545
+ return char !== char.toLowerCase();
546
+ }
547
+ function splitByCase(str, separators) {
548
+ const splitters = separators ?? STR_SPLITTERS;
549
+ const parts = [];
550
+ if (!str || typeof str !== "string")
551
+ return parts;
552
+ let buff = "";
553
+ let previousUpper;
554
+ let previousSplitter;
555
+ for (const char of str) {
556
+ const isSplitter = splitters.includes(char);
557
+ if (isSplitter === true) {
558
+ parts.push(buff);
559
+ buff = "";
560
+ previousUpper = undefined;
561
+ continue;
562
+ }
563
+ const isUpper = isUppercase(char);
564
+ if (previousSplitter === false) {
565
+ if (previousUpper === false && isUpper === true) {
566
+ parts.push(buff);
567
+ buff = char;
568
+ previousUpper = isUpper;
569
+ continue;
570
+ }
571
+ if (previousUpper === true && isUpper === false && buff.length > 1) {
572
+ const lastChar = buff.at(-1);
573
+ parts.push(buff.slice(0, Math.max(0, buff.length - 1)));
574
+ buff = lastChar + char;
575
+ previousUpper = isUpper;
576
+ continue;
577
+ }
578
+ }
579
+ buff += char;
580
+ previousUpper = isUpper;
581
+ previousSplitter = isSplitter;
582
+ }
583
+ parts.push(buff);
584
+ return parts;
585
+ }
586
+ function upperFirst(str) {
587
+ return str ? str[0].toUpperCase() + str.slice(1) : "";
588
+ }
589
+ function lowerFirst(str) {
590
+ return str ? str[0].toLowerCase() + str.slice(1) : "";
591
+ }
592
+ function pascalCase(str, opts) {
593
+ return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p) => upperFirst(opts?.normalize ? p.toLowerCase() : p)).join("") : "";
594
+ }
595
+ function camelCase(str, opts) {
596
+ return lowerFirst(pascalCase(str || "", opts));
597
+ }
598
+ function kebabCase(str, joiner) {
599
+ return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p) => p.toLowerCase()).join(joiner ?? "-") : "";
600
+ }
601
+ function snakeCase(str) {
602
+ return kebabCase(str || "", "_");
603
+ }
604
+
605
+ // node_modules/citty/dist/index.mjs
606
+ import { parseArgs as parseArgs$1 } from "util";
607
+ function toArray(val) {
608
+ if (Array.isArray(val))
609
+ return val;
610
+ return val === undefined ? [] : [val];
611
+ }
612
+ function formatLineColumns(lines, linePrefix = "") {
613
+ const maxLength = [];
614
+ for (const line of lines)
615
+ for (const [i, element] of line.entries())
616
+ maxLength[i] = Math.max(maxLength[i] || 0, element.length);
617
+ return lines.map((l) => l.map((c, i) => linePrefix + c[i === 0 ? "padStart" : "padEnd"](maxLength[i])).join(" ")).join(`
618
+ `);
619
+ }
620
+ function resolveValue(input) {
621
+ return typeof input === "function" ? input() : input;
622
+ }
623
+ var CLIError = class extends Error {
2641
624
  code;
2642
- hint;
2643
- constructor(code, message, hint) {
625
+ constructor(message, code) {
2644
626
  super(message);
627
+ this.name = "CLIError";
2645
628
  this.code = code;
2646
- this.hint = hint;
2647
- this.name = "CliError";
2648
629
  }
2649
- }
2650
- function exitCodeFor(err) {
2651
- if (!(err instanceof CliError))
2652
- return 1;
2653
- switch (err.code) {
2654
- case "BAD_ARGS":
2655
- return 1;
2656
- case "TOKEN_MISSING":
2657
- case "TOKEN_INVALID":
2658
- return 2;
2659
- case "API_ERROR":
2660
- return 3;
2661
- case "DB_ERROR":
2662
- return 4;
2663
- case "UNKNOWN":
2664
- return 1;
630
+ };
631
+ function parseRawArgs(args = [], opts = {}) {
632
+ const booleans = new Set(opts.boolean || []);
633
+ const strings = new Set(opts.string || []);
634
+ const aliasMap = opts.alias || {};
635
+ const defaults = opts.default || {};
636
+ const aliasToMain = /* @__PURE__ */ new Map;
637
+ const mainToAliases = /* @__PURE__ */ new Map;
638
+ for (const [key, value] of Object.entries(aliasMap)) {
639
+ const targets = value;
640
+ for (const target of targets) {
641
+ aliasToMain.set(key, target);
642
+ if (!mainToAliases.has(target))
643
+ mainToAliases.set(target, []);
644
+ mainToAliases.get(target).push(key);
645
+ aliasToMain.set(target, key);
646
+ if (!mainToAliases.has(key))
647
+ mainToAliases.set(key, []);
648
+ mainToAliases.get(key).push(target);
649
+ }
650
+ }
651
+ const options = {};
652
+ function getType(name) {
653
+ if (booleans.has(name))
654
+ return "boolean";
655
+ const aliases = mainToAliases.get(name) || [];
656
+ for (const alias of aliases)
657
+ if (booleans.has(alias))
658
+ return "boolean";
659
+ return "string";
660
+ }
661
+ function isStringType(name) {
662
+ if (strings.has(name))
663
+ return true;
664
+ const aliases = mainToAliases.get(name) || [];
665
+ for (const alias of aliases)
666
+ if (strings.has(alias))
667
+ return true;
668
+ return false;
2665
669
  }
2666
- }
2667
- function redactSecrets(s) {
2668
- return s.replace(/Bearer\s+[A-Za-z0-9._\-]{8,}/g, "Bearer [REDACTED]").replace(/"token"\s*:\s*"[^"]{8,}"/g, '"token":"[REDACTED]"');
2669
- }
2670
- function formatError(err, format) {
2671
- const code = err instanceof CliError ? err.code : "UNKNOWN";
2672
- const message = err instanceof Error ? err.message : String(err);
2673
- const hint = err instanceof CliError ? err.hint : undefined;
2674
- if (format === "json") {
2675
- return {
2676
- kind: "json",
2677
- text: JSON.stringify({ error: { code, message, ...hint ? { hint } : {} } })
670
+ const allOptions = new Set([
671
+ ...booleans,
672
+ ...strings,
673
+ ...Object.keys(aliasMap),
674
+ ...Object.values(aliasMap).flat(),
675
+ ...Object.keys(defaults)
676
+ ]);
677
+ for (const name of allOptions)
678
+ if (!options[name])
679
+ options[name] = {
680
+ type: getType(name),
681
+ default: defaults[name]
682
+ };
683
+ for (const [alias, main] of aliasToMain.entries())
684
+ if (alias.length === 1 && options[main] && !options[main].short)
685
+ options[main].short = alias;
686
+ const processedArgs = [];
687
+ const negatedFlags = {};
688
+ for (let i = 0;i < args.length; i++) {
689
+ const arg = args[i];
690
+ if (arg === "--") {
691
+ processedArgs.push(...args.slice(i));
692
+ break;
693
+ }
694
+ if (arg.startsWith("--no-")) {
695
+ const flagName = arg.slice(5);
696
+ negatedFlags[flagName] = true;
697
+ continue;
698
+ }
699
+ processedArgs.push(arg);
700
+ }
701
+ let parsed;
702
+ try {
703
+ parsed = parseArgs$1({
704
+ args: processedArgs,
705
+ options: Object.keys(options).length > 0 ? options : undefined,
706
+ allowPositionals: true,
707
+ strict: false
708
+ });
709
+ } catch {
710
+ parsed = {
711
+ values: {},
712
+ positionals: processedArgs
2678
713
  };
2679
714
  }
2680
- const head = source_default.red(`error: ${message}`);
2681
- return { kind: "text", text: hint ? `${head}
2682
- hint: ${hint}` : head };
2683
- }
2684
- function emitError(err, format) {
2685
- const env2 = formatError(err, format);
2686
- process.stderr.write(env2.text + `
2687
- `);
2688
- }
2689
-
2690
- // src/api/client.ts
2691
- var BASE_URL = "https://api.ouraring.com/v2/usercollection";
2692
-
2693
- class OuraClient {
2694
- token;
2695
- constructor(options = {}) {
2696
- const direct = options.token ?? process.env.OURA_TOKEN;
2697
- if (direct) {
2698
- this.token = direct.trim();
2699
- } else {
2700
- const tokenPath = options.tokenPath ?? process.env.OURA_TOKEN_PATH ?? resolve(homedir(), ".oura-token");
2701
- try {
2702
- this.token = readFileSync(tokenPath, "utf-8").trim();
2703
- } catch {
2704
- throw new CliError("TOKEN_MISSING", `No Oura access token at ${tokenPath}.`, "Run `oura-cli login` or set OURA_TOKEN.");
2705
- }
2706
- }
2707
- }
2708
- async fetch(endpoint, startDate, endDate) {
2709
- const params = new URLSearchParams({ start_date: startDate });
2710
- if (endDate)
2711
- params.set("end_date", endDate);
2712
- const url = `${BASE_URL}/${endpoint}?${params}`;
2713
- const response = await fetch(url, {
2714
- headers: { Authorization: `Bearer ${this.token}` }
715
+ const out = { _: [] };
716
+ out._ = parsed.positionals;
717
+ for (const [key, value] of Object.entries(parsed.values)) {
718
+ let coerced = value;
719
+ if (getType(key) === "boolean" && typeof value === "string")
720
+ coerced = value !== "false";
721
+ else if (isStringType(key) && typeof value === "boolean")
722
+ coerced = "";
723
+ out[key] = coerced;
724
+ }
725
+ for (const [name] of Object.entries(negatedFlags)) {
726
+ out[name] = false;
727
+ const mainName = aliasToMain.get(name);
728
+ if (mainName)
729
+ out[mainName] = false;
730
+ const aliases = mainToAliases.get(name);
731
+ if (aliases)
732
+ for (const alias of aliases)
733
+ out[alias] = false;
734
+ }
735
+ for (const [alias, main] of aliasToMain.entries()) {
736
+ if (out[alias] !== undefined && out[main] === undefined)
737
+ out[main] = out[alias];
738
+ if (out[main] !== undefined && out[alias] === undefined)
739
+ out[alias] = out[main];
740
+ if (out[alias] !== out[main] && defaults[main] === out[main])
741
+ out[main] = out[alias];
742
+ }
743
+ return out;
744
+ }
745
+ var noColor = /* @__PURE__ */ (() => {
746
+ const env2 = globalThis.process?.env ?? {};
747
+ return env2.NO_COLOR === "1" || env2.TERM === "dumb" || env2.TEST || env2.CI;
748
+ })();
749
+ var _c = (c, r = 39) => (t) => noColor ? t : `\x1B[${c}m${t}\x1B[${r}m`;
750
+ var bold = /* @__PURE__ */ _c(1, 22);
751
+ var cyan = /* @__PURE__ */ _c(36);
752
+ var gray = /* @__PURE__ */ _c(90);
753
+ var underline = /* @__PURE__ */ _c(4, 24);
754
+ function parseArgs(rawArgs, argsDef) {
755
+ const parseOptions = {
756
+ boolean: [],
757
+ string: [],
758
+ alias: {},
759
+ default: {}
760
+ };
761
+ const args = resolveArgs(argsDef);
762
+ for (const arg of args) {
763
+ if (arg.type === "positional")
764
+ continue;
765
+ if (arg.type === "string" || arg.type === "enum")
766
+ parseOptions.string.push(arg.name);
767
+ else if (arg.type === "boolean")
768
+ parseOptions.boolean.push(arg.name);
769
+ if (arg.default !== undefined)
770
+ parseOptions.default[arg.name] = arg.default;
771
+ if (arg.alias)
772
+ parseOptions.alias[arg.name] = arg.alias;
773
+ const camelName = camelCase(arg.name);
774
+ const kebabName = kebabCase(arg.name);
775
+ if (camelName !== arg.name || kebabName !== arg.name) {
776
+ const existingAliases = toArray(parseOptions.alias[arg.name] || []);
777
+ if (camelName !== arg.name && !existingAliases.includes(camelName))
778
+ existingAliases.push(camelName);
779
+ if (kebabName !== arg.name && !existingAliases.includes(kebabName))
780
+ existingAliases.push(kebabName);
781
+ if (existingAliases.length > 0)
782
+ parseOptions.alias[arg.name] = existingAliases;
783
+ }
784
+ }
785
+ const parsed = parseRawArgs(rawArgs, parseOptions);
786
+ const [...positionalArguments] = parsed._;
787
+ const parsedArgsProxy = new Proxy(parsed, { get(target, prop) {
788
+ return target[prop] ?? target[camelCase(prop)] ?? target[kebabCase(prop)];
789
+ } });
790
+ for (const [, arg] of args.entries())
791
+ if (arg.type === "positional") {
792
+ const nextPositionalArgument = positionalArguments.shift();
793
+ if (nextPositionalArgument !== undefined)
794
+ parsedArgsProxy[arg.name] = nextPositionalArgument;
795
+ else if (arg.default === undefined && arg.required !== false)
796
+ throw new CLIError(`Missing required positional argument: ${arg.name.toUpperCase()}`, "EARG");
797
+ else
798
+ parsedArgsProxy[arg.name] = arg.default;
799
+ } else if (arg.type === "enum") {
800
+ const argument = parsedArgsProxy[arg.name];
801
+ const options = arg.options || [];
802
+ if (argument !== undefined && options.length > 0 && !options.includes(argument))
803
+ throw new CLIError(`Invalid value for argument: ${cyan(`--${arg.name}`)} (${cyan(argument)}). Expected one of: ${options.map((o) => cyan(o)).join(", ")}.`, "EARG");
804
+ } else if (arg.required && parsedArgsProxy[arg.name] === undefined)
805
+ throw new CLIError(`Missing required argument: --${arg.name}`, "EARG");
806
+ return parsedArgsProxy;
807
+ }
808
+ function resolveArgs(argsDef) {
809
+ const args = [];
810
+ for (const [name, argDef] of Object.entries(argsDef || {}))
811
+ args.push({
812
+ ...argDef,
813
+ name,
814
+ alias: toArray(argDef.alias)
2715
815
  });
2716
- if (!response.ok) {
2717
- const rawBody = await response.text();
2718
- const redacted = redactSecrets(rawBody);
2719
- const body = redacted.length > 200 ? redacted.slice(0, 200) + "\u2026 (truncated)" : redacted;
2720
- if (response.status === 401 || response.status === 403) {
2721
- throw new CliError("TOKEN_INVALID", `Oura API ${response.status}: ${body}`);
2722
- }
2723
- throw new CliError("API_ERROR", `Oura API ${response.status}: ${body}`);
2724
- }
2725
- let json;
816
+ return args;
817
+ }
818
+ async function resolvePlugins(plugins) {
819
+ return Promise.all(plugins.map((p) => resolveValue(p)));
820
+ }
821
+ function defineCommand(def) {
822
+ return def;
823
+ }
824
+ async function runCommand(cmd, opts) {
825
+ const cmdArgs = await resolveValue(cmd.args || {});
826
+ const parsedArgs = parseArgs(opts.rawArgs, cmdArgs);
827
+ const context = {
828
+ rawArgs: opts.rawArgs,
829
+ args: parsedArgs,
830
+ data: opts.data,
831
+ cmd
832
+ };
833
+ const plugins = await resolvePlugins(cmd.plugins ?? []);
834
+ let result;
835
+ let runError;
836
+ try {
837
+ for (const plugin of plugins)
838
+ await plugin.setup?.(context);
839
+ if (typeof cmd.setup === "function")
840
+ await cmd.setup(context);
841
+ const subCommands = await resolveValue(cmd.subCommands);
842
+ if (subCommands && Object.keys(subCommands).length > 0) {
843
+ const subCommandArgIndex = findSubCommandIndex(opts.rawArgs, cmdArgs);
844
+ const explicitName = opts.rawArgs[subCommandArgIndex];
845
+ if (explicitName) {
846
+ const subCommand = await _findSubCommand(subCommands, explicitName);
847
+ if (!subCommand)
848
+ throw new CLIError(`Unknown command ${cyan(explicitName)}`, "E_UNKNOWN_COMMAND");
849
+ await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
850
+ } else {
851
+ const defaultSubCommand = await resolveValue(cmd.default);
852
+ if (defaultSubCommand) {
853
+ if (cmd.run)
854
+ throw new CLIError(`Cannot specify both 'run' and 'default' on the same command.`, "E_DEFAULT_CONFLICT");
855
+ const subCommand = await _findSubCommand(subCommands, defaultSubCommand);
856
+ if (!subCommand)
857
+ throw new CLIError(`Default sub command ${cyan(defaultSubCommand)} not found in subCommands.`, "E_UNKNOWN_COMMAND");
858
+ await runCommand(subCommand, { rawArgs: opts.rawArgs });
859
+ } else if (!cmd.run)
860
+ throw new CLIError(`No command specified.`, "E_NO_COMMAND");
861
+ }
862
+ }
863
+ if (typeof cmd.run === "function")
864
+ result = await cmd.run(context);
865
+ } catch (error) {
866
+ runError = error;
867
+ }
868
+ const cleanupErrors = [];
869
+ if (typeof cmd.cleanup === "function")
2726
870
  try {
2727
- json = await response.json();
2728
- } catch {
2729
- throw new CliError("API_ERROR", "Empty response body from Oura API.");
871
+ await cmd.cleanup(context);
872
+ } catch (error) {
873
+ cleanupErrors.push(error);
2730
874
  }
2731
- return json.data ?? [];
875
+ for (const plugin of [...plugins].reverse())
876
+ try {
877
+ await plugin.cleanup?.(context);
878
+ } catch (error) {
879
+ cleanupErrors.push(error);
880
+ }
881
+ if (runError)
882
+ throw runError;
883
+ if (cleanupErrors.length === 1)
884
+ throw cleanupErrors[0];
885
+ if (cleanupErrors.length > 1)
886
+ throw new Error("Multiple cleanup errors", { cause: cleanupErrors });
887
+ return { result };
888
+ }
889
+ async function resolveSubCommand(cmd, rawArgs, parent) {
890
+ const subCommands = await resolveValue(cmd.subCommands);
891
+ if (subCommands && Object.keys(subCommands).length > 0) {
892
+ const subCommandArgIndex = findSubCommandIndex(rawArgs, await resolveValue(cmd.args || {}));
893
+ const subCommandName = rawArgs[subCommandArgIndex];
894
+ const subCommand = await _findSubCommand(subCommands, subCommandName);
895
+ if (subCommand)
896
+ return resolveSubCommand(subCommand, rawArgs.slice(subCommandArgIndex + 1), cmd);
897
+ }
898
+ return [cmd, parent];
899
+ }
900
+ async function _findSubCommand(subCommands, name) {
901
+ if (name in subCommands)
902
+ return resolveValue(subCommands[name]);
903
+ for (const sub of Object.values(subCommands)) {
904
+ const resolved = await resolveValue(sub);
905
+ const meta = await resolveValue(resolved?.meta);
906
+ if (meta?.alias) {
907
+ if (toArray(meta.alias).includes(name))
908
+ return resolved;
909
+ }
910
+ }
911
+ }
912
+ function findSubCommandIndex(rawArgs, argsDef) {
913
+ for (let i = 0;i < rawArgs.length; i++) {
914
+ const arg = rawArgs[i];
915
+ if (arg === "--")
916
+ return -1;
917
+ if (arg.startsWith("-")) {
918
+ if (!arg.includes("=") && _isValueFlag(arg, argsDef))
919
+ i++;
920
+ continue;
921
+ }
922
+ return i;
923
+ }
924
+ return -1;
925
+ }
926
+ function _isValueFlag(flag, argsDef) {
927
+ const name = flag.replace(/^-{1,2}/, "");
928
+ const normalized = camelCase(name);
929
+ for (const [key, def] of Object.entries(argsDef)) {
930
+ if (def.type !== "string" && def.type !== "enum")
931
+ continue;
932
+ if (normalized === camelCase(key))
933
+ return true;
934
+ if ((Array.isArray(def.alias) ? def.alias : def.alias ? [def.alias] : []).includes(name))
935
+ return true;
2732
936
  }
937
+ return false;
2733
938
  }
2734
-
2735
- // src/lib/time.ts
2736
- function nowUtc() {
2737
- return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
939
+ async function showUsage(cmd, parent) {
940
+ try {
941
+ console.log(await renderUsage(cmd, parent) + `
942
+ `);
943
+ } catch (error) {
944
+ console.error(error);
945
+ }
946
+ }
947
+ var negativePrefixRe = /^no[-A-Z]/;
948
+ async function renderUsage(cmd, parent) {
949
+ const cmdMeta = await resolveValue(cmd.meta || {});
950
+ const cmdArgs = resolveArgs(await resolveValue(cmd.args || {}));
951
+ const parentMeta = await resolveValue(parent?.meta || {});
952
+ const commandName = `${parentMeta.name ? `${parentMeta.name} ` : ""}` + (cmdMeta.name || process.argv[1]);
953
+ const argLines = [];
954
+ const posLines = [];
955
+ const commandsLines = [];
956
+ const usageLine = [];
957
+ for (const arg of cmdArgs)
958
+ if (arg.type === "positional") {
959
+ const name = arg.name.toUpperCase();
960
+ const isRequired = arg.required !== false && arg.default === undefined;
961
+ posLines.push([cyan(name + renderValueHint(arg)), renderDescription(arg, isRequired)]);
962
+ usageLine.push(isRequired ? `<${name}>` : `[${name}]`);
963
+ } else {
964
+ const isRequired = arg.required === true && arg.default === undefined;
965
+ const argStr = [...(arg.alias || []).map((a) => `-${a}`), `--${arg.name}`].join(", ") + renderValueHint(arg);
966
+ argLines.push([cyan(argStr), renderDescription(arg, isRequired)]);
967
+ if (arg.type === "boolean" && (arg.default === true || arg.negativeDescription) && !negativePrefixRe.test(arg.name)) {
968
+ const negativeArgStr = [...(arg.alias || []).map((a) => `--no-${a}`), `--no-${arg.name}`].join(", ");
969
+ argLines.push([cyan(negativeArgStr), [arg.negativeDescription, isRequired ? gray("(Required)") : ""].filter(Boolean).join(" ")]);
970
+ }
971
+ if (isRequired)
972
+ usageLine.push(`--${arg.name}` + renderValueHint(arg));
973
+ }
974
+ if (cmd.subCommands) {
975
+ const commandNames = [];
976
+ const subCommands = await resolveValue(cmd.subCommands);
977
+ for (const [name, sub] of Object.entries(subCommands)) {
978
+ const meta = await resolveValue((await resolveValue(sub))?.meta);
979
+ if (meta?.hidden)
980
+ continue;
981
+ const aliases = toArray(meta?.alias);
982
+ const label = [name, ...aliases].join(", ");
983
+ commandsLines.push([cyan(label), meta?.description || ""]);
984
+ commandNames.push(name, ...aliases);
985
+ }
986
+ usageLine.push(commandNames.join("|"));
987
+ }
988
+ const usageLines = [];
989
+ const version = cmdMeta.version || parentMeta.version;
990
+ usageLines.push(gray(`${cmdMeta.description} (${commandName + (version ? ` v${version}` : "")})`), "");
991
+ const hasOptions = argLines.length > 0 || posLines.length > 0;
992
+ usageLines.push(`${underline(bold("USAGE"))} ${cyan(`${commandName}${hasOptions ? " [OPTIONS]" : ""} ${usageLine.join(" ")}`)}`, "");
993
+ if (posLines.length > 0) {
994
+ usageLines.push(underline(bold("ARGUMENTS")), "");
995
+ usageLines.push(formatLineColumns(posLines, " "));
996
+ usageLines.push("");
997
+ }
998
+ if (argLines.length > 0) {
999
+ usageLines.push(underline(bold("OPTIONS")), "");
1000
+ usageLines.push(formatLineColumns(argLines, " "));
1001
+ usageLines.push("");
1002
+ }
1003
+ if (commandsLines.length > 0) {
1004
+ usageLines.push(underline(bold("COMMANDS")), "");
1005
+ usageLines.push(formatLineColumns(commandsLines, " "));
1006
+ usageLines.push("", `Use ${cyan(`${commandName} <command> --help`)} for more information about a command.`);
1007
+ }
1008
+ return usageLines.filter((l) => typeof l === "string").join(`
1009
+ `);
2738
1010
  }
2739
- function formatLocal(utcStr, timezone) {
2740
- const dt = new Date(utcStr);
2741
- const parts = new Intl.DateTimeFormat("sv-SE", {
2742
- timeZone: timezone,
2743
- year: "numeric",
2744
- month: "2-digit",
2745
- day: "2-digit",
2746
- hour: "2-digit",
2747
- minute: "2-digit",
2748
- hour12: false
2749
- }).formatToParts(dt);
2750
- const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
2751
- return `${get("year")}-${get("month")}-${get("day")} ${get("hour")}:${get("minute")}`;
1011
+ function renderValueHint(arg) {
1012
+ const valueHint = arg.valueHint ? `=<${arg.valueHint}>` : "";
1013
+ const fallbackValueHint = valueHint || `=<${snakeCase(arg.name)}>`;
1014
+ if (!arg.type || arg.type === "positional" || arg.type === "boolean")
1015
+ return valueHint;
1016
+ if (arg.type === "enum" && arg.options?.length)
1017
+ return `=<${arg.options.join("|")}>`;
1018
+ return fallbackValueHint;
1019
+ }
1020
+ function renderDescription(arg, required) {
1021
+ const requiredHint = required ? gray("(Required)") : "";
1022
+ const defaultHint = arg.default === undefined ? "" : gray(`(Default: ${arg.default})`);
1023
+ return [
1024
+ arg.description,
1025
+ requiredHint,
1026
+ defaultHint
1027
+ ].filter(Boolean).join(" ");
1028
+ }
1029
+ async function runMain(cmd, opts = {}) {
1030
+ const rawArgs = opts.rawArgs || process.argv.slice(2);
1031
+ const showUsage$1 = opts.showUsage || showUsage;
1032
+ try {
1033
+ const builtinFlags = await _resolveBuiltinFlags(cmd);
1034
+ if (builtinFlags.help.length > 0 && rawArgs.some((arg) => builtinFlags.help.includes(arg))) {
1035
+ await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
1036
+ process.exit(0);
1037
+ } else if (rawArgs.length === 1 && builtinFlags.version.includes(rawArgs[0])) {
1038
+ const meta = typeof cmd.meta === "function" ? await cmd.meta() : await cmd.meta;
1039
+ if (!meta?.version)
1040
+ throw new CLIError("No version specified", "E_NO_VERSION");
1041
+ console.log(meta.version);
1042
+ } else
1043
+ await runCommand(cmd, { rawArgs });
1044
+ } catch (error) {
1045
+ if (error instanceof CLIError) {
1046
+ await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
1047
+ console.error(error.message);
1048
+ } else
1049
+ console.error(error, `
1050
+ `);
1051
+ process.exit(1);
1052
+ }
2752
1053
  }
2753
- function formatLocalDate(utcStr, timezone) {
2754
- return formatLocal(utcStr, timezone).split(" ")[0];
1054
+ async function _resolveBuiltinFlags(cmd) {
1055
+ const argsDef = await resolveValue(cmd.args || {});
1056
+ const userNames = /* @__PURE__ */ new Set;
1057
+ const userAliases = /* @__PURE__ */ new Set;
1058
+ for (const [name, def] of Object.entries(argsDef)) {
1059
+ userNames.add(name);
1060
+ for (const alias of toArray(def.alias))
1061
+ userAliases.add(alias);
1062
+ }
1063
+ return {
1064
+ help: _getBuiltinFlags("help", "h", userNames, userAliases),
1065
+ version: _getBuiltinFlags("version", "v", userNames, userAliases)
1066
+ };
2755
1067
  }
2756
- function todayLocal(timezone) {
2757
- return formatLocalDate(nowUtc(), timezone);
1068
+ function _getBuiltinFlags(long, short, userNames, userAliases) {
1069
+ if (userNames.has(long) || userAliases.has(long))
1070
+ return [];
1071
+ if (userNames.has(short) || userAliases.has(short))
1072
+ return [`--${long}`];
1073
+ return [`--${long}`, `-${short}`];
2758
1074
  }
2759
- function resolveDefaultTimezone() {
2760
- if (process.env.OURA_TZ)
2761
- return process.env.OURA_TZ;
2762
- try {
2763
- return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
2764
- } catch {
2765
- return "UTC";
1075
+
1076
+ // src/commands/login.ts
1077
+ init_source();
1078
+ import { writeFileSync, chmodSync, mkdirSync } from "fs";
1079
+ import { resolve, dirname } from "path";
1080
+ import { homedir } from "os";
1081
+ import { createInterface } from "readline/promises";
1082
+
1083
+ // src/lib/errors.ts
1084
+ init_source();
1085
+
1086
+ class CliError extends Error {
1087
+ code;
1088
+ hint;
1089
+ constructor(code, message, hint) {
1090
+ super(message);
1091
+ this.code = code;
1092
+ this.hint = hint;
1093
+ this.name = "CliError";
2766
1094
  }
2767
1095
  }
2768
-
2769
- // src/commands/helpers.ts
2770
- function getGlobalOpts(command) {
2771
- let node = command;
2772
- while (node?.parent) {
2773
- node = node.parent;
1096
+ function exitCodeFor(err) {
1097
+ if (!(err instanceof CliError))
1098
+ return 1;
1099
+ switch (err.code) {
1100
+ case "BAD_ARGS":
1101
+ return 1;
1102
+ case "TOKEN_MISSING":
1103
+ case "TOKEN_INVALID":
1104
+ return 2;
1105
+ case "API_ERROR":
1106
+ return 3;
1107
+ case "DB_ERROR":
1108
+ return 4;
1109
+ case "UNKNOWN":
1110
+ return 1;
2774
1111
  }
2775
- return node?.opts() ?? {};
2776
1112
  }
2777
- function getClient(opts) {
2778
- return new OuraClient(opts.token ? { token: opts.token } : {});
1113
+ function redactSecrets(s) {
1114
+ return s.replace(/Bearer\s+[A-Za-z0-9._\-]{8,}/g, "Bearer [REDACTED]").replace(/"token"\s*:\s*"[^"]{8,}"/g, '"token":"[REDACTED]"');
2779
1115
  }
2780
- function todayDate(timezone) {
2781
- return todayLocal(timezone ?? resolveDefaultTimezone());
1116
+ function formatError(err, format) {
1117
+ const code = err instanceof CliError ? err.code : "UNKNOWN";
1118
+ const message = err instanceof Error ? err.message : String(err);
1119
+ const hint = err instanceof CliError ? err.hint : undefined;
1120
+ if (format === "json") {
1121
+ return {
1122
+ kind: "json",
1123
+ text: JSON.stringify({ error: { code, message, ...hint ? { hint } : {} } })
1124
+ };
1125
+ }
1126
+ const head = source_default.red(`error: ${message}`);
1127
+ return { kind: "text", text: hint ? `${head}
1128
+ hint: ${hint}` : head };
2782
1129
  }
2783
- function dateRange(days, timezone) {
2784
- const tz = timezone ?? resolveDefaultTimezone();
2785
- const end = todayLocal(tz);
2786
- const startMs = new Date(`${end}T00:00:00Z`).getTime() - (days - 1) * 86400000;
2787
- const start = new Date(startMs).toISOString().slice(0, 10);
2788
- return { start, end };
1130
+ function emitError(err, format) {
1131
+ const env2 = formatError(err, format);
1132
+ process.stderr.write(env2.text + `
1133
+ `);
2789
1134
  }
2790
1135
 
2791
- // src/commands/api-command.ts
2792
- function createApiCommand(name, description, endpoint) {
2793
- const cmd = new Command(name).description(description);
2794
- cmd.command("today").description(`Today's ${name} data`).action(async (_, command) => {
2795
- const opts = getGlobalOpts(command);
2796
- const client = getClient(opts);
2797
- const data = await client.fetch(endpoint, todayDate(), todayDate());
2798
- console.log(JSON.stringify(data, null, 2));
2799
- });
2800
- cmd.command("date <day>").description(`${name} data for specific date (YYYY-MM-DD)`).action(async (day, _, command) => {
2801
- const opts = getGlobalOpts(command);
2802
- const client = getClient(opts);
2803
- const data = await client.fetch(endpoint, day, day);
2804
- console.log(JSON.stringify(data, null, 2));
2805
- });
2806
- cmd.command("week").description(`Last 7 days of ${name} data`).action(async (_, command) => {
2807
- const opts = getGlobalOpts(command);
2808
- const client = getClient(opts);
2809
- const { start, end } = dateRange(7);
2810
- const data = await client.fetch(endpoint, start, end);
2811
- console.log(JSON.stringify(data, null, 2));
1136
+ // src/commands/login.ts
1137
+ function writeToken(path, token) {
1138
+ const trimmed = token.trim();
1139
+ if (trimmed.length === 0) {
1140
+ throw new CliError("BAD_ARGS", "Token cannot be empty.");
1141
+ }
1142
+ mkdirSync(dirname(path), { recursive: true });
1143
+ writeFileSync(path, trimmed, { encoding: "utf-8" });
1144
+ if (process.platform !== "win32") {
1145
+ chmodSync(path, 384);
1146
+ }
1147
+ }
1148
+ var loginCommand = defineCommand({
1149
+ meta: { name: "login", description: "Save an Oura Personal Access Token for future commands." },
1150
+ args: {
1151
+ token: { type: "string", description: "Pass token non-interactively (e.g. for scripts)" },
1152
+ path: { type: "string", description: "Where to save the token (default: $OURA_TOKEN_PATH or ~/.oura-token)" },
1153
+ "no-color": { type: "boolean", default: false, description: "Disable ANSI colors (also honors NO_COLOR env)" }
1154
+ },
1155
+ async run({ args }) {
1156
+ if (args["no-color"] || process.env.NO_COLOR) {
1157
+ const { default: chk } = await Promise.resolve().then(() => (init_source(), exports_source));
1158
+ chk.level = 0;
1159
+ }
1160
+ const target = args.path ?? process.env.OURA_TOKEN_PATH ?? resolve(homedir(), ".oura-token");
1161
+ let token = args.token;
1162
+ if (!token) {
1163
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1164
+ console.log("Get a Personal Access Token at https://cloud.ouraring.com/personal-access-tokens");
1165
+ token = await rl.question("Paste your token: ");
1166
+ rl.close();
1167
+ }
1168
+ writeToken(target, token);
1169
+ console.log(source_default.green(`Saved to ${target}`));
1170
+ }
1171
+ });
1172
+
1173
+ // src/commands/describe.ts
1174
+ function buildManifest(version) {
1175
+ return {
1176
+ name: "oura-cli",
1177
+ version,
1178
+ compatManifestCommand: "oura-cli manifest",
1179
+ auth: {
1180
+ envVars: ["OURA_TOKEN", "OURA_TOKEN_PATH"],
1181
+ tokenFile: "~/.oura-token",
1182
+ loginCommand: "oura-cli login"
1183
+ },
1184
+ globalFlags: [
1185
+ { name: "--format", type: "enum", values: ["table", "json"], description: "Output format (auto-detected by TTY when omitted)" },
1186
+ { name: "--db", type: "string", description: "Override SQLite database path (env: OURA_DB_PATH)" },
1187
+ { name: "--tz", type: "string", description: "Display timezone (env: OURA_TZ; default auto-detected)" },
1188
+ { name: "--token", type: "string", description: "Inline access token (prefer env vars or `login`)" },
1189
+ { name: "--no-color", type: "boolean", description: "Disable ANSI colors in human output" }
1190
+ ],
1191
+ exitCodes: [
1192
+ { code: 0, meaning: "success" },
1193
+ { code: 1, meaning: "user error (bad arguments)" },
1194
+ { code: 2, meaning: "auth error (missing or invalid token)" },
1195
+ { code: 3, meaning: "API or network error" },
1196
+ { code: 4, meaning: "database or local storage error" }
1197
+ ],
1198
+ commands: [
1199
+ { name: "login", description: "Save an Oura Personal Access Token for future commands.", args: [
1200
+ { name: "--token", type: "string", required: false, description: "Pass token non-interactively" },
1201
+ { name: "--path", type: "string", required: false, description: "Override token file path" }
1202
+ ] },
1203
+ { name: "describe", description: "Emit a machine-readable manifest of commands, args, and outputs.", args: [] },
1204
+ {
1205
+ name: "sleep",
1206
+ description: "Fetch daily sleep scores from Oura API. Pick a subcommand: today | date <day> | week.",
1207
+ args: [],
1208
+ outputSchema: "docs/schemas/sleep.json",
1209
+ subcommands: [
1210
+ { name: "today", description: "Today's sleep data.", args: [] },
1211
+ { name: "date", description: "Sleep data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
1212
+ { name: "week", description: "Last 7 days of sleep data.", args: [] }
1213
+ ]
1214
+ },
1215
+ {
1216
+ name: "readiness",
1217
+ description: "Fetch daily readiness scores from Oura API. Pick a subcommand: today | date <day> | week.",
1218
+ args: [],
1219
+ outputSchema: "docs/schemas/readiness.json",
1220
+ subcommands: [
1221
+ { name: "today", description: "Today's readiness data.", args: [] },
1222
+ { name: "date", description: "Readiness data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
1223
+ { name: "week", description: "Last 7 days of readiness data.", args: [] }
1224
+ ]
1225
+ },
1226
+ {
1227
+ name: "activity",
1228
+ description: "Fetch daily activity scores from Oura API. Pick a subcommand: today | date <day> | week.",
1229
+ args: [],
1230
+ outputSchema: "docs/schemas/activity.json",
1231
+ subcommands: [
1232
+ { name: "today", description: "Today's activity data.", args: [] },
1233
+ { name: "date", description: "Activity data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
1234
+ { name: "week", description: "Last 7 days of activity data.", args: [] }
1235
+ ]
1236
+ },
1237
+ {
1238
+ name: "hr",
1239
+ description: "Fetch heart rate samples from Oura API. Pick a subcommand: today | date <day> | week.",
1240
+ args: [],
1241
+ outputSchema: "docs/schemas/hr.json",
1242
+ subcommands: [
1243
+ { name: "today", description: "Today's heart rate data.", args: [] },
1244
+ { name: "date", description: "Heart rate data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
1245
+ { name: "week", description: "Last 7 days of heart rate data.", args: [] }
1246
+ ]
1247
+ },
1248
+ {
1249
+ name: "spo2",
1250
+ description: "Fetch blood oxygen (SpO2) data from Oura API. Pick a subcommand: today | date <day> | week.",
1251
+ args: [],
1252
+ outputSchema: "docs/schemas/spo2.json",
1253
+ subcommands: [
1254
+ { name: "today", description: "Today's SpO2 data.", args: [] },
1255
+ { name: "date", description: "SpO2 data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
1256
+ { name: "week", description: "Last 7 days of SpO2 data.", args: [] }
1257
+ ]
1258
+ },
1259
+ {
1260
+ name: "stress",
1261
+ description: "Fetch daily stress data from Oura API. Pick a subcommand: today | date <day> | week.",
1262
+ args: [],
1263
+ outputSchema: "docs/schemas/stress.json",
1264
+ subcommands: [
1265
+ { name: "today", description: "Today's stress data.", args: [] },
1266
+ { name: "date", description: "Stress data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
1267
+ { name: "week", description: "Last 7 days of stress data.", args: [] }
1268
+ ]
1269
+ },
1270
+ {
1271
+ name: "workout",
1272
+ description: "Fetch workout data from Oura API. Pick a subcommand: today | date <day> | week.",
1273
+ args: [],
1274
+ outputSchema: "docs/schemas/workout.json",
1275
+ subcommands: [
1276
+ { name: "today", description: "Today's workout data.", args: [] },
1277
+ { name: "date", description: "Workout data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
1278
+ { name: "week", description: "Last 7 days of workout data.", args: [] }
1279
+ ]
1280
+ },
1281
+ { name: "sync", description: "Sync all Oura collections into the local database.", args: [] },
1282
+ {
1283
+ name: "db",
1284
+ description: "Query and manage the local SQLite cache. Pick a subcommand.",
1285
+ args: [],
1286
+ subcommands: [
1287
+ { name: "today", description: "Today's summary from local DB.", args: [] },
1288
+ { name: "date", description: "Summary for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
1289
+ { name: "week", description: "Last 7 days from local DB.", args: [] },
1290
+ { name: "trends", description: "Score and metric trends over N days (default 30).", args: [{ name: "[days]", type: "number", required: false, description: "Window size in days." }] },
1291
+ { name: "stats", description: "Row counts, date range, record highs.", args: [] },
1292
+ { name: "import", description: "Sync new data from Oura API into the local DB.", args: [] },
1293
+ { name: "reset", description: "Destroy and rebuild the database from exported CSVs.", args: [] }
1294
+ ]
1295
+ },
1296
+ {
1297
+ name: "report",
1298
+ description: "Generate a narrative health report from local data.",
1299
+ args: [
1300
+ { name: "--period", type: "enum", values: ["week", "month"], description: "Report window (default week)." }
1301
+ ]
1302
+ }
1303
+ ]
1304
+ };
1305
+ }
1306
+ function describeCommand(version) {
1307
+ return defineCommand({
1308
+ meta: { name: "describe", description: "Emit a machine-readable manifest of commands, args, and outputs." },
1309
+ args: {},
1310
+ run() {
1311
+ console.log(JSON.stringify(buildManifest(version), null, 2));
1312
+ }
2812
1313
  });
2813
- return cmd;
2814
1314
  }
2815
1315
 
2816
- // src/commands/db.ts
2817
- import { mkdirSync as mkdirSync3, unlinkSync } from "fs";
1316
+ // src/commands/sync.ts
1317
+ import { mkdirSync as mkdirSync3 } from "fs";
2818
1318
  import { dirname as dirname2 } from "path";
2819
1319
 
2820
1320
  // src/lib/db.ts
2821
1321
  import { Database } from "bun:sqlite";
2822
1322
  import { resolve as resolve2 } from "path";
2823
1323
  import { homedir as homedir2 } from "os";
2824
- import { mkdirSync } from "fs";
1324
+ import { mkdirSync as mkdirSync2 } from "fs";
2825
1325
  function getDbPath(options = {}) {
2826
1326
  if (options.dbPath)
2827
1327
  return options.dbPath;
@@ -2834,7 +1334,7 @@ function getDbPath(options = {}) {
2834
1334
  function openDatabase(options = {}) {
2835
1335
  const dbPath = getDbPath(options);
2836
1336
  if (dbPath !== ":memory:") {
2837
- mkdirSync(resolve2(dbPath, ".."), { recursive: true });
1337
+ mkdirSync2(resolve2(dbPath, ".."), { recursive: true });
2838
1338
  }
2839
1339
  const db = new Database(dbPath);
2840
1340
  db.exec("PRAGMA journal_mode = WAL");
@@ -3004,131 +1504,87 @@ function ensureSchema2(db) {
3004
1504
  ensureSchema(db, MIGRATIONS);
3005
1505
  }
3006
1506
 
3007
- // src/db/csv-import.ts
3008
- import { readFileSync as readFileSync2, existsSync } from "fs";
3009
- import { join } from "path";
3010
- var CSV_DIR = join(process.env.HOME ?? "", "Documents/OpenClaw/projects/oura-ring/data/App Data");
3011
- function parseCSV(filename) {
3012
- const path = join(CSV_DIR, filename);
3013
- if (!existsSync(path))
3014
- return [];
3015
- const text = readFileSync2(path, "utf-8");
3016
- const lines = text.split(`
3017
- `).filter((l) => l.trim());
3018
- if (lines.length < 2)
3019
- return [];
3020
- const headers = lines[0].split(";");
3021
- return lines.slice(1).map((line) => {
3022
- const vals = line.split(";");
3023
- const row = {};
3024
- headers.forEach((h, i) => {
3025
- row[h] = vals[i] ?? "";
3026
- });
3027
- return row;
3028
- });
3029
- }
3030
- function num(v) {
3031
- if (!v || v === "")
3032
- return null;
3033
- const n = Number(v);
3034
- return isNaN(n) ? null : n;
3035
- }
3036
- function str(v) {
3037
- return v && v !== "" ? v : null;
3038
- }
3039
- function importFromCSV(db, log) {
3040
- if (!existsSync(CSV_DIR)) {
3041
- throw new Error(`CSV directory not found: ${CSV_DIR}`);
1507
+ // src/db/import.ts
1508
+ async function importDaily(db, client, log) {
1509
+ const _log = log ?? (() => {});
1510
+ const today = new Date().toISOString().slice(0, 10);
1511
+ const lastDates = [];
1512
+ for (const tbl of ["daily_sleep", "daily_readiness", "daily_activity"]) {
1513
+ const row = db.query(`SELECT MAX(day) as d FROM ${tbl}`).get();
1514
+ if (row?.d)
1515
+ lastDates.push(row.d);
3042
1516
  }
3043
- const sleep = parseCSV("dailysleep.csv");
1517
+ const startDate = lastDates.length > 0 ? lastDates.sort()[0] : new Date(Date.now() - 30 * 86400000).toISOString().slice(0, 10);
1518
+ _log(`Syncing from ${startDate} to ${today}`);
1519
+ const counts = {};
1520
+ const sleepData = await client.fetch("daily_sleep", startDate, today);
3044
1521
  const insertSleep = db.query("INSERT OR REPLACE INTO daily_sleep VALUES (?,?,?,?,?)");
3045
- const sleepTx = db.transaction(() => {
3046
- for (const r of sleep)
3047
- insertSleep.run(r.id, r.day, num(r.score), str(r.contributors), str(r.timestamp));
3048
- });
3049
- sleepTx();
3050
- log(`daily_sleep: ${sleep.length} rows`);
3051
- const readiness = parseCSV("dailyreadiness.csv");
1522
+ for (const s of sleepData) {
1523
+ insertSleep.run(s.id, s.day, s.score, JSON.stringify(s.contributors), s.timestamp);
1524
+ _log(` + sleep ${s.day}`);
1525
+ }
1526
+ counts.daily_sleep = sleepData.length;
1527
+ const readinessData = await client.fetch("daily_readiness", startDate, today);
3052
1528
  const insertReadiness = db.query("INSERT OR REPLACE INTO daily_readiness VALUES (?,?,?,?,?,?,?)");
3053
- const readinessTx = db.transaction(() => {
3054
- for (const r of readiness)
3055
- insertReadiness.run(r.id, r.day, num(r.score), str(r.contributors), num(r.temperature_deviation), num(r.temperature_trend_deviation), str(r.timestamp));
3056
- });
3057
- readinessTx();
3058
- log(`daily_readiness: ${readiness.length} rows`);
3059
- const activity = parseCSV("dailyactivity.csv");
1529
+ for (const r of readinessData) {
1530
+ insertReadiness.run(r.id, r.day, r.score, JSON.stringify(r.contributors), r.temperature_deviation, r.temperature_trend_deviation, r.timestamp);
1531
+ _log(` + readiness ${r.day}`);
1532
+ }
1533
+ counts.daily_readiness = readinessData.length;
1534
+ const activityData = await client.fetch("daily_activity", startDate, today);
3060
1535
  const insertActivity = db.query("INSERT OR REPLACE INTO daily_activity VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
3061
- const activityTx = db.transaction(() => {
3062
- for (const r of activity)
3063
- insertActivity.run(r.id, r.day, num(r.score), num(r.active_calories), num(r.steps), num(r.equivalent_walking_distance), num(r.high_activity_time), num(r.medium_activity_time), num(r.low_activity_time), num(r.sedentary_time), num(r.total_calories), num(r.target_calories), str(r.contributors), str(r.timestamp));
3064
- });
3065
- activityTx();
3066
- log(`daily_activity: ${activity.length} rows`);
3067
- const spo2 = parseCSV("dailyspo2.csv");
1536
+ for (const a of activityData) {
1537
+ insertActivity.run(a.id, a.day, a.score, a.active_calories, a.steps, a.equivalent_walking_distance, a.high_activity_time, a.medium_activity_time, a.low_activity_time, a.sedentary_time, a.total_calories, a.target_calories, JSON.stringify(a.contributors), a.timestamp);
1538
+ _log(` + activity ${a.day}`);
1539
+ }
1540
+ counts.daily_activity = activityData.length;
1541
+ const hrData = await client.fetch("heartrate", today, today);
1542
+ const insertHr = db.query("INSERT OR IGNORE INTO heartrate VALUES (?,?,?,?)");
1543
+ for (const h of hrData) {
1544
+ const day = h.timestamp.slice(0, 10);
1545
+ insertHr.run(h.timestamp, h.bpm, h.source, day);
1546
+ }
1547
+ counts.heartrate = hrData.length;
1548
+ if (hrData.length > 0)
1549
+ _log(` + heartrate ${hrData.length} records`);
1550
+ const spo2Data = await client.fetch("daily_spo2", startDate, today);
3068
1551
  const insertSpo2 = db.query("INSERT OR REPLACE INTO daily_spo2 VALUES (?,?,?,?)");
3069
- const spo2Tx = db.transaction(() => {
3070
- for (const r of spo2) {
3071
- let avg = null;
3072
- try {
3073
- const parsed = JSON.parse(r.spo2_percentage);
3074
- avg = parsed?.average ?? null;
3075
- } catch {}
3076
- insertSpo2.run(r.id, r.day, avg, num(r.breathing_disturbance_index));
3077
- }
3078
- });
3079
- spo2Tx();
3080
- log(`daily_spo2: ${spo2.length} rows`);
3081
- const stress = parseCSV("dailystress.csv");
1552
+ for (const s of spo2Data) {
1553
+ const avg = s.spo2_percentage?.average ?? null;
1554
+ insertSpo2.run(s.id, s.day, avg, s.breathing_disturbance_index);
1555
+ _log(` + spo2 ${s.day}`);
1556
+ }
1557
+ counts.daily_spo2 = spo2Data.length;
1558
+ const stressData = await client.fetch("daily_stress", startDate, today);
3082
1559
  const insertStress = db.query("INSERT OR REPLACE INTO daily_stress VALUES (?,?,?,?,?)");
3083
- const stressTx = db.transaction(() => {
3084
- for (const r of stress)
3085
- insertStress.run(r.id, r.day, str(r.day_summary), num(r.recovery_high), num(r.stress_high));
3086
- });
3087
- stressTx();
3088
- log(`daily_stress: ${stress.length} rows`);
3089
- const hr = parseCSV("heartrate.csv");
3090
- const insertHr = db.query("INSERT OR IGNORE INTO heartrate VALUES (?,?,?,?)");
3091
- const hrTx = db.transaction(() => {
3092
- for (const r of hr) {
3093
- const day = r.timestamp?.slice(0, 10) ?? null;
3094
- insertHr.run(r.timestamp, num(r.bpm), str(r.source), day);
3095
- }
3096
- });
3097
- hrTx();
3098
- log(`heartrate: ${hr.length} rows`);
3099
- const sleepModel = parseCSV("sleepmodel.csv");
3100
- const insertSM = db.query("INSERT OR REPLACE INTO sleep_model VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
3101
- const smTx = db.transaction(() => {
3102
- for (const r of sleepModel)
3103
- insertSM.run(r.id, r.day, num(r.average_breath), num(r.average_heart_rate), num(r.average_hrv), num(r.awake_time), str(r.bedtime_end), str(r.bedtime_start), num(r.deep_sleep_duration), num(r.efficiency), num(r.latency), num(r.light_sleep_duration), num(r.lowest_heart_rate), num(r.period), num(r.rem_sleep_duration), num(r.restless_periods), num(r.time_in_bed), num(r.total_sleep_duration), str(r.type));
3104
- });
3105
- smTx();
3106
- log(`sleep_model: ${sleepModel.length} rows`);
3107
- const vo2 = parseCSV("vo2max.csv");
3108
- const insertVo2 = db.query("INSERT OR REPLACE INTO vo2max VALUES (?,?,?,?)");
3109
- const vo2Tx = db.transaction(() => {
3110
- for (const r of vo2)
3111
- insertVo2.run(r.id, r.day, num(r.vo2_max), str(r.timestamp));
3112
- });
3113
- vo2Tx();
3114
- log(`vo2max: ${vo2.length} rows`);
3115
- const cv = parseCSV("dailycardiovascularage.csv");
1560
+ for (const s of stressData) {
1561
+ insertStress.run(s.id, s.day, s.day_summary, s.recovery_high, s.stress_high);
1562
+ _log(` + stress ${s.day}`);
1563
+ }
1564
+ counts.daily_stress = stressData.length;
1565
+ const workoutData = await client.fetch("workout", startDate, today);
1566
+ const insertWorkout = db.query("INSERT OR REPLACE INTO workouts VALUES (?,?,?,?,?,?,?,?,?,?)");
1567
+ for (const w of workoutData) {
1568
+ insertWorkout.run(w.id, w.day, w.activity, w.calories, w.distance, w.start_datetime, w.end_datetime, w.intensity, w.label ?? "", w.source);
1569
+ _log(` + workout ${w.day} ${w.activity}`);
1570
+ }
1571
+ counts.workouts = workoutData.length;
1572
+ const sleepPeriods = await client.fetch("sleep", startDate, today);
1573
+ const insertSleepModel = db.query(`INSERT OR REPLACE INTO sleep_model VALUES (${Array(19).fill("?").join(",")})`);
1574
+ for (const sp of sleepPeriods) {
1575
+ insertSleepModel.run(sp.id, sp.day, sp.average_breath, sp.average_heart_rate, sp.average_hrv, sp.awake_time, sp.bedtime_end, sp.bedtime_start, sp.deep_sleep_duration, sp.efficiency, sp.latency, sp.light_sleep_duration, sp.lowest_heart_rate, sp.period, sp.rem_sleep_duration, sp.restless_periods, sp.time_in_bed, sp.total_sleep_duration, sp.type);
1576
+ _log(` + sleep_period ${sp.day} (${sp.type})`);
1577
+ }
1578
+ counts.sleep_model = sleepPeriods.length;
1579
+ const cvData = await client.fetch("daily_cardiovascular_age", startDate, today);
3116
1580
  const insertCv = db.query("INSERT OR REPLACE INTO cardiovascular_age VALUES (?,?,?)");
3117
- const cvTx = db.transaction(() => {
3118
- for (const r of cv)
3119
- insertCv.run(r.id, r.day, num(r.vascular_age));
3120
- });
3121
- cvTx();
3122
- log(`cardiovascular_age: ${cv.length} rows`);
3123
- const workouts = parseCSV("workout.csv");
3124
- const insertW = db.query("INSERT OR REPLACE INTO workouts VALUES (?,?,?,?,?,?,?,?,?,?)");
3125
- const wTx = db.transaction(() => {
3126
- for (const r of workouts)
3127
- insertW.run(r.id, r.day, str(r.activity), num(r.calories), num(r.distance), str(r.start_datetime), str(r.end_datetime), str(r.intensity), str(r.label), str(r.source));
3128
- });
3129
- wTx();
3130
- log(`workouts: ${workouts.length} rows`);
3131
- log("CSV import complete.");
1581
+ for (const c of cvData) {
1582
+ insertCv.run(c.id, c.day, c.vascular_age);
1583
+ _log(` + cardiovascular_age ${c.day}`);
1584
+ }
1585
+ counts.cardiovascular_age = cvData.length;
1586
+ _log("Import complete.");
1587
+ return { startDate, endDate: today, counts };
3132
1588
  }
3133
1589
 
3134
1590
  // src/db/queries.ts
@@ -3212,6 +1668,7 @@ function getStats(db) {
3212
1668
  }
3213
1669
 
3214
1670
  // src/format.ts
1671
+ init_source();
3215
1672
  function scoreColor(score) {
3216
1673
  if (score === null)
3217
1674
  return source_default.gray("\u2014");
@@ -3252,57 +1709,154 @@ function formatDaySummary(summary, format) {
3252
1709
  return lines.join(`
3253
1710
  `);
3254
1711
  }
3255
- function formatWeekTable(days, format) {
3256
- if (format === "json")
3257
- return JSON.stringify(days, null, 2);
3258
- const header = `${"Day".padEnd(12)} ${"Sleep".padStart(6)} ${"Ready".padStart(6)} ${"Activity".padStart(9)} ${"Steps".padStart(7)} ${"Stress".padEnd(10)}`;
3259
- const sep = source_default.gray("\u2500".repeat(56));
3260
- const rows = days.map((d) => `${d.day.padEnd(12)} ${scoreColor(d.sleep_score).padStart(6)} ${scoreColor(d.readiness_score).padStart(6)} ` + `${scoreColor(d.activity_score).padStart(9)} ${String(d.steps ?? "\u2014").padStart(7)} ${(d.stress ?? "\u2014").padEnd(10)}`);
3261
- return [`
3262
- Last 7 Days`, sep, ` ${header}`, sep, ...rows.map((r) => ` ${r}`)].join(`
3263
- `);
1712
+ function formatWeekTable(days, format) {
1713
+ if (format === "json")
1714
+ return JSON.stringify(days, null, 2);
1715
+ const header = `${"Day".padEnd(12)} ${"Sleep".padStart(6)} ${"Ready".padStart(6)} ${"Activity".padStart(9)} ${"Steps".padStart(7)} ${"Stress".padEnd(10)}`;
1716
+ const sep = source_default.gray("\u2500".repeat(56));
1717
+ const rows = days.map((d) => `${d.day.padEnd(12)} ${scoreColor(d.sleep_score).padStart(6)} ${scoreColor(d.readiness_score).padStart(6)} ` + `${scoreColor(d.activity_score).padStart(9)} ${String(d.steps ?? "\u2014").padStart(7)} ${(d.stress ?? "\u2014").padEnd(10)}`);
1718
+ return [`
1719
+ Last 7 Days`, sep, ` ${header}`, sep, ...rows.map((r) => ` ${r}`)].join(`
1720
+ `);
1721
+ }
1722
+ function formatTrends(trends, days, format) {
1723
+ if (format === "json")
1724
+ return JSON.stringify(trends, null, 2);
1725
+ const lines = [
1726
+ "",
1727
+ source_default.bold(` Trends: last ${days} days`),
1728
+ source_default.gray("\u2500".repeat(50))
1729
+ ];
1730
+ for (const t of trends) {
1731
+ lines.push(` ${t.label.padEnd(15)} avg: ${String(t.avg).padStart(5)} min: ${String(t.min).padStart(5)} max: ${String(t.max).padStart(5)} (${t.count} days)`);
1732
+ }
1733
+ return lines.join(`
1734
+ `);
1735
+ }
1736
+ function formatStats(stats, format) {
1737
+ if (format === "json")
1738
+ return JSON.stringify(stats, null, 2);
1739
+ const lines = [
1740
+ "",
1741
+ source_default.bold(" Database Statistics"),
1742
+ source_default.gray("\u2550".repeat(50))
1743
+ ];
1744
+ for (const t of stats.tables) {
1745
+ lines.push(` ${t.table.padEnd(22)} ${String(t.rows).padStart(8)} rows`);
1746
+ }
1747
+ if (stats.dateRange.first) {
1748
+ lines.push(`
1749
+ Date range: ${stats.dateRange.first} \u2192 ${stats.dateRange.last}`);
1750
+ }
1751
+ for (const t of stats.trends) {
1752
+ lines.push(` ${t.label.padEnd(15)} avg: ${String(t.avg).padStart(5)} min: ${String(t.min).padStart(5)} max: ${String(t.max).padStart(5)}`);
1753
+ }
1754
+ if (stats.records.mostSteps) {
1755
+ lines.push(`
1756
+ Most steps: ${stats.records.mostSteps.steps} on ${stats.records.mostSteps.day}`);
1757
+ }
1758
+ if (stats.records.bestSleep) {
1759
+ lines.push(` Best sleep: ${stats.records.bestSleep.score} on ${stats.records.bestSleep.day}`);
1760
+ }
1761
+ return lines.join(`
1762
+ `);
1763
+ }
1764
+
1765
+ // src/api/client.ts
1766
+ import { readFileSync } from "fs";
1767
+ import { resolve as resolve3 } from "path";
1768
+ import { homedir as homedir3 } from "os";
1769
+ var BASE_URL = "https://api.ouraring.com/v2/usercollection";
1770
+
1771
+ class OuraClient {
1772
+ token;
1773
+ constructor(options = {}) {
1774
+ const direct = options.token ?? process.env.OURA_TOKEN;
1775
+ if (direct) {
1776
+ this.token = direct.trim();
1777
+ } else {
1778
+ const tokenPath = options.tokenPath ?? process.env.OURA_TOKEN_PATH ?? resolve3(homedir3(), ".oura-token");
1779
+ try {
1780
+ this.token = readFileSync(tokenPath, "utf-8").trim();
1781
+ } catch {
1782
+ throw new CliError("TOKEN_MISSING", `No Oura access token at ${tokenPath}.`, "Run `oura-cli login` or set OURA_TOKEN.");
1783
+ }
1784
+ }
1785
+ }
1786
+ async fetch(endpoint, startDate, endDate) {
1787
+ const params = new URLSearchParams({ start_date: startDate });
1788
+ if (endDate)
1789
+ params.set("end_date", endDate);
1790
+ const url = `${BASE_URL}/${endpoint}?${params}`;
1791
+ const response = await fetch(url, {
1792
+ headers: { Authorization: `Bearer ${this.token}` }
1793
+ });
1794
+ if (!response.ok) {
1795
+ const rawBody = await response.text();
1796
+ const redacted = redactSecrets(rawBody);
1797
+ const body = redacted.length > 200 ? redacted.slice(0, 200) + "\u2026 (truncated)" : redacted;
1798
+ if (response.status === 401 || response.status === 403) {
1799
+ throw new CliError("TOKEN_INVALID", `Oura API ${response.status}: ${body}`);
1800
+ }
1801
+ throw new CliError("API_ERROR", `Oura API ${response.status}: ${body}`);
1802
+ }
1803
+ let json;
1804
+ try {
1805
+ json = await response.json();
1806
+ } catch {
1807
+ throw new CliError("API_ERROR", "Empty response body from Oura API.");
1808
+ }
1809
+ return json.data ?? [];
1810
+ }
1811
+ }
1812
+
1813
+ // src/lib/time.ts
1814
+ function nowUtc() {
1815
+ return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
1816
+ }
1817
+ function formatLocal(utcStr, timezone) {
1818
+ const dt = new Date(utcStr);
1819
+ const parts = new Intl.DateTimeFormat("sv-SE", {
1820
+ timeZone: timezone,
1821
+ year: "numeric",
1822
+ month: "2-digit",
1823
+ day: "2-digit",
1824
+ hour: "2-digit",
1825
+ minute: "2-digit",
1826
+ hour12: false
1827
+ }).formatToParts(dt);
1828
+ const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
1829
+ return `${get("year")}-${get("month")}-${get("day")} ${get("hour")}:${get("minute")}`;
1830
+ }
1831
+ function formatLocalDate(utcStr, timezone) {
1832
+ return formatLocal(utcStr, timezone).split(" ")[0];
3264
1833
  }
3265
- function formatTrends(trends, days, format) {
3266
- if (format === "json")
3267
- return JSON.stringify(trends, null, 2);
3268
- const lines = [
3269
- "",
3270
- source_default.bold(` Trends: last ${days} days`),
3271
- source_default.gray("\u2500".repeat(50))
3272
- ];
3273
- for (const t of trends) {
3274
- lines.push(` ${t.label.padEnd(15)} avg: ${String(t.avg).padStart(5)} min: ${String(t.min).padStart(5)} max: ${String(t.max).padStart(5)} (${t.count} days)`);
3275
- }
3276
- return lines.join(`
3277
- `);
1834
+ function todayLocal(timezone) {
1835
+ return formatLocalDate(nowUtc(), timezone);
3278
1836
  }
3279
- function formatStats(stats, format) {
3280
- if (format === "json")
3281
- return JSON.stringify(stats, null, 2);
3282
- const lines = [
3283
- "",
3284
- source_default.bold(" Database Statistics"),
3285
- source_default.gray("\u2550".repeat(50))
3286
- ];
3287
- for (const t of stats.tables) {
3288
- lines.push(` ${t.table.padEnd(22)} ${String(t.rows).padStart(8)} rows`);
3289
- }
3290
- if (stats.dateRange.first) {
3291
- lines.push(`
3292
- Date range: ${stats.dateRange.first} \u2192 ${stats.dateRange.last}`);
3293
- }
3294
- for (const t of stats.trends) {
3295
- lines.push(` ${t.label.padEnd(15)} avg: ${String(t.avg).padStart(5)} min: ${String(t.min).padStart(5)} max: ${String(t.max).padStart(5)}`);
3296
- }
3297
- if (stats.records.mostSteps) {
3298
- lines.push(`
3299
- Most steps: ${stats.records.mostSteps.steps} on ${stats.records.mostSteps.day}`);
3300
- }
3301
- if (stats.records.bestSleep) {
3302
- lines.push(` Best sleep: ${stats.records.bestSleep.score} on ${stats.records.bestSleep.day}`);
1837
+ function resolveDefaultTimezone() {
1838
+ if (process.env.OURA_TZ)
1839
+ return process.env.OURA_TZ;
1840
+ try {
1841
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
1842
+ } catch {
1843
+ return "UTC";
3303
1844
  }
3304
- return lines.join(`
3305
- `);
1845
+ }
1846
+
1847
+ // src/commands/helpers.ts
1848
+ function getClient(opts) {
1849
+ return new OuraClient(opts.token ? { token: opts.token } : {});
1850
+ }
1851
+ function todayDate(timezone) {
1852
+ return todayLocal(timezone ?? resolveDefaultTimezone());
1853
+ }
1854
+ function dateRange(days, timezone) {
1855
+ const tz = timezone ?? resolveDefaultTimezone();
1856
+ const end = todayLocal(tz);
1857
+ const startMs = new Date(`${end}T00:00:00Z`).getTime() - (days - 1) * 86400000;
1858
+ const start = new Date(startMs).toISOString().slice(0, 10);
1859
+ return { start, end };
3306
1860
  }
3307
1861
 
3308
1862
  // src/lib/format-resolve.ts
@@ -3314,104 +1868,41 @@ function resolveFormat({ explicit, isTty }) {
3314
1868
  throw new CliError("BAD_ARGS", `Unknown --format value: "${explicit}". Use "table" or "json".`);
3315
1869
  }
3316
1870
 
3317
- // src/commands/sync.ts
3318
- import { mkdirSync as mkdirSync2 } from "fs";
3319
- import { dirname } from "path";
3320
-
3321
- // src/db/import.ts
3322
- async function importDaily(db, client, log) {
3323
- const _log = log ?? (() => {});
3324
- const today = new Date().toISOString().slice(0, 10);
3325
- const lastDates = [];
3326
- for (const tbl of ["daily_sleep", "daily_readiness", "daily_activity"]) {
3327
- const row = db.query(`SELECT MAX(day) as d FROM ${tbl}`).get();
3328
- if (row?.d)
3329
- lastDates.push(row.d);
3330
- }
3331
- const startDate = lastDates.length > 0 ? lastDates.sort()[0] : new Date(Date.now() - 30 * 86400000).toISOString().slice(0, 10);
3332
- _log(`Syncing from ${startDate} to ${today}`);
3333
- const counts = {};
3334
- const sleepData = await client.fetch("daily_sleep", startDate, today);
3335
- const insertSleep = db.query("INSERT OR REPLACE INTO daily_sleep VALUES (?,?,?,?,?)");
3336
- for (const s of sleepData) {
3337
- insertSleep.run(s.id, s.day, s.score, JSON.stringify(s.contributors), s.timestamp);
3338
- _log(` + sleep ${s.day}`);
3339
- }
3340
- counts.daily_sleep = sleepData.length;
3341
- const readinessData = await client.fetch("daily_readiness", startDate, today);
3342
- const insertReadiness = db.query("INSERT OR REPLACE INTO daily_readiness VALUES (?,?,?,?,?,?,?)");
3343
- for (const r of readinessData) {
3344
- insertReadiness.run(r.id, r.day, r.score, JSON.stringify(r.contributors), r.temperature_deviation, r.temperature_trend_deviation, r.timestamp);
3345
- _log(` + readiness ${r.day}`);
3346
- }
3347
- counts.daily_readiness = readinessData.length;
3348
- const activityData = await client.fetch("daily_activity", startDate, today);
3349
- const insertActivity = db.query("INSERT OR REPLACE INTO daily_activity VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
3350
- for (const a of activityData) {
3351
- insertActivity.run(a.id, a.day, a.score, a.active_calories, a.steps, a.equivalent_walking_distance, a.high_activity_time, a.medium_activity_time, a.low_activity_time, a.sedentary_time, a.total_calories, a.target_calories, JSON.stringify(a.contributors), a.timestamp);
3352
- _log(` + activity ${a.day}`);
3353
- }
3354
- counts.daily_activity = activityData.length;
3355
- const hrData = await client.fetch("heartrate", today, today);
3356
- const insertHr = db.query("INSERT OR IGNORE INTO heartrate VALUES (?,?,?,?)");
3357
- for (const h of hrData) {
3358
- const day = h.timestamp.slice(0, 10);
3359
- insertHr.run(h.timestamp, h.bpm, h.source, day);
3360
- }
3361
- counts.heartrate = hrData.length;
3362
- if (hrData.length > 0)
3363
- _log(` + heartrate ${hrData.length} records`);
3364
- const spo2Data = await client.fetch("daily_spo2", startDate, today);
3365
- const insertSpo2 = db.query("INSERT OR REPLACE INTO daily_spo2 VALUES (?,?,?,?)");
3366
- for (const s of spo2Data) {
3367
- const avg = s.spo2_percentage?.average ?? null;
3368
- insertSpo2.run(s.id, s.day, avg, s.breathing_disturbance_index);
3369
- _log(` + spo2 ${s.day}`);
3370
- }
3371
- counts.daily_spo2 = spo2Data.length;
3372
- const stressData = await client.fetch("daily_stress", startDate, today);
3373
- const insertStress = db.query("INSERT OR REPLACE INTO daily_stress VALUES (?,?,?,?,?)");
3374
- for (const s of stressData) {
3375
- insertStress.run(s.id, s.day, s.day_summary, s.recovery_high, s.stress_high);
3376
- _log(` + stress ${s.day}`);
3377
- }
3378
- counts.daily_stress = stressData.length;
3379
- const workoutData = await client.fetch("workout", startDate, today);
3380
- const insertWorkout = db.query("INSERT OR REPLACE INTO workouts VALUES (?,?,?,?,?,?,?,?,?,?)");
3381
- for (const w of workoutData) {
3382
- insertWorkout.run(w.id, w.day, w.activity, w.calories, w.distance, w.start_datetime, w.end_datetime, w.intensity, w.label ?? "", w.source);
3383
- _log(` + workout ${w.day} ${w.activity}`);
3384
- }
3385
- counts.workouts = workoutData.length;
3386
- const sleepPeriods = await client.fetch("sleep", startDate, today);
3387
- const insertSleepModel = db.query(`INSERT OR REPLACE INTO sleep_model VALUES (${Array(19).fill("?").join(",")})`);
3388
- for (const sp of sleepPeriods) {
3389
- insertSleepModel.run(sp.id, sp.day, sp.average_breath, sp.average_heart_rate, sp.average_hrv, sp.awake_time, sp.bedtime_end, sp.bedtime_start, sp.deep_sleep_duration, sp.efficiency, sp.latency, sp.light_sleep_duration, sp.lowest_heart_rate, sp.period, sp.rem_sleep_duration, sp.restless_periods, sp.time_in_bed, sp.total_sleep_duration, sp.type);
3390
- _log(` + sleep_period ${sp.day} (${sp.type})`);
3391
- }
3392
- counts.sleep_model = sleepPeriods.length;
3393
- const cvData = await client.fetch("daily_cardiovascular_age", startDate, today);
3394
- const insertCv = db.query("INSERT OR REPLACE INTO cardiovascular_age VALUES (?,?,?)");
3395
- for (const c of cvData) {
3396
- insertCv.run(c.id, c.day, c.vascular_age);
3397
- _log(` + cardiovascular_age ${c.day}`);
1871
+ // src/commands/common.ts
1872
+ var commonArgs = {
1873
+ format: { type: "string", description: "Output format: table | json (auto-detected by TTY)" },
1874
+ token: { type: "string", description: "Inline access token (prefer env vars or `oura-cli login`)" },
1875
+ db: { type: "string", description: "Path to SQLite database file (env: OURA_DB_PATH)" },
1876
+ tz: { type: "string", description: "Display timezone (env: OURA_TZ; auto-detected)" },
1877
+ "no-color": { type: "boolean", default: false, description: "Disable ANSI colors (also honors NO_COLOR env)" }
1878
+ };
1879
+ function handleError(err, args) {
1880
+ const fmt = resolveFormat({
1881
+ explicit: args.format,
1882
+ isTty: process.stdout.isTTY === true
1883
+ });
1884
+ emitError(err, fmt);
1885
+ process.exit(exitCodeFor(err));
1886
+ }
1887
+ function applyNoColor(args) {
1888
+ if (args["no-color"] || process.env.NO_COLOR) {
1889
+ Promise.resolve().then(() => (init_source(), exports_source)).then(({ default: chalk2 }) => {
1890
+ chalk2.level = 0;
1891
+ });
3398
1892
  }
3399
- counts.cardiovascular_age = cvData.length;
3400
- _log("Import complete.");
3401
- return { startDate, endDate: today, counts };
3402
1893
  }
3403
1894
 
3404
1895
  // src/commands/sync.ts
3405
1896
  async function runSync(opts) {
3406
1897
  const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
3407
1898
  const dbPath = getDbPath2({ dbPath: opts.db });
3408
- mkdirSync2(dirname(dbPath), { recursive: true });
1899
+ mkdirSync3(dirname2(dbPath), { recursive: true });
3409
1900
  const db = openDatabase2({ dbPath: opts.db });
3410
1901
  ensureSchema2(db);
3411
1902
  const client = getClient(opts);
3412
1903
  const log = format === "table" ? console.log : undefined;
3413
1904
  const importResult = await importDaily(db, client, log);
3414
- const today = getDaySummary(db, todayDate());
1905
+ const today = getDaySummary(db, todayDate(opts.tz));
3415
1906
  db.close();
3416
1907
  if (format === "json") {
3417
1908
  console.log(JSON.stringify({ import: importResult, today }, null, 2));
@@ -3419,101 +1910,304 @@ async function runSync(opts) {
3419
1910
  console.log(formatDaySummary(today, format));
3420
1911
  }
3421
1912
  }
3422
- function syncCommand() {
3423
- return new Command("sync").description("Import latest data from Oura API and return today's summary").action(async (_, command) => {
3424
- const opts = command.parent.opts();
3425
- await runSync(opts);
3426
- });
3427
- }
1913
+ var syncCommand = defineCommand({
1914
+ meta: { name: "sync", description: "Import latest data from Oura API and return today's summary" },
1915
+ args: { ...commonArgs },
1916
+ async run({ args }) {
1917
+ applyNoColor(args);
1918
+ try {
1919
+ await runSync({ format: args.format, db: args.db, token: args.token, tz: args.tz });
1920
+ } catch (err) {
1921
+ handleError(err, args);
1922
+ }
1923
+ }
1924
+ });
3428
1925
 
3429
1926
  // src/commands/db.ts
3430
- function dbCommand() {
3431
- const cmd = new Command("db").description("Query and manage the local SQLite database");
3432
- cmd.command("import").description("Sync new data from Oura API into local database (alias of sync)").action(async (_, command) => {
3433
- const opts = command.parent.parent.opts();
3434
- await runSync(opts);
1927
+ import { mkdirSync as mkdirSync4, unlinkSync } from "fs";
1928
+ import { dirname as dirname3 } from "path";
1929
+
1930
+ // src/db/csv-import.ts
1931
+ import { readFileSync as readFileSync2, existsSync } from "fs";
1932
+ import { join } from "path";
1933
+ var CSV_DIR = join(process.env.HOME ?? "", "Documents/OpenClaw/projects/oura-ring/data/App Data");
1934
+ function parseCSV(filename) {
1935
+ const path = join(CSV_DIR, filename);
1936
+ if (!existsSync(path))
1937
+ return [];
1938
+ const text = readFileSync2(path, "utf-8");
1939
+ const lines = text.split(`
1940
+ `).filter((l) => l.trim());
1941
+ if (lines.length < 2)
1942
+ return [];
1943
+ const headers = lines[0].split(";");
1944
+ return lines.slice(1).map((line) => {
1945
+ const vals = line.split(";");
1946
+ const row = {};
1947
+ headers.forEach((h, i) => {
1948
+ row[h] = vals[i] ?? "";
1949
+ });
1950
+ return row;
1951
+ });
1952
+ }
1953
+ function num(v) {
1954
+ if (!v || v === "")
1955
+ return null;
1956
+ const n = Number(v);
1957
+ return isNaN(n) ? null : n;
1958
+ }
1959
+ function str(v) {
1960
+ return v && v !== "" ? v : null;
1961
+ }
1962
+ function importFromCSV(db, log) {
1963
+ if (!existsSync(CSV_DIR)) {
1964
+ throw new Error(`CSV directory not found: ${CSV_DIR}`);
1965
+ }
1966
+ const sleep = parseCSV("dailysleep.csv");
1967
+ const insertSleep = db.query("INSERT OR REPLACE INTO daily_sleep VALUES (?,?,?,?,?)");
1968
+ const sleepTx = db.transaction(() => {
1969
+ for (const r of sleep)
1970
+ insertSleep.run(r.id, r.day, num(r.score), str(r.contributors), str(r.timestamp));
3435
1971
  });
3436
- cmd.command("today").description("Today's summary from local database").action((_, command) => {
3437
- const opts = command.parent.parent.opts();
3438
- const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
3439
- const db = openDatabase2({ dbPath: opts.db });
3440
- ensureSchema2(db);
3441
- const summary = getDaySummary(db, todayDate());
3442
- console.log(formatDaySummary(summary, format));
3443
- db.close();
1972
+ sleepTx();
1973
+ log(`daily_sleep: ${sleep.length} rows`);
1974
+ const readiness = parseCSV("dailyreadiness.csv");
1975
+ const insertReadiness = db.query("INSERT OR REPLACE INTO daily_readiness VALUES (?,?,?,?,?,?,?)");
1976
+ const readinessTx = db.transaction(() => {
1977
+ for (const r of readiness)
1978
+ insertReadiness.run(r.id, r.day, num(r.score), str(r.contributors), num(r.temperature_deviation), num(r.temperature_trend_deviation), str(r.timestamp));
1979
+ });
1980
+ readinessTx();
1981
+ log(`daily_readiness: ${readiness.length} rows`);
1982
+ const activity = parseCSV("dailyactivity.csv");
1983
+ const insertActivity = db.query("INSERT OR REPLACE INTO daily_activity VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
1984
+ const activityTx = db.transaction(() => {
1985
+ for (const r of activity)
1986
+ insertActivity.run(r.id, r.day, num(r.score), num(r.active_calories), num(r.steps), num(r.equivalent_walking_distance), num(r.high_activity_time), num(r.medium_activity_time), num(r.low_activity_time), num(r.sedentary_time), num(r.total_calories), num(r.target_calories), str(r.contributors), str(r.timestamp));
1987
+ });
1988
+ activityTx();
1989
+ log(`daily_activity: ${activity.length} rows`);
1990
+ const spo2 = parseCSV("dailyspo2.csv");
1991
+ const insertSpo2 = db.query("INSERT OR REPLACE INTO daily_spo2 VALUES (?,?,?,?)");
1992
+ const spo2Tx = db.transaction(() => {
1993
+ for (const r of spo2) {
1994
+ let avg = null;
1995
+ try {
1996
+ const parsed = JSON.parse(r.spo2_percentage);
1997
+ avg = parsed?.average ?? null;
1998
+ } catch {}
1999
+ insertSpo2.run(r.id, r.day, avg, num(r.breathing_disturbance_index));
2000
+ }
3444
2001
  });
3445
- cmd.command("date <day>").description("Summary for specific date from local database").action((day, _, command) => {
3446
- const opts = command.parent.parent.opts();
3447
- const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
3448
- const db = openDatabase2({ dbPath: opts.db });
3449
- ensureSchema2(db);
3450
- const summary = getDaySummary(db, day);
3451
- console.log(formatDaySummary(summary, format));
3452
- db.close();
2002
+ spo2Tx();
2003
+ log(`daily_spo2: ${spo2.length} rows`);
2004
+ const stress = parseCSV("dailystress.csv");
2005
+ const insertStress = db.query("INSERT OR REPLACE INTO daily_stress VALUES (?,?,?,?,?)");
2006
+ const stressTx = db.transaction(() => {
2007
+ for (const r of stress)
2008
+ insertStress.run(r.id, r.day, str(r.day_summary), num(r.recovery_high), num(r.stress_high));
3453
2009
  });
3454
- cmd.command("week").description("Last 7 days from local database").action((_, command) => {
3455
- const opts = command.parent.parent.opts();
3456
- const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
3457
- const db = openDatabase2({ dbPath: opts.db });
3458
- ensureSchema2(db);
3459
- const days = [];
3460
- for (let i = 6;i >= 0; i--) {
3461
- const d = new Date(Date.now() - i * 86400000).toISOString().slice(0, 10);
3462
- days.push(getDaySummary(db, d));
2010
+ stressTx();
2011
+ log(`daily_stress: ${stress.length} rows`);
2012
+ const hr = parseCSV("heartrate.csv");
2013
+ const insertHr = db.query("INSERT OR IGNORE INTO heartrate VALUES (?,?,?,?)");
2014
+ const hrTx = db.transaction(() => {
2015
+ for (const r of hr) {
2016
+ const day = r.timestamp?.slice(0, 10) ?? null;
2017
+ insertHr.run(r.timestamp, num(r.bpm), str(r.source), day);
3463
2018
  }
3464
- console.log(formatWeekTable(days, format));
3465
- db.close();
3466
2019
  });
3467
- cmd.command("trends [days]").description("Score and metric trends over N days (default: 30)").action((days, _, command) => {
3468
- const opts = command.parent.parent.opts();
3469
- const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
3470
- const n = days ? parseInt(days, 10) : 30;
3471
- const db = openDatabase2({ dbPath: opts.db });
3472
- ensureSchema2(db);
3473
- const trends = getTrends(db, n);
3474
- console.log(formatTrends(trends, n, format));
3475
- db.close();
2020
+ hrTx();
2021
+ log(`heartrate: ${hr.length} rows`);
2022
+ const sleepModel = parseCSV("sleepmodel.csv");
2023
+ const insertSM = db.query("INSERT OR REPLACE INTO sleep_model VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
2024
+ const smTx = db.transaction(() => {
2025
+ for (const r of sleepModel)
2026
+ insertSM.run(r.id, r.day, num(r.average_breath), num(r.average_heart_rate), num(r.average_hrv), num(r.awake_time), str(r.bedtime_end), str(r.bedtime_start), num(r.deep_sleep_duration), num(r.efficiency), num(r.latency), num(r.light_sleep_duration), num(r.lowest_heart_rate), num(r.period), num(r.rem_sleep_duration), num(r.restless_periods), num(r.time_in_bed), num(r.total_sleep_duration), str(r.type));
3476
2027
  });
3477
- cmd.command("stats").description("Row counts, date range, and record highs from local database").action((_, command) => {
3478
- const opts = command.parent.parent.opts();
3479
- const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
3480
- const db = openDatabase2({ dbPath: opts.db });
3481
- ensureSchema2(db);
3482
- const stats = getStats(db);
3483
- console.log(formatStats(stats, format));
3484
- db.close();
2028
+ smTx();
2029
+ log(`sleep_model: ${sleepModel.length} rows`);
2030
+ const vo2 = parseCSV("vo2max.csv");
2031
+ const insertVo2 = db.query("INSERT OR REPLACE INTO vo2max VALUES (?,?,?,?)");
2032
+ const vo2Tx = db.transaction(() => {
2033
+ for (const r of vo2)
2034
+ insertVo2.run(r.id, r.day, num(r.vo2_max), str(r.timestamp));
3485
2035
  });
3486
- cmd.command("reset").description("Destroy and rebuild database from exported CSV files").option("--force", "Confirm destructive reset").action((resetOpts, command) => {
3487
- if (!resetOpts.force) {
3488
- console.log(JSON.stringify({ error: "Use --force to confirm destructive reset." }));
3489
- process.exit(1);
3490
- }
3491
- const opts = command.parent.parent.opts();
3492
- const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
3493
- const dbPath = getDbPath2({ dbPath: opts.db });
3494
- try {
3495
- unlinkSync(dbPath);
3496
- } catch {}
3497
- try {
3498
- unlinkSync(dbPath + "-wal");
3499
- } catch {}
3500
- try {
3501
- unlinkSync(dbPath + "-shm");
3502
- } catch {}
3503
- const log = format === "table" ? console.log : undefined;
3504
- log?.("Database deleted.");
3505
- mkdirSync3(dirname2(dbPath), { recursive: true });
3506
- const db = openDatabase2({ dbPath: opts.db });
3507
- ensureSchema2(db);
3508
- importFromCSV(db, log ?? (() => {}));
3509
- if (format === "json") {
3510
- console.log(JSON.stringify({ status: "reset complete" }));
3511
- }
3512
- db.close();
2036
+ vo2Tx();
2037
+ log(`vo2max: ${vo2.length} rows`);
2038
+ const cv = parseCSV("dailycardiovascularage.csv");
2039
+ const insertCv = db.query("INSERT OR REPLACE INTO cardiovascular_age VALUES (?,?,?)");
2040
+ const cvTx = db.transaction(() => {
2041
+ for (const r of cv)
2042
+ insertCv.run(r.id, r.day, num(r.vascular_age));
2043
+ });
2044
+ cvTx();
2045
+ log(`cardiovascular_age: ${cv.length} rows`);
2046
+ const workouts = parseCSV("workout.csv");
2047
+ const insertW = db.query("INSERT OR REPLACE INTO workouts VALUES (?,?,?,?,?,?,?,?,?,?)");
2048
+ const wTx = db.transaction(() => {
2049
+ for (const r of workouts)
2050
+ insertW.run(r.id, r.day, str(r.activity), num(r.calories), num(r.distance), str(r.start_datetime), str(r.end_datetime), str(r.intensity), str(r.label), str(r.source));
3513
2051
  });
3514
- return cmd;
2052
+ wTx();
2053
+ log(`workouts: ${workouts.length} rows`);
2054
+ log("CSV import complete.");
3515
2055
  }
3516
2056
 
2057
+ // src/commands/db.ts
2058
+ var dbCommand = defineCommand({
2059
+ meta: { name: "db", description: "Query and manage the local SQLite database" },
2060
+ subCommands: {
2061
+ import: defineCommand({
2062
+ meta: { name: "import", description: "Sync new data from Oura API into local database (alias of sync)" },
2063
+ args: { ...commonArgs },
2064
+ async run({ args }) {
2065
+ applyNoColor(args);
2066
+ try {
2067
+ await runSync({ format: args.format, db: args.db, token: args.token, tz: args.tz });
2068
+ } catch (err) {
2069
+ handleError(err, args);
2070
+ }
2071
+ }
2072
+ }),
2073
+ today: defineCommand({
2074
+ meta: { name: "today", description: "Today's summary from local database" },
2075
+ args: { ...commonArgs },
2076
+ run({ args }) {
2077
+ applyNoColor(args);
2078
+ try {
2079
+ const format = resolveFormat({ explicit: args.format, isTty: process.stdout.isTTY === true });
2080
+ const db = openDatabase2({ dbPath: args.db });
2081
+ ensureSchema2(db);
2082
+ const summary = getDaySummary(db, todayDate(args.tz));
2083
+ console.log(formatDaySummary(summary, format));
2084
+ db.close();
2085
+ } catch (err) {
2086
+ handleError(err, args);
2087
+ }
2088
+ }
2089
+ }),
2090
+ date: defineCommand({
2091
+ meta: { name: "date", description: "Summary for specific date from local database" },
2092
+ args: {
2093
+ ...commonArgs,
2094
+ day: { type: "positional", required: true, description: "Target date (YYYY-MM-DD)" }
2095
+ },
2096
+ run({ args }) {
2097
+ applyNoColor(args);
2098
+ try {
2099
+ const format = resolveFormat({ explicit: args.format, isTty: process.stdout.isTTY === true });
2100
+ const db = openDatabase2({ dbPath: args.db });
2101
+ ensureSchema2(db);
2102
+ const summary = getDaySummary(db, args.day);
2103
+ console.log(formatDaySummary(summary, format));
2104
+ db.close();
2105
+ } catch (err) {
2106
+ handleError(err, args);
2107
+ }
2108
+ }
2109
+ }),
2110
+ week: defineCommand({
2111
+ meta: { name: "week", description: "Last 7 days from local database" },
2112
+ args: { ...commonArgs },
2113
+ run({ args }) {
2114
+ applyNoColor(args);
2115
+ try {
2116
+ const format = resolveFormat({ explicit: args.format, isTty: process.stdout.isTTY === true });
2117
+ const db = openDatabase2({ dbPath: args.db });
2118
+ ensureSchema2(db);
2119
+ const days = [];
2120
+ for (let i = 6;i >= 0; i--) {
2121
+ const d = new Date(Date.now() - i * 86400000).toISOString().slice(0, 10);
2122
+ days.push(getDaySummary(db, d));
2123
+ }
2124
+ console.log(formatWeekTable(days, format));
2125
+ db.close();
2126
+ } catch (err) {
2127
+ handleError(err, args);
2128
+ }
2129
+ }
2130
+ }),
2131
+ trends: defineCommand({
2132
+ meta: { name: "trends", description: "Score and metric trends over N days (default: 30)" },
2133
+ args: {
2134
+ ...commonArgs,
2135
+ days: { type: "positional", required: false, description: "Window size in days (default: 30)" }
2136
+ },
2137
+ run({ args }) {
2138
+ applyNoColor(args);
2139
+ try {
2140
+ const format = resolveFormat({ explicit: args.format, isTty: process.stdout.isTTY === true });
2141
+ const n = args.days ? parseInt(args.days, 10) : 30;
2142
+ const db = openDatabase2({ dbPath: args.db });
2143
+ ensureSchema2(db);
2144
+ const trends = getTrends(db, n);
2145
+ console.log(formatTrends(trends, n, format));
2146
+ db.close();
2147
+ } catch (err) {
2148
+ handleError(err, args);
2149
+ }
2150
+ }
2151
+ }),
2152
+ stats: defineCommand({
2153
+ meta: { name: "stats", description: "Row counts, date range, and record highs from local database" },
2154
+ args: { ...commonArgs },
2155
+ run({ args }) {
2156
+ applyNoColor(args);
2157
+ try {
2158
+ const format = resolveFormat({ explicit: args.format, isTty: process.stdout.isTTY === true });
2159
+ const db = openDatabase2({ dbPath: args.db });
2160
+ ensureSchema2(db);
2161
+ const stats = getStats(db);
2162
+ console.log(formatStats(stats, format));
2163
+ db.close();
2164
+ } catch (err) {
2165
+ handleError(err, args);
2166
+ }
2167
+ }
2168
+ }),
2169
+ reset: defineCommand({
2170
+ meta: { name: "reset", description: "Destroy and rebuild database from exported CSV files" },
2171
+ args: {
2172
+ ...commonArgs,
2173
+ force: { type: "boolean", default: false, description: "Confirm destructive reset" }
2174
+ },
2175
+ run({ args }) {
2176
+ applyNoColor(args);
2177
+ try {
2178
+ if (!args.force) {
2179
+ console.log(JSON.stringify({ error: "Use --force to confirm destructive reset." }));
2180
+ process.exit(1);
2181
+ }
2182
+ const format = resolveFormat({ explicit: args.format, isTty: process.stdout.isTTY === true });
2183
+ const dbPath = getDbPath2({ dbPath: args.db });
2184
+ try {
2185
+ unlinkSync(dbPath);
2186
+ } catch {}
2187
+ try {
2188
+ unlinkSync(dbPath + "-wal");
2189
+ } catch {}
2190
+ try {
2191
+ unlinkSync(dbPath + "-shm");
2192
+ } catch {}
2193
+ const log = format === "table" ? console.log : undefined;
2194
+ log?.("Database deleted.");
2195
+ mkdirSync4(dirname3(dbPath), { recursive: true });
2196
+ const db = openDatabase2({ dbPath: args.db });
2197
+ ensureSchema2(db);
2198
+ importFromCSV(db, log ?? (() => {}));
2199
+ if (format === "json") {
2200
+ console.log(JSON.stringify({ status: "reset complete" }));
2201
+ }
2202
+ db.close();
2203
+ } catch (err) {
2204
+ handleError(err, args);
2205
+ }
2206
+ }
2207
+ })
2208
+ }
2209
+ });
2210
+
3517
2211
  // src/db/report.ts
3518
2212
  function dayLabel(dateStr) {
3519
2213
  const d = new Date(dateStr + "T12:00:00Z");
@@ -3602,6 +2296,7 @@ function getReport(db, days) {
3602
2296
  }
3603
2297
 
3604
2298
  // src/format-report.ts
2299
+ init_source();
3605
2300
  function colorizeScore(n) {
3606
2301
  if (n >= 85)
3607
2302
  return source_default.green;
@@ -3741,260 +2436,173 @@ function formatReport(data, format, period) {
3741
2436
  }
3742
2437
 
3743
2438
  // src/commands/report.ts
3744
- function reportCommand() {
3745
- return new Command("report").description("Generate a narrative health report from local data.").option("--period <name>", "Report window: week | month", "week").action((_, command) => {
3746
- const opts = command.parent.opts();
3747
- const period = command.opts().period ?? "week";
3748
- if (period !== "week" && period !== "month") {
3749
- throw new CliError("BAD_ARGS", `--period must be "week" or "month", got "${period}".`);
2439
+ var reportCommand = defineCommand({
2440
+ meta: { name: "report", description: "Generate a narrative health report from local data." },
2441
+ args: {
2442
+ ...commonArgs,
2443
+ period: { type: "string", description: "Report window: week | month", default: "week" }
2444
+ },
2445
+ run({ args }) {
2446
+ applyNoColor(args);
2447
+ try {
2448
+ const period = args.period;
2449
+ if (period !== "week" && period !== "month") {
2450
+ throw new CliError("BAD_ARGS", `--period must be "week" or "month", got "${period}".`);
2451
+ }
2452
+ const format = resolveFormat({ explicit: args.format, isTty: process.stdout.isTTY === true });
2453
+ const db = openDatabase2({ dbPath: args.db });
2454
+ ensureSchema2(db);
2455
+ const days = period === "week" ? 7 : 30;
2456
+ const data = getReport(db, days);
2457
+ console.log(formatReport(data, format, period));
2458
+ db.close();
2459
+ } catch (err) {
2460
+ handleError(err, args);
2461
+ }
2462
+ }
2463
+ });
2464
+
2465
+ // src/commands/healthcheck.ts
2466
+ function healthcheckCommand(version) {
2467
+ return defineCommand({
2468
+ meta: { name: "healthcheck", description: "Quick local DB health probe (JSON: {ok, version, latencyMs})." },
2469
+ args: { ...commonArgs },
2470
+ run({ args }) {
2471
+ const start = Date.now();
2472
+ let ok = true;
2473
+ let error;
2474
+ try {
2475
+ const db = openDatabase2({ dbPath: args.db });
2476
+ ensureSchema2(db);
2477
+ db.query("SELECT 1").get();
2478
+ db.close();
2479
+ } catch (err) {
2480
+ ok = false;
2481
+ error = err instanceof Error ? err.message : String(err);
2482
+ }
2483
+ console.log(JSON.stringify({ ok, version, latencyMs: Date.now() - start, ...error ? { error } : {} }));
3750
2484
  }
3751
- const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
3752
- const db = openDatabase2({ dbPath: opts.db });
3753
- ensureSchema2(db);
3754
- const days = period === "week" ? 7 : 30;
3755
- const data = getReport(db, days);
3756
- console.log(formatReport(data, format, period));
3757
- db.close();
3758
2485
  });
3759
2486
  }
3760
2487
 
3761
- // src/commands/login.ts
3762
- import { writeFileSync, chmodSync, mkdirSync as mkdirSync4 } from "fs";
3763
- import { resolve as resolve3, dirname as dirname3 } from "path";
3764
- import { homedir as homedir3 } from "os";
3765
- import { createInterface } from "readline/promises";
3766
- function writeToken(path, token) {
3767
- const trimmed = token.trim();
3768
- if (trimmed.length === 0) {
3769
- throw new CliError("BAD_ARGS", "Token cannot be empty.");
3770
- }
3771
- mkdirSync4(dirname3(path), { recursive: true });
3772
- writeFileSync(path, trimmed, { encoding: "utf-8" });
3773
- if (process.platform !== "win32") {
3774
- chmodSync(path, 384);
3775
- }
3776
- }
3777
- function loginCommand() {
3778
- return new Command("login").description("Save an Oura Personal Access Token for future commands.").option("--token <pat>", "Pass token non-interactively (e.g. for scripts)").option("--path <file>", "Where to save the token (default: $OURA_TOKEN_PATH or ~/.oura-token)").action(async (opts) => {
3779
- const target = opts.path ?? process.env.OURA_TOKEN_PATH ?? resolve3(homedir3(), ".oura-token");
3780
- let token = opts.token;
3781
- if (!token) {
3782
- const rl = createInterface({ input: process.stdin, output: process.stdout });
3783
- console.log("Get a Personal Access Token at https://cloud.ouraring.com/personal-access-tokens");
3784
- token = await rl.question("Paste your token: ");
3785
- rl.close();
2488
+ // src/commands/manifest.ts
2489
+ function manifestCommand(version) {
2490
+ return defineCommand({
2491
+ meta: { name: "manifest", description: "Print openclaw-tool-registry-compatible manifest as JSON." },
2492
+ args: {},
2493
+ run() {
2494
+ console.log(JSON.stringify({
2495
+ id: "oura-cli",
2496
+ version,
2497
+ runtime: "bun",
2498
+ bin: "oura-cli",
2499
+ description: "Oura Ring CLI \u2014 query and analyze Oura Ring health data. Designed for humans and agents.",
2500
+ commands: [
2501
+ { name: "login", description: "Save an Oura Personal Access Token.", examples: ["oura-cli login"] },
2502
+ { name: "describe", description: "Emit a machine-readable manifest of commands.", examples: ["oura-cli describe"] },
2503
+ { name: "sleep", description: "Fetch daily sleep scores from Oura API.", examples: ["oura-cli sleep --start 2026-05-01"] },
2504
+ { name: "readiness", description: "Fetch daily readiness scores from Oura API.", examples: ["oura-cli readiness --start 2026-05-01"] },
2505
+ { name: "activity", description: "Fetch daily activity scores from Oura API.", examples: ["oura-cli activity --start 2026-05-01"] },
2506
+ { name: "hr", description: "Fetch heart rate samples from Oura API.", examples: ["oura-cli hr --start 2026-05-01"] },
2507
+ { name: "spo2", description: "Fetch blood oxygen (SpO2) data from Oura API.", examples: ["oura-cli spo2 --start 2026-05-01"] },
2508
+ { name: "stress", description: "Fetch daily stress data from Oura API.", examples: ["oura-cli stress --start 2026-05-01"] },
2509
+ { name: "workout", description: "Fetch workout data from Oura API.", examples: ["oura-cli workout --start 2026-05-01"] },
2510
+ { name: "sync", description: "Sync all Oura collections into the local DB.", examples: ["oura-cli sync"] },
2511
+ { name: "db", description: "Query the local SQLite cache.", examples: ["oura-cli db today"] },
2512
+ { name: "report", description: "Render a weekly or monthly summary report.", examples: ["oura-cli report --period week"] },
2513
+ { name: "healthcheck", description: "Quick local DB health probe.", examples: ["oura-cli healthcheck"] },
2514
+ { name: "manifest", description: "Print openclaw-tool-registry-compatible manifest as JSON.", examples: ["oura-cli manifest"] }
2515
+ ],
2516
+ envVars: ["OURA_TOKEN", "OURA_TOKEN_PATH", "OURA_DB_PATH", "OURA_TZ"],
2517
+ healthcheck: { command: "healthcheck", expects: { ok: "boolean", version: "string", latencyMs: "number" } }
2518
+ }, null, 2));
3786
2519
  }
3787
- writeToken(target, token);
3788
- console.log(source_default.green(`Saved to ${target}`));
3789
2520
  });
3790
2521
  }
3791
2522
 
3792
- // src/commands/describe.ts
3793
- function buildManifest(version) {
3794
- return {
3795
- name: "oura-cli",
3796
- version,
3797
- compatManifestCommand: "oura-cli manifest",
3798
- auth: {
3799
- envVars: ["OURA_TOKEN", "OURA_TOKEN_PATH"],
3800
- tokenFile: "~/.oura-token",
3801
- loginCommand: "oura-cli login"
3802
- },
3803
- globalFlags: [
3804
- { name: "--format", type: "enum", values: ["table", "json"], description: "Output format (auto-detected by TTY when omitted)" },
3805
- { name: "--db", type: "string", description: "Override SQLite database path (env: OURA_DB_PATH)" },
3806
- { name: "--tz", type: "string", description: "Display timezone (env: OURA_TZ; default auto-detected)" },
3807
- { name: "--token", type: "string", description: "Inline access token (prefer env vars or `login`)" },
3808
- { name: "--no-color", type: "boolean", description: "Disable ANSI colors in human output" }
3809
- ],
3810
- exitCodes: [
3811
- { code: 0, meaning: "success" },
3812
- { code: 1, meaning: "user error (bad arguments)" },
3813
- { code: 2, meaning: "auth error (missing or invalid token)" },
3814
- { code: 3, meaning: "API or network error" },
3815
- { code: 4, meaning: "database or local storage error" }
3816
- ],
3817
- commands: [
3818
- { name: "login", description: "Save an Oura Personal Access Token for future commands.", args: [
3819
- { name: "--token", type: "string", required: false, description: "Pass token non-interactively" },
3820
- { name: "--path", type: "string", required: false, description: "Override token file path" }
3821
- ] },
3822
- { name: "describe", description: "Emit a machine-readable manifest of commands, args, and outputs.", args: [] },
3823
- {
3824
- name: "sleep",
3825
- description: "Fetch daily sleep scores from Oura API. Pick a subcommand: today | date <day> | week.",
3826
- args: [],
3827
- outputSchema: "docs/schemas/sleep.json",
3828
- subcommands: [
3829
- { name: "today", description: "Today's sleep data.", args: [] },
3830
- { name: "date", description: "Sleep data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
3831
- { name: "week", description: "Last 7 days of sleep data.", args: [] }
3832
- ]
3833
- },
3834
- {
3835
- name: "readiness",
3836
- description: "Fetch daily readiness scores from Oura API. Pick a subcommand: today | date <day> | week.",
3837
- args: [],
3838
- outputSchema: "docs/schemas/readiness.json",
3839
- subcommands: [
3840
- { name: "today", description: "Today's readiness data.", args: [] },
3841
- { name: "date", description: "Readiness data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
3842
- { name: "week", description: "Last 7 days of readiness data.", args: [] }
3843
- ]
3844
- },
3845
- {
3846
- name: "activity",
3847
- description: "Fetch daily activity scores from Oura API. Pick a subcommand: today | date <day> | week.",
3848
- args: [],
3849
- outputSchema: "docs/schemas/activity.json",
3850
- subcommands: [
3851
- { name: "today", description: "Today's activity data.", args: [] },
3852
- { name: "date", description: "Activity data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
3853
- { name: "week", description: "Last 7 days of activity data.", args: [] }
3854
- ]
3855
- },
3856
- {
3857
- name: "hr",
3858
- description: "Fetch heart rate samples from Oura API. Pick a subcommand: today | date <day> | week.",
3859
- args: [],
3860
- outputSchema: "docs/schemas/hr.json",
3861
- subcommands: [
3862
- { name: "today", description: "Today's heart rate data.", args: [] },
3863
- { name: "date", description: "Heart rate data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
3864
- { name: "week", description: "Last 7 days of heart rate data.", args: [] }
3865
- ]
3866
- },
3867
- {
3868
- name: "spo2",
3869
- description: "Fetch blood oxygen (SpO2) data from Oura API. Pick a subcommand: today | date <day> | week.",
3870
- args: [],
3871
- outputSchema: "docs/schemas/spo2.json",
3872
- subcommands: [
3873
- { name: "today", description: "Today's SpO2 data.", args: [] },
3874
- { name: "date", description: "SpO2 data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
3875
- { name: "week", description: "Last 7 days of SpO2 data.", args: [] }
3876
- ]
3877
- },
3878
- {
3879
- name: "stress",
3880
- description: "Fetch daily stress data from Oura API. Pick a subcommand: today | date <day> | week.",
3881
- args: [],
3882
- outputSchema: "docs/schemas/stress.json",
3883
- subcommands: [
3884
- { name: "today", description: "Today's stress data.", args: [] },
3885
- { name: "date", description: "Stress data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
3886
- { name: "week", description: "Last 7 days of stress data.", args: [] }
3887
- ]
3888
- },
3889
- {
3890
- name: "workout",
3891
- description: "Fetch workout data from Oura API. Pick a subcommand: today | date <day> | week.",
3892
- args: [],
3893
- outputSchema: "docs/schemas/workout.json",
3894
- subcommands: [
3895
- { name: "today", description: "Today's workout data.", args: [] },
3896
- { name: "date", description: "Workout data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
3897
- { name: "week", description: "Last 7 days of workout data.", args: [] }
3898
- ]
3899
- },
3900
- { name: "sync", description: "Sync all Oura collections into the local database.", args: [] },
3901
- {
3902
- name: "db",
3903
- description: "Query and manage the local SQLite cache. Pick a subcommand.",
3904
- args: [],
3905
- subcommands: [
3906
- { name: "today", description: "Today's summary from local DB.", args: [] },
3907
- { name: "date", description: "Summary for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
3908
- { name: "week", description: "Last 7 days from local DB.", args: [] },
3909
- { name: "trends", description: "Score and metric trends over N days (default 30).", args: [{ name: "[days]", type: "number", required: false, description: "Window size in days." }] },
3910
- { name: "stats", description: "Row counts, date range, record highs.", args: [] },
3911
- { name: "import", description: "Sync new data from Oura API into the local DB.", args: [] },
3912
- { name: "reset", description: "Destroy and rebuild the database from exported CSVs.", args: [] }
3913
- ]
3914
- },
3915
- {
3916
- name: "report",
3917
- description: "Generate a narrative health report from local data.",
3918
- args: [
3919
- { name: "--period", type: "enum", values: ["week", "month"], description: "Report window (default week)." }
3920
- ]
3921
- }
3922
- ]
3923
- };
3924
- }
3925
- function describeCommand(version) {
3926
- return new Command("describe").description("Emit a machine-readable manifest of commands, args, and outputs.").action(() => {
3927
- console.log(JSON.stringify(buildManifest(version), null, 2));
2523
+ // src/commands/api-command.ts
2524
+ function createApiCommand(name, description, endpoint) {
2525
+ return defineCommand({
2526
+ meta: { name, description },
2527
+ subCommands: {
2528
+ today: defineCommand({
2529
+ meta: { name: "today", description: `Today's ${name} data` },
2530
+ args: { ...commonArgs },
2531
+ async run({ args }) {
2532
+ applyNoColor(args);
2533
+ try {
2534
+ const client = getClient({ token: args.token });
2535
+ const day = todayDate(args.tz);
2536
+ const data = await client.fetch(endpoint, day, day);
2537
+ console.log(JSON.stringify(data, null, 2));
2538
+ } catch (err) {
2539
+ handleError(err, args);
2540
+ }
2541
+ }
2542
+ }),
2543
+ date: defineCommand({
2544
+ meta: { name: "date", description: `${name} data for a specific date (YYYY-MM-DD)` },
2545
+ args: {
2546
+ ...commonArgs,
2547
+ day: { type: "positional", required: true, description: "Target date (YYYY-MM-DD)" }
2548
+ },
2549
+ async run({ args }) {
2550
+ applyNoColor(args);
2551
+ try {
2552
+ const client = getClient({ token: args.token });
2553
+ const data = await client.fetch(endpoint, args.day, args.day);
2554
+ console.log(JSON.stringify(data, null, 2));
2555
+ } catch (err) {
2556
+ handleError(err, args);
2557
+ }
2558
+ }
2559
+ }),
2560
+ week: defineCommand({
2561
+ meta: { name: "week", description: `Last 7 days of ${name} data` },
2562
+ args: { ...commonArgs },
2563
+ async run({ args }) {
2564
+ applyNoColor(args);
2565
+ try {
2566
+ const client = getClient({ token: args.token });
2567
+ const { start, end } = dateRange(7, args.tz);
2568
+ const data = await client.fetch(endpoint, start, end);
2569
+ console.log(JSON.stringify(data, null, 2));
2570
+ } catch (err) {
2571
+ handleError(err, args);
2572
+ }
2573
+ }
2574
+ })
2575
+ }
3928
2576
  });
3929
2577
  }
3930
2578
 
3931
2579
  // src/index.ts
3932
- var VERSION = "0.3.4";
2580
+ var VERSION = "0.4.0";
3933
2581
  if (process.argv.includes("--no-color") || process.env.NO_COLOR) {
3934
2582
  source_default.level = 0;
3935
2583
  }
3936
- var program2 = new Command;
3937
- program2.name("oura-cli").description("Oura Ring CLI \u2014 query and analyze Oura Ring health data. Designed for humans and agents.").version(VERSION).option("--format <format>", "Output format: table | json (default auto-detect by TTY)").option("--token <pat>", "Inline access token (prefer env vars or `oura-cli login`)").option("--db <path>", "Path to SQLite database file (env: OURA_DB_PATH)").option("--tz <timezone>", "Display timezone (env: OURA_TZ; default auto-detect)").option("--no-color", "Disable ANSI colors in human output (also honors NO_COLOR env)");
3938
- program2.addCommand(loginCommand());
3939
- program2.addCommand(describeCommand(VERSION));
3940
- program2.addCommand(createApiCommand("sleep", "Fetch daily sleep scores from Oura API.", "daily_sleep"));
3941
- program2.addCommand(createApiCommand("readiness", "Fetch daily readiness scores from Oura API.", "daily_readiness"));
3942
- program2.addCommand(createApiCommand("activity", "Fetch daily activity scores from Oura API.", "daily_activity"));
3943
- program2.addCommand(createApiCommand("hr", "Fetch heart rate samples from Oura API.", "heartrate"));
3944
- program2.addCommand(createApiCommand("spo2", "Fetch blood oxygen (SpO2) data from Oura API.", "daily_spo2"));
3945
- program2.addCommand(createApiCommand("stress", "Fetch daily stress data from Oura API.", "daily_stress"));
3946
- program2.addCommand(createApiCommand("workout", "Fetch workout data from Oura API.", "workout"));
3947
- program2.addCommand(syncCommand());
3948
- program2.addCommand(dbCommand());
3949
- program2.addCommand(reportCommand());
3950
- program2.command("healthcheck").description("Quick local DB health probe (JSON: {ok, version, latencyMs}).").action(() => {
3951
- const start = Date.now();
3952
- const globalOpts = program2.opts();
3953
- let ok = true;
3954
- let error;
3955
- try {
3956
- const db = openDatabase2({ dbPath: globalOpts.db });
3957
- ensureSchema2(db);
3958
- db.query("SELECT 1").get();
3959
- db.close();
3960
- } catch (err) {
3961
- ok = false;
3962
- error = err instanceof Error ? err.message : String(err);
3963
- }
3964
- console.log(JSON.stringify({ ok, version: VERSION, latencyMs: Date.now() - start, ...error ? { error } : {} }));
3965
- });
3966
- program2.command("manifest").description("Print openclaw-tool-registry-compatible manifest as JSON.").action(() => {
3967
- console.log(JSON.stringify({
3968
- id: "oura-cli",
2584
+ var main = defineCommand({
2585
+ meta: {
2586
+ name: "oura-cli",
3969
2587
  version: VERSION,
3970
- runtime: "bun",
3971
- bin: "oura-cli",
3972
- description: "Oura Ring CLI \u2014 query and analyze Oura Ring health data. Designed for humans and agents.",
3973
- commands: [
3974
- { name: "login", description: "Save an Oura Personal Access Token.", examples: ["oura-cli login"] },
3975
- { name: "describe", description: "Emit a machine-readable manifest of commands.", examples: ["oura-cli describe"] },
3976
- { name: "sleep", description: "Fetch daily sleep scores from Oura API.", examples: ["oura-cli sleep --start 2026-05-01"] },
3977
- { name: "readiness", description: "Fetch daily readiness scores from Oura API.", examples: ["oura-cli readiness --start 2026-05-01"] },
3978
- { name: "activity", description: "Fetch daily activity scores from Oura API.", examples: ["oura-cli activity --start 2026-05-01"] },
3979
- { name: "hr", description: "Fetch heart rate samples from Oura API.", examples: ["oura-cli hr --start 2026-05-01"] },
3980
- { name: "spo2", description: "Fetch blood oxygen (SpO2) data from Oura API.", examples: ["oura-cli spo2 --start 2026-05-01"] },
3981
- { name: "stress", description: "Fetch daily stress data from Oura API.", examples: ["oura-cli stress --start 2026-05-01"] },
3982
- { name: "workout", description: "Fetch workout data from Oura API.", examples: ["oura-cli workout --start 2026-05-01"] },
3983
- { name: "sync", description: "Sync all Oura collections into the local DB.", examples: ["oura-cli sync"] },
3984
- { name: "db", description: "Query the local SQLite cache.", examples: ["oura-cli db today"] },
3985
- { name: "report", description: "Render a weekly or monthly summary report.", examples: ["oura-cli report --period week"] },
3986
- { name: "healthcheck", description: "Quick local DB health probe.", examples: ["oura-cli healthcheck"] },
3987
- { name: "manifest", description: "Print openclaw-tool-registry-compatible manifest as JSON.", examples: ["oura-cli manifest"] }
3988
- ],
3989
- envVars: ["OURA_TOKEN", "OURA_TOKEN_PATH", "OURA_DB_PATH", "OURA_TZ"],
3990
- healthcheck: { command: "healthcheck", expects: { ok: "boolean", version: "string", latencyMs: "number" } }
3991
- }, null, 2));
3992
- });
3993
- program2.parseAsync(process.argv).catch((err) => {
3994
- const fmt = resolveFormat({
3995
- explicit: program2.opts().format,
3996
- isTty: process.stdout.isTTY === true
3997
- });
3998
- emitError(err, fmt);
3999
- process.exit(exitCodeFor(err));
2588
+ description: "Oura Ring CLI \u2014 query and analyze Oura Ring health data. Designed for humans and agents."
2589
+ },
2590
+ args: { ...commonArgs },
2591
+ subCommands: {
2592
+ login: loginCommand,
2593
+ describe: describeCommand(VERSION),
2594
+ healthcheck: healthcheckCommand(VERSION),
2595
+ manifest: manifestCommand(VERSION),
2596
+ sleep: createApiCommand("sleep", "Fetch daily sleep scores from Oura API.", "daily_sleep"),
2597
+ readiness: createApiCommand("readiness", "Fetch daily readiness scores from Oura API.", "daily_readiness"),
2598
+ activity: createApiCommand("activity", "Fetch daily activity scores from Oura API.", "daily_activity"),
2599
+ hr: createApiCommand("hr", "Fetch heart rate samples from Oura API.", "heartrate"),
2600
+ spo2: createApiCommand("spo2", "Fetch blood oxygen (SpO2) data from Oura API.", "daily_spo2"),
2601
+ stress: createApiCommand("stress", "Fetch daily stress data from Oura API.", "daily_stress"),
2602
+ workout: createApiCommand("workout", "Fetch workout data from Oura API.", "workout"),
2603
+ sync: syncCommand,
2604
+ db: dbCommand,
2605
+ report: reportCommand
2606
+ }
4000
2607
  });
2608
+ runMain(main);