@commissionsight/cli 0.1.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/LICENSE +21 -0
- package/README.md +248 -0
- package/bin/cs.mjs +2 -0
- package/dist/commands/admin.d.ts +7 -0
- package/dist/commands/admin.js +409 -0
- package/dist/commands/auth.d.ts +7 -0
- package/dist/commands/auth.js +107 -0
- package/dist/commands/batch.d.ts +2 -0
- package/dist/commands/batch.js +68 -0
- package/dist/commands/billing.d.ts +6 -0
- package/dist/commands/billing.js +75 -0
- package/dist/commands/carrier.d.ts +6 -0
- package/dist/commands/carrier.js +111 -0
- package/dist/commands/completion.d.ts +6 -0
- package/dist/commands/completion.js +56 -0
- package/dist/commands/context.d.ts +6 -0
- package/dist/commands/context.js +73 -0
- package/dist/commands/file.d.ts +6 -0
- package/dist/commands/file.js +97 -0
- package/dist/commands/job.d.ts +2 -0
- package/dist/commands/job.js +186 -0
- package/dist/commands/member.d.ts +5 -0
- package/dist/commands/member.js +91 -0
- package/dist/commands/meta.d.ts +7 -0
- package/dist/commands/meta.js +36 -0
- package/dist/commands/rate.d.ts +5 -0
- package/dist/commands/rate.js +69 -0
- package/dist/commands/registry.d.ts +14 -0
- package/dist/commands/registry.js +56 -0
- package/dist/commands/report.d.ts +2 -0
- package/dist/commands/report.js +168 -0
- package/dist/commands/session.d.ts +5 -0
- package/dist/commands/session.js +21 -0
- package/dist/commands/team.d.ts +5 -0
- package/dist/commands/team.js +61 -0
- package/dist/commands/upload.d.ts +85 -0
- package/dist/commands/upload.js +111 -0
- package/dist/commands/webhook.d.ts +5 -0
- package/dist/commands/webhook.js +56 -0
- package/dist/commands/workspace.d.ts +8 -0
- package/dist/commands/workspace.js +65 -0
- package/dist/config/schema.d.ts +21 -0
- package/dist/config/schema.js +33 -0
- package/dist/config/store.d.ts +17 -0
- package/dist/config/store.js +74 -0
- package/dist/context.d.ts +22 -0
- package/dist/context.js +100 -0
- package/dist/errors.d.ts +37 -0
- package/dist/errors.js +70 -0
- package/dist/globals.d.ts +10 -0
- package/dist/globals.js +38 -0
- package/dist/io.d.ts +28 -0
- package/dist/io.js +28 -0
- package/dist/lib/batch.d.ts +52 -0
- package/dist/lib/batch.js +0 -0
- package/dist/lib/confirm.d.ts +2 -0
- package/dist/lib/confirm.js +23 -0
- package/dist/lib/file.d.ts +6 -0
- package/dist/lib/file.js +43 -0
- package/dist/lib/input.d.ts +2 -0
- package/dist/lib/input.js +35 -0
- package/dist/lib/paginate.d.ts +33 -0
- package/dist/lib/paginate.js +47 -0
- package/dist/lib/period.d.ts +15 -0
- package/dist/lib/period.js +43 -0
- package/dist/lib/poll.d.ts +14 -0
- package/dist/lib/poll.js +17 -0
- package/dist/lib/resolve.d.ts +30 -0
- package/dist/lib/resolve.js +81 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +17 -0
- package/dist/output/color.d.ts +26 -0
- package/dist/output/color.js +37 -0
- package/dist/output/csv.d.ts +25 -0
- package/dist/output/csv.js +119 -0
- package/dist/output/envelope.d.ts +29 -0
- package/dist/output/envelope.js +66 -0
- package/dist/output/help.d.ts +7 -0
- package/dist/output/help.js +57 -0
- package/dist/output/print.d.ts +14 -0
- package/dist/output/print.js +70 -0
- package/dist/output/schema-tree.d.ts +32 -0
- package/dist/output/schema-tree.js +33 -0
- package/dist/router.d.ts +6 -0
- package/dist/router.js +267 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.js +1 -0
- package/dist/util.d.ts +11 -0
- package/dist/util.js +39 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +41 -0
- package/package.json +53 -0
package/dist/router.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router (plan §7): parse argv → match command via longest-prefix → validate
|
|
3
|
+
* flags → run → wrap result in the JSON envelope (§5.1) → map errors to exit
|
|
4
|
+
* codes (§5.2). Commands return data; the router owns output and exit codes.
|
|
5
|
+
*/
|
|
6
|
+
import { parseArgs } from 'node:util';
|
|
7
|
+
import { defaultIO } from './io.js';
|
|
8
|
+
import { GLOBAL_OPTIONS, GLOBAL_KEYS, resolveGlobals } from './globals.js';
|
|
9
|
+
import { getCommandTable } from './commands/registry.js';
|
|
10
|
+
import { makeRunCtx } from './context.js';
|
|
11
|
+
import { ok, errEnvelope } from './output/envelope.js';
|
|
12
|
+
import { EXIT, UsageError, exitCodeFor } from './errors.js';
|
|
13
|
+
import { makePrinter } from './output/print.js';
|
|
14
|
+
import { cliVersion, sdkVersion } from './version.js';
|
|
15
|
+
import { renderTopHelp, renderCommandHelp } from './output/help.js';
|
|
16
|
+
/** Build the parseArgs `options` config from option specs. */
|
|
17
|
+
function toParseArgsOptions(specs) {
|
|
18
|
+
const out = {};
|
|
19
|
+
for (const [name, spec] of Object.entries(specs)) {
|
|
20
|
+
out[name] = {
|
|
21
|
+
type: spec.type,
|
|
22
|
+
...(spec.short ? { short: spec.short } : {}),
|
|
23
|
+
...(spec.multiple ? { multiple: true } : {}),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
const SHORT_TO_GLOBAL = {};
|
|
29
|
+
for (const [long, spec] of Object.entries(GLOBAL_OPTIONS)) {
|
|
30
|
+
if (spec.short)
|
|
31
|
+
SHORT_TO_GLOBAL[spec.short] = { ...spec, long };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Phase A: collect the leading "words" that could form a command path,
|
|
35
|
+
* skipping global flags (accounting for their value arity) and stopping at the
|
|
36
|
+
* first command-specific flag or `--`.
|
|
37
|
+
*/
|
|
38
|
+
function collectWords(argv) {
|
|
39
|
+
const words = [];
|
|
40
|
+
for (let i = 0; i < argv.length; i++) {
|
|
41
|
+
const t = argv[i];
|
|
42
|
+
if (t === '--')
|
|
43
|
+
break;
|
|
44
|
+
if (t.startsWith('--')) {
|
|
45
|
+
const eq = t.indexOf('=');
|
|
46
|
+
const name = eq >= 0 ? t.slice(2, eq) : t.slice(2);
|
|
47
|
+
const spec = GLOBAL_OPTIONS[name];
|
|
48
|
+
if (!spec)
|
|
49
|
+
break; // command-specific long flag → path ended
|
|
50
|
+
if (spec.type === 'string' && eq < 0)
|
|
51
|
+
i++; // consume the value token
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (t.startsWith('-') && t.length > 1) {
|
|
55
|
+
const short = t[1];
|
|
56
|
+
const g = SHORT_TO_GLOBAL[short];
|
|
57
|
+
if (!g)
|
|
58
|
+
break; // command-specific short flag → path ended
|
|
59
|
+
if (g.type === 'string' && t.length === 2)
|
|
60
|
+
i++;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
words.push(t);
|
|
64
|
+
}
|
|
65
|
+
return words;
|
|
66
|
+
}
|
|
67
|
+
/** Longest-prefix match of `words` against the registered command paths. */
|
|
68
|
+
function matchCommand(words, table) {
|
|
69
|
+
let best = null;
|
|
70
|
+
for (const cmd of table) {
|
|
71
|
+
const p = cmd.path;
|
|
72
|
+
if (p.length > words.length)
|
|
73
|
+
continue;
|
|
74
|
+
if (p.every((seg, i) => seg === words[i])) {
|
|
75
|
+
if (!best || p.length > best.depth)
|
|
76
|
+
best = { cmd, depth: p.length };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return best;
|
|
80
|
+
}
|
|
81
|
+
/** Group commands sharing a prefix (for "did you mean" / group help). */
|
|
82
|
+
function commandsUnder(prefix, table) {
|
|
83
|
+
return table.filter((c) => prefix.every((seg, i) => c.path[i] === seg));
|
|
84
|
+
}
|
|
85
|
+
/** Entry point used by main() and tests. Returns the process exit code. */
|
|
86
|
+
export async function run(argv, opts = {}) {
|
|
87
|
+
const io = opts.io ?? defaultIO();
|
|
88
|
+
const table = getCommandTable();
|
|
89
|
+
// Pre-scan for a bare top-level --version / -V (before any command).
|
|
90
|
+
const words = collectWords(argv);
|
|
91
|
+
const match = matchCommand(words, table);
|
|
92
|
+
// Top-level --version with no command.
|
|
93
|
+
if (!match && hasFlag(argv, 'version', 'V')) {
|
|
94
|
+
io.stdout(`cs ${cliVersion()} (@commissionsight/sdk ${sdkVersion()})\n`);
|
|
95
|
+
return EXIT.OK;
|
|
96
|
+
}
|
|
97
|
+
// No command resolved.
|
|
98
|
+
if (!match) {
|
|
99
|
+
const wantsHelp = hasFlag(argv, 'help', 'h') || argv.length === 0 || words.length === 0;
|
|
100
|
+
if (wantsHelp && (argv.length === 0 || hasFlag(argv, 'help', 'h'))) {
|
|
101
|
+
renderTopHelp(io, table);
|
|
102
|
+
return EXIT.OK;
|
|
103
|
+
}
|
|
104
|
+
// Unknown command word(s).
|
|
105
|
+
const attempted = words.join(' ') || argv[0] || '';
|
|
106
|
+
const near = commandsUnder([words[0] ?? ''], table);
|
|
107
|
+
io.stderr(`error: unknown command: ${attempted}\n`);
|
|
108
|
+
if (near.length) {
|
|
109
|
+
io.stderr('did you mean:\n');
|
|
110
|
+
for (const c of near)
|
|
111
|
+
io.stderr(` cs ${c.path.join(' ')}\n`);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
io.stderr("run 'cs --help' to see available commands\n");
|
|
115
|
+
}
|
|
116
|
+
return EXIT.USAGE;
|
|
117
|
+
}
|
|
118
|
+
const { cmd, depth } = match;
|
|
119
|
+
// Per-command help.
|
|
120
|
+
if (hasFlag(argv, 'help', 'h')) {
|
|
121
|
+
renderCommandHelp(io, cmd, table);
|
|
122
|
+
return EXIT.OK;
|
|
123
|
+
}
|
|
124
|
+
// Phase B: parse the full argv against merged (global + command) specs.
|
|
125
|
+
const merged = { ...GLOBAL_OPTIONS, ...(cmd.options ?? {}) };
|
|
126
|
+
let values;
|
|
127
|
+
let positionals;
|
|
128
|
+
try {
|
|
129
|
+
const parsed = parseArgs({
|
|
130
|
+
args: argv,
|
|
131
|
+
options: toParseArgsOptions(merged),
|
|
132
|
+
allowPositionals: true,
|
|
133
|
+
strict: true,
|
|
134
|
+
});
|
|
135
|
+
values = parsed.values;
|
|
136
|
+
positionals = parsed.positionals;
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
140
|
+
return finishError(io, new UsageError(msg), false, false);
|
|
141
|
+
}
|
|
142
|
+
const globals = resolveGlobals(values, io);
|
|
143
|
+
// Validate choices and apply defaults for command options.
|
|
144
|
+
try {
|
|
145
|
+
applyDefaultsAndChoices(cmd, values);
|
|
146
|
+
validateArgs(cmd, positionals.slice(depth));
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
return finishError(io, err, globals.json, globals.quiet);
|
|
150
|
+
}
|
|
151
|
+
// Strip the command path words from the front of positionals → command args.
|
|
152
|
+
const args = positionals.slice(depth);
|
|
153
|
+
// Command-facing options exclude global control keys.
|
|
154
|
+
const cmdOptions = {};
|
|
155
|
+
for (const [k, v] of Object.entries(values)) {
|
|
156
|
+
if (!GLOBAL_KEYS.has(k))
|
|
157
|
+
cmdOptions[k] = v;
|
|
158
|
+
}
|
|
159
|
+
const ctx = makeRunCtx(globals, io);
|
|
160
|
+
const parsed = { args, options: cmdOptions };
|
|
161
|
+
try {
|
|
162
|
+
const data = await cmd.run(ctx, parsed);
|
|
163
|
+
finishSuccess(io, cmd, data, ctx);
|
|
164
|
+
return EXIT.OK;
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
return finishError(io, err, globals.json, globals.quiet);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function finishSuccess(io, cmd, data, ctx) {
|
|
171
|
+
if (ctx.globals.json) {
|
|
172
|
+
io.stdout(JSON.stringify(ok(data)) + '\n');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (data === undefined || data === null) {
|
|
176
|
+
if (!ctx.globals.quiet)
|
|
177
|
+
io.stderr('ok\n');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (cmd.render) {
|
|
181
|
+
cmd.render(data, ctx);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
defaultRender(data, ctx);
|
|
185
|
+
}
|
|
186
|
+
function defaultRender(data, ctx) {
|
|
187
|
+
const p = makePrinter(ctx.io, ctx.globals.color);
|
|
188
|
+
if (Array.isArray(data)) {
|
|
189
|
+
if (data.every((r) => r && typeof r === 'object')) {
|
|
190
|
+
p.table(data);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
for (const item of data)
|
|
194
|
+
p.line(String(item));
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (data && typeof data === 'object') {
|
|
199
|
+
p.kv(data);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
p.line(String(data));
|
|
203
|
+
}
|
|
204
|
+
function finishError(io, err, json, quiet) {
|
|
205
|
+
const env = errEnvelope(err);
|
|
206
|
+
const code = exitCodeFor(err);
|
|
207
|
+
if (json) {
|
|
208
|
+
io.stderr(JSON.stringify(env) + '\n');
|
|
209
|
+
return code;
|
|
210
|
+
}
|
|
211
|
+
io.stderr(`error: ${env.error.message}\n`);
|
|
212
|
+
// Actionable hints.
|
|
213
|
+
if (env.error.status === 409 && env.error.code === 'period_exists') {
|
|
214
|
+
io.stderr('hint: retry with --replace to correct this period atomically\n');
|
|
215
|
+
}
|
|
216
|
+
if (env.error.status === 401 || env.error.status === 403) {
|
|
217
|
+
io.stderr("hint: check your token with 'cs auth status'\n");
|
|
218
|
+
}
|
|
219
|
+
if (err instanceof UsageError && err.candidates?.length) {
|
|
220
|
+
io.stderr('candidates:\n');
|
|
221
|
+
for (const c of err.candidates)
|
|
222
|
+
io.stderr(` ${c}\n`);
|
|
223
|
+
}
|
|
224
|
+
void quiet;
|
|
225
|
+
return code;
|
|
226
|
+
}
|
|
227
|
+
function applyDefaultsAndChoices(cmd, values) {
|
|
228
|
+
for (const [name, spec] of Object.entries(cmd.options ?? {})) {
|
|
229
|
+
if (values[name] === undefined && spec.default !== undefined) {
|
|
230
|
+
values[name] = spec.default;
|
|
231
|
+
}
|
|
232
|
+
if (spec.choices && values[name] !== undefined) {
|
|
233
|
+
const vals = Array.isArray(values[name]) ? values[name] : [values[name]];
|
|
234
|
+
for (const v of vals) {
|
|
235
|
+
if (!spec.choices.includes(v)) {
|
|
236
|
+
throw new UsageError(`invalid value for --${name}: ${v} (expected one of: ${spec.choices.join(', ')})`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function validateArgs(cmd, args) {
|
|
243
|
+
const specs = cmd.args ?? [];
|
|
244
|
+
const requiredCount = specs.filter((a) => a.required).length;
|
|
245
|
+
if (args.length < requiredCount) {
|
|
246
|
+
const usage = specs
|
|
247
|
+
.map((a) => (a.required ? `<${a.name}>` : `[${a.name}]`) + (a.variadic ? '...' : ''))
|
|
248
|
+
.join(' ');
|
|
249
|
+
throw new UsageError(`missing required argument(s). usage: cs ${cmd.path.join(' ')} ${usage}`);
|
|
250
|
+
}
|
|
251
|
+
const hasVariadic = specs.some((a) => a.variadic);
|
|
252
|
+
if (!hasVariadic && args.length > specs.length) {
|
|
253
|
+
throw new UsageError(`too many arguments for 'cs ${cmd.path.join(' ')}' (expected ${specs.length}, got ${args.length})`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/** Cheap flag presence check independent of parseArgs (for --help/--version). */
|
|
257
|
+
function hasFlag(argv, long, short) {
|
|
258
|
+
for (const t of argv) {
|
|
259
|
+
if (t === '--')
|
|
260
|
+
break;
|
|
261
|
+
if (t === `--${long}`)
|
|
262
|
+
return true;
|
|
263
|
+
if (t.startsWith('-') && !t.startsWith('--') && t.slice(1).includes(short))
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
267
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types shared by the router, command table, and runtime context.
|
|
3
|
+
* The command table (see commands/registry.ts) is the single source of truth
|
|
4
|
+
* consumed by the router, `--help`, and `cs schema`.
|
|
5
|
+
*/
|
|
6
|
+
import type { CommissionSightClient } from '@commissionsight/sdk';
|
|
7
|
+
import type { IO } from './io.js';
|
|
8
|
+
/** One CLI flag specification. */
|
|
9
|
+
export interface OptSpec {
|
|
10
|
+
type: 'string' | 'boolean';
|
|
11
|
+
short?: string;
|
|
12
|
+
desc: string;
|
|
13
|
+
default?: string | boolean;
|
|
14
|
+
choices?: readonly string[];
|
|
15
|
+
/** Flag may be repeated (parseArgs `multiple`). Values collect into an array. */
|
|
16
|
+
multiple?: boolean;
|
|
17
|
+
/** Placeholder shown in help for value-taking flags (e.g. `<YYYY-MM>`). */
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
}
|
|
20
|
+
/** One positional argument specification. */
|
|
21
|
+
export interface ArgSpec {
|
|
22
|
+
name: string;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
variadic?: boolean;
|
|
25
|
+
desc?: string;
|
|
26
|
+
}
|
|
27
|
+
/** The parsed inputs handed to a command's `run`. */
|
|
28
|
+
export interface Parsed {
|
|
29
|
+
args: string[];
|
|
30
|
+
options: Record<string, string | boolean | string[] | undefined>;
|
|
31
|
+
}
|
|
32
|
+
/** A single command (leaf) in the command tree. */
|
|
33
|
+
export interface Cmd {
|
|
34
|
+
/** e.g. ["carrier","config","test"] */
|
|
35
|
+
path: string[];
|
|
36
|
+
summary: string;
|
|
37
|
+
args?: ArgSpec[];
|
|
38
|
+
options?: Record<string, OptSpec>;
|
|
39
|
+
/** Returns plain data; the router owns the envelope + exit-code mapping. */
|
|
40
|
+
run(ctx: RunCtx, parsed: Parsed): Promise<unknown>;
|
|
41
|
+
/** Optional custom human renderer; defaults to the generic printer. */
|
|
42
|
+
render?(data: unknown, ctx: RunCtx): void;
|
|
43
|
+
}
|
|
44
|
+
/** Resolved global flags + injected dependencies. */
|
|
45
|
+
export interface Globals {
|
|
46
|
+
json: boolean;
|
|
47
|
+
quiet: boolean;
|
|
48
|
+
color: boolean;
|
|
49
|
+
yes: boolean;
|
|
50
|
+
token?: string;
|
|
51
|
+
tokenFile?: string;
|
|
52
|
+
tokenStdin?: boolean;
|
|
53
|
+
baseUrl?: string;
|
|
54
|
+
context?: string;
|
|
55
|
+
}
|
|
56
|
+
/** Runtime context threaded into every command. */
|
|
57
|
+
export interface RunCtx {
|
|
58
|
+
globals: Globals;
|
|
59
|
+
io: IO;
|
|
60
|
+
/** Lazily-constructed SDK client (token/baseUrl resolved on first use). */
|
|
61
|
+
client(): CommissionSightClient;
|
|
62
|
+
/** Per-run cache (carrier list, workspace list) for batch reuse. */
|
|
63
|
+
cache: Map<string, unknown>;
|
|
64
|
+
/** Log a line to stderr (suppressed in --quiet / --json chrome rules). */
|
|
65
|
+
log(msg: string): void;
|
|
66
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Small shared helpers. */
|
|
2
|
+
/** Mask a secret to a short suffix for display (e.g. `…a1b2`). Never logs the token. */
|
|
3
|
+
export declare function maskToken(token: string | undefined): string;
|
|
4
|
+
/** Coerce a parsed option value to a string (last wins for repeated flags). */
|
|
5
|
+
export declare function optStr(v: string | boolean | string[] | undefined): string | undefined;
|
|
6
|
+
/** Coerce a parsed option value to a boolean. */
|
|
7
|
+
export declare function optBool(v: string | boolean | string[] | undefined): boolean;
|
|
8
|
+
/** Coerce a parsed option value to a number, or undefined. */
|
|
9
|
+
export declare function optNum(v: string | boolean | string[] | undefined): number | undefined;
|
|
10
|
+
/** Collect a repeatable/comma-separated option into a string array. */
|
|
11
|
+
export declare function optList(v: string | boolean | string[] | undefined): string[];
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Small shared helpers. */
|
|
2
|
+
/** Mask a secret to a short suffix for display (e.g. `…a1b2`). Never logs the token. */
|
|
3
|
+
export function maskToken(token) {
|
|
4
|
+
if (!token)
|
|
5
|
+
return '(none)';
|
|
6
|
+
if (token.length <= 4)
|
|
7
|
+
return '…' + token;
|
|
8
|
+
return '…' + token.slice(-4);
|
|
9
|
+
}
|
|
10
|
+
/** Coerce a parsed option value to a string (last wins for repeated flags). */
|
|
11
|
+
export function optStr(v) {
|
|
12
|
+
if (typeof v === 'string')
|
|
13
|
+
return v;
|
|
14
|
+
if (Array.isArray(v))
|
|
15
|
+
return v[v.length - 1];
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
/** Coerce a parsed option value to a boolean. */
|
|
19
|
+
export function optBool(v) {
|
|
20
|
+
return v === true;
|
|
21
|
+
}
|
|
22
|
+
/** Coerce a parsed option value to a number, or undefined. */
|
|
23
|
+
export function optNum(v) {
|
|
24
|
+
const s = optStr(v);
|
|
25
|
+
if (s === undefined)
|
|
26
|
+
return undefined;
|
|
27
|
+
const n = Number(s);
|
|
28
|
+
if (!Number.isFinite(n))
|
|
29
|
+
return undefined;
|
|
30
|
+
return n;
|
|
31
|
+
}
|
|
32
|
+
/** Collect a repeatable/comma-separated option into a string array. */
|
|
33
|
+
export function optList(v) {
|
|
34
|
+
if (Array.isArray(v))
|
|
35
|
+
return v.flatMap((x) => x.split(',')).map((s) => s.trim()).filter(Boolean);
|
|
36
|
+
if (typeof v === 'string')
|
|
37
|
+
return v.split(',').map((s) => s.trim()).filter(Boolean);
|
|
38
|
+
return [];
|
|
39
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the CLI's own version (from package.json) and the installed SDK
|
|
3
|
+
* version — both read from disk at runtime so they never drift from reality.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
export function cliVersion() {
|
|
9
|
+
try {
|
|
10
|
+
const url = new URL('../package.json', import.meta.url);
|
|
11
|
+
const pkg = JSON.parse(readFileSync(fileURLToPath(url), 'utf8'));
|
|
12
|
+
return pkg.version;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return '0.0.0';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function sdkVersion() {
|
|
19
|
+
// The SDK is ESM-only with an `exports` map that omits a CJS entry, so
|
|
20
|
+
// `require.resolve` fails. Walk up from this module looking for the package's
|
|
21
|
+
// installed package.json under node_modules instead.
|
|
22
|
+
try {
|
|
23
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
for (let i = 0; i < 8; i++) {
|
|
25
|
+
const p = join(dir, 'node_modules', '@commissionsight', 'sdk', 'package.json');
|
|
26
|
+
if (existsSync(p)) {
|
|
27
|
+
const j = JSON.parse(readFileSync(p, 'utf8'));
|
|
28
|
+
if (j.version)
|
|
29
|
+
return j.version;
|
|
30
|
+
}
|
|
31
|
+
const parent = dirname(dir);
|
|
32
|
+
if (parent === dir)
|
|
33
|
+
break;
|
|
34
|
+
dir = parent;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
/* ignore */
|
|
39
|
+
}
|
|
40
|
+
return 'unknown';
|
|
41
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@commissionsight/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Command-line interface for the CommissionSight API — auth, workspaces, and statement uploads for any carrier and period.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"commissionsight",
|
|
7
|
+
"cli",
|
|
8
|
+
"commission",
|
|
9
|
+
"insurance",
|
|
10
|
+
"carrier",
|
|
11
|
+
"statements",
|
|
12
|
+
"upload"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "CommissionSight",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"bin": {
|
|
18
|
+
"cs": "bin/cs.mjs",
|
|
19
|
+
"commissionsight": "bin/cs.mjs"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"bin",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/main.d.ts",
|
|
33
|
+
"import": "./dist/main.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc -p tsconfig.build.json",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"test": "bun test",
|
|
40
|
+
"prepublishOnly": "bun run build"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@commissionsight/sdk": "^2.3.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/bun": "^1.1.0",
|
|
50
|
+
"@types/node": "^22.0.0",
|
|
51
|
+
"typescript": "^5.6.0"
|
|
52
|
+
}
|
|
53
|
+
}
|