@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.
- package/README.md +22 -1
- package/dist/chunk-NHQDO2E7.js +461 -0
- package/dist/chunk-NHQDO2E7.js.map +1 -0
- package/dist/cli.js +877 -148
- package/dist/cli.js.map +1 -1
- package/dist/index.js +148 -297
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/plugin/carrier/commands/storefront.md +24 -12
- package/plugin/carrier/skills/carrier-operations/SKILL.md +4 -1
- package/templates/storefront/{next.config.ts → next.config.mjs} +2 -6
- package/templates/storefront/package-lock.json +12722 -0
- package/templates/storefront/package.json +3 -3
- package/templates/storefront/public/brand/logo.svg +13 -0
- package/templates/storefront/src/app/activate/[orderId]/ActivateClient.tsx +12 -12
- package/templates/storefront/src/app/checkout/[templateId]/CheckoutClient.tsx +5 -5
- package/templates/storefront/src/app/checkout/success/CheckoutSuccessClient.tsx +29 -29
- package/templates/storefront/src/app/checkout/success/page.tsx +1 -1
- package/templates/storefront/src/app/contact/page.tsx +33 -25
- package/templates/storefront/src/app/dashboard/page.tsx +7 -4
- package/templates/storefront/src/app/globals.css +72 -82
- package/templates/storefront/src/app/help/page.tsx +22 -17
- package/templates/storefront/src/app/layout.tsx +15 -4
- package/templates/storefront/src/app/page.tsx +16 -7
- package/templates/storefront/src/app/shop/ShopClient.tsx +7 -3
- package/templates/storefront/src/app/sign-in/[[...sign-in]]/page.tsx +1 -1
- package/templates/storefront/src/app/sign-up/[[...sign-up]]/StorefrontSignUpClient.tsx +16 -16
- package/templates/storefront/src/app/sign-up/[[...sign-up]]/page.tsx +1 -1
- package/templates/storefront/src/brand.config.ts +3 -3
- package/templates/storefront/src/components/faq/FaqSection.tsx +23 -26
- package/templates/storefront/src/components/footer/StorefrontFooter.tsx +37 -22
- package/templates/storefront/src/components/landing/FinalCTA.tsx +28 -0
- package/templates/storefront/src/components/landing/HeroSection.tsx +57 -24
- package/templates/storefront/src/components/landing/HowItWorks.tsx +44 -0
- package/templates/storefront/src/components/landing/PlanCard.tsx +58 -28
- package/templates/storefront/src/components/nav/StorefrontNav.tsx +59 -24
- package/templates/storefront/src/components/theme/BrandStyles.tsx +8 -0
- package/templates/storefront/src/components/theme/ThemeToggle.tsx +27 -0
- package/templates/storefront/src/components/theme/clerk-appearance.ts +33 -35
- package/templates/storefront/src/components/theme/theme-provider.tsx +25 -32
- package/templates/storefront/src/components/theme/theme-script.tsx +4 -7
- package/templates/storefront/src/lib/checkout-order-claim.ts +16 -2
- package/templates/storefront/src/lib/complete-email-sign-up.ts +3 -3
- package/templates/storefront/src/lib/verify-checkout-session.ts +19 -2
- 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
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
313
|
+
} catch (err5) {
|
|
463
314
|
try {
|
|
464
|
-
Sentry.captureException(
|
|
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 =
|
|
474
|
-
const ocsCode =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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",
|
|
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",
|
|
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
|
|
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 (
|
|
3201
|
-
return { data: null, error:
|
|
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
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
throw
|
|
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 (
|
|
5160
|
-
if (
|
|
5161
|
-
const 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
|
|
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 (
|
|
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:
|
|
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 (
|
|
5613
|
-
const message =
|
|
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 (
|
|
5706
|
+
} catch (err5) {
|
|
5897
5707
|
return {
|
|
5898
5708
|
data: null,
|
|
5899
|
-
error:
|
|
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
|
|
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 (
|
|
5907
|
+
} catch (err5) {
|
|
6098
5908
|
return {
|
|
6099
5909
|
data: null,
|
|
6100
|
-
error:
|
|
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
|
|
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 (
|
|
6270
|
+
} catch (err5) {
|
|
6461
6271
|
return {
|
|
6462
6272
|
data: null,
|
|
6463
|
-
error:
|
|
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: "
|
|
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
|
|
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 (
|
|
8125
|
-
const message =
|
|
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 (
|
|
8446
|
-
console.error(`[manus-usage] threshold audit write failed: ${
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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 =
|
|
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 (
|
|
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: ${
|
|
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 (
|
|
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: ${
|
|
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 (
|
|
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: ${
|
|
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:
|
|
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
|
|
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
|
-
"
|
|
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:
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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:
|
|
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);
|