@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
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { cover } from './registry.js';
|
|
2
|
+
import { resolveCarrier } from '../lib/resolve.js';
|
|
3
|
+
import { parsePeriod } from '../lib/period.js';
|
|
4
|
+
import { makePrinter } from '../output/print.js';
|
|
5
|
+
import { optStr } from '../util.js';
|
|
6
|
+
export function memberCommands() {
|
|
7
|
+
cover('listMembers', 'cs member list');
|
|
8
|
+
cover('getMember', 'cs member get');
|
|
9
|
+
cover('getMemberTimeline', 'cs member timeline');
|
|
10
|
+
cover('getMemberJourney', 'cs member journey');
|
|
11
|
+
cover('getMemberLastSeen', 'cs member last-seen');
|
|
12
|
+
cover('getPolicyJourney', 'cs policy journey');
|
|
13
|
+
return [
|
|
14
|
+
{
|
|
15
|
+
path: ['member', 'list'],
|
|
16
|
+
summary: 'List members (filter by carrier/status/period)',
|
|
17
|
+
options: {
|
|
18
|
+
carrier: { type: 'string', desc: 'Filter by carrier', placeholder: '<c>' },
|
|
19
|
+
status: { type: 'string', desc: 'Filter by status', choices: ['green', 'yellow', 'red'], placeholder: '<s>' },
|
|
20
|
+
period: { type: 'string', desc: 'Filter by period YYYY-MM', placeholder: '<YYYY-MM>' },
|
|
21
|
+
},
|
|
22
|
+
async run(ctx, parsed) {
|
|
23
|
+
const carrier = optStr(parsed.options['carrier']);
|
|
24
|
+
const period = optStr(parsed.options['period']);
|
|
25
|
+
const p = period ? parsePeriod(period) : undefined;
|
|
26
|
+
const page = await ctx.client().listMembers({
|
|
27
|
+
...(carrier ? { carrierId: await resolveCarrier(ctx, carrier) } : {}),
|
|
28
|
+
...(optStr(parsed.options['status']) ? { status: optStr(parsed.options['status']) } : {}),
|
|
29
|
+
...(p ? { periodYear: p.periodYear, periodMonth: p.periodMonth } : {}),
|
|
30
|
+
});
|
|
31
|
+
return page.data;
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
path: ['member', 'get'],
|
|
36
|
+
summary: 'Get a member by ref id',
|
|
37
|
+
args: [{ name: 'memberRefId', required: true }],
|
|
38
|
+
async run(ctx, parsed) {
|
|
39
|
+
return ctx.client().getMember(parsed.args[0]);
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
path: ['member', 'timeline'],
|
|
44
|
+
summary: 'Period-by-period timeline for a member',
|
|
45
|
+
args: [{ name: 'memberRefId', required: true }],
|
|
46
|
+
async run(ctx, parsed) {
|
|
47
|
+
return (await ctx.client().getMemberTimeline(parsed.args[0])).data;
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
path: ['member', 'journey'],
|
|
52
|
+
summary: 'Full audit journey of a member',
|
|
53
|
+
args: [{ name: 'memberRefId', required: true }],
|
|
54
|
+
async run(ctx, parsed) {
|
|
55
|
+
return ctx.client().getMemberJourney(parsed.args[0]);
|
|
56
|
+
},
|
|
57
|
+
render: renderJourney,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
path: ['member', 'last-seen'],
|
|
61
|
+
summary: 'Where/when a member was last seen',
|
|
62
|
+
args: [{ name: 'memberRefId', required: true }],
|
|
63
|
+
async run(ctx, parsed) {
|
|
64
|
+
return ctx.client().getMemberLastSeen(parsed.args[0]);
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
path: ['policy', 'journey'],
|
|
69
|
+
summary: 'Full audit journey of a single policy',
|
|
70
|
+
args: [{ name: 'policyRefId', required: true }],
|
|
71
|
+
async run(ctx, parsed) {
|
|
72
|
+
return ctx.client().getPolicyJourney(parsed.args[0]);
|
|
73
|
+
},
|
|
74
|
+
render: renderJourney,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
function renderJourney(data, ctx) {
|
|
79
|
+
const j = data;
|
|
80
|
+
const p = makePrinter(ctx.io, ctx.globals.color);
|
|
81
|
+
p.line(p.paint('bold', `${j.member.memberName ?? j.memberRefId}`) +
|
|
82
|
+
` ${j.firstPeriod ?? '?'} → ${j.latestPeriod ?? '?'} (${j.periodCount} periods)`);
|
|
83
|
+
p.table(j.periods.map((per) => ({
|
|
84
|
+
period: per.period,
|
|
85
|
+
status: per.status ?? '—',
|
|
86
|
+
present: per.present,
|
|
87
|
+
commission: per.commissionAmount ?? '—',
|
|
88
|
+
flags: per.flags.join('|'),
|
|
89
|
+
file: per.file?.fileName ?? '—',
|
|
90
|
+
})), ['period', 'status', 'present', 'commission', 'flags', 'file']);
|
|
91
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Introspection & DX commands (plan §6.13): `cs version` and `cs schema`.
|
|
3
|
+
* Both are local (no API call). `cs schema` is built from the live command
|
|
4
|
+
* table so an AI harness can discover the full surface programmatically.
|
|
5
|
+
*/
|
|
6
|
+
import type { Cmd } from '../types.js';
|
|
7
|
+
export declare function metaCommands(getTable: () => Cmd[]): Cmd[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { cliVersion, sdkVersion } from '../version.js';
|
|
2
|
+
import { buildSchema } from '../output/schema-tree.js';
|
|
3
|
+
import { makePrinter } from '../output/print.js';
|
|
4
|
+
export function metaCommands(getTable) {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
path: ['version'],
|
|
8
|
+
summary: 'Print the CLI and resolved SDK version',
|
|
9
|
+
async run() {
|
|
10
|
+
return { cli: cliVersion(), sdk: sdkVersion() };
|
|
11
|
+
},
|
|
12
|
+
render(data, ctx) {
|
|
13
|
+
const d = data;
|
|
14
|
+
ctx.io.stdout(`cs ${d.cli} (@commissionsight/sdk ${d.sdk})\n`);
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
path: ['schema'],
|
|
19
|
+
summary: 'Emit the full command/flag tree (for humans or AI harnesses)',
|
|
20
|
+
async run() {
|
|
21
|
+
return buildSchema(getTable(), cliVersion());
|
|
22
|
+
},
|
|
23
|
+
render(data, ctx) {
|
|
24
|
+
const doc = data;
|
|
25
|
+
const p = makePrinter(ctx.io, ctx.globals.color);
|
|
26
|
+
p.line(p.paint('bold', `cs ${doc.version} — ${doc.commands.length} commands`));
|
|
27
|
+
p.line();
|
|
28
|
+
p.table(doc.commands.map((c) => ({
|
|
29
|
+
command: c.command,
|
|
30
|
+
args: c.args.map((a) => (a.required ? `<${a.name}>` : `[${a.name}]`)).join(' '),
|
|
31
|
+
summary: c.summary,
|
|
32
|
+
})), ['command', 'args', 'summary']);
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { cover } from './registry.js';
|
|
2
|
+
import { resolveCarrier } from '../lib/resolve.js';
|
|
3
|
+
import { confirmDestructive } from '../lib/confirm.js';
|
|
4
|
+
import { UsageError } from '../errors.js';
|
|
5
|
+
import { optStr } from '../util.js';
|
|
6
|
+
const RATE_TYPES = ['percent_of_premium', 'flat_per_member'];
|
|
7
|
+
export function rateCommands() {
|
|
8
|
+
cover('listExpectedRates', 'cs rate list');
|
|
9
|
+
cover('upsertExpectedRate', 'cs rate set');
|
|
10
|
+
cover('deleteExpectedRate', 'cs rate delete');
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
path: ['rate', 'list'],
|
|
14
|
+
summary: 'List expected commission rates',
|
|
15
|
+
options: {
|
|
16
|
+
carrier: { type: 'string', desc: 'Filter by carrier', placeholder: '<c>' },
|
|
17
|
+
},
|
|
18
|
+
async run(ctx, parsed) {
|
|
19
|
+
const carrier = optStr(parsed.options['carrier']);
|
|
20
|
+
const res = await ctx.client().listExpectedRates(carrier ? await resolveCarrier(ctx, carrier) : undefined);
|
|
21
|
+
return res.data;
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
path: ['rate', 'set'],
|
|
26
|
+
summary: 'Upsert a contracted rate (prints rescoredPeriods)',
|
|
27
|
+
options: {
|
|
28
|
+
carrier: { type: 'string', desc: 'Carrier (required)', placeholder: '<c>' },
|
|
29
|
+
plan: { type: 'string', desc: 'Plan code (omit for carrier-wide)', placeholder: '<code>' },
|
|
30
|
+
type: { type: 'string', desc: 'Rate type', choices: RATE_TYPES, placeholder: '<t>' },
|
|
31
|
+
value: { type: 'string', desc: 'Fraction (percent) or dollars (flat)', placeholder: '<n>' },
|
|
32
|
+
},
|
|
33
|
+
async run(ctx, parsed) {
|
|
34
|
+
const carrier = optStr(parsed.options['carrier']);
|
|
35
|
+
const type = optStr(parsed.options['type']);
|
|
36
|
+
const valueStr = optStr(parsed.options['value']);
|
|
37
|
+
if (!carrier)
|
|
38
|
+
throw new UsageError('--carrier is required');
|
|
39
|
+
if (!type)
|
|
40
|
+
throw new UsageError(`--type is required (${RATE_TYPES.join(' | ')})`);
|
|
41
|
+
if (valueStr === undefined)
|
|
42
|
+
throw new UsageError('--value is required');
|
|
43
|
+
const rateValue = Number(valueStr);
|
|
44
|
+
if (!Number.isFinite(rateValue))
|
|
45
|
+
throw new UsageError(`invalid --value: ${valueStr}`);
|
|
46
|
+
if (type === 'percent_of_premium' && rateValue > 1) {
|
|
47
|
+
ctx.log(`warning: --value ${rateValue} looks like a percentage; expected a fraction (e.g. 0.20 for 20%)`);
|
|
48
|
+
}
|
|
49
|
+
const plan = optStr(parsed.options['plan']);
|
|
50
|
+
return ctx.client().upsertExpectedRate({
|
|
51
|
+
carrierId: await resolveCarrier(ctx, carrier),
|
|
52
|
+
...(plan ? { planCode: plan } : {}),
|
|
53
|
+
rateType: type,
|
|
54
|
+
rateValue,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
path: ['rate', 'delete'],
|
|
60
|
+
summary: 'Delete an expected rate (destructive)',
|
|
61
|
+
args: [{ name: 'id', required: true }],
|
|
62
|
+
async run(ctx, parsed) {
|
|
63
|
+
await confirmDestructive(ctx, `delete expected rate ${parsed.args[0]}`);
|
|
64
|
+
await ctx.client().deleteExpectedRate(parsed.args[0]);
|
|
65
|
+
return { deleted: parsed.args[0] };
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command table — the single source of truth consumed by the router,
|
|
3
|
+
* `--help`, and `cs schema`. Each phase appends its command modules here.
|
|
4
|
+
*/
|
|
5
|
+
import type { Cmd } from '../types.js';
|
|
6
|
+
export declare function getCommandTable(): Cmd[];
|
|
7
|
+
/**
|
|
8
|
+
* The backing map of SDK method name → owning command path(s). Used by `cs
|
|
9
|
+
* schema` consumers and, crucially, by the coverage test (plan §14) that
|
|
10
|
+
* asserts every public SDK method is reachable. Populated as commands land.
|
|
11
|
+
*/
|
|
12
|
+
export declare const SDK_COVERAGE: Record<string, string>;
|
|
13
|
+
/** Register a command's backing SDK method(s) for the coverage matrix. */
|
|
14
|
+
export declare function cover(methods: string | string[], command: string): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { metaCommands } from './meta.js';
|
|
2
|
+
import { sessionCommands } from './session.js';
|
|
3
|
+
import { authCommands } from './auth.js';
|
|
4
|
+
import { contextCommands } from './context.js';
|
|
5
|
+
import { workspaceCommands } from './workspace.js';
|
|
6
|
+
import { carrierCommands } from './carrier.js';
|
|
7
|
+
import { uploadCommands } from './upload.js';
|
|
8
|
+
import { batchCommands } from './batch.js';
|
|
9
|
+
import { fileCommands } from './file.js';
|
|
10
|
+
import { jobCommands } from './job.js';
|
|
11
|
+
import { memberCommands } from './member.js';
|
|
12
|
+
import { teamCommands } from './team.js';
|
|
13
|
+
import { reportCommands } from './report.js';
|
|
14
|
+
import { rateCommands } from './rate.js';
|
|
15
|
+
import { webhookCommands } from './webhook.js';
|
|
16
|
+
import { billingCommands } from './billing.js';
|
|
17
|
+
import { adminCommands } from './admin.js';
|
|
18
|
+
import { completionCommands } from './completion.js';
|
|
19
|
+
let TABLE = null;
|
|
20
|
+
export function getCommandTable() {
|
|
21
|
+
if (!TABLE) {
|
|
22
|
+
const table = [];
|
|
23
|
+
table.push(...metaCommands(() => getCommandTable()));
|
|
24
|
+
table.push(...sessionCommands());
|
|
25
|
+
table.push(...authCommands());
|
|
26
|
+
table.push(...contextCommands());
|
|
27
|
+
table.push(...workspaceCommands());
|
|
28
|
+
table.push(...carrierCommands());
|
|
29
|
+
table.push(...uploadCommands());
|
|
30
|
+
table.push(...batchCommands());
|
|
31
|
+
table.push(...fileCommands());
|
|
32
|
+
table.push(...jobCommands());
|
|
33
|
+
table.push(...memberCommands());
|
|
34
|
+
table.push(...teamCommands());
|
|
35
|
+
table.push(...reportCommands());
|
|
36
|
+
table.push(...rateCommands());
|
|
37
|
+
table.push(...webhookCommands());
|
|
38
|
+
table.push(...billingCommands());
|
|
39
|
+
table.push(...adminCommands());
|
|
40
|
+
table.push(...completionCommands(() => getCommandTable()));
|
|
41
|
+
TABLE = table;
|
|
42
|
+
}
|
|
43
|
+
return TABLE;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The backing map of SDK method name → owning command path(s). Used by `cs
|
|
47
|
+
* schema` consumers and, crucially, by the coverage test (plan §14) that
|
|
48
|
+
* asserts every public SDK method is reachable. Populated as commands land.
|
|
49
|
+
*/
|
|
50
|
+
export const SDK_COVERAGE = {};
|
|
51
|
+
/** Register a command's backing SDK method(s) for the coverage matrix. */
|
|
52
|
+
export function cover(methods, command) {
|
|
53
|
+
for (const m of Array.isArray(methods) ? methods : [methods]) {
|
|
54
|
+
SDK_COVERAGE[m] = command;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reports (plan §6.8). NOTE: SDK 2.2.0's report methods do not accept a
|
|
3
|
+
* `workspaceId`, so `--workspace` is intentionally NOT offered here (the docs
|
|
4
|
+
* expose ?workspaceId at the HTTP layer, but the SDK can't pass it; a thin
|
|
5
|
+
* wrapper must not bypass the SDK). Lands when the SDK adds the parameter.
|
|
6
|
+
*/
|
|
7
|
+
import { writeFileSync } from 'node:fs';
|
|
8
|
+
import { cover } from './registry.js';
|
|
9
|
+
import { resolveCarrier } from '../lib/resolve.js';
|
|
10
|
+
import { parsePeriod } from '../lib/period.js';
|
|
11
|
+
import { collectOffset } from '../lib/paginate.js';
|
|
12
|
+
import { emitCSV, ATTRITION_COLUMNS, CHARGEBACK_COLUMNS, COMPARISON_COLUMNS, } from '../output/csv.js';
|
|
13
|
+
import { UsageError } from '../errors.js';
|
|
14
|
+
import { optStr, optBool, optNum } from '../util.js';
|
|
15
|
+
const writeF = (p, d) => writeFileSync(p, d);
|
|
16
|
+
export function reportCommands() {
|
|
17
|
+
cover('rollup', 'cs report rollup');
|
|
18
|
+
cover('compare', 'cs report compare');
|
|
19
|
+
cover('attrition', 'cs report attrition');
|
|
20
|
+
cover('attritionSeries', 'cs report attrition-series');
|
|
21
|
+
cover('dataQuality', 'cs report data-quality');
|
|
22
|
+
cover('listChargebacks', 'cs report chargebacks');
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
path: ['report', 'rollup'],
|
|
26
|
+
summary: 'Period rollup totals (owed, at-risk, chargebacks)',
|
|
27
|
+
options: {
|
|
28
|
+
period: { type: 'string', desc: 'Period YYYY-MM (default latest)', placeholder: '<YYYY-MM>' },
|
|
29
|
+
carrier: { type: 'string', desc: 'Filter by carrier', placeholder: '<c>' },
|
|
30
|
+
csv: { type: 'boolean', desc: 'Emit totals as CSV' },
|
|
31
|
+
output: { type: 'string', short: 'o', desc: 'CSV output file', placeholder: '<file>' },
|
|
32
|
+
},
|
|
33
|
+
async run(ctx, parsed) {
|
|
34
|
+
const carrier = optStr(parsed.options['carrier']);
|
|
35
|
+
const period = optStr(parsed.options['period']);
|
|
36
|
+
if (period)
|
|
37
|
+
parsePeriod(period);
|
|
38
|
+
const res = await ctx.client().rollup(period, carrier ? await resolveCarrier(ctx, carrier) : undefined);
|
|
39
|
+
if (optBool(parsed.options['csv']) && !ctx.globals.json) {
|
|
40
|
+
return emitCSV(ctx.io, [{ period: res.period, ...res.totals }], undefined, optStr(parsed.options['output']), writeF);
|
|
41
|
+
}
|
|
42
|
+
return res;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
path: ['report', 'compare'],
|
|
47
|
+
summary: 'Compare two periods',
|
|
48
|
+
options: {
|
|
49
|
+
from: { type: 'string', desc: 'From period YYYY-MM (required)', placeholder: '<YYYY-MM>' },
|
|
50
|
+
to: { type: 'string', desc: 'To period YYYY-MM (required)', placeholder: '<YYYY-MM>' },
|
|
51
|
+
carrier: { type: 'string', desc: 'Filter by carrier', placeholder: '<c>' },
|
|
52
|
+
granularity: { type: 'string', desc: 'Comparison granularity', placeholder: '<g>' },
|
|
53
|
+
csv: { type: 'boolean', desc: 'Emit rows as CSV' },
|
|
54
|
+
output: { type: 'string', short: 'o', desc: 'CSV output file', placeholder: '<file>' },
|
|
55
|
+
},
|
|
56
|
+
async run(ctx, parsed) {
|
|
57
|
+
const from = optStr(parsed.options['from']);
|
|
58
|
+
const to = optStr(parsed.options['to']);
|
|
59
|
+
if (!from || !to)
|
|
60
|
+
throw new UsageError('--from and --to are required (YYYY-MM)');
|
|
61
|
+
parsePeriod(from);
|
|
62
|
+
parsePeriod(to);
|
|
63
|
+
const carrier = optStr(parsed.options['carrier']);
|
|
64
|
+
const res = await ctx.client().compare({
|
|
65
|
+
from,
|
|
66
|
+
to,
|
|
67
|
+
...(carrier ? { carrierId: await resolveCarrier(ctx, carrier) } : {}),
|
|
68
|
+
...(optStr(parsed.options['granularity']) ? { granularity: optStr(parsed.options['granularity']) } : {}),
|
|
69
|
+
});
|
|
70
|
+
if (optBool(parsed.options['csv']) && !ctx.globals.json) {
|
|
71
|
+
return emitCSV(ctx.io, res.data, COMPARISON_COLUMNS, optStr(parsed.options['output']), writeF);
|
|
72
|
+
}
|
|
73
|
+
return res;
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
path: ['report', 'attrition'],
|
|
78
|
+
summary: 'Attrition for a period',
|
|
79
|
+
options: {
|
|
80
|
+
period: { type: 'string', desc: 'Period YYYY-MM (required)', placeholder: '<YYYY-MM>' },
|
|
81
|
+
carrier: { type: 'string', desc: 'Filter by carrier', placeholder: '<c>' },
|
|
82
|
+
},
|
|
83
|
+
async run(ctx, parsed) {
|
|
84
|
+
const period = optStr(parsed.options['period']);
|
|
85
|
+
if (!period)
|
|
86
|
+
throw new UsageError('--period YYYY-MM is required');
|
|
87
|
+
parsePeriod(period);
|
|
88
|
+
const carrier = optStr(parsed.options['carrier']);
|
|
89
|
+
return ctx.client().attrition(period, carrier ? await resolveCarrier(ctx, carrier) : undefined);
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
path: ['report', 'attrition-series'],
|
|
94
|
+
summary: 'Attrition over the last N months',
|
|
95
|
+
options: {
|
|
96
|
+
months: { type: 'string', desc: 'Number of months', placeholder: '<n>' },
|
|
97
|
+
carrier: { type: 'string', desc: 'Filter by carrier', placeholder: '<c>' },
|
|
98
|
+
csv: { type: 'boolean', desc: 'Emit series as CSV' },
|
|
99
|
+
output: { type: 'string', short: 'o', desc: 'CSV output file', placeholder: '<file>' },
|
|
100
|
+
},
|
|
101
|
+
async run(ctx, parsed) {
|
|
102
|
+
const carrier = optStr(parsed.options['carrier']);
|
|
103
|
+
const res = await ctx.client().attritionSeries({
|
|
104
|
+
...(optNum(parsed.options['months']) !== undefined ? { months: optNum(parsed.options['months']) } : {}),
|
|
105
|
+
...(carrier ? { carrierId: await resolveCarrier(ctx, carrier) } : {}),
|
|
106
|
+
});
|
|
107
|
+
if (optBool(parsed.options['csv']) && !ctx.globals.json) {
|
|
108
|
+
return emitCSV(ctx.io, res.data, ATTRITION_COLUMNS, optStr(parsed.options['output']), writeF);
|
|
109
|
+
}
|
|
110
|
+
return res.data;
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
path: ['report', 'data-quality'],
|
|
115
|
+
summary: 'Data-quality signals (ok/watch/alert) by carrier',
|
|
116
|
+
options: {
|
|
117
|
+
period: { type: 'string', desc: 'Period YYYY-MM (default latest)', placeholder: '<YYYY-MM>' },
|
|
118
|
+
},
|
|
119
|
+
async run(ctx, parsed) {
|
|
120
|
+
const period = optStr(parsed.options['period']);
|
|
121
|
+
if (period)
|
|
122
|
+
parsePeriod(period);
|
|
123
|
+
return ctx.client().dataQuality(period);
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
path: ['report', 'chargebacks'],
|
|
128
|
+
summary: 'Chargebacks for a period (with original payout)',
|
|
129
|
+
options: {
|
|
130
|
+
period: { type: 'string', desc: 'Period YYYY-MM', placeholder: '<YYYY-MM>' },
|
|
131
|
+
carrier: { type: 'string', desc: 'Filter by carrier', placeholder: '<c>' },
|
|
132
|
+
limit: { type: 'string', desc: 'Page size', placeholder: '<n>' },
|
|
133
|
+
offset: { type: 'string', desc: 'Offset', placeholder: '<n>' },
|
|
134
|
+
all: { type: 'boolean', desc: 'Auto-paginate all pages' },
|
|
135
|
+
csv: { type: 'boolean', desc: 'Emit rows as CSV' },
|
|
136
|
+
output: { type: 'string', short: 'o', desc: 'CSV output file', placeholder: '<file>' },
|
|
137
|
+
},
|
|
138
|
+
async run(ctx, parsed) {
|
|
139
|
+
const o = parsed.options;
|
|
140
|
+
const period = optStr(o['period']);
|
|
141
|
+
if (period)
|
|
142
|
+
parsePeriod(period);
|
|
143
|
+
const carrier = optStr(o['carrier']);
|
|
144
|
+
const base = {
|
|
145
|
+
...(period ? { period } : {}),
|
|
146
|
+
...(carrier ? { carrierId: await resolveCarrier(ctx, carrier) } : {}),
|
|
147
|
+
};
|
|
148
|
+
let rows;
|
|
149
|
+
if (optBool(o['all'])) {
|
|
150
|
+
const { items } = await collectOffset((p) => ctx.client().listChargebacks({ ...base, ...p }));
|
|
151
|
+
rows = items;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const res = await ctx.client().listChargebacks({
|
|
155
|
+
...base,
|
|
156
|
+
...(optNum(o['limit']) !== undefined ? { limit: optNum(o['limit']) } : {}),
|
|
157
|
+
...(optNum(o['offset']) !== undefined ? { offset: optNum(o['offset']) } : {}),
|
|
158
|
+
});
|
|
159
|
+
rows = res.data;
|
|
160
|
+
}
|
|
161
|
+
if (optBool(o['csv']) && !ctx.globals.json) {
|
|
162
|
+
return emitCSV(ctx.io, rows, CHARGEBACK_COLUMNS, optStr(o['output']), writeF);
|
|
163
|
+
}
|
|
164
|
+
return rows;
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { cover } from './registry.js';
|
|
2
|
+
export function sessionCommands() {
|
|
3
|
+
cover('me', 'cs whoami');
|
|
4
|
+
cover('health', 'cs health');
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
path: ['whoami'],
|
|
8
|
+
summary: 'Show the account behind the current token',
|
|
9
|
+
async run(ctx) {
|
|
10
|
+
return ctx.client().me();
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
path: ['health'],
|
|
15
|
+
summary: 'Liveness probe (no auth required)',
|
|
16
|
+
async run(ctx) {
|
|
17
|
+
return ctx.client().health();
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { cover } from './registry.js';
|
|
2
|
+
import { collectOffset } from '../lib/paginate.js';
|
|
3
|
+
import { confirmDestructive } from '../lib/confirm.js';
|
|
4
|
+
import { optStr, optBool, optNum } from '../util.js';
|
|
5
|
+
export function teamCommands() {
|
|
6
|
+
cover('listTeam', 'cs team list');
|
|
7
|
+
cover('inviteTeammate', 'cs team invite');
|
|
8
|
+
cover('removeTeammate', 'cs team remove');
|
|
9
|
+
cover('listAudit', 'cs audit list');
|
|
10
|
+
return [
|
|
11
|
+
{
|
|
12
|
+
path: ['team', 'list'],
|
|
13
|
+
summary: 'List account team members',
|
|
14
|
+
async run(ctx) {
|
|
15
|
+
return (await ctx.client().listTeam()).data;
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
path: ['team', 'invite'],
|
|
20
|
+
summary: 'Invite a teammate by email',
|
|
21
|
+
args: [{ name: 'email', required: true }],
|
|
22
|
+
async run(ctx, parsed) {
|
|
23
|
+
return ctx.client().inviteTeammate(parsed.args[0]);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
path: ['team', 'remove'],
|
|
28
|
+
summary: 'Remove a teammate (destructive)',
|
|
29
|
+
args: [{ name: 'userId', required: true }],
|
|
30
|
+
async run(ctx, parsed) {
|
|
31
|
+
await confirmDestructive(ctx, `remove teammate ${parsed.args[0]}`);
|
|
32
|
+
await ctx.client().removeTeammate(parsed.args[0]);
|
|
33
|
+
return { removed: parsed.args[0] };
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
path: ['audit', 'list'],
|
|
38
|
+
summary: 'Read the account audit trail (newest first)',
|
|
39
|
+
options: {
|
|
40
|
+
action: { type: 'string', desc: 'Filter by dotted action (e.g. file.upload)', placeholder: '<a>' },
|
|
41
|
+
limit: { type: 'string', desc: 'Page size', placeholder: '<n>' },
|
|
42
|
+
offset: { type: 'string', desc: 'Offset', placeholder: '<n>' },
|
|
43
|
+
all: { type: 'boolean', desc: 'Auto-paginate all pages' },
|
|
44
|
+
},
|
|
45
|
+
async run(ctx, parsed) {
|
|
46
|
+
const action = optStr(parsed.options['action']);
|
|
47
|
+
const base = action ? { action } : {};
|
|
48
|
+
if (optBool(parsed.options['all'])) {
|
|
49
|
+
const { items } = await collectOffset((p) => ctx.client().listAudit({ ...base, ...p }));
|
|
50
|
+
return items;
|
|
51
|
+
}
|
|
52
|
+
const page = await ctx.client().listAudit({
|
|
53
|
+
...base,
|
|
54
|
+
...(optNum(parsed.options['limit']) !== undefined ? { limit: optNum(parsed.options['limit']) } : {}),
|
|
55
|
+
...(optNum(parsed.options['offset']) !== undefined ? { offset: optNum(parsed.options['offset']) } : {}),
|
|
56
|
+
});
|
|
57
|
+
return page.data;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { Cmd } from '../types.js';
|
|
2
|
+
export declare const UPLOAD_OPTIONS: {
|
|
3
|
+
readonly carrier: {
|
|
4
|
+
readonly type: "string";
|
|
5
|
+
readonly desc: "Carrier id|slug|name (required)";
|
|
6
|
+
readonly placeholder: "<c>";
|
|
7
|
+
};
|
|
8
|
+
readonly period: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly desc: "Statement period YYYY-MM";
|
|
11
|
+
readonly placeholder: "<YYYY-MM>";
|
|
12
|
+
};
|
|
13
|
+
readonly year: {
|
|
14
|
+
readonly type: "string";
|
|
15
|
+
readonly desc: "Period year (with --month)";
|
|
16
|
+
readonly placeholder: "<n>";
|
|
17
|
+
};
|
|
18
|
+
readonly month: {
|
|
19
|
+
readonly type: "string";
|
|
20
|
+
readonly desc: "Period month (with --year)";
|
|
21
|
+
readonly placeholder: "<n>";
|
|
22
|
+
};
|
|
23
|
+
readonly workspace: {
|
|
24
|
+
readonly type: "string";
|
|
25
|
+
readonly desc: "Target workspace id|name";
|
|
26
|
+
readonly placeholder: "<w>";
|
|
27
|
+
};
|
|
28
|
+
readonly replace: {
|
|
29
|
+
readonly type: "boolean";
|
|
30
|
+
readonly desc: "Replace an existing carrier+period atomically";
|
|
31
|
+
};
|
|
32
|
+
readonly webhook: {
|
|
33
|
+
readonly type: "string";
|
|
34
|
+
readonly desc: "Webhook URL for job events";
|
|
35
|
+
readonly placeholder: "<url>";
|
|
36
|
+
};
|
|
37
|
+
readonly 'idempotency-key': {
|
|
38
|
+
readonly type: "string";
|
|
39
|
+
readonly desc: "Override the derived idempotency key";
|
|
40
|
+
readonly placeholder: "<k>";
|
|
41
|
+
};
|
|
42
|
+
readonly wait: {
|
|
43
|
+
readonly type: "boolean";
|
|
44
|
+
readonly desc: "Poll the job to a terminal state";
|
|
45
|
+
};
|
|
46
|
+
readonly timeout: {
|
|
47
|
+
readonly type: "string";
|
|
48
|
+
readonly desc: "Wait timeout seconds (default 300)";
|
|
49
|
+
readonly placeholder: "<s>";
|
|
50
|
+
};
|
|
51
|
+
readonly interval: {
|
|
52
|
+
readonly type: "string";
|
|
53
|
+
readonly desc: "Poll interval seconds (default 2)";
|
|
54
|
+
readonly placeholder: "<s>";
|
|
55
|
+
};
|
|
56
|
+
readonly results: {
|
|
57
|
+
readonly type: "boolean";
|
|
58
|
+
readonly desc: "Dump scored rows on completion (implies --wait)";
|
|
59
|
+
};
|
|
60
|
+
readonly status: {
|
|
61
|
+
readonly type: "string";
|
|
62
|
+
readonly desc: "Filter results by status";
|
|
63
|
+
readonly choices: readonly ["green", "yellow", "red"];
|
|
64
|
+
readonly placeholder: "<s>";
|
|
65
|
+
};
|
|
66
|
+
readonly 'owed-only': {
|
|
67
|
+
readonly type: "boolean";
|
|
68
|
+
readonly desc: "Only rows with commission owed";
|
|
69
|
+
};
|
|
70
|
+
readonly chargeback: {
|
|
71
|
+
readonly type: "boolean";
|
|
72
|
+
readonly desc: "Only chargeback rows";
|
|
73
|
+
};
|
|
74
|
+
readonly csv: {
|
|
75
|
+
readonly type: "boolean";
|
|
76
|
+
readonly desc: "Emit results as CSV (with --results)";
|
|
77
|
+
};
|
|
78
|
+
readonly output: {
|
|
79
|
+
readonly type: "string";
|
|
80
|
+
readonly short: "o";
|
|
81
|
+
readonly desc: "Write CSV to a file";
|
|
82
|
+
readonly placeholder: "<file>";
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
export declare function uploadCommands(): Cmd[];
|