@carrierllc/mcp 0.4.1 → 0.6.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/dist/{chunk-6OI56RSR.js → chunk-Y4JEN7M4.js} +77 -3
- package/dist/chunk-Y4JEN7M4.js.map +1 -0
- package/dist/cli.js +1706 -245
- package/dist/cli.js.map +1 -1
- package/dist/index.js +373 -87
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-6OI56RSR.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
verifyStorefront,
|
|
40
40
|
walletScreen,
|
|
41
41
|
which
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-Y4JEN7M4.js";
|
|
43
43
|
import {
|
|
44
44
|
copyTree,
|
|
45
45
|
exists,
|
|
@@ -94,6 +94,7 @@ function installedPluginDir() {
|
|
|
94
94
|
// src/cli/lib/urls.ts
|
|
95
95
|
import { spawn } from "child_process";
|
|
96
96
|
var MCP_URL = "https://mcp.carrier.llc/mcp";
|
|
97
|
+
var API_URL = "https://api.carrier.llc";
|
|
97
98
|
var MCP_HOME = "https://mcp.carrier.llc";
|
|
98
99
|
var SIGN_UP_URL = "https://accounts.carrier.llc/sign-up";
|
|
99
100
|
var SIGN_IN_URL = "https://accounts.carrier.llc/sign-in";
|
|
@@ -683,6 +684,9 @@ function isExpired(creds, skewMs = 6e4) {
|
|
|
683
684
|
if (!creds.expiresAt) return false;
|
|
684
685
|
return Date.now() >= creds.expiresAt - skewMs;
|
|
685
686
|
}
|
|
687
|
+
function redact(text3) {
|
|
688
|
+
return text3.replace(/\b(ak_|sk_|rt_)[A-Za-z0-9._-]{6,}/g, "$1***").replace(/\bBearer\s+[A-Za-z0-9._-]{8,}/gi, "Bearer ***");
|
|
689
|
+
}
|
|
686
690
|
|
|
687
691
|
// src/cli/lib/auth.ts
|
|
688
692
|
var DISCOVERY_PATH = "/.well-known/oauth-authorization-server";
|
|
@@ -2276,251 +2280,1633 @@ var CLI_DOMAINS = [
|
|
|
2276
2280
|
]
|
|
2277
2281
|
}
|
|
2278
2282
|
]
|
|
2279
|
-
}
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
if (!Number.isFinite(n)) return { error: `${opt.flags} expects a number, got "${String(raw)}"` };
|
|
2312
|
-
return { value: n };
|
|
2313
|
-
}
|
|
2314
|
-
return { value: String(raw) };
|
|
2315
|
-
}
|
|
2316
|
-
function buildToolArgs(cmd, opts) {
|
|
2317
|
-
const args = {};
|
|
2318
|
-
const errors = [];
|
|
2319
|
-
const notes = [];
|
|
2320
|
-
for (const opt of cmd.options) {
|
|
2321
|
-
const raw = opts[optionKey(opt.flags)];
|
|
2322
|
-
if (raw === void 0 || raw === false) {
|
|
2323
|
-
if (opt.required) errors.push(`Missing required ${opt.flags}`);
|
|
2324
|
-
continue;
|
|
2325
|
-
}
|
|
2326
|
-
const { value, error } = coerce(opt, raw);
|
|
2327
|
-
if (error) errors.push(error);
|
|
2328
|
-
else setArg(args, opt.arg, value);
|
|
2329
|
-
}
|
|
2330
|
-
if (cmd.requireOneOf && !cmd.requireOneOf.some((name) => args[name] !== void 0)) {
|
|
2331
|
-
const flags = cmd.options.filter((opt) => cmd.requireOneOf.includes(opt.arg)).map((opt) => opt.flags);
|
|
2332
|
-
errors.push(`Pass one of: ${flags.join(", ")}`);
|
|
2333
|
-
}
|
|
2334
|
-
if (cmd.usageWindow) {
|
|
2335
|
-
const start = args.startDate;
|
|
2336
|
-
const end = args.endDate;
|
|
2337
|
-
if (!start && !end) {
|
|
2338
|
-
const window = lastNDaysPeriod();
|
|
2339
|
-
args.startDate = window.start;
|
|
2340
|
-
args.endDate = window.end;
|
|
2341
|
-
notes.push(`Window defaulted to ${window.start} \u2026 ${window.end} (last ${OCS_MAX_USAGE_WINDOW_DAYS} days).`);
|
|
2342
|
-
} else if (!start || !end) {
|
|
2343
|
-
errors.push("Pass both --start and --end, or neither for the last 7 days");
|
|
2344
|
-
} else {
|
|
2345
|
-
const clamped = clampUsagePeriod(start, end);
|
|
2346
|
-
if (clamped.start !== start) {
|
|
2347
|
-
notes.push(
|
|
2348
|
-
`Start moved to ${clamped.start} \u2014 OCS rejects windows wider than ${OCS_MAX_USAGE_WINDOW_DAYS} days.`
|
|
2349
|
-
);
|
|
2283
|
+
},
|
|
2284
|
+
{
|
|
2285
|
+
name: "api-keys",
|
|
2286
|
+
summary: "Mint Carrier API keys (ak_\u2026) for headless and CI use",
|
|
2287
|
+
commands: [
|
|
2288
|
+
{
|
|
2289
|
+
name: "create",
|
|
2290
|
+
transport: "rest",
|
|
2291
|
+
restMethod: "POST",
|
|
2292
|
+
restPath: "/v1/api-keys",
|
|
2293
|
+
summary: "Create an org API key. The secret is shown once and never stored by the CLI.",
|
|
2294
|
+
options: [
|
|
2295
|
+
{
|
|
2296
|
+
flags: "--name <name>",
|
|
2297
|
+
description: "Label for the key, max 64 characters",
|
|
2298
|
+
arg: "name",
|
|
2299
|
+
type: "string",
|
|
2300
|
+
required: true
|
|
2301
|
+
},
|
|
2302
|
+
{
|
|
2303
|
+
flags: "--description <text>",
|
|
2304
|
+
description: "Optional note, max 256 characters",
|
|
2305
|
+
arg: "description",
|
|
2306
|
+
type: "string"
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
flags: "--seconds-until-expiration <n>",
|
|
2310
|
+
description: "Expiry in seconds, 60 to 31536000. Omit for a key that does not expire.",
|
|
2311
|
+
arg: "secondsUntilExpiration",
|
|
2312
|
+
type: "number"
|
|
2313
|
+
}
|
|
2314
|
+
]
|
|
2350
2315
|
}
|
|
2351
|
-
args.startDate = clamped.start;
|
|
2352
|
-
args.endDate = clamped.end;
|
|
2353
|
-
}
|
|
2354
|
-
}
|
|
2355
|
-
if (cmd.write) args.dry_run = true;
|
|
2356
|
-
return { args, errors, notes };
|
|
2357
|
-
}
|
|
2358
|
-
function formatJsonOutput(text3) {
|
|
2359
|
-
try {
|
|
2360
|
-
JSON.parse(text3);
|
|
2361
|
-
return text3;
|
|
2362
|
-
} catch {
|
|
2363
|
-
return JSON.stringify(text3);
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
async function runCapability(domain, cmd, opts) {
|
|
2367
|
-
const label = `${domain.name} ${cmd.name}`;
|
|
2368
|
-
const quiet = opts.json === true;
|
|
2369
|
-
const { args, errors, notes } = buildToolArgs(cmd, opts);
|
|
2370
|
-
if (cmd.write && opts.commit === true) delete args.dry_run;
|
|
2371
|
-
if (errors.length) {
|
|
2372
|
-
const message = withNextStep(`Cannot run \`carrier ${label}\`.`, [
|
|
2373
|
-
...errors,
|
|
2374
|
-
`See every flag: carrier ${label} --help`
|
|
2375
|
-
]);
|
|
2376
|
-
if (quiet) console.error(message);
|
|
2377
|
-
else p2.log.error(message);
|
|
2378
|
-
process.exitCode = 1;
|
|
2379
|
-
return;
|
|
2380
|
-
}
|
|
2381
|
-
const dryRun = cmd.write === true && args.dry_run === true;
|
|
2382
|
-
const warnings = dryRun ? [...notes, "Dry run \u2014 nothing changes. Re-run with --commit to apply."] : notes;
|
|
2383
|
-
for (const note4 of warnings) {
|
|
2384
|
-
if (quiet) console.error(note4);
|
|
2385
|
-
else p2.log.info(pc3.dim(note4));
|
|
2386
|
-
}
|
|
2387
|
-
const s = quiet ? null : p2.spinner();
|
|
2388
|
-
s?.start(`Calling ${cmd.tool}`);
|
|
2389
|
-
const result = await callMcpTool(cmd.tool, args, {
|
|
2390
|
-
errorHints: [
|
|
2391
|
-
`Check the arguments: carrier ${label} --help`,
|
|
2392
|
-
'Or describe the task in words: carrier ask "\u2026"'
|
|
2393
2316
|
]
|
|
2394
|
-
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
}
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2317
|
+
},
|
|
2318
|
+
// <generated:catalog-domains>
|
|
2319
|
+
// Generated from the MCP catalog by scripts/generate-domains.mjs. Do not edit by hand:
|
|
2320
|
+
// rebuild the server, re-run the generator, and review the diff.
|
|
2321
|
+
{
|
|
2322
|
+
name: "billing",
|
|
2323
|
+
summary: "Carrier plan credits, spend thresholds and rate-limit state",
|
|
2324
|
+
commands: [
|
|
2325
|
+
{
|
|
2326
|
+
name: "events",
|
|
2327
|
+
tool: "billing_events",
|
|
2328
|
+
summary: "View recent billing threshold events: notifications, invoice triggers, hard cap alerts, and overage pauses.",
|
|
2329
|
+
options: [
|
|
2330
|
+
{
|
|
2331
|
+
flags: "--limit <n>",
|
|
2332
|
+
description: "Maximum number of events to return (default: 20, max: 50).",
|
|
2333
|
+
arg: "limit",
|
|
2334
|
+
type: "number"
|
|
2335
|
+
}
|
|
2336
|
+
]
|
|
2337
|
+
},
|
|
2338
|
+
{
|
|
2339
|
+
name: "configure",
|
|
2340
|
+
tool: "configure_billing",
|
|
2341
|
+
summary: "Configure your billing preferences: enable/disable overages, set billing thresholds (bill shock prevention), configure notification percentages, and set hard spending caps.",
|
|
2342
|
+
requireConfirm: true,
|
|
2343
|
+
options: [
|
|
2344
|
+
{
|
|
2345
|
+
flags: "--overages-enabled <bool>",
|
|
2346
|
+
description: "Enable or disable auto-billed overages when monthly credits are exhausted.",
|
|
2347
|
+
arg: "overages_enabled",
|
|
2348
|
+
type: "boolean"
|
|
2349
|
+
},
|
|
2350
|
+
{
|
|
2351
|
+
flags: "--billing-threshold-cents <n>",
|
|
2352
|
+
description: "Amount in cents at which an invoice is automatically generated (e.g., 10000 = $100).",
|
|
2353
|
+
arg: "billing_threshold_cents",
|
|
2354
|
+
type: "number"
|
|
2355
|
+
},
|
|
2356
|
+
{
|
|
2357
|
+
flags: "--hard-cap-cents <n>",
|
|
2358
|
+
description: "Maximum overage spend in cents before overages are paused (0 = no cap).",
|
|
2359
|
+
arg: "hard_cap_cents",
|
|
2360
|
+
type: "number"
|
|
2361
|
+
},
|
|
2362
|
+
{
|
|
2363
|
+
flags: "--auto-pause-on-cap <bool>",
|
|
2364
|
+
description: "Whether to automatically pause overages when hard cap is reached.",
|
|
2365
|
+
arg: "auto_pause_on_cap",
|
|
2366
|
+
type: "boolean"
|
|
2367
|
+
},
|
|
2368
|
+
{
|
|
2369
|
+
flags: "--notify-at-pct <list>",
|
|
2370
|
+
description: "Percentage thresholds at which to send notifications (e.g., [50, 80, 95, 100]). Comma-separated.",
|
|
2371
|
+
arg: "notify_at_pct",
|
|
2372
|
+
type: "number[]"
|
|
2373
|
+
},
|
|
2374
|
+
{
|
|
2375
|
+
flags: "--notification-email <email>",
|
|
2376
|
+
description: "Email address for billing threshold notifications.",
|
|
2377
|
+
arg: "notification_email",
|
|
2378
|
+
type: "string"
|
|
2379
|
+
},
|
|
2380
|
+
{
|
|
2381
|
+
flags: "--notification-phone <phone>",
|
|
2382
|
+
description: "E.164 phone number for SMS billing threshold notifications via Twilio (e.g. +14155552671).",
|
|
2383
|
+
arg: "notification_phone",
|
|
2384
|
+
type: "string"
|
|
2385
|
+
},
|
|
2386
|
+
{
|
|
2387
|
+
flags: "--webhook-url <url>",
|
|
2388
|
+
description: "Webhook URL for billing threshold events.",
|
|
2389
|
+
arg: "webhook_url",
|
|
2390
|
+
type: "string"
|
|
2391
|
+
}
|
|
2392
|
+
]
|
|
2393
|
+
},
|
|
2394
|
+
{
|
|
2395
|
+
name: "credits",
|
|
2396
|
+
tool: "credit_balance",
|
|
2397
|
+
summary: "Read how much of this Carrier MCP plan is left: credits remaining, daily free credits, overage state, volume discount tier, and billing threshold state.",
|
|
2398
|
+
options: []
|
|
2399
|
+
},
|
|
2400
|
+
{
|
|
2401
|
+
name: "plans",
|
|
2402
|
+
tool: "pricing_plans",
|
|
2403
|
+
summary: "View all available Carrier MCP pricing plans with credit allotments, features, overage rates, and volume discount tiers.",
|
|
2404
|
+
options: []
|
|
2405
|
+
},
|
|
2406
|
+
{
|
|
2407
|
+
name: "projection",
|
|
2408
|
+
tool: "usage_projection",
|
|
2409
|
+
summary: "Project your credit usage and costs for the remainder of the billing period based on current consumption rate.",
|
|
2410
|
+
options: [
|
|
2411
|
+
{
|
|
2412
|
+
flags: "--days-to-project <n>",
|
|
2413
|
+
description: "Number of days to project forward (default: remaining days in month).",
|
|
2414
|
+
arg: "days_to_project",
|
|
2415
|
+
type: "number"
|
|
2416
|
+
}
|
|
2417
|
+
]
|
|
2418
|
+
},
|
|
2419
|
+
{
|
|
2420
|
+
name: "rate-limit",
|
|
2421
|
+
tool: "rate_limit_status",
|
|
2422
|
+
summary: "Inspect Bridge4IP OCS rate-limit governor state \u2014 bucket fill levels, per-endpoint limits, and 80% alert thresholds.",
|
|
2423
|
+
options: [
|
|
2424
|
+
{
|
|
2425
|
+
flags: "--endpoint <endpoint>",
|
|
2426
|
+
description: "OCS method name in camelCase (e.g. 'subscriberUsageOverPeriod').",
|
|
2427
|
+
arg: "endpoint",
|
|
2428
|
+
type: "string"
|
|
2429
|
+
}
|
|
2430
|
+
]
|
|
2431
|
+
}
|
|
2432
|
+
]
|
|
2433
|
+
},
|
|
2434
|
+
{
|
|
2435
|
+
name: "wallet",
|
|
2436
|
+
summary: "The Carrier prepaid wallet: balance and top-ups",
|
|
2437
|
+
commands: [
|
|
2438
|
+
{
|
|
2439
|
+
name: "balance",
|
|
2440
|
+
tool: "wallet_balance",
|
|
2441
|
+
summary: "Read the caller organisation's Carrier prepaid wallet: current balance and auto-top-up settings.",
|
|
2442
|
+
options: []
|
|
2443
|
+
},
|
|
2444
|
+
{
|
|
2445
|
+
name: "topup",
|
|
2446
|
+
tool: "wallet_topup_checkout",
|
|
2447
|
+
summary: "Create a Stripe Checkout link so a human can top up the Carrier prepaid wallet by card.",
|
|
2448
|
+
options: [
|
|
2449
|
+
{
|
|
2450
|
+
flags: "--pack <pack>",
|
|
2451
|
+
description: "Pack id (pack_500/pack_1000/pack_2500/pack_5000) or exact EUR-cents amount.",
|
|
2452
|
+
arg: "pack",
|
|
2453
|
+
type: "string"
|
|
2454
|
+
}
|
|
2455
|
+
]
|
|
2456
|
+
},
|
|
2457
|
+
{
|
|
2458
|
+
name: "auto-topup",
|
|
2459
|
+
tool: "wallet_auto_topup",
|
|
2460
|
+
summary: "Charge the organisation's saved card off-session, right now, and credit the Carrier prepaid wallet with the pack.",
|
|
2461
|
+
requireConfirm: true,
|
|
2462
|
+
options: [
|
|
2463
|
+
{
|
|
2464
|
+
flags: "--pack-cents <n>",
|
|
2465
|
+
description: "Override pack amount in EUR cents (must match a catalog pack).",
|
|
2466
|
+
arg: "pack_cents",
|
|
2467
|
+
type: "number"
|
|
2468
|
+
}
|
|
2469
|
+
]
|
|
2470
|
+
}
|
|
2471
|
+
]
|
|
2472
|
+
},
|
|
2473
|
+
{
|
|
2474
|
+
name: "stripe",
|
|
2475
|
+
summary: "Money in the operator's connected Stripe account",
|
|
2476
|
+
commands: [
|
|
2477
|
+
{
|
|
2478
|
+
name: "balance",
|
|
2479
|
+
tool: "stripe_connect_balance",
|
|
2480
|
+
summary: "Read the money sitting in the operator's connected Stripe account: available and pending, split per currency.",
|
|
2481
|
+
options: []
|
|
2482
|
+
},
|
|
2483
|
+
{
|
|
2484
|
+
name: "payouts",
|
|
2485
|
+
tool: "stripe_connect_payouts",
|
|
2486
|
+
summary: "List money Stripe has already sent from the operator's connected account to their bank, newest first.",
|
|
2487
|
+
options: [
|
|
2488
|
+
{
|
|
2489
|
+
flags: "--limit <n>",
|
|
2490
|
+
description: "Number of payouts to return. Default 10.",
|
|
2491
|
+
arg: "limit",
|
|
2492
|
+
type: "number"
|
|
2493
|
+
},
|
|
2494
|
+
{
|
|
2495
|
+
flags: "--status <status>",
|
|
2496
|
+
description: "Filter by payout status. One of: pending, paid, failed, canceled, in_transit.",
|
|
2497
|
+
arg: "status",
|
|
2498
|
+
type: "string"
|
|
2499
|
+
}
|
|
2500
|
+
]
|
|
2501
|
+
},
|
|
2502
|
+
{
|
|
2503
|
+
name: "disputes",
|
|
2504
|
+
tool: "stripe_connect_dispute_list",
|
|
2505
|
+
summary: "List chargebacks customers have raised with their bank against the operator's connected Stripe account.",
|
|
2506
|
+
options: [
|
|
2507
|
+
{
|
|
2508
|
+
flags: "--limit <n>",
|
|
2509
|
+
description: "limit (number). Default 10.",
|
|
2510
|
+
arg: "limit",
|
|
2511
|
+
type: "number"
|
|
2512
|
+
},
|
|
2513
|
+
{
|
|
2514
|
+
flags: "--status <status>",
|
|
2515
|
+
description: "Filter by dispute status (e.g. needs_response, under_review).",
|
|
2516
|
+
arg: "status",
|
|
2517
|
+
type: "string"
|
|
2518
|
+
}
|
|
2519
|
+
]
|
|
2520
|
+
},
|
|
2521
|
+
{
|
|
2522
|
+
name: "refund",
|
|
2523
|
+
tool: "stripe_connect_refund",
|
|
2524
|
+
summary: "Refund money to a customer on one charge in the operator's connected Stripe account.",
|
|
2525
|
+
options: [
|
|
2526
|
+
{
|
|
2527
|
+
flags: "--charge-id <id>",
|
|
2528
|
+
description: "Stripe charge ID (ch_...).",
|
|
2529
|
+
arg: "charge_id",
|
|
2530
|
+
type: "string",
|
|
2531
|
+
required: true
|
|
2532
|
+
},
|
|
2533
|
+
{
|
|
2534
|
+
flags: "--amount-cents <n>",
|
|
2535
|
+
description: "Partial refund amount in cents.",
|
|
2536
|
+
arg: "amount_cents",
|
|
2537
|
+
type: "number"
|
|
2538
|
+
},
|
|
2539
|
+
{
|
|
2540
|
+
flags: "--reason <reason>",
|
|
2541
|
+
description: "reason (string). One of: duplicate, fraudulent, requested_by_customer.",
|
|
2542
|
+
arg: "reason",
|
|
2543
|
+
type: "string"
|
|
2544
|
+
},
|
|
2545
|
+
{
|
|
2546
|
+
flags: "--confirm-token <token>",
|
|
2547
|
+
description: "Confirmation token from previous call.",
|
|
2548
|
+
arg: "confirm_token",
|
|
2549
|
+
type: "string"
|
|
2550
|
+
}
|
|
2551
|
+
]
|
|
2552
|
+
}
|
|
2553
|
+
]
|
|
2554
|
+
},
|
|
2555
|
+
{
|
|
2556
|
+
name: "radar",
|
|
2557
|
+
summary: "Stripe Radar fraud reviews and value lists",
|
|
2558
|
+
commands: [
|
|
2559
|
+
{
|
|
2560
|
+
name: "reviews",
|
|
2561
|
+
tool: "radar_review_list",
|
|
2562
|
+
summary: "List the Stripe Radar fraud reviews waiting on a manual approve/decline decision, newest first.",
|
|
2563
|
+
options: [
|
|
2564
|
+
{
|
|
2565
|
+
flags: "--open-only <bool>",
|
|
2566
|
+
description: "If true, only returns open (undecided) reviews. Default true.",
|
|
2567
|
+
arg: "open_only",
|
|
2568
|
+
type: "boolean"
|
|
2569
|
+
},
|
|
2570
|
+
{
|
|
2571
|
+
flags: "--limit <n>",
|
|
2572
|
+
description: "limit (number). Default 10.",
|
|
2573
|
+
arg: "limit",
|
|
2574
|
+
type: "number"
|
|
2575
|
+
}
|
|
2576
|
+
]
|
|
2577
|
+
},
|
|
2578
|
+
{
|
|
2579
|
+
name: "approve",
|
|
2580
|
+
tool: "radar_review_approve",
|
|
2581
|
+
summary: "Clear a Stripe Radar fraud review so the held charge is captured and the money is taken.",
|
|
2582
|
+
options: [
|
|
2583
|
+
{
|
|
2584
|
+
flags: "--review-id <id>",
|
|
2585
|
+
description: "Stripe Radar review ID (prv_...).",
|
|
2586
|
+
arg: "review_id",
|
|
2587
|
+
type: "string",
|
|
2588
|
+
required: true
|
|
2589
|
+
},
|
|
2590
|
+
{
|
|
2591
|
+
flags: "--confirm-token <token>",
|
|
2592
|
+
description: "confirm token (string).",
|
|
2593
|
+
arg: "confirm_token",
|
|
2594
|
+
type: "string"
|
|
2595
|
+
}
|
|
2596
|
+
]
|
|
2597
|
+
},
|
|
2598
|
+
{
|
|
2599
|
+
name: "decline",
|
|
2600
|
+
tool: "radar_review_decline",
|
|
2601
|
+
summary: "Close a Stripe Radar fraud review as fraudulent, so the held charge is blocked and the customer is never billed.",
|
|
2602
|
+
options: [
|
|
2603
|
+
{
|
|
2604
|
+
flags: "--review-id <id>",
|
|
2605
|
+
description: "review id (string).",
|
|
2606
|
+
arg: "review_id",
|
|
2607
|
+
type: "string",
|
|
2608
|
+
required: true
|
|
2609
|
+
},
|
|
2610
|
+
{
|
|
2611
|
+
flags: "--confirm-token <token>",
|
|
2612
|
+
description: "confirm token (string).",
|
|
2613
|
+
arg: "confirm_token",
|
|
2614
|
+
type: "string"
|
|
2615
|
+
}
|
|
2616
|
+
]
|
|
2617
|
+
},
|
|
2618
|
+
{
|
|
2619
|
+
name: "rule-toggle",
|
|
2620
|
+
tool: "radar_rule_toggle",
|
|
2621
|
+
summary: "Report a Stripe Radar rule's state. Stripe exposes no API to change it, so this changes nothing.",
|
|
2622
|
+
options: [
|
|
2623
|
+
{
|
|
2624
|
+
flags: "--rule-id <id>",
|
|
2625
|
+
description: "Stripe Radar rule ID.",
|
|
2626
|
+
arg: "rule_id",
|
|
2627
|
+
type: "string",
|
|
2628
|
+
required: true
|
|
2629
|
+
},
|
|
2630
|
+
{
|
|
2631
|
+
flags: "--enabled <bool>",
|
|
2632
|
+
description: "true = enable, false = disable.",
|
|
2633
|
+
arg: "enabled",
|
|
2634
|
+
type: "boolean",
|
|
2635
|
+
required: true
|
|
2636
|
+
}
|
|
2637
|
+
]
|
|
2638
|
+
},
|
|
2639
|
+
{
|
|
2640
|
+
name: "value-list add",
|
|
2641
|
+
tool: "radar_value_list_add",
|
|
2642
|
+
summary: "Add one value to an existing Stripe Radar value list, changing how every future charge is scored.",
|
|
2643
|
+
options: [
|
|
2644
|
+
{
|
|
2645
|
+
flags: "--value-list-id <id>",
|
|
2646
|
+
description: "Stripe Radar value list ID (rsl_...).",
|
|
2647
|
+
arg: "value_list_id",
|
|
2648
|
+
type: "string",
|
|
2649
|
+
required: true
|
|
2650
|
+
},
|
|
2651
|
+
{
|
|
2652
|
+
flags: "--value <value>",
|
|
2653
|
+
description: "The value to add (email, IP address, country code, etc.).",
|
|
2654
|
+
arg: "value",
|
|
2655
|
+
type: "string",
|
|
2656
|
+
required: true
|
|
2657
|
+
},
|
|
2658
|
+
{
|
|
2659
|
+
flags: "--confirm-token <token>",
|
|
2660
|
+
description: "confirm token (string).",
|
|
2661
|
+
arg: "confirm_token",
|
|
2662
|
+
type: "string"
|
|
2663
|
+
}
|
|
2664
|
+
]
|
|
2665
|
+
}
|
|
2666
|
+
]
|
|
2667
|
+
},
|
|
2668
|
+
{
|
|
2669
|
+
name: "greenzone",
|
|
2670
|
+
summary: "The Bridge4IP Greenzone whitelist",
|
|
2671
|
+
commands: [
|
|
2672
|
+
{
|
|
2673
|
+
name: "list",
|
|
2674
|
+
tool: "greenzone_whitelist_list",
|
|
2675
|
+
summary: "List current Greenzone whitelist entries from the KV cache.",
|
|
2676
|
+
options: [
|
|
2677
|
+
{
|
|
2678
|
+
flags: "--from-portal <bool>",
|
|
2679
|
+
description: "When true, return Kapture steps to read live portal state instead of KV cache.",
|
|
2680
|
+
arg: "from_portal",
|
|
2681
|
+
type: "boolean"
|
|
2682
|
+
}
|
|
2683
|
+
]
|
|
2684
|
+
},
|
|
2685
|
+
{
|
|
2686
|
+
name: "add",
|
|
2687
|
+
tool: "greenzone_whitelist_add",
|
|
2688
|
+
summary: "Add a host or IP to the Greenzone whitelist. Needs Kapture running in the operator's own Chrome \u2014 without it the dry run still returns the portal steps to follow by hand.",
|
|
2689
|
+
write: true,
|
|
2690
|
+
options: [
|
|
2691
|
+
{
|
|
2692
|
+
flags: "--host <host>",
|
|
2693
|
+
description: "Hostname to whitelist (e.g. 'example.com').",
|
|
2694
|
+
arg: "host",
|
|
2695
|
+
type: "string"
|
|
2696
|
+
},
|
|
2697
|
+
{
|
|
2698
|
+
flags: "--ip <ip>",
|
|
2699
|
+
description: "IP address or CIDR to whitelist (e.g. '203.0.113.0/24').",
|
|
2700
|
+
arg: "ip",
|
|
2701
|
+
type: "string"
|
|
2702
|
+
}
|
|
2703
|
+
]
|
|
2704
|
+
},
|
|
2705
|
+
{
|
|
2706
|
+
name: "remove",
|
|
2707
|
+
tool: "greenzone_whitelist_remove",
|
|
2708
|
+
summary: "Remove a host or IP from the Greenzone whitelist. Needs Kapture running in the operator's own Chrome \u2014 without it the dry run still returns the portal steps to follow by hand.",
|
|
2709
|
+
write: true,
|
|
2710
|
+
options: [
|
|
2711
|
+
{
|
|
2712
|
+
flags: "--host <host>",
|
|
2713
|
+
description: "Hostname to remove from whitelist.",
|
|
2714
|
+
arg: "host",
|
|
2715
|
+
type: "string"
|
|
2716
|
+
},
|
|
2717
|
+
{
|
|
2718
|
+
flags: "--ip <ip>",
|
|
2719
|
+
description: "IP address or CIDR to remove from whitelist.",
|
|
2720
|
+
arg: "ip",
|
|
2721
|
+
type: "string"
|
|
2722
|
+
}
|
|
2723
|
+
]
|
|
2724
|
+
}
|
|
2725
|
+
]
|
|
2726
|
+
},
|
|
2727
|
+
{
|
|
2728
|
+
name: "agent",
|
|
2729
|
+
summary: "Steel browsing agents: one-off tasks and cron schedules",
|
|
2730
|
+
commands: [
|
|
2731
|
+
{
|
|
2732
|
+
name: "ask",
|
|
2733
|
+
tool: "ui_agent_ask",
|
|
2734
|
+
summary: "Send a plain-language task to a Steel browsing agent, which drives a real browser on the open web \u2014 navigating pages, searching via Tavily, extracting content, filling forms outside the OCS portal.",
|
|
2735
|
+
write: true,
|
|
2736
|
+
options: [
|
|
2737
|
+
{
|
|
2738
|
+
flags: "--prompt <prompt>",
|
|
2739
|
+
description: "Natural-language task description for the Steel browsing agent.",
|
|
2740
|
+
arg: "prompt",
|
|
2741
|
+
type: "string",
|
|
2742
|
+
required: true
|
|
2743
|
+
},
|
|
2744
|
+
{
|
|
2745
|
+
flags: "--max-steps <n>",
|
|
2746
|
+
description: "Maximum agent steps (1\u201330, default 15).",
|
|
2747
|
+
arg: "max_steps",
|
|
2748
|
+
type: "number"
|
|
2749
|
+
}
|
|
2750
|
+
]
|
|
2751
|
+
},
|
|
2752
|
+
{
|
|
2753
|
+
name: "status",
|
|
2754
|
+
tool: "ui_agent_status",
|
|
2755
|
+
summary: "Poll the status of a Steel browser agent task dispatched by ui_agent_ask or any ui_* tool.",
|
|
2756
|
+
options: [
|
|
2757
|
+
{
|
|
2758
|
+
flags: "--task-id <id>",
|
|
2759
|
+
description: "Steel task ID returned by ui_agent_ask or any ui_* tool dispatch.",
|
|
2760
|
+
arg: "task_id",
|
|
2761
|
+
type: "string",
|
|
2762
|
+
required: true
|
|
2763
|
+
}
|
|
2764
|
+
]
|
|
2765
|
+
},
|
|
2766
|
+
{
|
|
2767
|
+
name: "pending",
|
|
2768
|
+
tool: "ui_agent_list_pending",
|
|
2769
|
+
summary: "Returns all Steel browser automation tasks that are currently paused waiting for human input (stop_reason 'ask').",
|
|
2770
|
+
options: []
|
|
2771
|
+
},
|
|
2772
|
+
{
|
|
2773
|
+
name: "reply",
|
|
2774
|
+
tool: "ui_agent_reply",
|
|
2775
|
+
summary: "Resumes a Steel browser automation task that paused with stop_reason 'ask'.",
|
|
2776
|
+
options: [
|
|
2777
|
+
{
|
|
2778
|
+
flags: "--task-id <id>",
|
|
2779
|
+
description: "Steel task ID to resume (from ui_agent_list_pending).",
|
|
2780
|
+
arg: "task_id",
|
|
2781
|
+
type: "string",
|
|
2782
|
+
required: true
|
|
2783
|
+
},
|
|
2784
|
+
{
|
|
2785
|
+
flags: "--reply <reply>",
|
|
2786
|
+
description: "Your answer to the agent's question (e.g. a 2FA code or confirmation).",
|
|
2787
|
+
arg: "reply",
|
|
2788
|
+
type: "string",
|
|
2789
|
+
required: true
|
|
2790
|
+
}
|
|
2791
|
+
]
|
|
2792
|
+
},
|
|
2793
|
+
{
|
|
2794
|
+
name: "usage",
|
|
2795
|
+
tool: "ui_agent_usage",
|
|
2796
|
+
summary: "Returns an estimated Anthropic API cost for Steel agent tasks dispatched this calendar month.",
|
|
2797
|
+
options: []
|
|
2798
|
+
},
|
|
2799
|
+
{
|
|
2800
|
+
name: "schedule list",
|
|
2801
|
+
tool: "ui_agent_schedule_list",
|
|
2802
|
+
summary: "Lists all Steel recurring schedules stored in KV.",
|
|
2803
|
+
options: []
|
|
2804
|
+
},
|
|
2805
|
+
{
|
|
2806
|
+
name: "schedule create",
|
|
2807
|
+
tool: "ui_agent_schedule_create",
|
|
2808
|
+
summary: "Creates a recurring Steel agent run on a cron schedule.",
|
|
2809
|
+
requireConfirm: true,
|
|
2810
|
+
options: [
|
|
2811
|
+
{
|
|
2812
|
+
flags: "--name <name>",
|
|
2813
|
+
description: "Human-readable name for this schedule.",
|
|
2814
|
+
arg: "name",
|
|
2815
|
+
type: "string",
|
|
2816
|
+
required: true
|
|
2817
|
+
},
|
|
2818
|
+
{
|
|
2819
|
+
flags: "--cron <cron>",
|
|
2820
|
+
description: "Standard 5-field cron expression (minute hour day month weekday).",
|
|
2821
|
+
arg: "cron",
|
|
2822
|
+
type: "string",
|
|
2823
|
+
required: true
|
|
2824
|
+
},
|
|
2825
|
+
{
|
|
2826
|
+
flags: "--prompt-template <template>",
|
|
2827
|
+
description: "Agent prompt/task template the Steel agent will execute on each run.",
|
|
2828
|
+
arg: "prompt_template",
|
|
2829
|
+
type: "string",
|
|
2830
|
+
required: true
|
|
2831
|
+
}
|
|
2832
|
+
]
|
|
2833
|
+
},
|
|
2834
|
+
{
|
|
2835
|
+
name: "schedule pause",
|
|
2836
|
+
tool: "ui_agent_schedule_pause",
|
|
2837
|
+
summary: "Pauses an active Steel recurring schedule.",
|
|
2838
|
+
requireConfirm: true,
|
|
2839
|
+
options: [
|
|
2840
|
+
{
|
|
2841
|
+
flags: "--schedule-id <id>",
|
|
2842
|
+
description: "ID of the schedule to pause.",
|
|
2843
|
+
arg: "schedule_id",
|
|
2844
|
+
type: "string",
|
|
2845
|
+
required: true
|
|
2846
|
+
}
|
|
2847
|
+
]
|
|
2848
|
+
},
|
|
2849
|
+
{
|
|
2850
|
+
name: "schedule resume",
|
|
2851
|
+
tool: "ui_agent_schedule_resume",
|
|
2852
|
+
summary: "Resumes a paused Steel recurring schedule.",
|
|
2853
|
+
requireConfirm: true,
|
|
2854
|
+
options: [
|
|
2855
|
+
{
|
|
2856
|
+
flags: "--schedule-id <id>",
|
|
2857
|
+
description: "ID of the schedule to resume.",
|
|
2858
|
+
arg: "schedule_id",
|
|
2859
|
+
type: "string",
|
|
2860
|
+
required: true
|
|
2861
|
+
}
|
|
2862
|
+
]
|
|
2863
|
+
},
|
|
2864
|
+
{
|
|
2865
|
+
name: "schedule delete",
|
|
2866
|
+
tool: "ui_agent_schedule_delete",
|
|
2867
|
+
summary: "Permanently deletes a Steel recurring schedule.",
|
|
2868
|
+
requireConfirm: true,
|
|
2869
|
+
options: [
|
|
2870
|
+
{
|
|
2871
|
+
flags: "--schedule-id <id>",
|
|
2872
|
+
description: "ID of the schedule to delete.",
|
|
2873
|
+
arg: "schedule_id",
|
|
2874
|
+
type: "string",
|
|
2875
|
+
required: true
|
|
2876
|
+
}
|
|
2877
|
+
]
|
|
2878
|
+
}
|
|
2879
|
+
]
|
|
2880
|
+
},
|
|
2881
|
+
{
|
|
2882
|
+
name: "portal",
|
|
2883
|
+
summary: "OCS portal changes that only exist in the web UI, driven by Kapture",
|
|
2884
|
+
commands: [
|
|
2885
|
+
{
|
|
2886
|
+
name: "account create",
|
|
2887
|
+
tool: "ui_create_account",
|
|
2888
|
+
summary: "Creates a new sub-account under the reseller via the OCS web dashboard.",
|
|
2889
|
+
write: true,
|
|
2890
|
+
options: [
|
|
2891
|
+
{
|
|
2892
|
+
flags: "--name <name>",
|
|
2893
|
+
description: "Name for the new account.",
|
|
2894
|
+
arg: "name",
|
|
2895
|
+
type: "string",
|
|
2896
|
+
required: true
|
|
2897
|
+
},
|
|
2898
|
+
{
|
|
2899
|
+
flags: "--description <description>",
|
|
2900
|
+
description: "Optional description.",
|
|
2901
|
+
arg: "description",
|
|
2902
|
+
type: "string"
|
|
2903
|
+
},
|
|
2904
|
+
{
|
|
2905
|
+
flags: "--initial-balance <n>",
|
|
2906
|
+
description: "Initial balance in account currency (default 0).",
|
|
2907
|
+
arg: "initial_balance",
|
|
2908
|
+
type: "number"
|
|
2909
|
+
}
|
|
2910
|
+
]
|
|
2911
|
+
},
|
|
2912
|
+
{
|
|
2913
|
+
name: "steering build",
|
|
2914
|
+
tool: "ui_build_steering_list",
|
|
2915
|
+
summary: "Change which mobile operators sit on a steering list that already exists, by driving the OCS web dashboard \u2014 the OCS REST API cannot edit list membership.",
|
|
2916
|
+
write: true,
|
|
2917
|
+
options: [
|
|
2918
|
+
{
|
|
2919
|
+
flags: "--steering-list-id <n>",
|
|
2920
|
+
description: "ID of the steering list to modify.",
|
|
2921
|
+
arg: "steering_list_id",
|
|
2922
|
+
type: "number",
|
|
2923
|
+
required: true
|
|
2924
|
+
},
|
|
2925
|
+
{
|
|
2926
|
+
flags: "--add-operators <list>",
|
|
2927
|
+
description: "MCC-MNC codes to add (e.g. ['20801', '26201']). Comma-separated.",
|
|
2928
|
+
arg: "add_operators",
|
|
2929
|
+
type: "string[]"
|
|
2930
|
+
},
|
|
2931
|
+
{
|
|
2932
|
+
flags: "--remove-operators <list>",
|
|
2933
|
+
description: "MCC-MNC codes to remove. Comma-separated.",
|
|
2934
|
+
arg: "remove_operators",
|
|
2935
|
+
type: "string[]"
|
|
2936
|
+
},
|
|
2937
|
+
{
|
|
2938
|
+
flags: "--operator-type <type>",
|
|
2939
|
+
description: 'Whether operators are priority or excluded. One of: priority, excluded. Default "priority".',
|
|
2940
|
+
arg: "operator_type",
|
|
2941
|
+
type: "string"
|
|
2942
|
+
}
|
|
2943
|
+
]
|
|
2944
|
+
},
|
|
2945
|
+
{
|
|
2946
|
+
name: "steering create",
|
|
2947
|
+
tool: "ui_create_steering_list",
|
|
2948
|
+
summary: "Create a new, empty network steering list (OPLMN preference set) by driving the OCS web dashboard, because the OCS REST API cannot create one.",
|
|
2949
|
+
write: true,
|
|
2950
|
+
options: [
|
|
2951
|
+
{
|
|
2952
|
+
flags: "--name <name>",
|
|
2953
|
+
description: "Name for the new steering list.",
|
|
2954
|
+
arg: "name",
|
|
2955
|
+
type: "string",
|
|
2956
|
+
required: true
|
|
2957
|
+
},
|
|
2958
|
+
{
|
|
2959
|
+
flags: "--description <description>",
|
|
2960
|
+
description: "Optional description for the steering list.",
|
|
2961
|
+
arg: "description",
|
|
2962
|
+
type: "string"
|
|
2963
|
+
}
|
|
2964
|
+
]
|
|
2965
|
+
},
|
|
2966
|
+
{
|
|
2967
|
+
name: "steering set-account",
|
|
2968
|
+
tool: "ui_set_account_steering_list",
|
|
2969
|
+
summary: "Assigns or removes a steering list at the account level via the OCS web dashboard.",
|
|
2970
|
+
write: true,
|
|
2971
|
+
options: [
|
|
2972
|
+
{
|
|
2973
|
+
flags: "--account-id <n>",
|
|
2974
|
+
description: "Account ID to assign the steering list to.",
|
|
2975
|
+
arg: "account_id",
|
|
2976
|
+
type: "number",
|
|
2977
|
+
required: true
|
|
2978
|
+
},
|
|
2979
|
+
{
|
|
2980
|
+
flags: "--steering-list-id <n>",
|
|
2981
|
+
description: "Steering list ID to assign (0 to remove/unset).",
|
|
2982
|
+
arg: "steering_list_id",
|
|
2983
|
+
type: "number",
|
|
2984
|
+
required: true
|
|
2985
|
+
}
|
|
2986
|
+
]
|
|
2987
|
+
},
|
|
2988
|
+
{
|
|
2989
|
+
name: "destinations create",
|
|
2990
|
+
tool: "ui_create_destination_list",
|
|
2991
|
+
summary: "Creates a new destination list (named set of phone number prefixes for MOC call permissions) via the OCS web dashboard.",
|
|
2992
|
+
write: true,
|
|
2993
|
+
options: [
|
|
2994
|
+
{
|
|
2995
|
+
flags: "--name <name>",
|
|
2996
|
+
description: "Name for the new destination list.",
|
|
2997
|
+
arg: "name",
|
|
2998
|
+
type: "string",
|
|
2999
|
+
required: true
|
|
3000
|
+
},
|
|
3001
|
+
{
|
|
3002
|
+
flags: "--prefixes <list>",
|
|
3003
|
+
description: "Phone number prefixes to include (e.g. ['+31', '+49']). Comma-separated.",
|
|
3004
|
+
arg: "prefixes",
|
|
3005
|
+
type: "string[]"
|
|
3006
|
+
},
|
|
3007
|
+
{
|
|
3008
|
+
flags: "--description <description>",
|
|
3009
|
+
description: "Optional description.",
|
|
3010
|
+
arg: "description",
|
|
3011
|
+
type: "string"
|
|
3012
|
+
}
|
|
3013
|
+
]
|
|
3014
|
+
},
|
|
3015
|
+
{
|
|
3016
|
+
name: "destinations edit",
|
|
3017
|
+
tool: "ui_edit_destination_list",
|
|
3018
|
+
summary: "Edits an existing destination list via the OCS web dashboard.",
|
|
3019
|
+
write: true,
|
|
3020
|
+
options: [
|
|
3021
|
+
{
|
|
3022
|
+
flags: "--destination-list-id <n>",
|
|
3023
|
+
description: "ID of the destination list to edit.",
|
|
3024
|
+
arg: "destination_list_id",
|
|
3025
|
+
type: "number",
|
|
3026
|
+
required: true
|
|
3027
|
+
},
|
|
3028
|
+
{
|
|
3029
|
+
flags: "--add-prefixes <list>",
|
|
3030
|
+
description: "Prefixes to add. Comma-separated.",
|
|
3031
|
+
arg: "add_prefixes",
|
|
3032
|
+
type: "string[]"
|
|
3033
|
+
},
|
|
3034
|
+
{
|
|
3035
|
+
flags: "--remove-prefixes <list>",
|
|
3036
|
+
description: "Prefixes to remove. Comma-separated.",
|
|
3037
|
+
arg: "remove_prefixes",
|
|
3038
|
+
type: "string[]"
|
|
3039
|
+
},
|
|
3040
|
+
{
|
|
3041
|
+
flags: "--new-name <name>",
|
|
3042
|
+
description: "Rename the destination list.",
|
|
3043
|
+
arg: "new_name",
|
|
3044
|
+
type: "string"
|
|
3045
|
+
}
|
|
3046
|
+
]
|
|
3047
|
+
},
|
|
3048
|
+
{
|
|
3049
|
+
name: "destinations delete",
|
|
3050
|
+
tool: "ui_delete_destination_list",
|
|
3051
|
+
summary: "Delete a destination list \u2014 a named set of phone-number prefixes \u2014 by driving the OCS web dashboard.",
|
|
3052
|
+
write: true,
|
|
3053
|
+
options: [
|
|
3054
|
+
{
|
|
3055
|
+
flags: "--destination-list-id <n>",
|
|
3056
|
+
description: "ID of the destination list to delete.",
|
|
3057
|
+
arg: "destination_list_id",
|
|
3058
|
+
type: "number",
|
|
3059
|
+
required: true
|
|
3060
|
+
}
|
|
3061
|
+
]
|
|
3062
|
+
},
|
|
3063
|
+
{
|
|
3064
|
+
name: "zones edit",
|
|
3065
|
+
tool: "ui_edit_location_zone",
|
|
3066
|
+
summary: "Edits an existing location zone via the OCS web dashboard. `create_location_zone` is available via API; edit is UI-only.",
|
|
3067
|
+
write: true,
|
|
3068
|
+
options: [
|
|
3069
|
+
{
|
|
3070
|
+
flags: "--zone-id <n>",
|
|
3071
|
+
description: "ID of the location zone to edit.",
|
|
3072
|
+
arg: "zone_id",
|
|
3073
|
+
type: "number",
|
|
3074
|
+
required: true
|
|
3075
|
+
},
|
|
3076
|
+
{
|
|
3077
|
+
flags: "--new-name <name>",
|
|
3078
|
+
description: "Rename the location zone.",
|
|
3079
|
+
arg: "new_name",
|
|
3080
|
+
type: "string"
|
|
3081
|
+
},
|
|
3082
|
+
{
|
|
3083
|
+
flags: "--add-countries <list>",
|
|
3084
|
+
description: "ISO country codes to add (e.g. ['NL', 'DE']). Comma-separated.",
|
|
3085
|
+
arg: "add_countries",
|
|
3086
|
+
type: "string[]"
|
|
3087
|
+
},
|
|
3088
|
+
{
|
|
3089
|
+
flags: "--remove-countries <list>",
|
|
3090
|
+
description: "ISO country codes to remove. Comma-separated.",
|
|
3091
|
+
arg: "remove_countries",
|
|
3092
|
+
type: "string[]"
|
|
3093
|
+
}
|
|
3094
|
+
]
|
|
3095
|
+
},
|
|
3096
|
+
{
|
|
3097
|
+
name: "zones delete",
|
|
3098
|
+
tool: "ui_delete_location_zone",
|
|
3099
|
+
summary: "Delete a location zone by driving the OCS web dashboard, because the OCS REST API can create a zone (`create_location_zone`) but not remove one.",
|
|
3100
|
+
write: true,
|
|
3101
|
+
options: [
|
|
3102
|
+
{
|
|
3103
|
+
flags: "--zone-id <n>",
|
|
3104
|
+
description: "ID of the location zone to delete.",
|
|
3105
|
+
arg: "zone_id",
|
|
3106
|
+
type: "number",
|
|
3107
|
+
required: true
|
|
3108
|
+
}
|
|
3109
|
+
]
|
|
3110
|
+
},
|
|
3111
|
+
{
|
|
3112
|
+
name: "templates delete",
|
|
3113
|
+
tool: "ui_delete_package_template",
|
|
3114
|
+
summary: "Remove a package template from the reseller's product catalogue for good, by driving the OCS web dashboard \u2014 the OCS REST API cannot delete a template.",
|
|
3115
|
+
write: true,
|
|
3116
|
+
options: [
|
|
3117
|
+
{
|
|
3118
|
+
flags: "--template-id <n>",
|
|
3119
|
+
description: "ID of the package template to delete.",
|
|
3120
|
+
arg: "template_id",
|
|
3121
|
+
type: "number",
|
|
3122
|
+
required: true
|
|
3123
|
+
}
|
|
3124
|
+
]
|
|
3125
|
+
}
|
|
3126
|
+
]
|
|
3127
|
+
},
|
|
3128
|
+
{
|
|
3129
|
+
name: "events",
|
|
3130
|
+
summary: "Buffered OCS event history per subscriber",
|
|
3131
|
+
commands: [
|
|
3132
|
+
{
|
|
3133
|
+
name: "ocs",
|
|
3134
|
+
tool: "list_recent_ocs_events",
|
|
3135
|
+
summary: "Return the last N OCS events buffered for a given ICCID.",
|
|
3136
|
+
options: [
|
|
3137
|
+
{
|
|
3138
|
+
flags: "--iccid <iccid>",
|
|
3139
|
+
description: "ICCID, 19 or 20 digits, ITU-T E.118 format.",
|
|
3140
|
+
arg: "iccid",
|
|
3141
|
+
type: "string",
|
|
3142
|
+
required: true
|
|
3143
|
+
},
|
|
3144
|
+
{
|
|
3145
|
+
flags: "--limit <n>",
|
|
3146
|
+
description: "Max events to return, newest first. Default 20.",
|
|
3147
|
+
arg: "limit",
|
|
3148
|
+
type: "number"
|
|
3149
|
+
},
|
|
3150
|
+
{
|
|
3151
|
+
flags: "--event-types <list>",
|
|
3152
|
+
description: "Filter to specific event types. Comma-separated.",
|
|
3153
|
+
arg: "event_types",
|
|
3154
|
+
type: "string[]"
|
|
3155
|
+
},
|
|
3156
|
+
{
|
|
3157
|
+
flags: "--since <since>",
|
|
3158
|
+
description: "ISO-8601 timestamp; only events after this point.",
|
|
3159
|
+
arg: "since",
|
|
3160
|
+
type: "string"
|
|
3161
|
+
}
|
|
3162
|
+
]
|
|
3163
|
+
},
|
|
3164
|
+
{
|
|
3165
|
+
name: "countries",
|
|
3166
|
+
tool: "subscriber_country_history",
|
|
3167
|
+
summary: "Return cross-border movement history for a subscriber from Relay LU events.",
|
|
3168
|
+
options: [
|
|
3169
|
+
{
|
|
3170
|
+
flags: "--subscriber-id <id>",
|
|
3171
|
+
description: "Subscriber ICCID (19\u201320 digits, ITU-T E.118).",
|
|
3172
|
+
arg: "subscriberId",
|
|
3173
|
+
type: "string",
|
|
3174
|
+
required: true
|
|
3175
|
+
},
|
|
3176
|
+
{
|
|
3177
|
+
flags: "--limit <n>",
|
|
3178
|
+
description: "Maximum number of events to return, newest first (default 20, max 50). Default 20.",
|
|
3179
|
+
arg: "limit",
|
|
3180
|
+
type: "number"
|
|
3181
|
+
}
|
|
3182
|
+
]
|
|
3183
|
+
},
|
|
3184
|
+
{
|
|
3185
|
+
name: "depletion",
|
|
3186
|
+
tool: "subscriber_depletion_events",
|
|
3187
|
+
summary: "Look up bundle depletion events for a subscriber (or list recent fleet-wide depletions).",
|
|
3188
|
+
options: [
|
|
3189
|
+
{
|
|
3190
|
+
flags: "--subscriber-id <id>",
|
|
3191
|
+
description: "OCS subscriber ID to look up.",
|
|
3192
|
+
arg: "subscriberId",
|
|
3193
|
+
type: "string"
|
|
3194
|
+
},
|
|
3195
|
+
{
|
|
3196
|
+
flags: "--since <since>",
|
|
3197
|
+
description: "ISO-8601 timestamp \u2014 only return events at or after this time (for single-subscriber lookup).",
|
|
3198
|
+
arg: "since",
|
|
3199
|
+
type: "string"
|
|
3200
|
+
}
|
|
3201
|
+
]
|
|
3202
|
+
}
|
|
3203
|
+
]
|
|
3204
|
+
},
|
|
3205
|
+
{
|
|
3206
|
+
name: "panels",
|
|
3207
|
+
summary: "MCP UI surfaces. A terminal sees the underlying data, not the panel.",
|
|
3208
|
+
commands: [
|
|
3209
|
+
{
|
|
3210
|
+
name: "fleet",
|
|
3211
|
+
tool: "fleet_health_app",
|
|
3212
|
+
summary: "Fleet overview as a UI panel. Prefer `carrier intelligence fleet-health` in a terminal; use --json to read the panel's data.",
|
|
3213
|
+
options: [
|
|
3214
|
+
{
|
|
3215
|
+
flags: "--account-id <n>",
|
|
3216
|
+
description: "Filter to a specific account (omit for all).",
|
|
3217
|
+
arg: "accountId",
|
|
3218
|
+
type: "number"
|
|
3219
|
+
}
|
|
3220
|
+
]
|
|
3221
|
+
},
|
|
3222
|
+
{
|
|
3223
|
+
name: "topup",
|
|
3224
|
+
tool: "balance_topup_form",
|
|
3225
|
+
summary: "Adjust the OCS account balance behind one subscriber. Previews unless --preview false.",
|
|
3226
|
+
requireConfirm: true,
|
|
3227
|
+
options: [
|
|
3228
|
+
{
|
|
3229
|
+
flags: "--iccid <iccid>",
|
|
3230
|
+
description: "The subscriber ICCID for the account lookup.",
|
|
3231
|
+
arg: "iccid",
|
|
3232
|
+
type: "string",
|
|
3233
|
+
required: true
|
|
3234
|
+
},
|
|
3235
|
+
{
|
|
3236
|
+
flags: "--delta <n>",
|
|
3237
|
+
description: "Amount to add (positive) or deduct (negative) from the account balance.",
|
|
3238
|
+
arg: "delta",
|
|
3239
|
+
type: "number",
|
|
3240
|
+
required: true
|
|
3241
|
+
},
|
|
3242
|
+
{
|
|
3243
|
+
flags: "--preview <bool>",
|
|
3244
|
+
description: "If true, return preview without writing. Default true.",
|
|
3245
|
+
arg: "preview",
|
|
3246
|
+
type: "boolean"
|
|
3247
|
+
}
|
|
3248
|
+
]
|
|
3249
|
+
},
|
|
3250
|
+
{
|
|
3251
|
+
name: "provision",
|
|
3252
|
+
tool: "provision_esim_wizard",
|
|
3253
|
+
summary: "Step through the provisioning wizard. Pass --step confirm to execute; every earlier step only reads.",
|
|
3254
|
+
options: [
|
|
3255
|
+
{
|
|
3256
|
+
flags: "--step <step>",
|
|
3257
|
+
description: "Current wizard step. One of: init, select-package, preview, confirm.",
|
|
3258
|
+
arg: "step",
|
|
3259
|
+
type: "string",
|
|
3260
|
+
required: true
|
|
3261
|
+
},
|
|
3262
|
+
{
|
|
3263
|
+
flags: "--wizard-id <id>",
|
|
3264
|
+
description: "Wizard session ID (absent on init).",
|
|
3265
|
+
arg: "wizardId",
|
|
3266
|
+
type: "string"
|
|
3267
|
+
},
|
|
3268
|
+
{
|
|
3269
|
+
flags: "--subscriber-iccid <iccid>",
|
|
3270
|
+
description: "Subscriber ICCID (required for select-package).",
|
|
3271
|
+
arg: "subscriber_iccid",
|
|
3272
|
+
type: "string"
|
|
3273
|
+
},
|
|
3274
|
+
{
|
|
3275
|
+
flags: "--package-template-id <n>",
|
|
3276
|
+
description: "Package template ID (required for preview).",
|
|
3277
|
+
arg: "package_template_id",
|
|
3278
|
+
type: "number"
|
|
3279
|
+
}
|
|
3280
|
+
]
|
|
3281
|
+
}
|
|
3282
|
+
]
|
|
3283
|
+
},
|
|
3284
|
+
{
|
|
3285
|
+
name: "env",
|
|
3286
|
+
summary: "This environment: credentials, catalog and machine-readable context",
|
|
3287
|
+
commands: [
|
|
3288
|
+
{
|
|
3289
|
+
name: "info",
|
|
3290
|
+
tool: "environment_info",
|
|
3291
|
+
summary: "View your Carrier environment configuration \u2014 active organization, reseller details, connected services, and deployment environment.",
|
|
3292
|
+
options: []
|
|
3293
|
+
},
|
|
3294
|
+
{
|
|
3295
|
+
name: "credentials",
|
|
3296
|
+
tool: "credential_status",
|
|
3297
|
+
summary: "Report on the stored eSIMVault credential without changing it: whether a token is present, whether it is encrypted, how old it is, and whether rotation is recommended (over 90 days).",
|
|
3298
|
+
options: []
|
|
3299
|
+
},
|
|
3300
|
+
{
|
|
3301
|
+
name: "rotate",
|
|
3302
|
+
tool: "rotate_credentials",
|
|
3303
|
+
summary: "Replace the stored eSIMVault API token with one you supply.",
|
|
3304
|
+
options: [
|
|
3305
|
+
{
|
|
3306
|
+
flags: "--new-token <token>",
|
|
3307
|
+
description: "New eSIMVault API token to encrypt and store.",
|
|
3308
|
+
arg: "new_token",
|
|
3309
|
+
type: "string",
|
|
3310
|
+
required: true
|
|
3311
|
+
},
|
|
3312
|
+
{
|
|
3313
|
+
flags: "--confirm <bool>",
|
|
3314
|
+
description: "Confirm rotation \u2014 this will replace the current token immediately.",
|
|
3315
|
+
arg: "confirm",
|
|
3316
|
+
type: "boolean",
|
|
3317
|
+
required: true
|
|
3318
|
+
}
|
|
3319
|
+
]
|
|
3320
|
+
},
|
|
3321
|
+
{
|
|
3322
|
+
name: "catalog",
|
|
3323
|
+
tool: "service_catalog",
|
|
3324
|
+
summary: "Browse the Carrier service catalog \u2014 discover available services, their requirements, endpoints, and documentation.",
|
|
3325
|
+
options: [
|
|
3326
|
+
{
|
|
3327
|
+
flags: "--category <category>",
|
|
3328
|
+
description: "Filter services by category. One of: connectivity, analytics, marketplace, coverage, billing, integration, dashboard.",
|
|
3329
|
+
arg: "category",
|
|
3330
|
+
type: "string"
|
|
3331
|
+
},
|
|
3332
|
+
{
|
|
3333
|
+
flags: "--tier <tier>",
|
|
3334
|
+
description: "Filter services accessible at this tier level. One of: free, pro, enterprise.",
|
|
3335
|
+
arg: "tier",
|
|
3336
|
+
type: "string"
|
|
3337
|
+
}
|
|
3338
|
+
]
|
|
3339
|
+
},
|
|
3340
|
+
{
|
|
3341
|
+
name: "llm-context",
|
|
3342
|
+
tool: "llm_context",
|
|
3343
|
+
summary: "Generate a comprehensive LLM context document describing your Carrier environment, available tools, current tier, usage patterns, and best practices.",
|
|
3344
|
+
options: [
|
|
3345
|
+
{
|
|
3346
|
+
flags: "--format <format>",
|
|
3347
|
+
description: "Output format for the context document (default: markdown). One of: markdown, json, yaml.",
|
|
3348
|
+
arg: "format",
|
|
3349
|
+
type: "string"
|
|
3350
|
+
},
|
|
3351
|
+
{
|
|
3352
|
+
flags: "--include-examples <bool>",
|
|
3353
|
+
description: "Include example tool invocations (default: true).",
|
|
3354
|
+
arg: "include_examples",
|
|
3355
|
+
type: "boolean"
|
|
3356
|
+
}
|
|
3357
|
+
]
|
|
3358
|
+
},
|
|
3359
|
+
{
|
|
3360
|
+
name: "describe",
|
|
3361
|
+
tool: "carrier_ask_describe",
|
|
3362
|
+
summary: "Get full documentation for any registered Carrier MCP tool: description, parameters, 2-3 example invocations, required scope, destructive flag, and guidance.",
|
|
3363
|
+
options: [
|
|
3364
|
+
{
|
|
3365
|
+
flags: "--tool-name <name>",
|
|
3366
|
+
description: "The exact MCP tool name to describe (e.g. 'assign_package', 'hlr_set_bitrate').",
|
|
3367
|
+
arg: "tool_name",
|
|
3368
|
+
type: "string",
|
|
3369
|
+
required: true
|
|
3370
|
+
}
|
|
3371
|
+
]
|
|
3372
|
+
}
|
|
3373
|
+
]
|
|
3374
|
+
},
|
|
3375
|
+
{
|
|
3376
|
+
name: "brand",
|
|
3377
|
+
summary: "Storefront brand assets",
|
|
3378
|
+
commands: [
|
|
3379
|
+
{
|
|
3380
|
+
name: "logo",
|
|
3381
|
+
tool: "generate_storefront_logo",
|
|
3382
|
+
summary: "Generate a storefront logo (SVG always; PNG when an image key is configured on the Carrier worker).",
|
|
3383
|
+
options: [
|
|
3384
|
+
{
|
|
3385
|
+
flags: "--name <name>",
|
|
3386
|
+
description: "Brand / shop name, e.g. Bananas.",
|
|
3387
|
+
arg: "name",
|
|
3388
|
+
type: "string",
|
|
3389
|
+
required: true
|
|
3390
|
+
},
|
|
3391
|
+
{
|
|
3392
|
+
flags: "--accent <accent>",
|
|
3393
|
+
description: "Accent hex, e.g. #FF8A00.",
|
|
3394
|
+
arg: "accent",
|
|
3395
|
+
type: "string"
|
|
3396
|
+
},
|
|
3397
|
+
{
|
|
3398
|
+
flags: "--tagline <tagline>",
|
|
3399
|
+
description: "Optional tagline for AI-enhanced marks.",
|
|
3400
|
+
arg: "tagline",
|
|
3401
|
+
type: "string"
|
|
3402
|
+
}
|
|
3403
|
+
]
|
|
3404
|
+
}
|
|
3405
|
+
]
|
|
3406
|
+
}
|
|
3407
|
+
// </generated:catalog-domains>
|
|
3408
|
+
];
|
|
3409
|
+
function capabilityTarget(cmd) {
|
|
3410
|
+
return cmd.transport === "rest" ? `${cmd.restMethod} ${cmd.restPath}` : cmd.tool;
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3413
|
+
// src/cli/lib/capability.ts
|
|
3414
|
+
import * as p2 from "@clack/prompts";
|
|
3415
|
+
import pc3 from "picocolors";
|
|
3416
|
+
|
|
3417
|
+
// src/cli/lib/rest.ts
|
|
3418
|
+
var DEFAULT_ERROR_HINTS2 = [
|
|
3419
|
+
"Re-check the arguments: carrier <domain> <command> --help",
|
|
3420
|
+
"Or open Claude and ask there with full tool routing"
|
|
3421
|
+
];
|
|
3422
|
+
function resolveApiKey() {
|
|
3423
|
+
return process.env.CARRIER_API_KEY?.trim() || process.env.CARRIER_ORG_API_KEY?.trim() || null;
|
|
3424
|
+
}
|
|
3425
|
+
function ocsTokenOnly() {
|
|
3426
|
+
return Boolean(
|
|
3427
|
+
process.env.ESIMVAULT_API_TOKEN?.trim() || process.env.CARRIER_OCS_API_TOKEN?.trim()
|
|
3428
|
+
);
|
|
3429
|
+
}
|
|
3430
|
+
function applyPath(path, args) {
|
|
3431
|
+
const rest = { ...args };
|
|
3432
|
+
const missing = [];
|
|
3433
|
+
const filled = path.replace(/\{(\w+)\}/g, (_match, name) => {
|
|
3434
|
+
const value = rest[name];
|
|
3435
|
+
if (value === void 0 || value === null || value === "") {
|
|
3436
|
+
missing.push(name);
|
|
3437
|
+
return `{${name}}`;
|
|
3438
|
+
}
|
|
3439
|
+
delete rest[name];
|
|
3440
|
+
return encodeURIComponent(String(value));
|
|
3441
|
+
});
|
|
3442
|
+
return { path: filled, rest, missing };
|
|
3443
|
+
}
|
|
3444
|
+
function queryString(args) {
|
|
3445
|
+
const params = new URLSearchParams();
|
|
3446
|
+
for (const [key, value] of Object.entries(args)) {
|
|
3447
|
+
if (value === void 0 || value === null) continue;
|
|
3448
|
+
params.set(key, String(value));
|
|
3449
|
+
}
|
|
3450
|
+
const qs = params.toString();
|
|
3451
|
+
return qs ? `?${qs}` : "";
|
|
3452
|
+
}
|
|
3453
|
+
function bodyText(raw) {
|
|
3454
|
+
const trimmed = raw.trim();
|
|
3455
|
+
if (!trimmed) return "";
|
|
3456
|
+
try {
|
|
3457
|
+
const parsed = JSON.parse(trimmed);
|
|
3458
|
+
if (typeof parsed.error === "string") return parsed.error;
|
|
3459
|
+
if (typeof parsed.message === "string") return parsed.message;
|
|
3460
|
+
return trimmed;
|
|
3461
|
+
} catch {
|
|
3462
|
+
return trimmed;
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
async function callRestEndpoint(method, path, args, opts = {}) {
|
|
3466
|
+
const token = resolveApiKey() ?? await getAccessToken();
|
|
3467
|
+
if (!token) {
|
|
3468
|
+
return {
|
|
3469
|
+
ok: false,
|
|
3470
|
+
text: withNextStep(
|
|
3471
|
+
ocsTokenOnly() ? "Not signed in. An eSIMVault/OCS token is set, but the Carrier API only accepts Carrier credentials." : "Not signed in.",
|
|
3472
|
+
[
|
|
3473
|
+
"Sign in from this terminal: carrier login",
|
|
3474
|
+
"No account yet? carrier open signup",
|
|
3475
|
+
"Headless/CI instead: export CARRIER_API_KEY=ak_\u2026 from Console \u2192 Settings \u2192 API Keys"
|
|
3476
|
+
]
|
|
3477
|
+
)
|
|
3478
|
+
};
|
|
3479
|
+
}
|
|
3480
|
+
const { path: resolvedPath, rest, missing } = applyPath(path, args);
|
|
3481
|
+
if (missing.length) {
|
|
3482
|
+
return {
|
|
3483
|
+
ok: false,
|
|
3484
|
+
text: withNextStep(`Cannot build ${method} ${path}.`, [
|
|
3485
|
+
`Missing path value(s): ${missing.join(", ")}`,
|
|
3486
|
+
"See every flag: carrier <domain> <command> --help"
|
|
3487
|
+
])
|
|
3488
|
+
};
|
|
3489
|
+
}
|
|
3490
|
+
const sendsBody = method === "POST" || method === "PUT" || method === "PATCH";
|
|
3491
|
+
const url = `${API_URL}${resolvedPath}${sendsBody ? "" : queryString(rest)}`;
|
|
3492
|
+
const headers = {
|
|
3493
|
+
Authorization: `Bearer ${token}`,
|
|
3494
|
+
Accept: "application/json",
|
|
3495
|
+
"User-Agent": `carrier-cli/${CARRIER_VERSION}`
|
|
3496
|
+
};
|
|
3497
|
+
if (sendsBody) headers["Content-Type"] = "application/json";
|
|
3498
|
+
if (opts.confirmToken) headers["X-Confirm-Token"] = opts.confirmToken;
|
|
3499
|
+
const timeoutMs = mcpTimeoutMs();
|
|
3500
|
+
const controller = new AbortController();
|
|
3501
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3502
|
+
try {
|
|
3503
|
+
const res = await fetch(url, {
|
|
3504
|
+
method,
|
|
3505
|
+
headers,
|
|
3506
|
+
signal: controller.signal,
|
|
3507
|
+
body: sendsBody ? JSON.stringify(rest) : void 0
|
|
3508
|
+
});
|
|
3509
|
+
const raw = await res.text();
|
|
3510
|
+
if (res.status === 202) {
|
|
3511
|
+
let confirmToken;
|
|
3512
|
+
let expires;
|
|
3513
|
+
let message = "";
|
|
3514
|
+
try {
|
|
3515
|
+
const parsed = JSON.parse(raw);
|
|
3516
|
+
confirmToken = parsed.confirm_token;
|
|
3517
|
+
expires = parsed.expires_in_seconds;
|
|
3518
|
+
message = parsed.message ?? "";
|
|
3519
|
+
} catch {
|
|
3520
|
+
}
|
|
3521
|
+
return {
|
|
3522
|
+
ok: false,
|
|
3523
|
+
text: withNextStep(
|
|
3524
|
+
message || `${method} ${path} needs an explicit confirmation.`,
|
|
3525
|
+
confirmToken ? [
|
|
3526
|
+
`Re-run the same command with: --confirm-token ${confirmToken}`,
|
|
3527
|
+
`The token is single-use and expires in ${expires ?? 120}s.`
|
|
3528
|
+
] : ["The server asked for confirmation but returned no token \u2014 retry the command."]
|
|
3529
|
+
)
|
|
3530
|
+
};
|
|
3531
|
+
}
|
|
3532
|
+
if (res.status === 401 || res.status === 403) {
|
|
3533
|
+
return {
|
|
3534
|
+
ok: false,
|
|
3535
|
+
text: withNextStep(
|
|
3536
|
+
`Carrier API returned ${res.status} (auth rejected).`,
|
|
3537
|
+
[
|
|
3538
|
+
"Confirm CARRIER_API_KEY is a valid org key (ak_\u2026) from app.carrier.llc",
|
|
3539
|
+
"Or sign in from this terminal: carrier login",
|
|
3540
|
+
...res.status === 403 ? ["A 403 here usually means the key lacks write scope."] : []
|
|
3541
|
+
]
|
|
3542
|
+
)
|
|
3543
|
+
};
|
|
3544
|
+
}
|
|
3545
|
+
if (!res.ok) {
|
|
3546
|
+
return {
|
|
3547
|
+
ok: false,
|
|
3548
|
+
text: withNextStep(
|
|
3549
|
+
redact(`${method} ${path} failed (${res.status}). ${bodyText(raw).slice(0, 500)}`),
|
|
3550
|
+
opts.errorHints ?? DEFAULT_ERROR_HINTS2
|
|
3551
|
+
)
|
|
3552
|
+
};
|
|
3553
|
+
}
|
|
3554
|
+
return { ok: true, text: raw.trim() || JSON.stringify({ status: res.status }) };
|
|
3555
|
+
} catch (e) {
|
|
3556
|
+
const aborted = e instanceof Error && (e.name === "AbortError" || e.name === "TimeoutError");
|
|
3557
|
+
if (aborted) {
|
|
3558
|
+
const secs = Math.round(timeoutMs / 1e3);
|
|
3559
|
+
return {
|
|
3560
|
+
ok: false,
|
|
3561
|
+
text: withNextStep(`${method} ${path} timed out after ${secs}s (no response).`, [
|
|
3562
|
+
`Raise the deadline for one slow call: CARRIER_MCP_TIMEOUT_MS=${timeoutMs * 2} carrier \u2026`,
|
|
3563
|
+
"Confirm the service is up: check network access to https://api.carrier.llc"
|
|
3564
|
+
])
|
|
3565
|
+
};
|
|
3566
|
+
}
|
|
3567
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
3568
|
+
return {
|
|
3569
|
+
ok: false,
|
|
3570
|
+
text: withNextStep(redact(`Could not reach the Carrier API: ${msg}`), [
|
|
3571
|
+
"Verify outbound HTTPS to api.carrier.llc",
|
|
3572
|
+
"Use the interactive Claude path while offline from this machine"
|
|
3573
|
+
])
|
|
3574
|
+
};
|
|
3575
|
+
} finally {
|
|
3576
|
+
clearTimeout(timer);
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
|
|
3580
|
+
// src/cli/lib/capability.ts
|
|
3581
|
+
var MAX_PRETTY_CHARS = 8e3;
|
|
3582
|
+
function optionKey(flags) {
|
|
3583
|
+
const long = flags.split(/[ ,|]+/).find((t) => t.startsWith("--"));
|
|
3584
|
+
if (!long) throw new Error(`Option "${flags}" has no long flag`);
|
|
3585
|
+
return long.replace(/^--/, "").split("-").map((part, i) => i === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
3586
|
+
}
|
|
3587
|
+
function setArg(target, path, value) {
|
|
3588
|
+
const parts = path.split(".");
|
|
3589
|
+
let node = target;
|
|
3590
|
+
for (const part of parts.slice(0, -1)) {
|
|
3591
|
+
const next = node[part];
|
|
3592
|
+
if (typeof next !== "object" || next === null) node[part] = {};
|
|
3593
|
+
node = node[part];
|
|
3594
|
+
}
|
|
3595
|
+
node[parts[parts.length - 1]] = value;
|
|
3596
|
+
}
|
|
3597
|
+
function coerce(opt, raw) {
|
|
3598
|
+
if (opt.type === "boolean") {
|
|
3599
|
+
if (raw === true) return { value: true };
|
|
3600
|
+
const text3 = String(raw).toLowerCase();
|
|
3601
|
+
if (text3 === "true") return { value: true };
|
|
3602
|
+
if (text3 === "false") return { value: false };
|
|
3603
|
+
return { error: `${opt.flags} expects true or false, got "${String(raw)}"` };
|
|
3604
|
+
}
|
|
3605
|
+
if (opt.type === "number") {
|
|
3606
|
+
const n = Number(raw);
|
|
3607
|
+
if (!Number.isFinite(n)) return { error: `${opt.flags} expects a number, got "${String(raw)}"` };
|
|
3608
|
+
return { value: n };
|
|
3609
|
+
}
|
|
3610
|
+
if (opt.type === "string[]" || opt.type === "number[]") {
|
|
3611
|
+
const items = String(raw).split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
3612
|
+
if (!items.length) return { error: `${opt.flags} expects a comma-separated list, got "${String(raw)}"` };
|
|
3613
|
+
if (opt.type === "string[]") return { value: items };
|
|
3614
|
+
const numbers = items.map(Number);
|
|
3615
|
+
const bad = items.find((_, i) => !Number.isFinite(numbers[i]));
|
|
3616
|
+
if (bad !== void 0) return { error: `${opt.flags} expects numbers, got "${bad}"` };
|
|
3617
|
+
return { value: numbers };
|
|
3618
|
+
}
|
|
3619
|
+
return { value: String(raw) };
|
|
3620
|
+
}
|
|
3621
|
+
function buildToolArgs(cmd, opts) {
|
|
3622
|
+
const args = {};
|
|
3623
|
+
const errors = [];
|
|
3624
|
+
const notes = [];
|
|
3625
|
+
for (const opt of cmd.options) {
|
|
3626
|
+
const raw = opts[optionKey(opt.flags)];
|
|
3627
|
+
if (raw === void 0 || raw === false) {
|
|
3628
|
+
if (opt.required) errors.push(`Missing required ${opt.flags}`);
|
|
3629
|
+
continue;
|
|
3630
|
+
}
|
|
3631
|
+
const { value, error } = coerce(opt, raw);
|
|
3632
|
+
if (error) errors.push(error);
|
|
3633
|
+
else setArg(args, opt.arg, value);
|
|
3634
|
+
}
|
|
3635
|
+
if (cmd.requireOneOf && !cmd.requireOneOf.some((name) => args[name] !== void 0)) {
|
|
3636
|
+
const flags = cmd.options.filter((opt) => cmd.requireOneOf.includes(opt.arg)).map((opt) => opt.flags);
|
|
3637
|
+
errors.push(`Pass one of: ${flags.join(", ")}`);
|
|
3638
|
+
}
|
|
3639
|
+
if (cmd.usageWindow) {
|
|
3640
|
+
const start = args.startDate;
|
|
3641
|
+
const end = args.endDate;
|
|
3642
|
+
if (!start && !end) {
|
|
3643
|
+
const window = lastNDaysPeriod();
|
|
3644
|
+
args.startDate = window.start;
|
|
3645
|
+
args.endDate = window.end;
|
|
3646
|
+
notes.push(`Window defaulted to ${window.start} \u2026 ${window.end} (last ${OCS_MAX_USAGE_WINDOW_DAYS} days).`);
|
|
3647
|
+
} else if (!start || !end) {
|
|
3648
|
+
errors.push("Pass both --start and --end, or neither for the last 7 days");
|
|
3649
|
+
} else {
|
|
3650
|
+
const clamped = clampUsagePeriod(start, end);
|
|
3651
|
+
if (clamped.start !== start) {
|
|
3652
|
+
notes.push(
|
|
3653
|
+
`Start moved to ${clamped.start} \u2014 OCS rejects windows wider than ${OCS_MAX_USAGE_WINDOW_DAYS} days.`
|
|
3654
|
+
);
|
|
3655
|
+
}
|
|
3656
|
+
args.startDate = clamped.start;
|
|
3657
|
+
args.endDate = clamped.end;
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
if (cmd.write && cmd.transport !== "rest") args.dry_run = true;
|
|
3661
|
+
return { args, errors, notes };
|
|
3662
|
+
}
|
|
3663
|
+
function formatJsonOutput(text3) {
|
|
3664
|
+
try {
|
|
3665
|
+
JSON.parse(text3);
|
|
3666
|
+
return text3;
|
|
3667
|
+
} catch {
|
|
3668
|
+
return JSON.stringify(text3);
|
|
3669
|
+
}
|
|
3670
|
+
}
|
|
3671
|
+
async function runCapability(domain, cmd, opts) {
|
|
3672
|
+
const label = `${domain.name} ${cmd.name}`;
|
|
3673
|
+
const quiet = opts.json === true;
|
|
3674
|
+
const { args, errors, notes } = buildToolArgs(cmd, opts);
|
|
3675
|
+
if (cmd.write && opts.commit === true) delete args.dry_run;
|
|
3676
|
+
if (cmd.requireConfirm && opts.confirm !== true) {
|
|
3677
|
+
errors.push(`${capabilityTarget(cmd)} has no preview mode. Pass --confirm to run it for real.`);
|
|
3678
|
+
}
|
|
3679
|
+
if (errors.length) {
|
|
3680
|
+
const message = withNextStep(`Cannot run \`carrier ${label}\`.`, [
|
|
3681
|
+
...errors,
|
|
3682
|
+
`See every flag: carrier ${label} --help`
|
|
3683
|
+
]);
|
|
3684
|
+
if (quiet) console.error(message);
|
|
3685
|
+
else p2.log.error(message);
|
|
3686
|
+
process.exitCode = 1;
|
|
3687
|
+
return;
|
|
3688
|
+
}
|
|
3689
|
+
if (cmd.transport === "rest" && cmd.write && opts.commit !== true) {
|
|
3690
|
+
const preview = [
|
|
3691
|
+
`${cmd.restMethod} ${cmd.restPath}`,
|
|
3692
|
+
JSON.stringify(args, null, 2),
|
|
3693
|
+
"",
|
|
3694
|
+
"Dry run \u2014 nothing sent. Re-run with --commit to apply."
|
|
3695
|
+
].join("\n");
|
|
3696
|
+
if (quiet) process.stdout.write(`${formatJsonOutput(preview)}
|
|
3697
|
+
`);
|
|
3698
|
+
else p2.note(preview, `carrier ${label}`);
|
|
3699
|
+
return;
|
|
3700
|
+
}
|
|
3701
|
+
const dryRun = cmd.write === true && args.dry_run === true;
|
|
3702
|
+
const warnings = dryRun ? [...notes, "Dry run \u2014 nothing changes. Re-run with --commit to apply."] : notes;
|
|
3703
|
+
for (const note4 of warnings) {
|
|
3704
|
+
if (quiet) console.error(note4);
|
|
3705
|
+
else p2.log.info(pc3.dim(note4));
|
|
3706
|
+
}
|
|
3707
|
+
const target = capabilityTarget(cmd);
|
|
3708
|
+
const errorHints = [
|
|
3709
|
+
`Check the arguments: carrier ${label} --help`,
|
|
3710
|
+
'Or describe the task in words: carrier ask "\u2026"'
|
|
3711
|
+
];
|
|
3712
|
+
const s = quiet ? null : p2.spinner();
|
|
3713
|
+
s?.start(`Calling ${target}`);
|
|
3714
|
+
const result = cmd.transport === "rest" ? await callRestEndpoint(cmd.restMethod, cmd.restPath, args, {
|
|
3715
|
+
errorHints,
|
|
3716
|
+
confirmToken: opts.confirmToken
|
|
3717
|
+
}) : await callMcpTool(cmd.tool, args, { errorHints });
|
|
3718
|
+
s?.stop(result.ok ? "Done" : "Failed");
|
|
3719
|
+
if (!result.ok) {
|
|
3720
|
+
if (quiet) console.error(result.text);
|
|
3721
|
+
else p2.log.error(result.text);
|
|
3722
|
+
process.exitCode = 1;
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3725
|
+
if (quiet) {
|
|
3726
|
+
process.stdout.write(`${formatJsonOutput(result.text)}
|
|
3727
|
+
`);
|
|
3728
|
+
return;
|
|
3729
|
+
}
|
|
3730
|
+
const body = result.text.length > MAX_PRETTY_CHARS ? `${result.text.slice(0, MAX_PRETTY_CHARS)}
|
|
3731
|
+
\u2026truncated. Re-run with --json for the whole response.` : result.text;
|
|
3732
|
+
p2.note(body, target);
|
|
3733
|
+
}
|
|
3734
|
+
function parseArgValue(text3) {
|
|
3735
|
+
if (text3 === "true") return true;
|
|
3736
|
+
if (text3 === "false") return false;
|
|
3737
|
+
if (text3 === "null") return null;
|
|
3738
|
+
if (/^[[{"]/.test(text3)) {
|
|
3739
|
+
try {
|
|
3740
|
+
return JSON.parse(text3);
|
|
3741
|
+
} catch {
|
|
3742
|
+
return text3;
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
if (/^-?\d+(?:\.\d+)?$/.test(text3)) {
|
|
3746
|
+
const n = Number(text3);
|
|
3747
|
+
if (Number.isFinite(n) && String(n) === text3) return n;
|
|
3748
|
+
}
|
|
3749
|
+
return text3;
|
|
3750
|
+
}
|
|
3751
|
+
async function runRawTool(name, pairs, opts) {
|
|
3752
|
+
const quiet = opts.json === true;
|
|
3753
|
+
const args = {};
|
|
3754
|
+
const errors = [];
|
|
3755
|
+
for (const pair of pairs) {
|
|
3756
|
+
const eq = pair.indexOf("=");
|
|
3757
|
+
if (eq < 1) {
|
|
3758
|
+
errors.push(`--arg ${pair} is not key=value`);
|
|
3759
|
+
continue;
|
|
3760
|
+
}
|
|
3761
|
+
setArg(args, pair.slice(0, eq), parseArgValue(pair.slice(eq + 1)));
|
|
3762
|
+
}
|
|
3763
|
+
if (errors.length) {
|
|
3764
|
+
const message = withNextStep(`Cannot call \`${name}\`.`, [
|
|
3765
|
+
...errors,
|
|
3766
|
+
"Arguments look like: --arg iccid=8931000000000000000 --arg limit=20"
|
|
3767
|
+
]);
|
|
3768
|
+
if (quiet) console.error(message);
|
|
3769
|
+
else p2.log.error(message);
|
|
3770
|
+
process.exitCode = 1;
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3773
|
+
const s = quiet ? null : p2.spinner();
|
|
3774
|
+
s?.start(`Calling ${name}`);
|
|
3775
|
+
const result = await callMcpTool(name, args, {
|
|
3776
|
+
errorHints: [
|
|
3777
|
+
"List every tool this server registers: carrier env catalog",
|
|
3778
|
+
'Or describe the task in words: carrier ask "\u2026"'
|
|
3779
|
+
]
|
|
3780
|
+
});
|
|
3781
|
+
s?.stop(result.ok ? "Done" : "Failed");
|
|
3782
|
+
if (!result.ok) {
|
|
3783
|
+
if (quiet) console.error(result.text);
|
|
3784
|
+
else p2.log.error(result.text);
|
|
3785
|
+
process.exitCode = 1;
|
|
3786
|
+
return;
|
|
3787
|
+
}
|
|
3788
|
+
if (quiet) {
|
|
3789
|
+
process.stdout.write(`${formatJsonOutput(result.text)}
|
|
3790
|
+
`);
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3793
|
+
const body = result.text.length > MAX_PRETTY_CHARS ? `${result.text.slice(0, MAX_PRETTY_CHARS)}
|
|
3794
|
+
\u2026truncated. Re-run with --json for the whole response.` : result.text;
|
|
3795
|
+
p2.note(body, name);
|
|
3796
|
+
}
|
|
3797
|
+
|
|
3798
|
+
// src/cli/index.ts
|
|
3799
|
+
var VERSION = CARRIER_VERSION;
|
|
3800
|
+
function header() {
|
|
3801
|
+
p3.intro(`${pc4.bold(pc4.yellow("\u25C6 carrier"))} ${pc4.dim("\xB7 the Stripe of telecom \u2014 CLI v" + VERSION)}`);
|
|
3802
|
+
}
|
|
3803
|
+
function ok(msg) {
|
|
3804
|
+
p3.log.success(pc4.green(msg));
|
|
3805
|
+
}
|
|
3806
|
+
function info(msg) {
|
|
3807
|
+
p3.log.info(msg);
|
|
3808
|
+
}
|
|
3809
|
+
function fail(msg, next) {
|
|
3810
|
+
p3.log.error(msg);
|
|
3811
|
+
p3.note(next.map((s) => `\u2192 ${s}`).join("\n"), "What to do next");
|
|
3812
|
+
}
|
|
3813
|
+
async function promptBrand(seed) {
|
|
3814
|
+
const name = await p3.text({
|
|
3815
|
+
message: "Brand name",
|
|
3816
|
+
placeholder: seed.name,
|
|
3817
|
+
defaultValue: seed.name
|
|
3818
|
+
});
|
|
3819
|
+
if (p3.isCancel(name)) process.exit(0);
|
|
3820
|
+
const domain = await p3.text({
|
|
3821
|
+
message: "Domain",
|
|
3822
|
+
placeholder: seed.domain,
|
|
3823
|
+
defaultValue: seed.domain
|
|
3824
|
+
});
|
|
3825
|
+
if (p3.isCancel(domain)) process.exit(0);
|
|
3826
|
+
const accent = await p3.text({
|
|
3827
|
+
message: "Accent color (hex)",
|
|
3828
|
+
placeholder: seed.colors.accent,
|
|
3829
|
+
defaultValue: seed.colors.accent
|
|
3830
|
+
});
|
|
3831
|
+
if (p3.isCancel(accent)) process.exit(0);
|
|
3832
|
+
const supportEmail = await p3.text({
|
|
3833
|
+
message: "Support email",
|
|
3834
|
+
placeholder: `support@${domain}`,
|
|
3835
|
+
defaultValue: `support@${domain}`
|
|
3836
|
+
});
|
|
3837
|
+
if (p3.isCancel(supportEmail)) process.exit(0);
|
|
3838
|
+
const accentDark = deriveAccentDark(accent, seed);
|
|
3839
|
+
const isCarrier = name === CARRIER_BRAND.name && domain === CARRIER_BRAND.domain;
|
|
3840
|
+
return {
|
|
3841
|
+
...seed,
|
|
3842
|
+
name,
|
|
3843
|
+
legalName: name,
|
|
3844
|
+
tagline: isCarrier ? seed.tagline : `Mobile connectivity by ${name}.`,
|
|
3845
|
+
domain,
|
|
3846
|
+
supportEmail,
|
|
3847
|
+
supportUrl: `https://${domain}/help`,
|
|
3848
|
+
supportWhatsapp: isCarrier ? seed.supportWhatsapp : "",
|
|
3849
|
+
social: isCarrier ? seed.social : {},
|
|
3850
|
+
colors: { ...seed.colors, accent, accentDark }
|
|
3851
|
+
};
|
|
3852
|
+
}
|
|
3853
|
+
async function doPluginInstall() {
|
|
3854
|
+
const s = p3.spinner();
|
|
3855
|
+
s.start("Installing Carrier Claude Code plugin + zero-cred MCP");
|
|
3856
|
+
let r;
|
|
3857
|
+
try {
|
|
3858
|
+
r = await installPlugin();
|
|
3859
|
+
} catch (e) {
|
|
3860
|
+
s.stop("Install failed");
|
|
3861
|
+
fail(String(e instanceof Error ? e.message : e), [
|
|
3862
|
+
"Reinstall the package: npm i -g @carrierllc/mcp (or npx @carrierllc/mcp)",
|
|
3863
|
+
"Or finish manually with the commands under `carrier plugin install` help",
|
|
3864
|
+
`Sign up anytime: ${SIGN_UP_URL}`
|
|
3865
|
+
]);
|
|
3866
|
+
return;
|
|
3867
|
+
}
|
|
3868
|
+
s.stop("Plugin staged");
|
|
3869
|
+
ok(`Plugin \u2192 ${r.copiedTo}`);
|
|
3870
|
+
info(
|
|
3871
|
+
`MCP: ${r.mcpAdded ? pc4.green("registered") : pc4.yellow("manual")} \xB7 marketplace: ${r.marketplaceAdded ? pc4.green("added") : pc4.yellow("manual")} \xB7 install: ${r.pluginInstalled ? pc4.green("done") : pc4.yellow("manual")}`
|
|
3872
|
+
);
|
|
3873
|
+
p3.note(installAuthGuidance().join("\n"), "OAuth on first use (Entry A)");
|
|
3874
|
+
if (!r.claudeFound || r.notes.length) {
|
|
3875
|
+
p3.note(manualCommands().join("\n"), "Finish wiring (run in your terminal)");
|
|
3876
|
+
if (r.notes.length) info(pc4.dim(r.notes.join("\n")));
|
|
3877
|
+
p3.note(
|
|
3878
|
+
[
|
|
3879
|
+
"You can still create an account now:",
|
|
3880
|
+
` carrier open signup`,
|
|
3881
|
+
"Then open Claude and talk to your fleet \u2014 browser OAuth completes auth."
|
|
3882
|
+
].join("\n"),
|
|
3883
|
+
"Next"
|
|
3884
|
+
);
|
|
3885
|
+
} else {
|
|
3886
|
+
p3.note(
|
|
3887
|
+
[
|
|
3888
|
+
"Open Claude Code and say something like:",
|
|
3889
|
+
' "Show my fleet health"',
|
|
3890
|
+
"First call opens the browser for sign-in / sign-up. No token paste.",
|
|
3891
|
+
"",
|
|
3892
|
+
"More prompts: carrier examples"
|
|
3893
|
+
].join("\n"),
|
|
3894
|
+
"Talk to your fleet"
|
|
3895
|
+
);
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
async function doSiteCreate(target, brand) {
|
|
3899
|
+
const s = p3.spinner();
|
|
3900
|
+
s.start(`Scaffolding ${brand.name} storefront \u2192 ${target}`);
|
|
3901
|
+
try {
|
|
3902
|
+
await scaffoldStorefront(target, brand);
|
|
3903
|
+
} catch (e) {
|
|
3904
|
+
s.stop("Scaffold failed");
|
|
3905
|
+
fail(String(e instanceof Error ? e.message : e), [
|
|
3906
|
+
"Pick a free directory: carrier site create ./my-storefront",
|
|
3907
|
+
"Ensure the package templates shipped with @carrierllc/mcp",
|
|
3908
|
+
"Still stuck? carrier open console"
|
|
3909
|
+
]);
|
|
2524
3910
|
throw e;
|
|
2525
3911
|
}
|
|
2526
3912
|
s.stop("Storefront scaffolded");
|
|
@@ -2938,6 +4324,65 @@ program.command("whoami").description("Show the account, org and scopes the curr
|
|
|
2938
4324
|
p3.note(r.text, "environment_info");
|
|
2939
4325
|
p3.outro("");
|
|
2940
4326
|
});
|
|
4327
|
+
var connectCmd = program.command("connect").description("Stripe Connect onboarding and status.");
|
|
4328
|
+
connectCmd.command("status").description("Show the authenticated operator's Stripe Connect status.").option("--json", "Print raw JSON").action(async (opts) => {
|
|
4329
|
+
if (!opts.json) header();
|
|
4330
|
+
const r = await callMcpTool("stripe_connect_status", {}, {
|
|
4331
|
+
errorHints: ["Sign in first: carrier login", "Start onboarding: carrier connect begin"]
|
|
4332
|
+
});
|
|
4333
|
+
if (!r.ok) {
|
|
4334
|
+
if (opts.json) console.error(r.text);
|
|
4335
|
+
else p3.log.error(r.text);
|
|
4336
|
+
process.exitCode = 1;
|
|
4337
|
+
return;
|
|
4338
|
+
}
|
|
4339
|
+
if (opts.json) process.stdout.write(`${r.text}
|
|
4340
|
+
`);
|
|
4341
|
+
else {
|
|
4342
|
+
p3.note(r.text, "Stripe Connect");
|
|
4343
|
+
p3.outro("");
|
|
4344
|
+
}
|
|
4345
|
+
});
|
|
4346
|
+
connectCmd.command("begin").description("Start or resume Stripe Connect onboarding and open the secure Stripe flow.").option("--type <type>", "Connected account type: express or standard", "express").option("--no-open", "Print the onboarding URL instead of opening it").action(async (opts) => {
|
|
4347
|
+
header();
|
|
4348
|
+
if (!["express", "standard"].includes(opts.type)) {
|
|
4349
|
+
p3.log.error("--type must be express or standard");
|
|
4350
|
+
process.exitCode = 2;
|
|
4351
|
+
return;
|
|
4352
|
+
}
|
|
4353
|
+
const r = await callMcpTool("stripe_connect_begin", { account_type: opts.type }, {
|
|
4354
|
+
errorHints: ["Sign in first: carrier login", "Check status: carrier connect status"]
|
|
4355
|
+
});
|
|
4356
|
+
if (!r.ok) {
|
|
4357
|
+
p3.log.error(r.text);
|
|
4358
|
+
process.exitCode = 1;
|
|
4359
|
+
return;
|
|
4360
|
+
}
|
|
4361
|
+
let data = {};
|
|
4362
|
+
try {
|
|
4363
|
+
data = JSON.parse(r.text);
|
|
4364
|
+
} catch {
|
|
4365
|
+
}
|
|
4366
|
+
if (!data.onboarding_url) {
|
|
4367
|
+
p3.log.error(r.text);
|
|
4368
|
+
process.exitCode = 1;
|
|
4369
|
+
return;
|
|
4370
|
+
}
|
|
4371
|
+
if (opts.open) {
|
|
4372
|
+
const opened = await openUrl(data.onboarding_url);
|
|
4373
|
+
if (opened.ok) ok(opened.hint);
|
|
4374
|
+
else p3.note(data.onboarding_url, "Open this secure Stripe URL");
|
|
4375
|
+
} else {
|
|
4376
|
+
process.stdout.write(`${data.onboarding_url}
|
|
4377
|
+
`);
|
|
4378
|
+
}
|
|
4379
|
+
p3.note([
|
|
4380
|
+
`Account: ${data.account_id ?? "created by Stripe"}`,
|
|
4381
|
+
data.account_created ? "A new connected account was created." : "Resuming the existing account.",
|
|
4382
|
+
"After Stripe: carrier connect status"
|
|
4383
|
+
].join("\n"), "Onboarding");
|
|
4384
|
+
p3.outro("");
|
|
4385
|
+
});
|
|
2941
4386
|
var openCmd = program.command("open").description("Open Carrier account / product URLs in your browser.");
|
|
2942
4387
|
for (const [name, url, desc] of [
|
|
2943
4388
|
["signup", SIGN_UP_URL, "Create a Carrier account (Clerk sign-up)"],
|
|
@@ -3026,10 +4471,16 @@ for (const domain of CLI_DOMAINS) {
|
|
|
3026
4471
|
}
|
|
3027
4472
|
parent = nested;
|
|
3028
4473
|
}
|
|
3029
|
-
const sub = parent.command(parts[parts.length - 1]).description(
|
|
4474
|
+
const sub = parent.command(parts[parts.length - 1]).description(
|
|
4475
|
+
cmd.write ? `${cmd.summary} Dry run unless --commit.` : cmd.requireConfirm ? `${cmd.summary} Refuses without --confirm.` : cmd.summary
|
|
4476
|
+
);
|
|
3030
4477
|
for (const opt of cmd.options) sub.option(opt.flags, opt.description);
|
|
3031
4478
|
sub.option("--json", "Print the raw tool response on stdout and nothing else");
|
|
3032
4479
|
if (cmd.write) sub.option("--commit", "Apply the change instead of previewing it");
|
|
4480
|
+
if (cmd.transport === "rest") {
|
|
4481
|
+
sub.option("--confirm-token <token>", "Token from a prior 202, to confirm this call");
|
|
4482
|
+
}
|
|
4483
|
+
if (cmd.requireConfirm) sub.option("--confirm", "Required. This call takes effect immediately.");
|
|
3033
4484
|
sub.action(async (opts) => {
|
|
3034
4485
|
if (opts.json !== true) header();
|
|
3035
4486
|
await runCapability(domain, cmd, opts);
|
|
@@ -3037,6 +4488,16 @@ for (const domain of CLI_DOMAINS) {
|
|
|
3037
4488
|
});
|
|
3038
4489
|
}
|
|
3039
4490
|
}
|
|
4491
|
+
program.command("tool <name>").description("Call one MCP tool directly, by name, with raw arguments").option(
|
|
4492
|
+
"--arg <key=value>",
|
|
4493
|
+
"One tool argument. Repeat for more. Dots nest: context.iccid=8931\u2026",
|
|
4494
|
+
(value, prev) => [...prev, value],
|
|
4495
|
+
[]
|
|
4496
|
+
).option("--json", "Print the raw tool response on stdout and nothing else").action(async (name, o) => {
|
|
4497
|
+
if (o.json !== true) header();
|
|
4498
|
+
await runRawTool(name, o.arg, o);
|
|
4499
|
+
if (o.json !== true) p3.outro("");
|
|
4500
|
+
});
|
|
3040
4501
|
program.command("dash [domain]").description(`Render a status screen in the terminal: ${DASH_DOMAINS.join(" | ")}`).option("--json", "Emit the screen model as JSON instead of drawing it").option("--no-color", "Plain text, safe to pipe").option("--width <n>", "Terminal width override").action(async (domain, o) => {
|
|
3041
4502
|
const target = domain ?? "fleet";
|
|
3042
4503
|
if (!isDashDomain(target)) {
|