@drakulavich/oura-cli 0.3.3 → 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.
- package/CHANGELOG.md +35 -0
- package/dist/index.js +1658 -3038
- 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
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
|
2320
|
-
var
|
|
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
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
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
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
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
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
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/
|
|
2635
|
-
|
|
2636
|
-
import { resolve } from "path";
|
|
2637
|
-
import { homedir } from "os";
|
|
531
|
+
// src/index.ts
|
|
532
|
+
init_source();
|
|
2638
533
|
|
|
2639
|
-
//
|
|
2640
|
-
|
|
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
|
-
|
|
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
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
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
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
const
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
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
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
}
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
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
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
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
|
-
|
|
2728
|
-
} catch {
|
|
2729
|
-
|
|
871
|
+
await cmd.cleanup(context);
|
|
872
|
+
} catch (error) {
|
|
873
|
+
cleanupErrors.push(error);
|
|
2730
874
|
}
|
|
2731
|
-
|
|
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
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
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
|
|
2740
|
-
const
|
|
2741
|
-
const
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
const
|
|
2751
|
-
return
|
|
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
|
|
2754
|
-
|
|
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
|
|
2757
|
-
|
|
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
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
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
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
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
|
|
2778
|
-
return
|
|
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
|
|
2781
|
-
|
|
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
|
|
2784
|
-
const
|
|
2785
|
-
|
|
2786
|
-
|
|
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/
|
|
2792
|
-
function
|
|
2793
|
-
const
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
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/
|
|
2817
|
-
import { mkdirSync as mkdirSync3
|
|
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
|
-
|
|
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/
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
const
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
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
|
|
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
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
}
|
|
3049
|
-
|
|
3050
|
-
|
|
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
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
}
|
|
3057
|
-
|
|
3058
|
-
|
|
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
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
}
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
const
|
|
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
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
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
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
}
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
const
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
});
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
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
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
}
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
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
|
|
3266
|
-
|
|
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
|
|
3280
|
-
if (
|
|
3281
|
-
return
|
|
3282
|
-
|
|
3283
|
-
""
|
|
3284
|
-
|
|
3285
|
-
|
|
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
|
-
|
|
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/
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
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
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
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));
|
|
1971
|
+
});
|
|
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));
|
|
3435
1987
|
});
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
const
|
|
3442
|
-
|
|
3443
|
-
|
|
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
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
const
|
|
3451
|
-
|
|
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
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
const
|
|
3460
|
-
|
|
3461
|
-
|
|
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
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
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
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
const
|
|
3483
|
-
|
|
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
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
const
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
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
|
-
|
|
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,24 @@ function getReport(db, days) {
|
|
|
3602
2296
|
}
|
|
3603
2297
|
|
|
3604
2298
|
// src/format-report.ts
|
|
2299
|
+
init_source();
|
|
2300
|
+
function colorizeScore(n) {
|
|
2301
|
+
if (n >= 85)
|
|
2302
|
+
return source_default.green;
|
|
2303
|
+
if (n >= 70)
|
|
2304
|
+
return source_default.yellow;
|
|
2305
|
+
return source_default.red;
|
|
2306
|
+
}
|
|
2307
|
+
function scoreCell(n, width) {
|
|
2308
|
+
if (n === null)
|
|
2309
|
+
return source_default.gray("\u2014".padStart(width));
|
|
2310
|
+
return colorizeScore(n)(String(n).padStart(width));
|
|
2311
|
+
}
|
|
2312
|
+
function stepsCell(n, width) {
|
|
2313
|
+
if (n === null)
|
|
2314
|
+
return source_default.gray("\u2014".padStart(width));
|
|
2315
|
+
return n.toLocaleString().padStart(width);
|
|
2316
|
+
}
|
|
3605
2317
|
function fmtSeconds(s) {
|
|
3606
2318
|
if (s === null)
|
|
3607
2319
|
return "\u2014";
|
|
@@ -3659,11 +2371,7 @@ function formatReport(data, format, period) {
|
|
|
3659
2371
|
lines.push(` ${"Day".padEnd(10)} ${"Sleep".padStart(6)} ${"Ready".padStart(6)} ${"Active".padStart(7)} ${"Steps".padStart(8)}`);
|
|
3660
2372
|
lines.push(source_default.gray(" " + "\u2500".repeat(52)));
|
|
3661
2373
|
for (const d of data.days) {
|
|
3662
|
-
|
|
3663
|
-
const ready = d.readiness !== null ? d.readiness >= 85 ? source_default.green(String(d.readiness)) : d.readiness >= 70 ? source_default.yellow(String(d.readiness)) : source_default.red(String(d.readiness)) : source_default.gray("\u2014");
|
|
3664
|
-
const active = d.activity !== null ? d.activity >= 85 ? source_default.green(String(d.activity)) : d.activity >= 70 ? source_default.yellow(String(d.activity)) : source_default.red(String(d.activity)) : source_default.gray("\u2014");
|
|
3665
|
-
const steps = d.steps !== null ? d.steps.toLocaleString() : source_default.gray("\u2014");
|
|
3666
|
-
lines.push(` ${d.dayLabel.padEnd(10)} ${sleep.padStart(6)} ${ready.padStart(6)} ${active.padStart(7)} ${steps.padStart(8)}`);
|
|
2374
|
+
lines.push(` ${d.dayLabel.padEnd(10)} ${scoreCell(d.sleep, 6)} ${scoreCell(d.readiness, 6)} ${scoreCell(d.activity, 7)} ${stepsCell(d.steps, 8)}`);
|
|
3667
2375
|
}
|
|
3668
2376
|
lines.push("");
|
|
3669
2377
|
} else {
|
|
@@ -3673,11 +2381,10 @@ function formatReport(data, format, period) {
|
|
|
3673
2381
|
lines.push(` ${"Week of".padEnd(12)} ${"Sleep".padStart(6)} ${"Ready".padStart(6)} ${"Active".padStart(7)} ${"Steps".padStart(10)}`);
|
|
3674
2382
|
lines.push(source_default.gray(" " + "\u2500".repeat(60)));
|
|
3675
2383
|
for (const b of buckets) {
|
|
3676
|
-
const
|
|
3677
|
-
const
|
|
3678
|
-
const
|
|
3679
|
-
|
|
3680
|
-
lines.push(` ${b.weekOf.padEnd(12)} ${sleep.padStart(6)} ${ready.padStart(6)} ${active.padStart(7)} ${steps.padStart(10)}`);
|
|
2384
|
+
const avgSleepInt = b.avgSleep !== null ? Math.round(b.avgSleep) : null;
|
|
2385
|
+
const avgReadyInt = b.avgReadiness !== null ? Math.round(b.avgReadiness) : null;
|
|
2386
|
+
const avgActiveInt = b.avgActivity !== null ? Math.round(b.avgActivity) : null;
|
|
2387
|
+
lines.push(` ${b.weekOf.padEnd(12)} ${scoreCell(avgSleepInt, 6)} ${scoreCell(avgReadyInt, 6)} ${scoreCell(avgActiveInt, 7)} ${stepsCell(b.totalSteps, 10)}`);
|
|
3681
2388
|
}
|
|
3682
2389
|
lines.push("");
|
|
3683
2390
|
}
|
|
@@ -3729,260 +2436,173 @@ function formatReport(data, format, period) {
|
|
|
3729
2436
|
}
|
|
3730
2437
|
|
|
3731
2438
|
// src/commands/report.ts
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
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 } : {} }));
|
|
3738
2484
|
}
|
|
3739
|
-
const format = resolveFormat({ explicit: opts.format, isTty: process.stdout.isTTY === true });
|
|
3740
|
-
const db = openDatabase2({ dbPath: opts.db });
|
|
3741
|
-
ensureSchema2(db);
|
|
3742
|
-
const days = period === "week" ? 7 : 30;
|
|
3743
|
-
const data = getReport(db, days);
|
|
3744
|
-
console.log(formatReport(data, format, period));
|
|
3745
|
-
db.close();
|
|
3746
2485
|
});
|
|
3747
2486
|
}
|
|
3748
2487
|
|
|
3749
|
-
// src/commands/
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
}
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
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));
|
|
3774
2519
|
}
|
|
3775
|
-
writeToken(target, token);
|
|
3776
|
-
console.log(source_default.green(`Saved to ${target}`));
|
|
3777
2520
|
});
|
|
3778
2521
|
}
|
|
3779
2522
|
|
|
3780
|
-
// src/commands/
|
|
3781
|
-
function
|
|
3782
|
-
return {
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
{
|
|
3834
|
-
name: "activity",
|
|
3835
|
-
description: "Fetch daily activity scores from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3836
|
-
args: [],
|
|
3837
|
-
outputSchema: "docs/schemas/activity.json",
|
|
3838
|
-
subcommands: [
|
|
3839
|
-
{ name: "today", description: "Today's activity data.", args: [] },
|
|
3840
|
-
{ name: "date", description: "Activity data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3841
|
-
{ name: "week", description: "Last 7 days of activity data.", args: [] }
|
|
3842
|
-
]
|
|
3843
|
-
},
|
|
3844
|
-
{
|
|
3845
|
-
name: "hr",
|
|
3846
|
-
description: "Fetch heart rate samples from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3847
|
-
args: [],
|
|
3848
|
-
outputSchema: "docs/schemas/hr.json",
|
|
3849
|
-
subcommands: [
|
|
3850
|
-
{ name: "today", description: "Today's heart rate data.", args: [] },
|
|
3851
|
-
{ name: "date", description: "Heart rate data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3852
|
-
{ name: "week", description: "Last 7 days of heart rate data.", args: [] }
|
|
3853
|
-
]
|
|
3854
|
-
},
|
|
3855
|
-
{
|
|
3856
|
-
name: "spo2",
|
|
3857
|
-
description: "Fetch blood oxygen (SpO2) data from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3858
|
-
args: [],
|
|
3859
|
-
outputSchema: "docs/schemas/spo2.json",
|
|
3860
|
-
subcommands: [
|
|
3861
|
-
{ name: "today", description: "Today's SpO2 data.", args: [] },
|
|
3862
|
-
{ name: "date", description: "SpO2 data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3863
|
-
{ name: "week", description: "Last 7 days of SpO2 data.", args: [] }
|
|
3864
|
-
]
|
|
3865
|
-
},
|
|
3866
|
-
{
|
|
3867
|
-
name: "stress",
|
|
3868
|
-
description: "Fetch daily stress data from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3869
|
-
args: [],
|
|
3870
|
-
outputSchema: "docs/schemas/stress.json",
|
|
3871
|
-
subcommands: [
|
|
3872
|
-
{ name: "today", description: "Today's stress data.", args: [] },
|
|
3873
|
-
{ name: "date", description: "Stress data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3874
|
-
{ name: "week", description: "Last 7 days of stress data.", args: [] }
|
|
3875
|
-
]
|
|
3876
|
-
},
|
|
3877
|
-
{
|
|
3878
|
-
name: "workout",
|
|
3879
|
-
description: "Fetch workout data from Oura API. Pick a subcommand: today | date <day> | week.",
|
|
3880
|
-
args: [],
|
|
3881
|
-
outputSchema: "docs/schemas/workout.json",
|
|
3882
|
-
subcommands: [
|
|
3883
|
-
{ name: "today", description: "Today's workout data.", args: [] },
|
|
3884
|
-
{ name: "date", description: "Workout data for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3885
|
-
{ name: "week", description: "Last 7 days of workout data.", args: [] }
|
|
3886
|
-
]
|
|
3887
|
-
},
|
|
3888
|
-
{ name: "sync", description: "Sync all Oura collections into the local database.", args: [] },
|
|
3889
|
-
{
|
|
3890
|
-
name: "db",
|
|
3891
|
-
description: "Query and manage the local SQLite cache. Pick a subcommand.",
|
|
3892
|
-
args: [],
|
|
3893
|
-
subcommands: [
|
|
3894
|
-
{ name: "today", description: "Today's summary from local DB.", args: [] },
|
|
3895
|
-
{ name: "date", description: "Summary for a specific date.", args: [{ name: "<day>", type: "date", format: "YYYY-MM-DD", required: true, description: "Target date." }] },
|
|
3896
|
-
{ name: "week", description: "Last 7 days from local DB.", args: [] },
|
|
3897
|
-
{ name: "trends", description: "Score and metric trends over N days (default 30).", args: [{ name: "[days]", type: "number", required: false, description: "Window size in days." }] },
|
|
3898
|
-
{ name: "stats", description: "Row counts, date range, record highs.", args: [] },
|
|
3899
|
-
{ name: "import", description: "Sync new data from Oura API into the local DB.", args: [] },
|
|
3900
|
-
{ name: "reset", description: "Destroy and rebuild the database from exported CSVs.", args: [] }
|
|
3901
|
-
]
|
|
3902
|
-
},
|
|
3903
|
-
{
|
|
3904
|
-
name: "report",
|
|
3905
|
-
description: "Generate a narrative health report from local data.",
|
|
3906
|
-
args: [
|
|
3907
|
-
{ name: "--period", type: "enum", values: ["week", "month"], description: "Report window (default week)." }
|
|
3908
|
-
]
|
|
3909
|
-
}
|
|
3910
|
-
]
|
|
3911
|
-
};
|
|
3912
|
-
}
|
|
3913
|
-
function describeCommand(version) {
|
|
3914
|
-
return new Command("describe").description("Emit a machine-readable manifest of commands, args, and outputs.").action(() => {
|
|
3915
|
-
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
|
+
}
|
|
3916
2576
|
});
|
|
3917
2577
|
}
|
|
3918
2578
|
|
|
3919
2579
|
// src/index.ts
|
|
3920
|
-
var VERSION = "0.
|
|
2580
|
+
var VERSION = "0.4.0";
|
|
3921
2581
|
if (process.argv.includes("--no-color") || process.env.NO_COLOR) {
|
|
3922
2582
|
source_default.level = 0;
|
|
3923
2583
|
}
|
|
3924
|
-
var
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
program2.addCommand(describeCommand(VERSION));
|
|
3928
|
-
program2.addCommand(createApiCommand("sleep", "Fetch daily sleep scores from Oura API.", "daily_sleep"));
|
|
3929
|
-
program2.addCommand(createApiCommand("readiness", "Fetch daily readiness scores from Oura API.", "daily_readiness"));
|
|
3930
|
-
program2.addCommand(createApiCommand("activity", "Fetch daily activity scores from Oura API.", "daily_activity"));
|
|
3931
|
-
program2.addCommand(createApiCommand("hr", "Fetch heart rate samples from Oura API.", "heartrate"));
|
|
3932
|
-
program2.addCommand(createApiCommand("spo2", "Fetch blood oxygen (SpO2) data from Oura API.", "daily_spo2"));
|
|
3933
|
-
program2.addCommand(createApiCommand("stress", "Fetch daily stress data from Oura API.", "daily_stress"));
|
|
3934
|
-
program2.addCommand(createApiCommand("workout", "Fetch workout data from Oura API.", "workout"));
|
|
3935
|
-
program2.addCommand(syncCommand());
|
|
3936
|
-
program2.addCommand(dbCommand());
|
|
3937
|
-
program2.addCommand(reportCommand());
|
|
3938
|
-
program2.command("healthcheck").description("Quick local DB health probe (JSON: {ok, version, latencyMs}).").action(() => {
|
|
3939
|
-
const start = Date.now();
|
|
3940
|
-
const globalOpts = program2.opts();
|
|
3941
|
-
let ok = true;
|
|
3942
|
-
let error;
|
|
3943
|
-
try {
|
|
3944
|
-
const db = openDatabase2({ dbPath: globalOpts.db });
|
|
3945
|
-
ensureSchema2(db);
|
|
3946
|
-
db.query("SELECT 1").get();
|
|
3947
|
-
db.close();
|
|
3948
|
-
} catch (err) {
|
|
3949
|
-
ok = false;
|
|
3950
|
-
error = err instanceof Error ? err.message : String(err);
|
|
3951
|
-
}
|
|
3952
|
-
console.log(JSON.stringify({ ok, version: VERSION, latencyMs: Date.now() - start, ...error ? { error } : {} }));
|
|
3953
|
-
});
|
|
3954
|
-
program2.command("manifest").description("Print openclaw-tool-registry-compatible manifest as JSON.").action(() => {
|
|
3955
|
-
console.log(JSON.stringify({
|
|
3956
|
-
id: "oura-cli",
|
|
2584
|
+
var main = defineCommand({
|
|
2585
|
+
meta: {
|
|
2586
|
+
name: "oura-cli",
|
|
3957
2587
|
version: VERSION,
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
envVars: ["OURA_TOKEN", "OURA_TOKEN_PATH", "OURA_DB_PATH", "OURA_TZ"],
|
|
3978
|
-
healthcheck: { command: "healthcheck", expects: { ok: "boolean", version: "string", latencyMs: "number" } }
|
|
3979
|
-
}, null, 2));
|
|
3980
|
-
});
|
|
3981
|
-
program2.parseAsync(process.argv).catch((err) => {
|
|
3982
|
-
const fmt = resolveFormat({
|
|
3983
|
-
explicit: program2.opts().format,
|
|
3984
|
-
isTty: process.stdout.isTTY === true
|
|
3985
|
-
});
|
|
3986
|
-
emitError(err, fmt);
|
|
3987
|
-
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
|
+
}
|
|
3988
2607
|
});
|
|
2608
|
+
runMain(main);
|