@carrierllc/mcp 0.2.18 → 0.2.20

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 (45) hide show
  1. package/README.md +22 -1
  2. package/dist/chunk-NHQDO2E7.js +461 -0
  3. package/dist/chunk-NHQDO2E7.js.map +1 -0
  4. package/dist/cli.js +877 -148
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.js +148 -297
  7. package/dist/index.js.map +1 -1
  8. package/package.json +6 -6
  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/package-lock.json +12722 -0
  13. package/templates/storefront/package.json +3 -3
  14. package/templates/storefront/public/brand/logo.svg +13 -0
  15. package/templates/storefront/src/app/activate/[orderId]/ActivateClient.tsx +12 -12
  16. package/templates/storefront/src/app/checkout/[templateId]/CheckoutClient.tsx +5 -5
  17. package/templates/storefront/src/app/checkout/success/CheckoutSuccessClient.tsx +29 -29
  18. package/templates/storefront/src/app/checkout/success/page.tsx +1 -1
  19. package/templates/storefront/src/app/contact/page.tsx +33 -25
  20. package/templates/storefront/src/app/dashboard/page.tsx +7 -4
  21. package/templates/storefront/src/app/globals.css +72 -82
  22. package/templates/storefront/src/app/help/page.tsx +22 -17
  23. package/templates/storefront/src/app/layout.tsx +15 -4
  24. package/templates/storefront/src/app/page.tsx +16 -7
  25. package/templates/storefront/src/app/shop/ShopClient.tsx +7 -3
  26. package/templates/storefront/src/app/sign-in/[[...sign-in]]/page.tsx +1 -1
  27. package/templates/storefront/src/app/sign-up/[[...sign-up]]/StorefrontSignUpClient.tsx +16 -16
  28. package/templates/storefront/src/app/sign-up/[[...sign-up]]/page.tsx +1 -1
  29. package/templates/storefront/src/brand.config.ts +3 -3
  30. package/templates/storefront/src/components/faq/FaqSection.tsx +23 -26
  31. package/templates/storefront/src/components/footer/StorefrontFooter.tsx +37 -22
  32. package/templates/storefront/src/components/landing/FinalCTA.tsx +28 -0
  33. package/templates/storefront/src/components/landing/HeroSection.tsx +57 -24
  34. package/templates/storefront/src/components/landing/HowItWorks.tsx +44 -0
  35. package/templates/storefront/src/components/landing/PlanCard.tsx +58 -28
  36. package/templates/storefront/src/components/nav/StorefrontNav.tsx +59 -24
  37. package/templates/storefront/src/components/theme/BrandStyles.tsx +8 -0
  38. package/templates/storefront/src/components/theme/ThemeToggle.tsx +27 -0
  39. package/templates/storefront/src/components/theme/clerk-appearance.ts +33 -35
  40. package/templates/storefront/src/components/theme/theme-provider.tsx +25 -32
  41. package/templates/storefront/src/components/theme/theme-script.tsx +4 -7
  42. package/templates/storefront/src/lib/checkout-order-claim.ts +16 -2
  43. package/templates/storefront/src/lib/complete-email-sign-up.ts +3 -3
  44. package/templates/storefront/src/lib/verify-checkout-session.ts +19 -2
  45. package/templates/storefront/src/vendor/ui/brand.ts +6 -6
package/dist/index.js CHANGED
@@ -1,4 +1,16 @@
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-NHQDO2E7.js";
2
14
 
3
15
  // src/index.ts
4
16
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -8,169 +20,8 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
8
20
  import { z } from "zod";
9
21
  import * as Sentry from "@sentry/cloudflare";
10
22
 
11
- // ../../packages/ocs-client/dist/chunk-PMFMORPK.js
12
- var ENDPOINT_LIMITS_PER_MIN = {
13
- // Global sentinel (keyed as "__global__")
14
- __global__: 600,
15
- // 30/min — tightest endpoint
16
- subscriberNetworkEventsOverPeriod: 30,
17
- // 100/min
18
- subscriberUsageOverPeriod: 100,
19
- // 150/min
20
- listLocationZoneElement: 150,
21
- sendMtSms: 150,
22
- // 300/min (explicit; also the fallback default)
23
- modifySubscriberMobilePlan: 300,
24
- affectRecurringPackageToSubscriber: 300,
25
- affectSubscriberFakePhoneNumber: 300,
26
- affectSubscriberRealPhoneNumber: 300,
27
- esimStatusPerAccount: 300,
28
- getSubscriberActivePeriod: 300,
29
- hlrGetBitrate: 300,
30
- hlrSetBitrate: 300,
31
- listSubscriber: 300,
32
- listSubscriberPrepaidPackages: 300,
33
- moveSubscriberRangeToAccount: 300,
34
- pushSteeringToSubs: 300,
35
- setSubscriberTrafficRestrictions: 300,
36
- getSingleSubscriber: 300,
37
- getSubscriberLocationByCellId: 300
38
- };
39
- var DEFAULT_LIMIT_PER_MIN = 300;
40
- var WINDOW_MS2 = 6e4;
41
- var METRIC_EMIT_MIN_INTERVAL_MS = 1e4;
42
- var BATCH_FRACTION = 0.2;
43
- function resellerKeyHash(resellerKey) {
44
- if (!resellerKey) return "00000000";
45
- let h = 5381;
46
- for (let i = 0; i < resellerKey.length; i++) {
47
- h = ((h << 5) + h ^ resellerKey.charCodeAt(i)) >>> 0;
48
- }
49
- return h.toString(16).padStart(8, "0");
50
- }
51
- function emitMetric(endpoint, resellerKey, callsInWindow, limitPerMin) {
52
- const pct = Math.round(callsInWindow / limitPerMin * 100);
53
- const reseller_hash = resellerKeyHash(resellerKey);
54
- console.log(
55
- JSON.stringify({
56
- metric: "carrier_ocs_calls_per_min",
57
- endpoint,
58
- reseller_hash,
59
- calls_in_window: callsInWindow,
60
- limit_per_min: limitPerMin,
61
- utilisation_pct: pct,
62
- alert: pct >= 80,
63
- ts: Date.now()
64
- })
65
- );
66
- if (pct >= 80) {
67
- console.warn(
68
- `[rate-governor] ALERT: ${endpoint} at ${pct}% capacity (${callsInWindow}/${limitPerMin} per min) reseller=${reseller_hash}`
69
- );
70
- }
71
- }
72
- var _endpointWindows = /* @__PURE__ */ new Map();
73
- function _getEndpointState(key) {
74
- let s = _endpointWindows.get(key);
75
- if (!s) {
76
- s = {
77
- log: [],
78
- batchLog: [],
79
- gate: Promise.resolve(),
80
- lastMetricEmitAt: 0,
81
- metricBelowHighUtil: true
82
- };
83
- _endpointWindows.set(key, s);
84
- }
85
- return s;
86
- }
87
- function _prune(log, windowStart) {
88
- let i = 0;
89
- while (i < log.length && log[i] <= windowStart) i++;
90
- return i > 0 ? log.slice(i) : log;
91
- }
92
- async function acquireEndpointSlot(resellerId, endpoint, priority = "interactive") {
93
- const proc = globalThis["process"];
94
- if (proc?.env?.["RATE_FLOOR_DISABLED"] === "true" || globalThis["RATE_FLOOR_DISABLED"] === "true") {
95
- return;
96
- }
97
- await _acquireOneSlot(resellerId, "__global__", priority);
98
- await _acquireOneSlot(resellerId, endpoint, priority);
99
- }
100
- async function _acquireOneSlot(resellerId, endpoint, priority) {
101
- const bucketKey = `${resellerId}:${endpoint}`;
102
- const limitPerMin = ENDPOINT_LIMITS_PER_MIN[endpoint] ?? DEFAULT_LIMIT_PER_MIN;
103
- const batchCap = Math.floor(limitPerMin * BATCH_FRACTION);
104
- const state = _getEndpointState(bucketKey);
105
- const ticket = state.gate.then(async () => {
106
- while (true) {
107
- const now = Date.now();
108
- const windowStart = now - WINDOW_MS2;
109
- state.log = _prune(state.log, windowStart);
110
- state.batchLog = _prune(state.batchLog, windowStart);
111
- const totalInWindow = state.log.length;
112
- const batchInWindow = state.batchLog.length;
113
- if (totalInWindow > 0 && endpoint !== "__global__") {
114
- const utilPct = Math.round(totalInWindow / limitPerMin * 100);
115
- const intervalOk = now - state.lastMetricEmitAt >= METRIC_EMIT_MIN_INTERVAL_MS;
116
- const enteredHighUtil = utilPct >= 80 && state.metricBelowHighUtil;
117
- if (intervalOk || enteredHighUtil) {
118
- emitMetric(endpoint, resellerId, totalInWindow, limitPerMin);
119
- state.lastMetricEmitAt = now;
120
- if (utilPct >= 80) {
121
- state.metricBelowHighUtil = false;
122
- }
123
- }
124
- if (utilPct < 80) {
125
- state.metricBelowHighUtil = true;
126
- }
127
- }
128
- const globalFull = totalInWindow >= limitPerMin;
129
- const batchFull = priority === "batch" && batchInWindow >= batchCap;
130
- if (!globalFull && !batchFull) {
131
- state.log.push(now);
132
- if (priority === "batch") {
133
- state.batchLog.push(now);
134
- }
135
- return;
136
- }
137
- let waitMs;
138
- if (globalFull) {
139
- const oldest = state.log[0];
140
- waitMs = WINDOW_MS2 - (now - oldest) + 1;
141
- } else {
142
- const oldestBatch = state.batchLog[0];
143
- waitMs = WINDOW_MS2 - (now - oldestBatch) + 1;
144
- }
145
- await new Promise((r) => setTimeout(r, waitMs));
146
- }
147
- });
148
- state.gate = ticket;
149
- return ticket;
150
- }
151
- function getLimitForEndpoint(endpoint) {
152
- return ENDPOINT_LIMITS_PER_MIN[endpoint] ?? DEFAULT_LIMIT_PER_MIN;
153
- }
154
- function getRateLimitWindowCounts(resellerKey, endpoint) {
155
- const bucketKey = `${resellerKey}:${endpoint}`;
156
- const state = _endpointWindows.get(bucketKey);
157
- if (!state) {
158
- return { calls_in_window: 0, batch_calls_in_window: 0 };
159
- }
160
- const windowStart = Date.now() - WINDOW_MS2;
161
- let calls_in_window = 0;
162
- for (const ts of state.log) {
163
- if (ts > windowStart) calls_in_window++;
164
- }
165
- let batch_calls_in_window = 0;
166
- for (const ts of state.batchLog) {
167
- if (ts > windowStart) batch_calls_in_window++;
168
- }
169
- return { calls_in_window, batch_calls_in_window };
170
- }
171
-
172
23
  // src/client.ts
173
- var OcsApiError2 = class extends Error {
24
+ var OcsApiError = class extends Error {
174
25
  constructor(code, message, method) {
175
26
  super(`[${method}] OCS error ${code}: ${message}`);
176
27
  this.code = code;
@@ -180,7 +31,7 @@ var OcsApiError2 = class extends Error {
180
31
  code;
181
32
  method;
182
33
  };
183
- var OcsClient2 = class {
34
+ var OcsClient = class {
184
35
  baseUrl;
185
36
  token;
186
37
  constructor(baseUrl2, token2) {
@@ -197,11 +48,11 @@ var OcsClient2 = class {
197
48
  body
198
49
  });
199
50
  if (!res.ok) {
200
- throw new OcsApiError2(res.status, `HTTP ${res.status} ${res.statusText}`, method);
51
+ throw new OcsApiError(res.status, `HTTP ${res.status} ${res.statusText}`, method);
201
52
  }
202
53
  const json = await res.json();
203
54
  if (json.status?.code !== 0) {
204
- 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);
205
56
  }
206
57
  if (method === "getCustomerTariff" && json["listTariffRule"] !== void 0) {
207
58
  return json["listTariffRule"];
@@ -459,9 +310,9 @@ function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler) {
459
310
  try {
460
311
  const token2 = await ctx.getUserToken(ctx.props.sub);
461
312
  result2 = await handler(args, token2);
462
- } catch (err4) {
313
+ } catch (err5) {
463
314
  try {
464
- Sentry.captureException(err4, {
315
+ Sentry.captureException(err5, {
465
316
  tags: {
466
317
  tool: toolName,
467
318
  feature: "mcp",
@@ -470,8 +321,8 @@ function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler) {
470
321
  });
471
322
  } catch {
472
323
  }
473
- const message = err4 instanceof Error ? err4.message : String(err4);
474
- 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;
475
326
  ctx.audit({
476
327
  tool_name: toolName,
477
328
  ocs_method: ocsMethod,
@@ -499,7 +350,7 @@ function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler) {
499
350
  };
500
351
  }
501
352
  async function ocsCall(env, token2, method, params = {}) {
502
- const client = new OcsClient2(env.CARRIER_OCS_BASE_URL, token2);
353
+ const client = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
503
354
  const result2 = await client.call(method, params);
504
355
  return {
505
356
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -508,13 +359,13 @@ async function ocsCall(env, token2, method, params = {}) {
508
359
  async function resolveSubscriberByIccid(env, token2, iccid, cache) {
509
360
  const hit = cache.get(iccid);
510
361
  if (hit) return hit;
511
- const client = new OcsClient2(env.CARRIER_OCS_BASE_URL, token2);
362
+ const client = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
512
363
  const record = await client.call("getSingleSubscriber", { iccid });
513
364
  cache.set(iccid, record);
514
365
  return record;
515
366
  }
516
367
  async function getDefaultResellerId(env, token2) {
517
- const client = new OcsClient2(env.CARRIER_OCS_BASE_URL, token2);
368
+ const client = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
518
369
  const info = await client.call("getResellerInfo", {});
519
370
  const id = info?.id;
520
371
  if (typeof id !== "number") {
@@ -729,7 +580,7 @@ function registerAllTools(server2, ctx) {
729
580
  if (args.msisdn) params.msisdn = args.msisdn;
730
581
  if (args.status) params.status = args.status;
731
582
  if (args.offset !== void 0) params.offset = args.offset;
732
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
583
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
733
584
  const raw = await client.call("listSubscriber", params);
734
585
  const limit = args.limit;
735
586
  const payload = Array.isArray(raw) && typeof limit === "number" && limit >= 0 ? raw.slice(0, limit) : raw;
@@ -864,7 +715,7 @@ function registerAllTools(server2, ctx) {
864
715
  "getSubscriberLocation",
865
716
  TOOL_SCOPES["get_subscriber_location"],
866
717
  ctx,
867
- async ({ iccid }, token2) => ocsCall(ctx.env, token2, "getSubscriberLocation", { iccid })
718
+ async ({ iccid }, token2) => ocsCall(ctx.env, token2, "getSubscriberLocation", locationParams(iccid))
868
719
  )
869
720
  );
870
721
  server2.registerTool(
@@ -1530,10 +1381,7 @@ function registerAllTools(server2, ctx) {
1530
1381
  "subscriberUsageOverPeriod",
1531
1382
  TOOL_SCOPES["subscriber_usage"],
1532
1383
  ctx,
1533
- async ({ iccid, startDate, endDate }, token2) => ocsCall(ctx.env, token2, "subscriberUsageOverPeriod", {
1534
- subscriber: { iccid },
1535
- period: { start: startDate, end: endDate }
1536
- })
1384
+ async ({ iccid, startDate, endDate }, token2) => ocsCall(ctx.env, token2, "subscriberUsageOverPeriod", usageOverPeriodParams(iccid, startDate, endDate))
1537
1385
  )
1538
1386
  );
1539
1387
  server2.registerTool(
@@ -1553,10 +1401,7 @@ function registerAllTools(server2, ctx) {
1553
1401
  "subscriberNetworkEventsOverPeriod",
1554
1402
  TOOL_SCOPES["subscriber_network_events"],
1555
1403
  ctx,
1556
- async ({ iccid, startDate, endDate }, token2) => ocsCall(ctx.env, token2, "subscriberNetworkEventsOverPeriod", {
1557
- subscriber: { iccid },
1558
- period: { start: startDate, end: endDate }
1559
- })
1404
+ async ({ iccid, startDate, endDate }, token2) => ocsCall(ctx.env, token2, "subscriberNetworkEventsOverPeriod", networkEventsOverPeriodParams(iccid, startDate, endDate))
1560
1405
  )
1561
1406
  );
1562
1407
  server2.registerTool(
@@ -1572,7 +1417,7 @@ function registerAllTools(server2, ctx) {
1572
1417
  "getSubscriberActivePeriod",
1573
1418
  TOOL_SCOPES["subscriber_active_period"],
1574
1419
  ctx,
1575
- async ({ iccid }, token2) => ocsCall(ctx.env, token2, "getSubscriberActivePeriod", { iccid })
1420
+ async ({ iccid }, token2) => ocsCall(ctx.env, token2, "getSubscriberActivePeriod", subscriberIdParams(iccid))
1576
1421
  )
1577
1422
  );
1578
1423
  server2.registerTool(
@@ -3194,11 +3039,11 @@ var ocsAppMethods = ocsSpec.v1_app_methods;
3194
3039
  // src/intelligence.ts
3195
3040
  async function safeCall(env, token2, method, params = {}) {
3196
3041
  try {
3197
- const client = new OcsClient2(env.CARRIER_OCS_BASE_URL, token2);
3042
+ const client = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
3198
3043
  const data = await client.call(method, params);
3199
3044
  return { data, error: null };
3200
- } catch (err4) {
3201
- 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) };
3202
3047
  }
3203
3048
  }
3204
3049
  async function fetchActiveSubscribers(env, token2, accountId, resellerId) {
@@ -3398,52 +3243,16 @@ function registerIntelligenceTools(server2, ctx) {
3398
3243
  )
3399
3244
  ]);
3400
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);
3401
3248
  const statusRaw = statusResult.data;
3402
3249
  const statusAccounts = Array.isArray(statusRaw) ? statusRaw : statusRaw?.account ?? [];
3403
- const statusOk = statusResult.data !== null && (statusAccounts.length > 0 || statusResult.error === null);
3404
- const countByState = (account) => {
3405
- const sponsors = account.sponsor ?? [];
3406
- let active = 0, suspended = 0, inventory = 0, other = 0;
3407
- for (const sp of sponsors) {
3408
- const esim = sp.esim ?? {};
3409
- const statuses = esim.status ?? [];
3410
- for (const s of statuses) {
3411
- const count = Number(s.count ?? 0);
3412
- const num = s.statusNum;
3413
- if (typeof num === "number") {
3414
- if (num === 1) active += count;
3415
- else if (num === 2) suspended += count;
3416
- else if (num === 0) inventory += count;
3417
- else other += count;
3418
- continue;
3419
- }
3420
- const str = String(s.statusStr ?? s.name ?? "").toUpperCase();
3421
- if (str === "ACTIVATED" || str === "ACTIVE") active += count;
3422
- else if (str === "SUSPENDED") suspended += count;
3423
- else if (str === "FREE" || str === "INVENTORY" || str === "NOT_ACTIVATED" || str === "AVAILABLE") inventory += count;
3424
- else other += count;
3425
- }
3426
- }
3427
- return { active, suspended, inventory, other };
3428
- };
3429
- let totalActive = 0, totalSuspended = 0, totalInventory = 0, totalOther = 0;
3430
3250
  if (statusOk) {
3431
- for (const account of statusAccounts) {
3432
- const hasSponsors = Array.isArray(account.sponsor);
3433
- if (hasSponsors) {
3434
- const c = countByState(account);
3435
- totalActive += c.active;
3436
- totalSuspended += c.suspended;
3437
- totalInventory += c.inventory;
3438
- totalOther += c.other;
3439
- } else {
3440
- totalActive += Number(account.active ?? 0);
3441
- totalSuspended += Number(account.suspended ?? 0);
3442
- totalInventory += Number(account.inventory ?? account.notActivated ?? 0);
3443
- totalOther += Number(account.other ?? account.terminated ?? 0);
3444
- }
3445
- }
3446
- 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;
3447
3256
  const utilization = total > 0 ? (totalActive / total * 100).toFixed(1) : "0";
3448
3257
  sections.push(`## eSIM Fleet Status`);
3449
3258
  if (total === 0) {
@@ -4240,7 +4049,7 @@ function registerAllBacklogTools(server2, ctx) {
4240
4049
  ctx,
4241
4050
  async ({ iccid, phone_number, phone_type }, token2) => {
4242
4051
  const ocsMethod = phone_type === "fake" ? "affectSubscriberFakePhoneNumber" : "affectSubscriberRealPhoneNumber";
4243
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4052
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4244
4053
  const result2 = await client.call(ocsMethod, { subscriber: iccid, phoneNumber: phone_number });
4245
4054
  return {
4246
4055
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -4278,7 +4087,7 @@ function registerAllBacklogTools(server2, ctx) {
4278
4087
  cell_id,
4279
4088
  signal_strength
4280
4089
  }, token2) => {
4281
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4090
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4282
4091
  const params = { radioType: radio_type, mcc, mnc, lac };
4283
4092
  if (cell_id !== void 0) params.cellId = cell_id;
4284
4093
  if (signal_strength !== void 0) params.signalStrength = signal_strength;
@@ -4306,7 +4115,7 @@ function registerAllBacklogTools(server2, ctx) {
4306
4115
  ctx,
4307
4116
  async ({ resellerId }, token2) => {
4308
4117
  const id = resellerId ?? await (async () => {
4309
- const client2 = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4118
+ const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4310
4119
  const info = await client2.call("getResellerInfo", {});
4311
4120
  const resolvedId = info?.id;
4312
4121
  if (typeof resolvedId !== "number") {
@@ -4314,7 +4123,7 @@ function registerAllBacklogTools(server2, ctx) {
4314
4123
  }
4315
4124
  return resolvedId;
4316
4125
  })();
4317
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4126
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4318
4127
  const result2 = await client.call("listDetailedDestinationList", id);
4319
4128
  return {
4320
4129
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -4340,7 +4149,7 @@ function registerAllBacklogTools(server2, ctx) {
4340
4149
  BACKLOG_TOOL_SCOPES["modify_subscriber_mobile_plan"],
4341
4150
  ctx,
4342
4151
  async ({ iccid, mobile_plan_id }, token2) => {
4343
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4152
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4344
4153
  const result2 = await client.call(
4345
4154
  "modifySubscriberMobilePlan",
4346
4155
  { subscriber: iccid, mobilePlanId: mobile_plan_id }
@@ -4374,7 +4183,7 @@ function registerAllBacklogTools(server2, ctx) {
4374
4183
  const params = { subscriber: iccid, packageId: package_id };
4375
4184
  if (start_date !== void 0) params.startDate = start_date;
4376
4185
  if (end_date !== void 0) params.endDate = end_date;
4377
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4186
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4378
4187
  const result2 = await client.call(
4379
4188
  "modifySubscriberPrepaidPackageActivePeriod",
4380
4189
  params
@@ -4403,7 +4212,7 @@ function registerAllBacklogTools(server2, ctx) {
4403
4212
  BACKLOG_TOOL_SCOPES["modify_subscriber_voip_plan"],
4404
4213
  ctx,
4405
4214
  async ({ iccid, voip_plan_id }, token2) => {
4406
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4215
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4407
4216
  const result2 = await client.call(
4408
4217
  "modifySubscriberVoipPlan",
4409
4218
  { subscriber: iccid, voipPlanId: voip_plan_id }
@@ -4434,7 +4243,7 @@ function registerAllBacklogTools(server2, ctx) {
4434
4243
  const cache = /* @__PURE__ */ new Map();
4435
4244
  const sub = await resolveSubscriberByIccid(ctx.env, token2, iccid, cache);
4436
4245
  const subscriberId = sub.id ?? sub.subscriberId ?? iccid;
4437
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4246
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4438
4247
  const result2 = await client.call(
4439
4248
  "pushSteeringToSubs",
4440
4249
  { subscriber: subscriberId }
@@ -4462,7 +4271,7 @@ function registerAllBacklogTools(server2, ctx) {
4462
4271
  BACKLOG_TOOL_SCOPES["reset_subscriber_gz_counter"],
4463
4272
  ctx,
4464
4273
  async ({ iccid }, token2) => {
4465
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4274
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4466
4275
  const result2 = await client.call("resetSubsGzCounter", { subscriber: iccid });
4467
4276
  return {
4468
4277
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -4486,7 +4295,7 @@ function registerAllBacklogTools(server2, ctx) {
4486
4295
  BACKLOG_TOOL_SCOPES["carrier_webhook_config"],
4487
4296
  ctx,
4488
4297
  async ({ reseller_id }, token2) => {
4489
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4298
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4490
4299
  let resellerId = reseller_id;
4491
4300
  if (resellerId === void 0) {
4492
4301
  resellerId = await getDefaultResellerId(ctx.env, token2);
@@ -4528,7 +4337,7 @@ function registerAllBacklogTools(server2, ctx) {
4528
4337
  BACKLOG_TOOL_SCOPES["list_subscriber_voip_tariff"],
4529
4338
  ctx,
4530
4339
  async ({ reseller_id }, token2) => {
4531
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4340
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4532
4341
  const params = {};
4533
4342
  if (reseller_id !== void 0) {
4534
4343
  params.resellerId = reseller_id;
@@ -4558,7 +4367,7 @@ function registerAllBacklogTools(server2, ctx) {
4558
4367
  BACKLOG_TOOL_SCOPES["list_voip_tariff_rule"],
4559
4368
  ctx,
4560
4369
  async ({ voip_plan_id }, token2) => {
4561
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4370
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4562
4371
  const result2 = await client.call("listVoipTariffRule", voip_plan_id);
4563
4372
  return {
4564
4373
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
@@ -4587,7 +4396,7 @@ function registerAllBacklogTools(server2, ctx) {
4587
4396
  location_zone_id,
4588
4397
  network_profile_id
4589
4398
  }, token2) => {
4590
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
4399
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
4591
4400
  const result2 = await client.call("changeNetworkProfileOfLocationZone", {
4592
4401
  locationZoneId: location_zone_id,
4593
4402
  networkProfileId: network_profile_id
@@ -4637,7 +4446,8 @@ var TOOL_REGISTRY = /* @__PURE__ */ new Set([
4637
4446
  "greenzone_whitelist_list",
4638
4447
  // router tools (self-reference)
4639
4448
  "carrier_ask",
4640
- "carrier_ask_describe"
4449
+ "carrier_ask_describe",
4450
+ "generate_storefront_logo"
4641
4451
  ]);
4642
4452
  var HARD_BLOCK_TOOLS = /* @__PURE__ */ new Set([
4643
4453
  "clean_all_packages",
@@ -5115,10 +4925,10 @@ async function callBedrock(env, payload) {
5115
4925
  const body = await resp.text();
5116
4926
  if (resp.status === 429) {
5117
4927
  const retryAfter = resp.headers.get("retry-after");
5118
- const err4 = new Error(`Bedrock rate limit: ${body}`);
5119
- err4.isRateLimit = true;
5120
- err4.retryAfter = retryAfter;
5121
- throw err4;
4928
+ const err5 = new Error(`Bedrock rate limit: ${body}`);
4929
+ err5.isRateLimit = true;
4930
+ err5.retryAfter = retryAfter;
4931
+ throw err5;
5122
4932
  }
5123
4933
  throw new Error(`Bedrock invoke failed: ${resp.status} ${body}`);
5124
4934
  }
@@ -5156,9 +4966,9 @@ Pre-resolved context: ${JSON.stringify(definedContext)}` : "";
5156
4966
  AWS_REGION: env.AWS_REGION,
5157
4967
  BEDROCK_MODEL_ID: env.BEDROCK_MODEL_ID
5158
4968
  }, payload);
5159
- } catch (err4) {
5160
- if (err4 instanceof Error && err4.isRateLimit) {
5161
- const retryAfter = err4.retryAfter;
4969
+ } catch (err5) {
4970
+ if (err5 instanceof Error && err5.isRateLimit) {
4971
+ const retryAfter = err5.retryAfter;
5162
4972
  const parsedSeconds = retryAfter ? parseInt(retryAfter, 10) : 60;
5163
4973
  return {
5164
4974
  match: "rate_limited",
@@ -5166,7 +4976,7 @@ Pre-resolved context: ${JSON.stringify(definedContext)}` : "";
5166
4976
  suggestion: "Bedrock rate limit reached. Please retry after the indicated delay."
5167
4977
  };
5168
4978
  }
5169
- throw err4;
4979
+ throw err5;
5170
4980
  }
5171
4981
  const toolUseBlock = response.content.find(
5172
4982
  (block) => block.type === "tool_use"
@@ -5340,7 +5150,7 @@ function registerAllCarrierAskTools(server2, ctx) {
5340
5150
  let route;
5341
5151
  try {
5342
5152
  route = await _routeIntent(intent, context, ctx.env);
5343
- } catch (err4) {
5153
+ } catch (err5) {
5344
5154
  writeCarrierAskAudit(ctx.env, {
5345
5155
  intent_hash: intentHash,
5346
5156
  match: "error",
@@ -5357,7 +5167,7 @@ function registerAllCarrierAskTools(server2, ctx) {
5357
5167
  type: "text",
5358
5168
  text: JSON.stringify({
5359
5169
  error: "routing_error",
5360
- 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."
5361
5171
  })
5362
5172
  }
5363
5173
  ],
@@ -5609,8 +5419,8 @@ function registerListRecentOcsEventsTool(server2, env) {
5609
5419
  return {
5610
5420
  content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
5611
5421
  };
5612
- } catch (err4) {
5613
- const message = err4 instanceof Error ? err4.message : String(err4);
5422
+ } catch (err5) {
5423
+ const message = err5 instanceof Error ? err5.message : String(err5);
5614
5424
  return {
5615
5425
  isError: true,
5616
5426
  content: [{ type: "text", text: `Error reading OCS event buffer: ${message}` }]
@@ -5893,10 +5703,10 @@ import {
5893
5703
  async function safeCallWithToken(client, _token, method, params = {}) {
5894
5704
  try {
5895
5705
  return { data: await client.call(method, params), error: null };
5896
- } catch (err4) {
5706
+ } catch (err5) {
5897
5707
  return {
5898
5708
  data: null,
5899
- error: err4 instanceof Error ? err4.message : String(err4)
5709
+ error: err5 instanceof Error ? err5.message : String(err5)
5900
5710
  };
5901
5711
  }
5902
5712
  }
@@ -5955,7 +5765,7 @@ function registerFleetHealthApp(server2, ctx) {
5955
5765
  },
5956
5766
  async ({ accountId }) => {
5957
5767
  const token2 = await ctx.getUserToken(ctx.props.sub);
5958
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
5768
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
5959
5769
  const [statusResult, accountsResult] = await Promise.all([
5960
5770
  safeCallWithToken(
5961
5771
  client,
@@ -6094,10 +5904,10 @@ async function deleteWizardSession(env, sub, wizardId) {
6094
5904
  async function safeCallWithToken2(client, _token, method, params = {}) {
6095
5905
  try {
6096
5906
  return { data: await client.call(method, params), error: null };
6097
- } catch (err4) {
5907
+ } catch (err5) {
6098
5908
  return {
6099
5909
  data: null,
6100
- error: err4 instanceof Error ? err4.message : String(err4)
5910
+ error: err5 instanceof Error ? err5.message : String(err5)
6101
5911
  };
6102
5912
  }
6103
5913
  }
@@ -6160,7 +5970,7 @@ function registerProvisioningWizard(server2, ctx) {
6160
5970
  },
6161
5971
  async ({ step, wizardId, subscriber_iccid, package_template_id }) => {
6162
5972
  const token2 = await ctx.getUserToken(ctx.props.sub);
6163
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
5973
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
6164
5974
  if (step === "init") {
6165
5975
  const newWizardId = generateWizardId();
6166
5976
  const subscribersResult = await safeCallWithToken2(
@@ -6457,10 +6267,10 @@ import {
6457
6267
  async function safeCallWithToken3(client, _token, method, params = {}) {
6458
6268
  try {
6459
6269
  return { data: await client.call(method, params), error: null };
6460
- } catch (err4) {
6270
+ } catch (err5) {
6461
6271
  return {
6462
6272
  data: null,
6463
- error: err4 instanceof Error ? err4.message : String(err4)
6273
+ error: err5 instanceof Error ? err5.message : String(err5)
6464
6274
  };
6465
6275
  }
6466
6276
  }
@@ -6499,7 +6309,7 @@ function registerBalanceTopupApp(server2, ctx) {
6499
6309
  "balance_topup_form",
6500
6310
  {
6501
6311
  title: "Balance Top-up Form",
6502
- 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`.",
6503
6313
  inputSchema: {
6504
6314
  iccid: z11.string().describe("The subscriber ICCID for the account lookup"),
6505
6315
  delta: z11.number().describe("Amount to add (positive) or deduct (negative) from the account balance"),
@@ -6520,7 +6330,7 @@ function registerBalanceTopupApp(server2, ctx) {
6520
6330
  ctx,
6521
6331
  async ({ iccid, delta, preview }) => {
6522
6332
  const token2 = await ctx.getUserToken(ctx.props.sub);
6523
- const client = new OcsClient2(ctx.env.CARRIER_OCS_BASE_URL, token2);
6333
+ const client = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
6524
6334
  if (preview === true) {
6525
6335
  const result2 = await safeCallWithToken3(
6526
6336
  client,
@@ -8121,8 +7931,8 @@ function buildPricingHandler(tool, ctx) {
8121
7931
  }
8122
7932
  ]
8123
7933
  };
8124
- } catch (err4) {
8125
- const message = err4 instanceof Error ? err4.message : String(err4);
7934
+ } catch (err5) {
7935
+ const message = err5 instanceof Error ? err5.message : String(err5);
8126
7936
  ctx.audit({
8127
7937
  tool_name: tool.name,
8128
7938
  ocs_method: "billing",
@@ -8442,8 +8252,8 @@ function writeUsageThresholdAudit(env, severity, remainingCredits, month, taskCo
8442
8252
  doubles: [remainingCredits],
8443
8253
  indexes: ["manus_usage"]
8444
8254
  });
8445
- } catch (err4) {
8446
- console.error(`[manus-usage] threshold audit write failed: ${err4.message}`);
8255
+ } catch (err5) {
8256
+ console.error(`[manus-usage] threshold audit write failed: ${err5.message}`);
8447
8257
  }
8448
8258
  }
8449
8259
 
@@ -8553,7 +8363,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8553
8363
  }
8554
8364
  ]
8555
8365
  };
8556
- } catch (err4) {
8366
+ } catch (err5) {
8557
8367
  ctx.audit({
8558
8368
  tool_name: "ui_agent_schedule_create",
8559
8369
  ocs_method: "[manus:schedule.create]",
@@ -8562,7 +8372,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8562
8372
  duration_ms: Date.now() - start,
8563
8373
  event_type: "ui_agent_dispatch"
8564
8374
  });
8565
- 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);
8566
8376
  return { isError: true, content: [{ type: "text", text: msg }] };
8567
8377
  }
8568
8378
  }
@@ -8620,7 +8430,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8620
8430
  }
8621
8431
  ]
8622
8432
  };
8623
- } catch (err4) {
8433
+ } catch (err5) {
8624
8434
  ctx.audit({
8625
8435
  tool_name: "ui_agent_schedule_list",
8626
8436
  ocs_method: "[manus:schedule.list]",
@@ -8628,7 +8438,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8628
8438
  dry_run: false,
8629
8439
  duration_ms: Date.now() - start
8630
8440
  });
8631
- 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);
8632
8442
  return { isError: true, content: [{ type: "text", text: msg }] };
8633
8443
  }
8634
8444
  }
@@ -8689,7 +8499,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8689
8499
  }
8690
8500
  ]
8691
8501
  };
8692
- } catch (err4) {
8502
+ } catch (err5) {
8693
8503
  ctx.audit({
8694
8504
  tool_name: "ui_agent_schedule_delete",
8695
8505
  ocs_method: "[manus:schedule.delete]",
@@ -8698,7 +8508,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8698
8508
  duration_ms: Date.now() - start,
8699
8509
  event_type: "ui_agent_dispatch"
8700
8510
  });
8701
- 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);
8702
8512
  return { isError: true, content: [{ type: "text", text: msg }] };
8703
8513
  }
8704
8514
  }
@@ -8759,7 +8569,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8759
8569
  }
8760
8570
  ]
8761
8571
  };
8762
- } catch (err4) {
8572
+ } catch (err5) {
8763
8573
  ctx.audit({
8764
8574
  tool_name: "ui_agent_schedule_pause",
8765
8575
  ocs_method: "[manus:schedule.pause]",
@@ -8768,7 +8578,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8768
8578
  duration_ms: Date.now() - start,
8769
8579
  event_type: "ui_agent_dispatch"
8770
8580
  });
8771
- 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);
8772
8582
  return { isError: true, content: [{ type: "text", text: msg }] };
8773
8583
  }
8774
8584
  }
@@ -8829,7 +8639,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8829
8639
  }
8830
8640
  ]
8831
8641
  };
8832
- } catch (err4) {
8642
+ } catch (err5) {
8833
8643
  ctx.audit({
8834
8644
  tool_name: "ui_agent_schedule_resume",
8835
8645
  ocs_method: "[manus:schedule.resume]",
@@ -8838,7 +8648,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8838
8648
  duration_ms: Date.now() - start,
8839
8649
  event_type: "ui_agent_dispatch"
8840
8650
  });
8841
- 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);
8842
8652
  return { isError: true, content: [{ type: "text", text: msg }] };
8843
8653
  }
8844
8654
  }
@@ -8883,7 +8693,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8883
8693
  }
8884
8694
  ]
8885
8695
  };
8886
- } catch (err4) {
8696
+ } catch (err5) {
8887
8697
  ctx.audit({
8888
8698
  tool_name: "ui_agent_usage",
8889
8699
  ocs_method: "[manus:usage.get]",
@@ -8891,7 +8701,7 @@ function registerScheduleAndUsageTools(server2, ctx) {
8891
8701
  dry_run: false,
8892
8702
  duration_ms: Date.now() - start
8893
8703
  });
8894
- const msg = err4 instanceof Error ? err4.message : String(err4);
8704
+ const msg = err5 instanceof Error ? err5.message : String(err5);
8895
8705
  return { isError: true, content: [{ type: "text", text: msg }] };
8896
8706
  }
8897
8707
  }
@@ -9134,7 +8944,7 @@ Report success or failure with a clear summary.`;
9134
8944
  }
9135
8945
  ]
9136
8946
  };
9137
- } catch (err4) {
8947
+ } catch (err5) {
9138
8948
  ctx.audit({
9139
8949
  tool_name: toolName,
9140
8950
  ocs_method: `[ui-agent:${gapId}]`,
@@ -9148,7 +8958,7 @@ Report success or failure with a clear summary.`;
9148
8958
  content: [
9149
8959
  {
9150
8960
  type: "text",
9151
- 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)}`
9152
8962
  }
9153
8963
  ]
9154
8964
  };
@@ -9572,7 +9382,7 @@ function registerUiAgentAskTools(server2, ctx) {
9572
9382
  try {
9573
9383
  const replyOutcome = await askReply(keys, task_id, reply);
9574
9384
  result2 = replyOutcome.data;
9575
- } catch (err4) {
9385
+ } catch (err5) {
9576
9386
  ctx.audit({
9577
9387
  tool_name: "ui_agent_reply",
9578
9388
  ocs_method: "[ui-agent:ask-reply]",
@@ -9587,7 +9397,7 @@ function registerUiAgentAskTools(server2, ctx) {
9587
9397
  content: [
9588
9398
  {
9589
9399
  type: "text",
9590
- 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)}`
9591
9401
  }
9592
9402
  ]
9593
9403
  };
@@ -9665,13 +9475,13 @@ function registerUiAgentAskTools(server2, ctx) {
9665
9475
  try {
9666
9476
  const listing = await ctx.env.CARRIER_USERS.list({ prefix: PENDING_ASK_PREFIX });
9667
9477
  keys = listing.keys;
9668
- } catch (err4) {
9478
+ } catch (err5) {
9669
9479
  return {
9670
9480
  isError: true,
9671
9481
  content: [
9672
9482
  {
9673
9483
  type: "text",
9674
- 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)}`
9675
9485
  }
9676
9486
  ]
9677
9487
  };
@@ -9842,7 +9652,7 @@ function registerStripeConnectTools(server2, ctx) {
9842
9652
  );
9843
9653
  server2.tool(
9844
9654
  "stripe_connect_payouts",
9845
- "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). Returns: payouts with amount (smallest currency unit), currency, status, and arrival date. Do NOT use this for money still sitting at Stripe and not yet paid out \u2014 use `stripe_connect_balance`.",
9846
9656
  {
9847
9657
  limit: z17.number().int().min(1).max(50).default(10).describe("Number of payouts to return."),
9848
9658
  status: z17.enum(["pending", "paid", "failed", "canceled", "in_transit"]).optional().describe("Filter by payout status.")
@@ -9876,7 +9686,7 @@ function registerStripeConnectTools(server2, ctx) {
9876
9686
  );
9877
9687
  server2.tool(
9878
9688
  "stripe_connect_balance",
9879
- "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`.",
9880
9690
  {},
9881
9691
  async () => {
9882
9692
  const start = Date.now();
@@ -9909,7 +9719,7 @@ function registerStripeConnectTools(server2, ctx) {
9909
9719
  );
9910
9720
  server2.tool(
9911
9721
  "stripe_connect_refund",
9912
- "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.",
9913
9723
  {
9914
9724
  charge_id: z17.string().min(1).describe("Stripe charge ID (ch_...)."),
9915
9725
  amount_cents: z17.number().int().min(1).optional().describe("Partial refund amount in cents. Omit for full refund."),
@@ -9959,7 +9769,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
9959
9769
  );
9960
9770
  server2.tool(
9961
9771
  "stripe_connect_dispute_list",
9962
- "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 with amount, reason, status, and the evidence deadline. 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.",
9963
9773
  {
9964
9774
  limit: z17.number().int().min(1).max(50).default(10),
9965
9775
  status: z17.string().optional().describe("Filter by dispute status (e.g. needs_response, under_review).")
@@ -9993,7 +9803,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
9993
9803
  );
9994
9804
  server2.tool(
9995
9805
  "radar_review_list",
9996
- "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`.",
9997
9807
  {
9998
9808
  open_only: z17.boolean().default(true).describe("If true, only returns open (undecided) reviews."),
9999
9809
  limit: z17.number().int().min(1).max(50).default(10)
@@ -10025,7 +9835,7 @@ Call again with confirm_token="${token2}" to execute. Token expires in 5 minutes
10025
9835
  );
10026
9836
  server2.tool(
10027
9837
  "radar_review_approve",
10028
- "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`.",
10029
9839
  {
10030
9840
  review_id: z17.string().min(1).describe("Stripe Radar review ID (prv_...)."),
10031
9841
  confirm_token: z17.string().optional()
@@ -10070,7 +9880,7 @@ Call again with confirm_token="${token2}" to execute. Expires in 5 minutes.`
10070
9880
  );
10071
9881
  server2.tool(
10072
9882
  "radar_review_decline",
10073
- "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`.",
10074
9884
  {
10075
9885
  review_id: z17.string().min(1),
10076
9886
  confirm_token: z17.string().optional()
@@ -10115,7 +9925,7 @@ Expires in 5 minutes.`
10115
9925
  );
10116
9926
  server2.tool(
10117
9927
  "radar_value_list_add",
10118
- "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`).",
10119
9929
  {
10120
9930
  value_list_id: z17.string().min(1).describe("Stripe Radar value list ID (rsl_...)."),
10121
9931
  value: z17.string().min(1).describe("The value to add (email, IP address, country code, etc.)."),
@@ -10161,7 +9971,7 @@ Expires in 5 minutes.`
10161
9971
  );
10162
9972
  server2.tool(
10163
9973
  "radar_rule_toggle",
10164
- "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`.",
10165
9975
  {
10166
9976
  rule_id: z17.string().min(1).describe("Stripe Radar rule ID."),
10167
9977
  enabled: z17.boolean().describe("true = enable, false = disable.")
@@ -10686,6 +10496,46 @@ function registerUiAgentGenericTools(server2, _ctx) {
10686
10496
  );
10687
10497
  }
10688
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
+
10689
10539
  // src/index.ts
10690
10540
  var baseUrl = process.env.CARRIER_OCS_BASE_URL ?? process.env.ESIMVAULT_BASE_URL ?? "https://ocs.esimvault.cloud";
10691
10541
  var token = process.env.CARRIER_OCS_API_TOKEN ?? process.env.ESIMVAULT_API_TOKEN;
@@ -10723,7 +10573,7 @@ var audit = (_row) => {
10723
10573
  var getUserToken = async (_sub) => token;
10724
10574
  var toolCtx = { env: stdioEnv, props, audit, getUserToken };
10725
10575
  var server = new McpServer(
10726
- { name: "carrier-mcp", version: "0.2.18" },
10576
+ { name: "carrier-mcp", version: CARRIER_VERSION },
10727
10577
  {
10728
10578
  instructions: "Carrier MCP \u2014 single-user stdio mode. Full tool registry (mirrors the deployed Worker)."
10729
10579
  }
@@ -10744,6 +10594,7 @@ registerUiAgentAskTools(server, toolCtx);
10744
10594
  registerStripeConnectTools(server, { env: stdioEnv, props });
10745
10595
  registerGreenzoneTools(server, toolCtx);
10746
10596
  registerUiAgentGenericTools(server, toolCtx);
10597
+ registerStorefrontLogoTools(server, stdioEnv);
10747
10598
  registerAllPrompts(server);
10748
10599
  var transport = new StdioServerTransport();
10749
10600
  await server.connect(transport);