@carrierllc/mcp 0.2.19 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +22 -1
  2. package/dist/chunk-ZII4CD4U.js +461 -0
  3. package/dist/chunk-ZII4CD4U.js.map +1 -0
  4. package/dist/cli.js +1294 -105
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.js +144 -315
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/plugin/carrier/commands/storefront.md +24 -12
  10. package/plugin/carrier/skills/carrier-operations/SKILL.md +4 -1
  11. package/templates/storefront/{next.config.ts → next.config.mjs} +2 -6
  12. package/templates/storefront/public/brand/logo.svg +13 -0
  13. package/templates/storefront/src/app/activate/[orderId]/ActivateClient.tsx +12 -12
  14. package/templates/storefront/src/app/checkout/[templateId]/CheckoutClient.tsx +5 -5
  15. package/templates/storefront/src/app/checkout/success/CheckoutSuccessClient.tsx +29 -29
  16. package/templates/storefront/src/app/checkout/success/page.tsx +1 -1
  17. package/templates/storefront/src/app/contact/page.tsx +33 -25
  18. package/templates/storefront/src/app/dashboard/page.tsx +7 -4
  19. package/templates/storefront/src/app/globals.css +72 -82
  20. package/templates/storefront/src/app/help/page.tsx +22 -17
  21. package/templates/storefront/src/app/layout.tsx +15 -4
  22. package/templates/storefront/src/app/page.tsx +16 -7
  23. package/templates/storefront/src/app/shop/ShopClient.tsx +7 -3
  24. package/templates/storefront/src/app/sign-in/[[...sign-in]]/page.tsx +1 -1
  25. package/templates/storefront/src/app/sign-up/[[...sign-up]]/StorefrontSignUpClient.tsx +16 -16
  26. package/templates/storefront/src/app/sign-up/[[...sign-up]]/page.tsx +1 -1
  27. package/templates/storefront/src/brand.config.ts +3 -3
  28. package/templates/storefront/src/components/faq/FaqSection.tsx +23 -26
  29. package/templates/storefront/src/components/footer/StorefrontFooter.tsx +37 -22
  30. package/templates/storefront/src/components/landing/FinalCTA.tsx +28 -0
  31. package/templates/storefront/src/components/landing/HeroSection.tsx +57 -24
  32. package/templates/storefront/src/components/landing/HowItWorks.tsx +44 -0
  33. package/templates/storefront/src/components/landing/PlanCard.tsx +58 -28
  34. package/templates/storefront/src/components/nav/StorefrontNav.tsx +59 -24
  35. package/templates/storefront/src/components/theme/BrandStyles.tsx +8 -0
  36. package/templates/storefront/src/components/theme/ThemeToggle.tsx +27 -0
  37. package/templates/storefront/src/components/theme/clerk-appearance.ts +33 -35
  38. package/templates/storefront/src/components/theme/theme-provider.tsx +25 -32
  39. package/templates/storefront/src/components/theme/theme-script.tsx +4 -7
  40. package/templates/storefront/src/lib/complete-email-sign-up.ts +3 -3
  41. package/templates/storefront/src/vendor/ui/brand.ts +6 -6
package/dist/index.js CHANGED
@@ -1,204 +1,27 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ CARRIER_VERSION,
4
+ acquireEndpointSlot,
5
+ extractEsimStatusCounts,
6
+ generateStorefrontLogo,
7
+ getLimitForEndpoint,
8
+ getRateLimitWindowCounts,
9
+ locationParams,
10
+ networkEventsOverPeriodParams,
11
+ subscriberIdParams,
12
+ usageOverPeriodParams
13
+ } from "./chunk-ZII4CD4U.js";
2
14
 
3
15
  // src/index.ts
4
16
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
17
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
18
 
7
- // ../../packages/ocs-client/dist/chunk-PMFMORPK.js
8
- var ENDPOINT_LIMITS_PER_MIN = {
9
- // Global sentinel (keyed as "__global__")
10
- __global__: 600,
11
- // 30/min — tightest endpoint
12
- subscriberNetworkEventsOverPeriod: 30,
13
- // 100/min
14
- subscriberUsageOverPeriod: 100,
15
- // 150/min
16
- listLocationZoneElement: 150,
17
- sendMtSms: 150,
18
- // 300/min (explicit; also the fallback default)
19
- modifySubscriberMobilePlan: 300,
20
- affectRecurringPackageToSubscriber: 300,
21
- affectSubscriberFakePhoneNumber: 300,
22
- affectSubscriberRealPhoneNumber: 300,
23
- esimStatusPerAccount: 300,
24
- getSubscriberActivePeriod: 300,
25
- hlrGetBitrate: 300,
26
- hlrSetBitrate: 300,
27
- listSubscriber: 300,
28
- listSubscriberPrepaidPackages: 300,
29
- moveSubscriberRangeToAccount: 300,
30
- pushSteeringToSubs: 300,
31
- setSubscriberTrafficRestrictions: 300,
32
- getSingleSubscriber: 300,
33
- getSubscriberLocationByCellId: 300
34
- };
35
- var DEFAULT_LIMIT_PER_MIN = 300;
36
- var WINDOW_MS2 = 6e4;
37
- var METRIC_EMIT_MIN_INTERVAL_MS = 1e4;
38
- var BATCH_FRACTION = 0.2;
39
- function resellerKeyHash(resellerKey) {
40
- if (!resellerKey) return "00000000";
41
- let h = 5381;
42
- for (let i = 0; i < resellerKey.length; i++) {
43
- h = ((h << 5) + h ^ resellerKey.charCodeAt(i)) >>> 0;
44
- }
45
- return h.toString(16).padStart(8, "0");
46
- }
47
- function emitMetric(endpoint, resellerKey, callsInWindow, limitPerMin) {
48
- const pct = Math.round(callsInWindow / limitPerMin * 100);
49
- const reseller_hash = resellerKeyHash(resellerKey);
50
- console.log(
51
- JSON.stringify({
52
- metric: "carrier_ocs_calls_per_min",
53
- endpoint,
54
- reseller_hash,
55
- calls_in_window: callsInWindow,
56
- limit_per_min: limitPerMin,
57
- utilisation_pct: pct,
58
- alert: pct >= 80,
59
- ts: Date.now()
60
- })
61
- );
62
- if (pct >= 80) {
63
- console.warn(
64
- `[rate-governor] ALERT: ${endpoint} at ${pct}% capacity (${callsInWindow}/${limitPerMin} per min) reseller=${reseller_hash}`
65
- );
66
- }
67
- }
68
- var _endpointWindows = /* @__PURE__ */ new Map();
69
- function _getEndpointState(key) {
70
- let s = _endpointWindows.get(key);
71
- if (!s) {
72
- s = {
73
- log: [],
74
- batchLog: [],
75
- gate: Promise.resolve(),
76
- lastMetricEmitAt: 0,
77
- metricBelowHighUtil: true
78
- };
79
- _endpointWindows.set(key, s);
80
- }
81
- return s;
82
- }
83
- function _prune(log, windowStart) {
84
- let i = 0;
85
- while (i < log.length && log[i] <= windowStart) i++;
86
- return i > 0 ? log.slice(i) : log;
87
- }
88
- async function acquireEndpointSlot(resellerId, endpoint, priority = "interactive") {
89
- const proc = globalThis["process"];
90
- if (proc?.env?.["RATE_FLOOR_DISABLED"] === "true" || globalThis["RATE_FLOOR_DISABLED"] === "true") {
91
- return;
92
- }
93
- await _acquireOneSlot(resellerId, "__global__", priority);
94
- await _acquireOneSlot(resellerId, endpoint, priority);
95
- }
96
- async function _acquireOneSlot(resellerId, endpoint, priority) {
97
- const bucketKey = `${resellerId}:${endpoint}`;
98
- const limitPerMin = ENDPOINT_LIMITS_PER_MIN[endpoint] ?? DEFAULT_LIMIT_PER_MIN;
99
- const batchCap = Math.floor(limitPerMin * BATCH_FRACTION);
100
- const state = _getEndpointState(bucketKey);
101
- const ticket = state.gate.then(async () => {
102
- while (true) {
103
- const now = Date.now();
104
- const windowStart = now - WINDOW_MS2;
105
- state.log = _prune(state.log, windowStart);
106
- state.batchLog = _prune(state.batchLog, windowStart);
107
- const totalInWindow = state.log.length;
108
- const batchInWindow = state.batchLog.length;
109
- if (totalInWindow > 0 && endpoint !== "__global__") {
110
- const utilPct = Math.round(totalInWindow / limitPerMin * 100);
111
- const intervalOk = now - state.lastMetricEmitAt >= METRIC_EMIT_MIN_INTERVAL_MS;
112
- const enteredHighUtil = utilPct >= 80 && state.metricBelowHighUtil;
113
- if (intervalOk || enteredHighUtil) {
114
- emitMetric(endpoint, resellerId, totalInWindow, limitPerMin);
115
- state.lastMetricEmitAt = now;
116
- if (utilPct >= 80) {
117
- state.metricBelowHighUtil = false;
118
- }
119
- }
120
- if (utilPct < 80) {
121
- state.metricBelowHighUtil = true;
122
- }
123
- }
124
- const globalFull = totalInWindow >= limitPerMin;
125
- const batchFull = priority === "batch" && batchInWindow >= batchCap;
126
- if (!globalFull && !batchFull) {
127
- state.log.push(now);
128
- if (priority === "batch") {
129
- state.batchLog.push(now);
130
- }
131
- return;
132
- }
133
- let waitMs;
134
- if (globalFull) {
135
- const oldest = state.log[0];
136
- waitMs = WINDOW_MS2 - (now - oldest) + 1;
137
- } else {
138
- const oldestBatch = state.batchLog[0];
139
- waitMs = WINDOW_MS2 - (now - oldestBatch) + 1;
140
- }
141
- await new Promise((r) => setTimeout(r, waitMs));
142
- }
143
- });
144
- state.gate = ticket;
145
- return ticket;
146
- }
147
- function getLimitForEndpoint(endpoint) {
148
- return ENDPOINT_LIMITS_PER_MIN[endpoint] ?? DEFAULT_LIMIT_PER_MIN;
149
- }
150
- function getRateLimitWindowCounts(resellerKey, endpoint) {
151
- const bucketKey = `${resellerKey}:${endpoint}`;
152
- const state = _endpointWindows.get(bucketKey);
153
- if (!state) {
154
- return { calls_in_window: 0, batch_calls_in_window: 0 };
155
- }
156
- const windowStart = Date.now() - WINDOW_MS2;
157
- let calls_in_window = 0;
158
- for (const ts of state.log) {
159
- if (ts > windowStart) calls_in_window++;
160
- }
161
- let batch_calls_in_window = 0;
162
- for (const ts of state.batchLog) {
163
- if (ts > windowStart) batch_calls_in_window++;
164
- }
165
- return { calls_in_window, batch_calls_in_window };
166
- }
167
-
168
- // ../../packages/ocs-client/dist/chunk-W6L6SMW5.js
169
- var OCS_MAX_USAGE_WINDOW_DAYS = 7;
170
- function clampUsagePeriod(start, end, maxDays = OCS_MAX_USAGE_WINDOW_DAYS) {
171
- const endMs = Date.parse(`${end}T00:00:00Z`);
172
- const startMs = Date.parse(`${start}T00:00:00Z`);
173
- if (Number.isNaN(endMs) || Number.isNaN(startMs) || startMs > endMs) {
174
- return { start, end };
175
- }
176
- const minStartMs = endMs - (maxDays - 1) * 864e5;
177
- if (startMs < minStartMs) {
178
- return { start: new Date(minStartMs).toISOString().slice(0, 10), end };
179
- }
180
- return { start, end };
181
- }
182
- function locationParams(iccid) {
183
- return { iccid };
184
- }
185
- function subscriberIdParams(iccid) {
186
- return { iccid };
187
- }
188
- function networkEventsOverPeriodParams(iccid, start, end) {
189
- return usageOverPeriodParams(iccid, start, end);
190
- }
191
- function usageOverPeriodParams(iccid, start, end) {
192
- const period = clampUsagePeriod(start, end);
193
- return { subscriber: { iccid }, period };
194
- }
195
-
196
19
  // src/tools.ts
197
20
  import { z } from "zod";
198
21
  import * as Sentry from "@sentry/cloudflare";
199
22
 
200
23
  // src/client.ts
201
- var OcsApiError2 = class extends Error {
24
+ var OcsApiError = class extends Error {
202
25
  constructor(code, message, method) {
203
26
  super(`[${method}] OCS error ${code}: ${message}`);
204
27
  this.code = code;
@@ -208,7 +31,7 @@ var OcsApiError2 = class extends Error {
208
31
  code;
209
32
  method;
210
33
  };
211
- var OcsClient2 = class {
34
+ var OcsClient = class {
212
35
  baseUrl;
213
36
  token;
214
37
  constructor(baseUrl2, token2) {
@@ -225,11 +48,11 @@ var OcsClient2 = class {
225
48
  body
226
49
  });
227
50
  if (!res.ok) {
228
- throw new OcsApiError2(res.status, `HTTP ${res.status} ${res.statusText}`, method);
51
+ throw new OcsApiError(res.status, `HTTP ${res.status} ${res.statusText}`, method);
229
52
  }
230
53
  const json = await res.json();
231
54
  if (json.status?.code !== 0) {
232
- throw new OcsApiError2(json.status?.code ?? -1, json.status?.msg ?? "Unknown error", method);
55
+ throw new OcsApiError(json.status?.code ?? -1, json.status?.msg ?? "Unknown error", method);
233
56
  }
234
57
  if (method === "getCustomerTariff" && json["listTariffRule"] !== void 0) {
235
58
  return json["listTariffRule"];
@@ -487,9 +310,9 @@ function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler) {
487
310
  try {
488
311
  const token2 = await ctx.getUserToken(ctx.props.sub);
489
312
  result2 = await handler(args, token2);
490
- } catch (err4) {
313
+ } catch (err5) {
491
314
  try {
492
- Sentry.captureException(err4, {
315
+ Sentry.captureException(err5, {
493
316
  tags: {
494
317
  tool: toolName,
495
318
  feature: "mcp",
@@ -498,8 +321,8 @@ function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler) {
498
321
  });
499
322
  } catch {
500
323
  }
501
- const message = err4 instanceof Error ? err4.message : String(err4);
502
- const ocsCode = err4 instanceof OcsApiError2 ? err4.code : void 0;
324
+ const message = err5 instanceof Error ? err5.message : String(err5);
325
+ const ocsCode = err5 instanceof OcsApiError ? err5.code : void 0;
503
326
  ctx.audit({
504
327
  tool_name: toolName,
505
328
  ocs_method: ocsMethod,
@@ -527,7 +350,7 @@ function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler) {
527
350
  };
528
351
  }
529
352
  async function ocsCall(env, token2, method, params = {}) {
530
- const client = new OcsClient2(env.CARRIER_OCS_BASE_URL, token2);
353
+ const client = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
531
354
  const result2 = await client.call(method, params);
532
355
  return {
533
356
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -536,13 +359,13 @@ async function ocsCall(env, token2, method, params = {}) {
536
359
  async function resolveSubscriberByIccid(env, token2, iccid, cache) {
537
360
  const hit = cache.get(iccid);
538
361
  if (hit) return hit;
539
- const client = new OcsClient2(env.CARRIER_OCS_BASE_URL, token2);
362
+ const client = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
540
363
  const record = await client.call("getSingleSubscriber", { iccid });
541
364
  cache.set(iccid, record);
542
365
  return record;
543
366
  }
544
367
  async function getDefaultResellerId(env, token2) {
545
- const client = new OcsClient2(env.CARRIER_OCS_BASE_URL, token2);
368
+ const client = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
546
369
  const info = await client.call("getResellerInfo", {});
547
370
  const id = info?.id;
548
371
  if (typeof id !== "number") {
@@ -757,7 +580,7 @@ function registerAllTools(server2, ctx) {
757
580
  if (args.msisdn) params.msisdn = args.msisdn;
758
581
  if (args.status) params.status = args.status;
759
582
  if (args.offset !== void 0) params.offset = args.offset;
760
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
583
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
761
584
  const raw = await client.call("listSubscriber", params);
762
585
  const limit = args.limit;
763
586
  const payload = Array.isArray(raw) && typeof limit === "number" && limit >= 0 ? raw.slice(0, limit) : raw;
@@ -3216,11 +3039,11 @@ var ocsAppMethods = ocsSpec.v1_app_methods;
3216
3039
  // src/intelligence.ts
3217
3040
  async function safeCall(env, token2, method, params = {}) {
3218
3041
  try {
3219
- const client = new OcsClient2(env.CARRIER_OCS_BASE_URL, token2);
3042
+ const client = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
3220
3043
  const data = await client.call(method, params);
3221
3044
  return { data, error: null };
3222
- } catch (err4) {
3223
- return { data: null, error: err4 instanceof Error ? err4.message : String(err4) };
3045
+ } catch (err5) {
3046
+ return { data: null, error: err5 instanceof Error ? err5.message : String(err5) };
3224
3047
  }
3225
3048
  }
3226
3049
  async function fetchActiveSubscribers(env, token2, accountId, resellerId) {
@@ -3420,52 +3243,16 @@ function registerIntelligenceTools(server2, ctx) {
3420
3243
  )
3421
3244
  ]);
3422
3245
  const sections = ["# Fleet Health Dashboard\n"];
3246
+ const counts = extractEsimStatusCounts(statusResult.data);
3247
+ const statusOk = statusResult.data !== null && (counts.total > 0 || statusResult.error === null);
3423
3248
  const statusRaw = statusResult.data;
3424
3249
  const statusAccounts = Array.isArray(statusRaw) ? statusRaw : statusRaw?.account ?? [];
3425
- const statusOk = statusResult.data !== null && (statusAccounts.length > 0 || statusResult.error === null);
3426
- const countByState = (account) => {
3427
- const sponsors = account.sponsor ?? [];
3428
- let active = 0, suspended = 0, inventory = 0, other = 0;
3429
- for (const sp of sponsors) {
3430
- const esim = sp.esim ?? {};
3431
- const statuses = esim.status ?? [];
3432
- for (const s of statuses) {
3433
- const count = Number(s.count ?? 0);
3434
- const num = s.statusNum;
3435
- if (typeof num === "number") {
3436
- if (num === 1) active += count;
3437
- else if (num === 2) suspended += count;
3438
- else if (num === 0) inventory += count;
3439
- else other += count;
3440
- continue;
3441
- }
3442
- const str = String(s.statusStr ?? s.name ?? "").toUpperCase();
3443
- if (str === "ACTIVATED" || str === "ACTIVE") active += count;
3444
- else if (str === "SUSPENDED") suspended += count;
3445
- else if (str === "FREE" || str === "INVENTORY" || str === "NOT_ACTIVATED" || str === "AVAILABLE") inventory += count;
3446
- else other += count;
3447
- }
3448
- }
3449
- return { active, suspended, inventory, other };
3450
- };
3451
- let totalActive = 0, totalSuspended = 0, totalInventory = 0, totalOther = 0;
3452
3250
  if (statusOk) {
3453
- for (const account of statusAccounts) {
3454
- const hasSponsors = Array.isArray(account.sponsor);
3455
- if (hasSponsors) {
3456
- const c = countByState(account);
3457
- totalActive += c.active;
3458
- totalSuspended += c.suspended;
3459
- totalInventory += c.inventory;
3460
- totalOther += c.other;
3461
- } else {
3462
- totalActive += Number(account.active ?? 0);
3463
- totalSuspended += Number(account.suspended ?? 0);
3464
- totalInventory += Number(account.inventory ?? account.notActivated ?? 0);
3465
- totalOther += Number(account.other ?? account.terminated ?? 0);
3466
- }
3467
- }
3468
- const total = totalActive + totalSuspended + totalInventory + totalOther;
3251
+ const totalActive = counts.active;
3252
+ const totalSuspended = counts.suspended;
3253
+ const totalInventory = counts.inventory;
3254
+ const totalOther = counts.other;
3255
+ const total = counts.total;
3469
3256
  const utilization = total > 0 ? (totalActive / total * 100).toFixed(1) : "0";
3470
3257
  sections.push(`## eSIM Fleet Status`);
3471
3258
  if (total === 0) {
@@ -4262,7 +4049,7 @@ function registerAllBacklogTools(server2, ctx) {
4262
4049
  ctx,
4263
4050
  async ({ iccid, phone_number, phone_type }, token2) => {
4264
4051
  const ocsMethod = phone_type === "fake" ? "affectSubscriberFakePhoneNumber" : "affectSubscriberRealPhoneNumber";
4265
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4052
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4266
4053
  const result2 = await client.call(ocsMethod, { subscriber: iccid, phoneNumber: phone_number });
4267
4054
  return {
4268
4055
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -4300,7 +4087,7 @@ function registerAllBacklogTools(server2, ctx) {
4300
4087
  cell_id,
4301
4088
  signal_strength
4302
4089
  }, token2) => {
4303
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4090
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4304
4091
  const params = { radioType: radio_type, mcc, mnc, lac };
4305
4092
  if (cell_id !== void 0) params.cellId = cell_id;
4306
4093
  if (signal_strength !== void 0) params.signalStrength = signal_strength;
@@ -4328,7 +4115,7 @@ function registerAllBacklogTools(server2, ctx) {
4328
4115
  ctx,
4329
4116
  async ({ resellerId }, token2) => {
4330
4117
  const id = resellerId ?? await (async () => {
4331
- const client2 = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4118
+ const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4332
4119
  const info = await client2.call("getResellerInfo", {});
4333
4120
  const resolvedId = info?.id;
4334
4121
  if (typeof resolvedId !== "number") {
@@ -4336,7 +4123,7 @@ function registerAllBacklogTools(server2, ctx) {
4336
4123
  }
4337
4124
  return resolvedId;
4338
4125
  })();
4339
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4126
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4340
4127
  const result2 = await client.call("listDetailedDestinationList", id);
4341
4128
  return {
4342
4129
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -4362,7 +4149,7 @@ function registerAllBacklogTools(server2, ctx) {
4362
4149
  BACKLOG_TOOL_SCOPES["modify_subscriber_mobile_plan"],
4363
4150
  ctx,
4364
4151
  async ({ iccid, mobile_plan_id }, token2) => {
4365
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4152
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4366
4153
  const result2 = await client.call(
4367
4154
  "modifySubscriberMobilePlan",
4368
4155
  { subscriber: iccid, mobilePlanId: mobile_plan_id }
@@ -4396,7 +4183,7 @@ function registerAllBacklogTools(server2, ctx) {
4396
4183
  const params = { subscriber: iccid, packageId: package_id };
4397
4184
  if (start_date !== void 0) params.startDate = start_date;
4398
4185
  if (end_date !== void 0) params.endDate = end_date;
4399
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4186
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4400
4187
  const result2 = await client.call(
4401
4188
  "modifySubscriberPrepaidPackageActivePeriod",
4402
4189
  params
@@ -4425,7 +4212,7 @@ function registerAllBacklogTools(server2, ctx) {
4425
4212
  BACKLOG_TOOL_SCOPES["modify_subscriber_voip_plan"],
4426
4213
  ctx,
4427
4214
  async ({ iccid, voip_plan_id }, token2) => {
4428
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4215
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4429
4216
  const result2 = await client.call(
4430
4217
  "modifySubscriberVoipPlan",
4431
4218
  { subscriber: iccid, voipPlanId: voip_plan_id }
@@ -4456,7 +4243,7 @@ function registerAllBacklogTools(server2, ctx) {
4456
4243
  const cache = /* @__PURE__ */ new Map();
4457
4244
  const sub = await resolveSubscriberByIccid(ctx.env, token2, iccid, cache);
4458
4245
  const subscriberId = sub.id ?? sub.subscriberId ?? iccid;
4459
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4246
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4460
4247
  const result2 = await client.call(
4461
4248
  "pushSteeringToSubs",
4462
4249
  { subscriber: subscriberId }
@@ -4484,7 +4271,7 @@ function registerAllBacklogTools(server2, ctx) {
4484
4271
  BACKLOG_TOOL_SCOPES["reset_subscriber_gz_counter"],
4485
4272
  ctx,
4486
4273
  async ({ iccid }, token2) => {
4487
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4274
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4488
4275
  const result2 = await client.call("resetSubsGzCounter", { subscriber: iccid });
4489
4276
  return {
4490
4277
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -4508,7 +4295,7 @@ function registerAllBacklogTools(server2, ctx) {
4508
4295
  BACKLOG_TOOL_SCOPES["carrier_webhook_config"],
4509
4296
  ctx,
4510
4297
  async ({ reseller_id }, token2) => {
4511
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4298
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4512
4299
  let resellerId = reseller_id;
4513
4300
  if (resellerId === void 0) {
4514
4301
  resellerId = await getDefaultResellerId(ctx.env, token2);
@@ -4550,7 +4337,7 @@ function registerAllBacklogTools(server2, ctx) {
4550
4337
  BACKLOG_TOOL_SCOPES["list_subscriber_voip_tariff"],
4551
4338
  ctx,
4552
4339
  async ({ reseller_id }, token2) => {
4553
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4340
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4554
4341
  const params = {};
4555
4342
  if (reseller_id !== void 0) {
4556
4343
  params.resellerId = reseller_id;
@@ -4580,7 +4367,7 @@ function registerAllBacklogTools(server2, ctx) {
4580
4367
  BACKLOG_TOOL_SCOPES["list_voip_tariff_rule"],
4581
4368
  ctx,
4582
4369
  async ({ voip_plan_id }, token2) => {
4583
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4370
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4584
4371
  const result2 = await client.call("listVoipTariffRule", voip_plan_id);
4585
4372
  return {
4586
4373
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -4609,7 +4396,7 @@ function registerAllBacklogTools(server2, ctx) {
4609
4396
  location_zone_id,
4610
4397
  network_profile_id
4611
4398
  }, token2) => {
4612
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4399
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4613
4400
  const result2 = await client.call("changeNetworkProfileOfLocationZone", {
4614
4401
  locationZoneId: location_zone_id,
4615
4402
  networkProfileId: network_profile_id
@@ -4659,7 +4446,8 @@ var TOOL_REGISTRY = /* @__PURE__ */ new Set([
4659
4446
  "greenzone_whitelist_list",
4660
4447
  // router tools (self-reference)
4661
4448
  "carrier_ask",
4662
- "carrier_ask_describe"
4449
+ "carrier_ask_describe",
4450
+ "generate_storefront_logo"
4663
4451
  ]);
4664
4452
  var HARD_BLOCK_TOOLS = /* @__PURE__ */ new Set([
4665
4453
  "clean_all_packages",
@@ -5137,10 +4925,10 @@ async function callBedrock(env, payload) {
5137
4925
  const body = await resp.text();
5138
4926
  if (resp.status === 429) {
5139
4927
  const retryAfter = resp.headers.get("retry-after");
5140
- const err4 = new Error(`Bedrock rate limit: ${body}`);
5141
- err4.isRateLimit = true;
5142
- err4.retryAfter = retryAfter;
5143
- throw err4;
4928
+ const err5 = new Error(`Bedrock rate limit: ${body}`);
4929
+ err5.isRateLimit = true;
4930
+ err5.retryAfter = retryAfter;
4931
+ throw err5;
5144
4932
  }
5145
4933
  throw new Error(`Bedrock invoke failed: ${resp.status} ${body}`);
5146
4934
  }
@@ -5178,9 +4966,9 @@ Pre-resolved context: ${JSON.stringify(definedContext)}` : "";
5178
4966
  AWS_REGION: env.AWS_REGION,
5179
4967
  BEDROCK_MODEL_ID: env.BEDROCK_MODEL_ID
5180
4968
  }, payload);
5181
- } catch (err4) {
5182
- if (err4 instanceof Error && err4.isRateLimit) {
5183
- const retryAfter = err4.retryAfter;
4969
+ } catch (err5) {
4970
+ if (err5 instanceof Error && err5.isRateLimit) {
4971
+ const retryAfter = err5.retryAfter;
5184
4972
  const parsedSeconds = retryAfter ? parseInt(retryAfter, 10) : 60;
5185
4973
  return {
5186
4974
  match: "rate_limited",
@@ -5188,7 +4976,7 @@ Pre-resolved context: ${JSON.stringify(definedContext)}` : "";
5188
4976
  suggestion: "Bedrock rate limit reached. Please retry after the indicated delay."
5189
4977
  };
5190
4978
  }
5191
- throw err4;
4979
+ throw err5;
5192
4980
  }
5193
4981
  const toolUseBlock = response.content.find(
5194
4982
  (block) => block.type === "tool_use"
@@ -5362,7 +5150,7 @@ function registerAllCarrierAskTools(server2, ctx) {
5362
5150
  let route;
5363
5151
  try {
5364
5152
  route = await _routeIntent(intent, context, ctx.env);
5365
- } catch (err4) {
5153
+ } catch (err5) {
5366
5154
  writeCarrierAskAudit(ctx.env, {
5367
5155
  intent_hash: intentHash,
5368
5156
  match: "error",
@@ -5379,7 +5167,7 @@ function registerAllCarrierAskTools(server2, ctx) {
5379
5167
  type: "text",
5380
5168
  text: JSON.stringify({
5381
5169
  error: "routing_error",
5382
- message: err4 instanceof Error ? err4.message : "An unexpected error occurred during routing."
5170
+ message: err5 instanceof Error ? err5.message : "An unexpected error occurred during routing."
5383
5171
  })
5384
5172
  }
5385
5173
  ],
@@ -5631,8 +5419,8 @@ function registerListRecentOcsEventsTool(server2, env) {
5631
5419
  return {
5632
5420
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
5633
5421
  };
5634
- } catch (err4) {
5635
- const message = err4 instanceof Error ? err4.message : String(err4);
5422
+ } catch (err5) {
5423
+ const message = err5 instanceof Error ? err5.message : String(err5);
5636
5424
  return {
5637
5425
  isError: true,
5638
5426
  content: [{ type: "text", text: `Error reading OCS event buffer: ${message}` }]
@@ -5915,10 +5703,10 @@ import {
5915
5703
  async function safeCallWithToken(client, _token, method, params = {}) {
5916
5704
  try {
5917
5705
  return { data: await client.call(method, params), error: null };
5918
- } catch (err4) {
5706
+ } catch (err5) {
5919
5707
  return {
5920
5708
  data: null,
5921
- error: err4 instanceof Error ? err4.message : String(err4)
5709
+ error: err5 instanceof Error ? err5.message : String(err5)
5922
5710
  };
5923
5711
  }
5924
5712
  }
@@ -5977,7 +5765,7 @@ function registerFleetHealthApp(server2, ctx) {
5977
5765
  },
5978
5766
  async ({ accountId }) => {
5979
5767
  const token2 = await ctx.getUserToken(ctx.props.sub);
5980
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
5768
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
5981
5769
  const [statusResult, accountsResult] = await Promise.all([
5982
5770
  safeCallWithToken(
5983
5771
  client,
@@ -6116,10 +5904,10 @@ async function deleteWizardSession(env, sub, wizardId) {
6116
5904
  async function safeCallWithToken2(client, _token, method, params = {}) {
6117
5905
  try {
6118
5906
  return { data: await client.call(method, params), error: null };
6119
- } catch (err4) {
5907
+ } catch (err5) {
6120
5908
  return {
6121
5909
  data: null,
6122
- error: err4 instanceof Error ? err4.message : String(err4)
5910
+ error: err5 instanceof Error ? err5.message : String(err5)
6123
5911
  };
6124
5912
  }
6125
5913
  }
@@ -6182,7 +5970,7 @@ function registerProvisioningWizard(server2, ctx) {
6182
5970
  },
6183
5971
  async ({ step, wizardId, subscriber_iccid, package_template_id }) => {
6184
5972
  const token2 = await ctx.getUserToken(ctx.props.sub);
6185
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
5973
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
6186
5974
  if (step === "init") {
6187
5975
  const newWizardId = generateWizardId();
6188
5976
  const subscribersResult = await safeCallWithToken2(
@@ -6479,10 +6267,10 @@ import {
6479
6267
  async function safeCallWithToken3(client, _token, method, params = {}) {
6480
6268
  try {
6481
6269
  return { data: await client.call(method, params), error: null };
6482
- } catch (err4) {
6270
+ } catch (err5) {
6483
6271
  return {
6484
6272
  data: null,
6485
- error: err4 instanceof Error ? err4.message : String(err4)
6273
+ error: err5 instanceof Error ? err5.message : String(err5)
6486
6274
  };
6487
6275
  }
6488
6276
  }
@@ -6521,7 +6309,7 @@ function registerBalanceTopupApp(server2, ctx) {
6521
6309
  "balance_topup_form",
6522
6310
  {
6523
6311
  title: "Balance Top-up Form",
6524
- description: "Enterprise admin tool: preview or commit an account balance adjustment. Set preview=true to fetch projection (no OCS write); preview=false (default) to execute. Requires admin scope + recent MFA.",
6312
+ description: "Adjust the OCS reseller-account balance behind one subscriber, through a form panel the user can review before it commits. Defaults to preview: a call that omits `preview` returns a projection and writes nothing. Only `preview: false` performs the OCS write. Params: `iccid` (subscriber identifier used to find the account), `delta` (amount to add when positive, deduct when negative), `preview` (boolean, default true). Requires `admin` scope plus recent MFA, and a client that can render UI panels. Do NOT use this in a headless or scripted context \u2014 call `modify_account_balance` directly, which takes an `accountId` and needs no panel. Do NOT use this for a subscriber's own balance \u2014 the `iccid` here only locates the account; per-subscriber money is `modify_subscriber_balance`. Do NOT use this for the Carrier prepaid wallet or MCP credits \u2014 see `wallet_topup_checkout` and `credit_balance`.",
6525
6313
  inputSchema: {
6526
6314
  iccid: z11.string().describe("The subscriber ICCID for the account lookup"),
6527
6315
  delta: z11.number().describe("Amount to add (positive) or deduct (negative) from the account balance"),
@@ -6542,7 +6330,7 @@ function registerBalanceTopupApp(server2, ctx) {
6542
6330
  ctx,
6543
6331
  async ({ iccid, delta, preview }) => {
6544
6332
  const token2 = await ctx.getUserToken(ctx.props.sub);
6545
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
6333
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
6546
6334
  if (preview === true) {
6547
6335
  const result2 = await safeCallWithToken3(
6548
6336
  client,
@@ -8143,8 +7931,8 @@ function buildPricingHandler(tool, ctx) {
8143
7931
  }
8144
7932
  ]
8145
7933
  };
8146
- } catch (err4) {
8147
- const message = err4 instanceof Error ? err4.message : String(err4);
7934
+ } catch (err5) {
7935
+ const message = err5 instanceof Error ? err5.message : String(err5);
8148
7936
  ctx.audit({
8149
7937
  tool_name: tool.name,
8150
7938
  ocs_method: "billing",
@@ -8464,8 +8252,8 @@ function writeUsageThresholdAudit(env, severity, remainingCredits, month, taskCo
8464
8252
  doubles: [remainingCredits],
8465
8253
  indexes: ["manus_usage"]
8466
8254
  });
8467
- } catch (err4) {
8468
- console.error(`[manus-usage] threshold audit write failed: ${err4.message}`);
8255
+ } catch (err5) {
8256
+ console.error(`[manus-usage] threshold audit write failed: ${err5.message}`);
8469
8257
  }
8470
8258
  }
8471
8259
 
@@ -8575,7 +8363,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8575
8363
  }
8576
8364
  ]
8577
8365
  };
8578
- } catch (err4) {
8366
+ } catch (err5) {
8579
8367
  ctx.audit({
8580
8368
  tool_name: "ui_agent_schedule_create",
8581
8369
  ocs_method: "[manus:schedule.create]",
@@ -8584,7 +8372,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8584
8372
  duration_ms: Date.now() - start,
8585
8373
  event_type: "ui_agent_dispatch"
8586
8374
  });
8587
- const msg = err4 instanceof ManusScheduleError ? `Manus API error (HTTP ${err4.statusCode}): ${err4.message}` : err4 instanceof Error ? err4.message : String(err4);
8375
+ const msg = err5 instanceof ManusScheduleError ? `Manus API error (HTTP ${err5.statusCode}): ${err5.message}` : err5 instanceof Error ? err5.message : String(err5);
8588
8376
  return { isError: true, content: [{ type: "text", text: msg }] };
8589
8377
  }
8590
8378
  }
@@ -8642,7 +8430,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8642
8430
  }
8643
8431
  ]
8644
8432
  };
8645
- } catch (err4) {
8433
+ } catch (err5) {
8646
8434
  ctx.audit({
8647
8435
  tool_name: "ui_agent_schedule_list",
8648
8436
  ocs_method: "[manus:schedule.list]",
@@ -8650,7 +8438,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8650
8438
  dry_run: false,
8651
8439
  duration_ms: Date.now() - start
8652
8440
  });
8653
- const msg = err4 instanceof ManusScheduleError ? `Manus API error (HTTP ${err4.statusCode}): ${err4.message}` : err4 instanceof Error ? err4.message : String(err4);
8441
+ const msg = err5 instanceof ManusScheduleError ? `Manus API error (HTTP ${err5.statusCode}): ${err5.message}` : err5 instanceof Error ? err5.message : String(err5);
8654
8442
  return { isError: true, content: [{ type: "text", text: msg }] };
8655
8443
  }
8656
8444
  }
@@ -8711,7 +8499,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8711
8499
  }
8712
8500
  ]
8713
8501
  };
8714
- } catch (err4) {
8502
+ } catch (err5) {
8715
8503
  ctx.audit({
8716
8504
  tool_name: "ui_agent_schedule_delete",
8717
8505
  ocs_method: "[manus:schedule.delete]",
@@ -8720,7 +8508,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8720
8508
  duration_ms: Date.now() - start,
8721
8509
  event_type: "ui_agent_dispatch"
8722
8510
  });
8723
- const msg = err4 instanceof ManusScheduleError ? `Manus API error (HTTP ${err4.statusCode}): ${err4.message}` : err4 instanceof Error ? err4.message : String(err4);
8511
+ const msg = err5 instanceof ManusScheduleError ? `Manus API error (HTTP ${err5.statusCode}): ${err5.message}` : err5 instanceof Error ? err5.message : String(err5);
8724
8512
  return { isError: true, content: [{ type: "text", text: msg }] };
8725
8513
  }
8726
8514
  }
@@ -8781,7 +8569,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8781
8569
  }
8782
8570
  ]
8783
8571
  };
8784
- } catch (err4) {
8572
+ } catch (err5) {
8785
8573
  ctx.audit({
8786
8574
  tool_name: "ui_agent_schedule_pause",
8787
8575
  ocs_method: "[manus:schedule.pause]",
@@ -8790,7 +8578,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8790
8578
  duration_ms: Date.now() - start,
8791
8579
  event_type: "ui_agent_dispatch"
8792
8580
  });
8793
- const msg = err4 instanceof ManusScheduleError ? `Manus API error (HTTP ${err4.statusCode}): ${err4.message}` : err4 instanceof Error ? err4.message : String(err4);
8581
+ const msg = err5 instanceof ManusScheduleError ? `Manus API error (HTTP ${err5.statusCode}): ${err5.message}` : err5 instanceof Error ? err5.message : String(err5);
8794
8582
  return { isError: true, content: [{ type: "text", text: msg }] };
8795
8583
  }
8796
8584
  }
@@ -8851,7 +8639,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8851
8639
  }
8852
8640
  ]
8853
8641
  };
8854
- } catch (err4) {
8642
+ } catch (err5) {
8855
8643
  ctx.audit({
8856
8644
  tool_name: "ui_agent_schedule_resume",
8857
8645
  ocs_method: "[manus:schedule.resume]",
@@ -8860,7 +8648,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8860
8648
  duration_ms: Date.now() - start,
8861
8649
  event_type: "ui_agent_dispatch"
8862
8650
  });
8863
- const msg = err4 instanceof ManusScheduleError ? `Manus API error (HTTP ${err4.statusCode}): ${err4.message}` : err4 instanceof Error ? err4.message : String(err4);
8651
+ const msg = err5 instanceof ManusScheduleError ? `Manus API error (HTTP ${err5.statusCode}): ${err5.message}` : err5 instanceof Error ? err5.message : String(err5);
8864
8652
  return { isError: true, content: [{ type: "text", text: msg }] };
8865
8653
  }
8866
8654
  }
@@ -8905,7 +8693,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8905
8693
  }
8906
8694
  ]
8907
8695
  };
8908
- } catch (err4) {
8696
+ } catch (err5) {
8909
8697
  ctx.audit({
8910
8698
  tool_name: "ui_agent_usage",
8911
8699
  ocs_method: "[manus:usage.get]",
@@ -8913,7 +8701,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8913
8701
  dry_run: false,
8914
8702
  duration_ms: Date.now() - start
8915
8703
  });
8916
- const msg = err4 instanceof Error ? err4.message : String(err4);
8704
+ const msg = err5 instanceof Error ? err5.message : String(err5);
8917
8705
  return { isError: true, content: [{ type: "text", text: msg }] };
8918
8706
  }
8919
8707
  }
@@ -9156,7 +8944,7 @@ Report success or failure with a clear summary.`;
9156
8944
  }
9157
8945
  ]
9158
8946
  };
9159
- } catch (err4) {
8947
+ } catch (err5) {
9160
8948
  ctx.audit({
9161
8949
  tool_name: toolName,
9162
8950
  ocs_method: `[ui-agent:${gapId}]`,
@@ -9170,7 +8958,7 @@ Report success or failure with a clear summary.`;
9170
8958
  content: [
9171
8959
  {
9172
8960
  type: "text",
9173
- text: `Error dispatching UI agent: ${err4 instanceof Error ? err4.message : String(err4)}`
8961
+ text: `Error dispatching UI agent: ${err5 instanceof Error ? err5.message : String(err5)}`
9174
8962
  }
9175
8963
  ]
9176
8964
  };
@@ -9594,7 +9382,7 @@ function registerUiAgentAskTools(server2, ctx) {
9594
9382
  try {
9595
9383
  const replyOutcome = await askReply(keys, task_id, reply);
9596
9384
  result2 = replyOutcome.data;
9597
- } catch (err4) {
9385
+ } catch (err5) {
9598
9386
  ctx.audit({
9599
9387
  tool_name: "ui_agent_reply",
9600
9388
  ocs_method: "[ui-agent:ask-reply]",
@@ -9609,7 +9397,7 @@ function registerUiAgentAskTools(server2, ctx) {
9609
9397
  content: [
9610
9398
  {
9611
9399
  type: "text",
9612
- text: `Error calling Manus task.reply: ${err4 instanceof Error ? err4.message : String(err4)}`
9400
+ text: `Error calling Manus task.reply: ${err5 instanceof Error ? err5.message : String(err5)}`
9613
9401
  }
9614
9402
  ]
9615
9403
  };
@@ -9687,13 +9475,13 @@ function registerUiAgentAskTools(server2, ctx) {
9687
9475
  try {
9688
9476
  const listing = await ctx.env.CARRIER_USERS.list({ prefix: PENDING_ASK_PREFIX });
9689
9477
  keys = listing.keys;
9690
- } catch (err4) {
9478
+ } catch (err5) {
9691
9479
  return {
9692
9480
  isError: true,
9693
9481
  content: [
9694
9482
  {
9695
9483
  type: "text",
9696
- text: `Error listing pending tasks: ${err4 instanceof Error ? err4.message : String(err4)}`
9484
+ text: `Error listing pending tasks: ${err5 instanceof Error ? err5.message : String(err5)}`
9697
9485
  }
9698
9486
  ]
9699
9487
  };
@@ -9864,7 +9652,7 @@ function registerStripeConnectTools(server2, ctx) {
9864
9652
  );
9865
9653
  server2.tool(
9866
9654
  "stripe_connect_payouts",
9867
- "Read-only: list recent payouts for the operator's connected Stripe account.",
9655
+ "List money Stripe has already sent from the operator's connected account to their bank, newest first. Read-only. Params: `limit` (1-50, default 10), `status` (optional Stripe payout status, e.g. 'paid', 'pending', 'failed'). Returns: { payouts: [{ id, amount, currency, status, arrival_date, automatic, created }], has_more } \u2014 amount in the currency's smallest unit. Do NOT use this for money still sitting at Stripe and not yet paid out \u2014 use `stripe_connect_balance`.",
9868
9656
  {
9869
9657
  limit: z17.number().int().min(1).max(50).default(10).describe("Number of payouts to return."),
9870
9658
  status: z17.enum(["pending", "paid", "failed", "canceled", "in_transit"]).optional().describe("Filter by payout status.")
@@ -9898,7 +9686,7 @@ function registerStripeConnectTools(server2, ctx) {
9898
9686
  );
9899
9687
  server2.tool(
9900
9688
  "stripe_connect_balance",
9901
- "Read-only: returns the current available and pending balance per currency for the operator's connected Stripe account.",
9689
+ "Read the money sitting in the operator's connected Stripe account: available and pending, split per currency. Params: none (the connected account is resolved from the session). Returns: { account_id, available: [{ amount, currency }], pending: [{ amount, currency }] } \u2014 amounts in the currency's smallest unit (cents for EUR/USD). Do NOT use this for the Carrier prepaid wallet \u2014 use `wallet_balance`. Do NOT use this for money already paid out to the bank \u2014 use `stripe_connect_payouts`.",
9902
9690
  {},
9903
9691
  async () => {
9904
9692
  const start = Date.now();
@@ -9931,7 +9719,7 @@ function registerStripeConnectTools(server2, ctx) {
9931
9719
  );
9932
9720
  server2.tool(
9933
9721
  "stripe_connect_refund",
9934
- "Admin: issue a refund on a charge via the operator's connected Stripe account. Requires confirm_token (call without token first to get one).",
9722
+ "Refund money to a customer on one charge in the operator's connected Stripe account. This returns real funds and Stripe cannot reverse a refund once issued. Two-step by design: call without `confirm_token` to get a token and a summary of what would be refunded, then call again with that token to execute. The token expires in 5 minutes. Params: `charge_id` (Stripe charge id, `ch_...`), `amount_cents` (optional integer in the charge's smallest currency unit \u2014 omit for a full refund), `reason` ('duplicate' | 'fraudulent' | 'requested_by_customer', optional), `confirm_token`. Returns: the refund id and status. Requires `write` scope. Do NOT use this to stop a charge that has not settled yet \u2014 decline it with `radar_review_decline`. Do NOT use this to contest a chargeback \u2014 read the case with `stripe_connect_dispute_list` first, since refunding a disputed charge can cost the operator twice.",
9935
9723
  {
9936
9724
  charge_id: z17.string().min(1).describe("Stripe charge ID (ch_...)."),
9937
9725
  amount_cents: z17.number().int().min(1).optional().describe("Partial refund amount in cents. Omit for full refund."),
@@ -9981,7 +9769,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
9981
9769
  );
9982
9770
  server2.tool(
9983
9771
  "stripe_connect_dispute_list",
9984
- "Read-only: list active disputes for the operator's connected Stripe account.",
9772
+ "List chargebacks customers have raised with their bank against the operator's connected Stripe account. Read-only \u2014 responding to one is Dashboard work. Params: `limit` (1-50, default 10), `status` (optional Stripe dispute status, e.g. 'needs_response', 'under_review'). Returns: { disputes: [{ id, charge, amount, currency, status, reason, evidence_details.due_by }], has_more } \u2014 amount in the currency's smallest unit, `due_by` a Unix timestamp or null. Do NOT use this for charges Stripe is holding for fraud review before they settle \u2014 those are `radar_review_list`. Check this before refunding: refunding a disputed charge can cost the operator the amount twice.",
9985
9773
  {
9986
9774
  limit: z17.number().int().min(1).max(50).default(10),
9987
9775
  status: z17.string().optional().describe("Filter by dispute status (e.g. needs_response, under_review).")
@@ -10015,7 +9803,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
10015
9803
  );
10016
9804
  server2.tool(
10017
9805
  "radar_review_list",
10018
- "Read-only: list pending Radar reviews requiring manual platform decision.",
9806
+ "List the Stripe Radar fraud reviews waiting on a manual approve/decline decision, newest first. Reads only \u2014 deciding a review is a separate call. Params: `open_only` (boolean, default true \u2014 false also returns already-decided reviews), `limit` (1-50, default 10). Returns: { reviews: [{ id (`prv_...`), charge, reason, opened_reason, closed_reason, created, closed }], has_more }. Call this first to get the `review_id` that `radar_review_approve` and `radar_review_decline` require. Do NOT use this for chargebacks the customer has already raised with their bank \u2014 use `stripe_connect_dispute_list`.",
10019
9807
  {
10020
9808
  open_only: z17.boolean().default(true).describe("If true, only returns open (undecided) reviews."),
10021
9809
  limit: z17.number().int().min(1).max(50).default(10)
@@ -10047,7 +9835,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
10047
9835
  );
10048
9836
  server2.tool(
10049
9837
  "radar_review_approve",
10050
- "Admin: approve a Radar review, allowing the charge to proceed. Requires confirm_token.",
9838
+ "Clear a Stripe Radar fraud review so the held charge is captured and the money is taken. Approving overrides Radar's fraud signal, so a genuinely fraudulent charge approved here usually returns later as a chargeback plus a fee. Two-step by design: call without `confirm_token` to get a token, then call again with it to execute. Params: `review_id` (`prv_...`, from `radar_review_list`), `confirm_token`. Requires `admin` scope. Do NOT call this to block a suspicious charge \u2014 that is `radar_review_decline`, the opposite outcome. Do NOT call this to return money on a charge that already went through \u2014 that is `stripe_connect_refund`.",
10051
9839
  {
10052
9840
  review_id: z17.string().min(1).describe("Stripe Radar review ID (prv_...)."),
10053
9841
  confirm_token: z17.string().optional()
@@ -10092,7 +9880,7 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
10092
9880
  );
10093
9881
  server2.tool(
10094
9882
  "radar_review_decline",
10095
- "Admin: decline a Radar review, blocking/closing the charge. Requires confirm_token.",
9883
+ "Close a Stripe Radar fraud review as fraudulent, so the held charge is blocked and the customer is never billed. The customer sees a failed payment; if they were legitimate, they have to pay again. Two-step by design: call without `confirm_token` to get a token, then call again with it to execute. Params: `review_id` (`prv_...`, from `radar_review_list`), `confirm_token`. Requires `admin` scope. Do NOT call this to let a charge through \u2014 that is `radar_review_approve`, the opposite outcome. Do NOT call this on a charge that already succeeded; a review only exists while the charge is held, and returning settled money is `stripe_connect_refund`.",
10096
9884
  {
10097
9885
  review_id: z17.string().min(1),
10098
9886
  confirm_token: z17.string().optional()
@@ -10137,7 +9925,7 @@ Expires in 5 minutes.`
10137
9925
  );
10138
9926
  server2.tool(
10139
9927
  "radar_value_list_add",
10140
- "Admin: add an item (email, IP, card fingerprint, country code) to a Stripe Radar block/allow list. Requires confirm_token.",
9928
+ "Add one value to an existing Stripe Radar value list, changing how every future charge is scored. Whether the value ends up blocked or allowed depends entirely on which list you name in `value_list_id` \u2014 this tool does not choose, and putting a value on the allow list when you meant the block list silently lets fraud through. Confirm the list's purpose before calling. Two-step by design: call without `confirm_token` to get a token, then call again with it to execute. Params: `value_list_id` (`rsl_...`, an existing list), `value` (one email, IP address, card fingerprint, or ISO country code \u2014 one item per call), `confirm_token`. Requires `admin` scope. Do NOT use this to decide a single charge that is already under review \u2014 use `radar_review_approve` or `radar_review_decline`. Do NOT use this to create a list or a rule: only `value` is added, and rules cannot be edited through this API at all (see `radar_rule_toggle`).",
10141
9929
  {
10142
9930
  value_list_id: z17.string().min(1).describe("Stripe Radar value list ID (rsl_...)."),
10143
9931
  value: z17.string().min(1).describe("The value to add (email, IP address, country code, etc.)."),
@@ -10183,7 +9971,7 @@ Expires in 5 minutes.`
10183
9971
  );
10184
9972
  server2.tool(
10185
9973
  "radar_rule_toggle",
10186
- "Admin: enable or disable a Stripe Radar rule. NOTE: Stripe does not expose rule CRUD via the public API \u2014 this tool returns Dashboard instructions.",
9974
+ "Return the Stripe Dashboard steps for enabling or disabling a Radar rule. This tool changes nothing: Stripe has no public API for rule state, so the call always succeeds and the rule stays exactly as it was. Never report the rule as toggled. Params: `rule_id` (Stripe Radar rule id), `enabled` (true for the enable instructions, false for disable). Returns: the Dashboard URL and steps for a human to follow. Requires `admin` scope. Do NOT use this when a change must actually take effect from an agent \u2014 the only Radar state reachable through this API is value-list membership, via `radar_value_list_add`.",
10187
9975
  {
10188
9976
  rule_id: z17.string().min(1).describe("Stripe Radar rule ID."),
10189
9977
  enabled: z17.boolean().describe("true = enable, false = disable.")
@@ -10708,6 +10496,46 @@ function registerUiAgentGenericTools(server2, _ctx) {
10708
10496
  );
10709
10497
  }
10710
10498
 
10499
+ // src/tools-storefront-logo.ts
10500
+ import { z as z20 } from "zod";
10501
+ var ok4 = (text) => ({ content: [{ type: "text", text }] });
10502
+ var err4 = (text) => ({ isError: true, content: [{ type: "text", text }] });
10503
+ function registerStorefrontLogoTools(server2, env = {}) {
10504
+ server2.tool(
10505
+ "generate_storefront_logo",
10506
+ "Generate a storefront logo (SVG always; PNG when an image key is configured on the Carrier worker). Works for any authenticated Carrier MCP user \u2014 no local image-API key required. Write the SVG to public/brand/logo.svg in the storefront.",
10507
+ {
10508
+ name: z20.string().min(1).describe("Brand / shop name, e.g. Bananas"),
10509
+ accent: z20.string().regex(/^#?[0-9A-Fa-f]{6}$/).optional().describe("Accent hex, e.g. #FF8A00"),
10510
+ tagline: z20.string().optional().describe("Optional tagline for AI-enhanced marks")
10511
+ },
10512
+ async ({ name, accent, tagline }) => {
10513
+ try {
10514
+ const hex = accent ? accent.startsWith("#") ? accent : `#${accent}` : void 0;
10515
+ const logo = await generateStorefrontLogo({
10516
+ name,
10517
+ accent: hex,
10518
+ tagline,
10519
+ env: { ...env, ...process.env }
10520
+ });
10521
+ return ok4(
10522
+ JSON.stringify({
10523
+ brand: name,
10524
+ source: logo.source,
10525
+ filename: "public/brand/logo.svg",
10526
+ png_filename: logo.pngBase64 ? "public/brand/logo.png" : null,
10527
+ svg: logo.svg,
10528
+ png_base64: logo.pngBase64 ?? null,
10529
+ next: "Write svg to the storefront public/brand/logo.svg (and png if present). Nav and icons read that path."
10530
+ })
10531
+ );
10532
+ } catch (e) {
10533
+ return err4(e instanceof Error ? e.message : "logo generation failed");
10534
+ }
10535
+ }
10536
+ );
10537
+ }
10538
+
10711
10539
  // src/index.ts
10712
10540
  var baseUrl = process.env.CARRIER_OCS_BASE_URL ?? process.env.ESIMVAULT_BASE_URL ?? "https://ocs.esimvault.cloud";
10713
10541
  var token = process.env.CARRIER_OCS_API_TOKEN ?? process.env.ESIMVAULT_API_TOKEN;
@@ -10745,7 +10573,7 @@ var audit = (_row) => {
10745
10573
  var getUserToken = async (_sub) => token;
10746
10574
  var toolCtx = { env: stdioEnv, props, audit, getUserToken };
10747
10575
  var server = new McpServer(
10748
- { name: "carrier-mcp", version: "0.2.19" },
10576
+ { name: "carrier-mcp", version: CARRIER_VERSION },
10749
10577
  {
10750
10578
  instructions: "Carrier MCP \u2014 single-user stdio mode. Full tool registry (mirrors the deployed Worker)."
10751
10579
  }
@@ -10766,6 +10594,7 @@ registerUiAgentAskTools(server, toolCtx);
10766
10594
  registerStripeConnectTools(server, { env: stdioEnv, props });
10767
10595
  registerGreenzoneTools(server, toolCtx);
10768
10596
  registerUiAgentGenericTools(server, toolCtx);
10597
+ registerStorefrontLogoTools(server, stdioEnv);
10769
10598
  registerAllPrompts(server);
10770
10599
  var transport = new StdioServerTransport();
10771
10600
  await server.connect(transport);