@carrierllc/mcp 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-DUAENMJE.js → chunk-PYXTCG4L.js} +668 -8
- package/dist/chunk-PYXTCG4L.js.map +1 -0
- package/dist/cli.js +40 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.js +287 -118
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/marketplace.json +2 -2
- package/plugin/carrier/.claude-plugin/plugin.json +1 -1
- package/plugin/carrier/README.md +7 -3
- package/plugin/carrier/{commands/billing.md → skills/billing/SKILL.md} +2 -1
- package/plugin/carrier/{commands/churn.md → skills/churn/SKILL.md} +2 -1
- package/plugin/carrier/{commands/credits.md → skills/credits/SKILL.md} +2 -1
- package/plugin/carrier/{commands/esim-status.md → skills/esim-status/SKILL.md} +2 -1
- package/plugin/carrier/{commands/fleet.md → skills/fleet/SKILL.md} +2 -1
- package/plugin/carrier/{commands/greenzone.md → skills/greenzone/SKILL.md} +2 -1
- package/plugin/carrier/{commands/onboard.md → skills/onboard/SKILL.md} +2 -1
- package/plugin/carrier/{commands/packages.md → skills/packages/SKILL.md} +2 -1
- package/plugin/carrier/{commands/provision.md → skills/provision/SKILL.md} +2 -1
- package/plugin/carrier/{commands/sms.md → skills/sms/SKILL.md} +2 -1
- package/plugin/carrier/{commands/status.md → skills/status/SKILL.md} +2 -1
- package/plugin/carrier/{commands/storefront.md → skills/storefront/SKILL.md} +2 -1
- package/plugin/carrier/{commands/subscribers.md → skills/subscribers/SKILL.md} +2 -1
- package/plugin/carrier/{commands/usage.md → skills/usage/SKILL.md} +2 -1
- package/plugin/carrier/{commands/wallet.md → skills/wallet/SKILL.md} +2 -1
- package/dist/chunk-DUAENMJE.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
CARRIER_VERSION,
|
|
4
4
|
OCS_MAX_USAGE_WINDOW_DAYS,
|
|
5
|
+
OcsApiError,
|
|
6
|
+
OcsClient,
|
|
5
7
|
ROUTER_RULES,
|
|
6
8
|
TARGET_IDS,
|
|
7
|
-
|
|
8
|
-
applyParamRenames,
|
|
9
|
+
activePeriodFromPackages,
|
|
9
10
|
applySubscriberFilters,
|
|
10
11
|
buildListSubscriberParams,
|
|
11
12
|
buildRouterCatalog,
|
|
@@ -33,21 +34,24 @@ import {
|
|
|
33
34
|
networkEventsOverPeriodParams,
|
|
34
35
|
normalizePackageTemplate,
|
|
35
36
|
normalizePackageTemplateChanges,
|
|
37
|
+
ocsLocalDateTime,
|
|
38
|
+
packageActivePeriodParams,
|
|
39
|
+
prepaidPackageLimits,
|
|
36
40
|
probeAll,
|
|
37
41
|
provisionClerk,
|
|
38
42
|
rankTargets,
|
|
39
43
|
recordToolDescription,
|
|
44
|
+
recurringIdForPackage,
|
|
40
45
|
recurringPackageParams,
|
|
41
46
|
renderHtml,
|
|
42
47
|
repairPlanFor,
|
|
43
|
-
runWithBudget,
|
|
44
48
|
storefrontClerkUrls,
|
|
45
49
|
subscriberIdParams,
|
|
46
50
|
subscriberRows,
|
|
47
51
|
usageOverPeriodParams,
|
|
48
52
|
verifyStorefront,
|
|
49
53
|
withOcsListSummary
|
|
50
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-PYXTCG4L.js";
|
|
51
55
|
import "./chunk-SHKKVIIA.js";
|
|
52
56
|
|
|
53
57
|
// src/index.ts
|
|
@@ -58,59 +62,6 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
58
62
|
import { z } from "zod";
|
|
59
63
|
import * as Sentry from "@sentry/cloudflare";
|
|
60
64
|
|
|
61
|
-
// src/client.ts
|
|
62
|
-
var OcsApiError = class extends Error {
|
|
63
|
-
constructor(code, message, method) {
|
|
64
|
-
super(`[${method}] OCS error ${code}: ${message}`);
|
|
65
|
-
this.code = code;
|
|
66
|
-
this.method = method;
|
|
67
|
-
this.name = "OcsApiError";
|
|
68
|
-
}
|
|
69
|
-
code;
|
|
70
|
-
method;
|
|
71
|
-
};
|
|
72
|
-
var OcsClient = class {
|
|
73
|
-
baseUrl;
|
|
74
|
-
token;
|
|
75
|
-
constructor(baseUrl2, token2) {
|
|
76
|
-
this.baseUrl = baseUrl2.replace(/\/+$/, "");
|
|
77
|
-
this.token = token2;
|
|
78
|
-
}
|
|
79
|
-
async call(method, params = {}) {
|
|
80
|
-
await acquireEndpointSlot(this.token, method, "interactive");
|
|
81
|
-
const url = `${this.baseUrl}/v1?token=${this.token}`;
|
|
82
|
-
const body2 = JSON.stringify({ [method]: applyParamRenames(method, params) });
|
|
83
|
-
return runWithBudget(method, async (signal) => {
|
|
84
|
-
const res = await fetch(url, {
|
|
85
|
-
method: "POST",
|
|
86
|
-
headers: { "Content-Type": "application/json" },
|
|
87
|
-
body: body2,
|
|
88
|
-
signal
|
|
89
|
-
});
|
|
90
|
-
if (!res.ok) {
|
|
91
|
-
throw new OcsApiError(res.status, `HTTP ${res.status} ${res.statusText}`, method);
|
|
92
|
-
}
|
|
93
|
-
const json = await res.json();
|
|
94
|
-
if (json.status?.code !== 0) {
|
|
95
|
-
throw new OcsApiError(json.status?.code ?? -1, json.status?.msg ?? "Unknown error", method);
|
|
96
|
-
}
|
|
97
|
-
if (method === "getCustomerTariff" && json["listTariffRule"] !== void 0) {
|
|
98
|
-
return json["listTariffRule"];
|
|
99
|
-
}
|
|
100
|
-
if (method === "getSubscriberLocationByCellId") {
|
|
101
|
-
const byMethod = json[method];
|
|
102
|
-
if (byMethod !== void 0) {
|
|
103
|
-
return byMethod;
|
|
104
|
-
}
|
|
105
|
-
if (json["subscriberLocation"] !== void 0) {
|
|
106
|
-
return json["subscriberLocation"];
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return json[method] ?? json;
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
65
|
// ../../packages/carrier-ai/dist/index.js
|
|
115
66
|
import { AwsClient } from "aws4fetch";
|
|
116
67
|
var AI_TIER_POLICY = {
|
|
@@ -1370,7 +1321,12 @@ function registerAllTools(server2, ctx) {
|
|
|
1370
1321
|
TOOL_SCOPES["modify_account_balance"],
|
|
1371
1322
|
ctx,
|
|
1372
1323
|
async ({ accountId, amount, mode }, token2) => {
|
|
1373
|
-
const params = { accountId
|
|
1324
|
+
const params = { accountId };
|
|
1325
|
+
if (mode === "set") {
|
|
1326
|
+
params.setBalance = amount;
|
|
1327
|
+
} else {
|
|
1328
|
+
params.amount = amount;
|
|
1329
|
+
}
|
|
1374
1330
|
return ocsCall(ctx.env, token2, "modifyAccountBalance", params);
|
|
1375
1331
|
}
|
|
1376
1332
|
)
|
|
@@ -1751,11 +1707,13 @@ function registerAllTools(server2, ctx) {
|
|
|
1751
1707
|
"move_subscriber_range_to_account",
|
|
1752
1708
|
{
|
|
1753
1709
|
title: "Move Subscribers to Account",
|
|
1754
|
-
description: "Use this to move a contiguous
|
|
1710
|
+
description: "BREAKING CHANGE (2026-08-28): this tool's contract was rebuilt around account-ID ranges to match what OCS actually accepts \u2014 ICCID-pair targeting (`iccidFrom`/`iccidTo` + a single `accountId`) is gone. Zero field names were ever shared with OCS's real `moveSubscriberRangeToAccount` shape (verified live 2026-08-24 \u2014 see packages/ocs-spec/ocs-accepted-params.json), so every prior call to this tool failed outright; nothing that used to work stops working. Use this to move a contiguous range of subscribers, identified by IMSI or ICCID, from one account to another. Cross-reseller moves lose the subscribers' packages. Params: `srcAccountId` (source account ID from `list_reseller_accounts`), `destAccount` (destination account ID), `rangeType` ('IMSI' | 'ICCID' \u2014 which identifier `rangeStart`/`rangeEnd` are expressed in), `rangeStart` (inclusive start of the range), `rangeEnd` (inclusive end of the range). Returns: OCS confirmation with the count of subscribers moved. Do NOT use this for a single subscriber move \u2014 provide identical rangeStart and rangeEnd. Always call `list_subscribers` on the range first to verify the correct subscribers are included.",
|
|
1755
1711
|
inputSchema: {
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1712
|
+
srcAccountId: z.number().describe("Source account ID to move subscribers FROM"),
|
|
1713
|
+
destAccount: z.number().describe("Destination account ID to move subscribers TO"),
|
|
1714
|
+
rangeType: z.enum(["IMSI", "ICCID"]).describe("Whether rangeStart/rangeEnd identify subscribers by IMSI or ICCID"),
|
|
1715
|
+
rangeStart: z.string().describe("Inclusive start of the identifier range"),
|
|
1716
|
+
rangeEnd: z.string().describe("Inclusive end of the identifier range"),
|
|
1759
1717
|
...DRY_RUN_FIELD
|
|
1760
1718
|
},
|
|
1761
1719
|
annotations: { destructiveHint: true }
|
|
@@ -1765,10 +1723,12 @@ function registerAllTools(server2, ctx) {
|
|
|
1765
1723
|
"moveSubscriberRangeToAccount",
|
|
1766
1724
|
TOOL_SCOPES["move_subscriber_range_to_account"],
|
|
1767
1725
|
ctx,
|
|
1768
|
-
async ({
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1726
|
+
async ({ srcAccountId, destAccount, rangeType, rangeStart, rangeEnd }, token2) => ocsCall(ctx.env, token2, "moveSubscriberRangeToAccount", {
|
|
1727
|
+
srcAccountId,
|
|
1728
|
+
destAccount,
|
|
1729
|
+
rangeType,
|
|
1730
|
+
rangeStart,
|
|
1731
|
+
rangeEnd
|
|
1772
1732
|
})
|
|
1773
1733
|
)
|
|
1774
1734
|
);
|
|
@@ -1957,11 +1917,17 @@ function registerAllTools(server2, ctx) {
|
|
|
1957
1917
|
"modifySubscriberPrepaidPackageLimits",
|
|
1958
1918
|
TOOL_SCOPES["modify_package_limits"],
|
|
1959
1919
|
ctx,
|
|
1960
|
-
async ({
|
|
1961
|
-
iccid
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1920
|
+
async ({ packageId, limits }, token2) => (
|
|
1921
|
+
// OCS accepts only packageId/newLimits/comment here, so `iccid` never
|
|
1922
|
+
// reaches the wire, and the limits nest under `newLimits`
|
|
1923
|
+
// (dataByte/mocSecond/mtcSecond/moSms/mtSms) rather than sitting flat.
|
|
1924
|
+
// mcp-stdio is a BYO-token surface, so unlike mcp-server there is no
|
|
1925
|
+
// ownership-evidence use for the ICCID here.
|
|
1926
|
+
ocsCall(ctx.env, token2, "modifySubscriberPrepaidPackageLimits", {
|
|
1927
|
+
packageId,
|
|
1928
|
+
newLimits: prepaidPackageLimits(JSON.parse(limits))
|
|
1929
|
+
})
|
|
1930
|
+
)
|
|
1965
1931
|
)
|
|
1966
1932
|
);
|
|
1967
1933
|
server2.registerTool(
|
|
@@ -1993,9 +1959,11 @@ function registerAllTools(server2, ctx) {
|
|
|
1993
1959
|
"modifySubscriberPrepaidPackageExpDate",
|
|
1994
1960
|
TOOL_SCOPES["modify_package_expiry"],
|
|
1995
1961
|
ctx,
|
|
1996
|
-
async ({
|
|
1997
|
-
const params = {
|
|
1998
|
-
if (expirationDate !== void 0)
|
|
1962
|
+
async ({ packageId, expirationDate, validity_days }, token2) => {
|
|
1963
|
+
const params = { packageId };
|
|
1964
|
+
if (expirationDate !== void 0) {
|
|
1965
|
+
params.newExpirationDate = ocsLocalDateTime(expirationDate);
|
|
1966
|
+
}
|
|
1999
1967
|
if (validity_days !== void 0) params.newValidityDuration = validity_days;
|
|
2000
1968
|
return ocsCall(ctx.env, token2, "modifySubscriberPrepaidPackageExpDate", params);
|
|
2001
1969
|
}
|
|
@@ -2019,11 +1987,24 @@ function registerAllTools(server2, ctx) {
|
|
|
2019
1987
|
"modifySubscriberPrepaidPackageStatus",
|
|
2020
1988
|
TOOL_SCOPES["modify_package_status"],
|
|
2021
1989
|
ctx,
|
|
2022
|
-
async ({
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
1990
|
+
async ({ packageId, status }, token2) => {
|
|
1991
|
+
const normalised = String(status).trim().toUpperCase();
|
|
1992
|
+
if (normalised !== "ACTIVE" && normalised !== "INACTIVE") {
|
|
1993
|
+
return {
|
|
1994
|
+
isError: true,
|
|
1995
|
+
content: [
|
|
1996
|
+
{
|
|
1997
|
+
type: "text",
|
|
1998
|
+
text: `Invalid status "${status}". Use "ACTIVE" or "INACTIVE".`
|
|
1999
|
+
}
|
|
2000
|
+
]
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
2003
|
+
return ocsCall(ctx.env, token2, "modifySubscriberPrepaidPackageStatus", {
|
|
2004
|
+
subsPrepaidPackageId: packageId,
|
|
2005
|
+
active: normalised === "ACTIVE"
|
|
2006
|
+
});
|
|
2007
|
+
}
|
|
2027
2008
|
)
|
|
2028
2009
|
);
|
|
2029
2010
|
server2.registerTool(
|
|
@@ -2044,11 +2025,29 @@ function registerAllTools(server2, ctx) {
|
|
|
2044
2025
|
"stopResumeSubsRecurringPackage",
|
|
2045
2026
|
TOOL_SCOPES["stop_resume_recurring_package"],
|
|
2046
2027
|
ctx,
|
|
2047
|
-
async ({ iccid, packageId, action }, token2) =>
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2028
|
+
async ({ iccid, packageId, action }, token2) => {
|
|
2029
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
2030
|
+
const listed = await client2.call(
|
|
2031
|
+
"listSubscriberPrepaidPackages",
|
|
2032
|
+
{ iccid }
|
|
2033
|
+
);
|
|
2034
|
+
const recurringId = recurringIdForPackage(listed, packageId);
|
|
2035
|
+
if (recurringId === void 0) {
|
|
2036
|
+
return {
|
|
2037
|
+
isError: true,
|
|
2038
|
+
content: [
|
|
2039
|
+
{
|
|
2040
|
+
type: "text",
|
|
2041
|
+
text: `Package ${packageId} is not a recurring package on ICCID ${iccid}. stop_resume_recurring_package needs a package that came from a recurring template \u2014 call list_subscriber_packages and pick one that reports a recurring subscription.`
|
|
2042
|
+
}
|
|
2043
|
+
]
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
return ocsCall(ctx.env, token2, "stopResumeSubsRecurringPackage", {
|
|
2047
|
+
recurringId,
|
|
2048
|
+
active: action === "resume"
|
|
2049
|
+
});
|
|
2050
|
+
}
|
|
2052
2051
|
)
|
|
2053
2052
|
);
|
|
2054
2053
|
server2.registerTool(
|
|
@@ -4171,7 +4170,7 @@ function registerIntelligenceTools(server2, ctx) {
|
|
|
4171
4170
|
}, async ({ accountId }) => {
|
|
4172
4171
|
const token2 = await ctx.getUserToken(ctx.props.sub);
|
|
4173
4172
|
const resellerId = await getDefaultResellerId(ctx.env, token2).catch(() => void 0);
|
|
4174
|
-
const [statusResult, accountsResult] = await Promise.all([
|
|
4173
|
+
const [statusResult, accountsResult, resellerInfoResult] = await Promise.all([
|
|
4175
4174
|
safeCall(
|
|
4176
4175
|
ctx.env,
|
|
4177
4176
|
token2,
|
|
@@ -4183,7 +4182,17 @@ function registerIntelligenceTools(server2, ctx) {
|
|
|
4183
4182
|
token2,
|
|
4184
4183
|
"listResellerAccount",
|
|
4185
4184
|
resellerId !== void 0 ? { resellerId } : {}
|
|
4186
|
-
)
|
|
4185
|
+
),
|
|
4186
|
+
// The reseller's OWN balance. Sub-account balances cannot show that the
|
|
4187
|
+
// parent is out of credit, and that is the one state which silently
|
|
4188
|
+
// zeroes every rating group (2026-08-28: reseller 1170 at 0.00 while
|
|
4189
|
+
// fleet_health reported "require no action").
|
|
4190
|
+
resellerId !== void 0 ? safeCall(
|
|
4191
|
+
ctx.env,
|
|
4192
|
+
token2,
|
|
4193
|
+
"getResellerInfo",
|
|
4194
|
+
{ id: resellerId }
|
|
4195
|
+
) : Promise.resolve({ data: null, error: null })
|
|
4187
4196
|
]);
|
|
4188
4197
|
const sections = ["# Fleet Health Dashboard\n"];
|
|
4189
4198
|
const counts = extractEsimStatusCounts(statusResult.data);
|
|
@@ -4232,11 +4241,20 @@ High suspension rate (${totalSuspended} suspended vs ${totalActive} active)`);
|
|
|
4232
4241
|
const criticalZero = accounts.filter(
|
|
4233
4242
|
(a) => a.packageOnly === false && Number(a.balance ?? 0) <= 0
|
|
4234
4243
|
);
|
|
4244
|
+
const resellerRaw = resellerInfoResult?.data ?? null;
|
|
4245
|
+
const rawBalance = resellerRaw?.getResellerInfo?.balance;
|
|
4246
|
+
const resellerBalance = rawBalance === void 0 || rawBalance === null ? null : Number(rawBalance);
|
|
4247
|
+
const resellerOutOfCredit = resellerBalance !== null && resellerBalance <= 0;
|
|
4235
4248
|
sections.push(`
|
|
4236
4249
|
## Account Summary`);
|
|
4237
4250
|
sections.push(`- Total accounts: ${accounts.length}`);
|
|
4238
4251
|
sections.push(`- Low balance (< 10): ${lowBalance.length}`);
|
|
4239
4252
|
sections.push(`- Package-only with 0 balance: ${packageOnlyZero.length}`);
|
|
4253
|
+
if (resellerBalance !== null) {
|
|
4254
|
+
sections.push(
|
|
4255
|
+
`- Reseller balance: ${resellerBalance.toFixed(2)}` + (resellerOutOfCredit ? ` (OUT OF CREDIT - nothing can be rated)` : ``)
|
|
4256
|
+
);
|
|
4257
|
+
}
|
|
4240
4258
|
if (lowBalance.length > 0) {
|
|
4241
4259
|
sections.push(`
|
|
4242
4260
|
### Low Balance Accounts (< 10)`);
|
|
@@ -4266,8 +4284,15 @@ Action: top up non-package-only accounts at 0 balance to restore rated traffic.`
|
|
|
4266
4284
|
sections.push(`
|
|
4267
4285
|
All accounts healthy.`);
|
|
4268
4286
|
} else if (informational > 0 && warning <= 0) {
|
|
4269
|
-
|
|
4287
|
+
if (resellerOutOfCredit) {
|
|
4288
|
+
sections.push(
|
|
4289
|
+
`
|
|
4290
|
+
Action: reseller balance is ${resellerBalance.toFixed(2)}. Package-only accounts draw on their packages, but a reseller at 0 cannot rate any traffic - sessions are accepted and granted 0 bytes. Top up the reseller.`
|
|
4291
|
+
);
|
|
4292
|
+
} else {
|
|
4293
|
+
sections.push(`
|
|
4270
4294
|
Package-only accounts at 0 balance require no action.`);
|
|
4295
|
+
}
|
|
4271
4296
|
}
|
|
4272
4297
|
} else {
|
|
4273
4298
|
sections.push(`
|
|
@@ -5088,7 +5113,7 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
5088
5113
|
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
5089
5114
|
const result2 = await client2.call(
|
|
5090
5115
|
"modifySubscriberMobilePlan",
|
|
5091
|
-
{
|
|
5116
|
+
{ subscriberId: { iccid }, mobilePlanId: mobile_plan_id }
|
|
5092
5117
|
);
|
|
5093
5118
|
return {
|
|
5094
5119
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
@@ -5106,6 +5131,9 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
5106
5131
|
package_id: z3.number().describe("The subscriber package ID (from list_subscriber_packages)"),
|
|
5107
5132
|
start_date: z3.string().optional().describe("New start date in ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss)"),
|
|
5108
5133
|
end_date: z3.string().optional().describe("New end date in ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss)"),
|
|
5134
|
+
comment: z3.string().optional().describe(
|
|
5135
|
+
"Audit note stored on the OCS package record. OCS requires this field, so a default is sent when it is omitted."
|
|
5136
|
+
),
|
|
5109
5137
|
...DRY_RUN_FIELD2
|
|
5110
5138
|
},
|
|
5111
5139
|
annotations: { destructiveHint: true }
|
|
@@ -5115,11 +5143,22 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
5115
5143
|
"modifySubscriberPrepaidPackageActivePeriod",
|
|
5116
5144
|
BACKLOG_TOOL_SCOPES["modify_subscriber_package_active_period"],
|
|
5117
5145
|
ctx,
|
|
5118
|
-
async ({ iccid, package_id, start_date, end_date }, token2) => {
|
|
5119
|
-
const params = { subscriber: iccid, packageId: package_id };
|
|
5120
|
-
if (start_date !== void 0) params.startDate = start_date;
|
|
5121
|
-
if (end_date !== void 0) params.endDate = end_date;
|
|
5146
|
+
async ({ iccid, package_id, start_date, end_date, comment }, token2) => {
|
|
5122
5147
|
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
5148
|
+
let current;
|
|
5149
|
+
if (start_date === void 0 || end_date === void 0) {
|
|
5150
|
+
const listed = await client2.call("listSubscriberPrepaidPackages", { iccid });
|
|
5151
|
+
current = activePeriodFromPackages(listed, package_id);
|
|
5152
|
+
if (!current) {
|
|
5153
|
+
throw new Error(`Package ${package_id} is not on subscriber ${iccid}`);
|
|
5154
|
+
}
|
|
5155
|
+
}
|
|
5156
|
+
const params = packageActivePeriodParams(package_id, {
|
|
5157
|
+
startDate: start_date,
|
|
5158
|
+
endDate: end_date,
|
|
5159
|
+
comment,
|
|
5160
|
+
current
|
|
5161
|
+
});
|
|
5123
5162
|
const result2 = await client2.call(
|
|
5124
5163
|
"modifySubscriberPrepaidPackageActivePeriod",
|
|
5125
5164
|
params
|
|
@@ -5151,7 +5190,7 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
5151
5190
|
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
5152
5191
|
const result2 = await client2.call(
|
|
5153
5192
|
"modifySubscriberVoipPlan",
|
|
5154
|
-
{
|
|
5193
|
+
{ subscriberId: { iccid }, voipPlanId: voip_plan_id }
|
|
5155
5194
|
);
|
|
5156
5195
|
return {
|
|
5157
5196
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
@@ -5176,13 +5215,10 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
5176
5215
|
BACKLOG_TOOL_SCOPES["push_steering_to_subscriber"],
|
|
5177
5216
|
ctx,
|
|
5178
5217
|
async ({ iccid }, token2) => {
|
|
5179
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5180
|
-
const sub = await resolveSubscriberByIccid(ctx.env, token2, iccid, cache);
|
|
5181
|
-
const subscriberId = sub.id ?? sub.subscriberId ?? iccid;
|
|
5182
5218
|
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
5183
5219
|
const result2 = await client2.call(
|
|
5184
5220
|
"pushSteeringToSubs",
|
|
5185
|
-
{
|
|
5221
|
+
{ iccid }
|
|
5186
5222
|
);
|
|
5187
5223
|
return {
|
|
5188
5224
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
@@ -5208,7 +5244,7 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
5208
5244
|
ctx,
|
|
5209
5245
|
async ({ iccid }, token2) => {
|
|
5210
5246
|
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
5211
|
-
const result2 = await client2.call("resetSubsGzCounter", {
|
|
5247
|
+
const result2 = await client2.call("resetSubsGzCounter", { iccid });
|
|
5212
5248
|
return {
|
|
5213
5249
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
5214
5250
|
};
|
|
@@ -6683,6 +6719,11 @@ async function createTopupCheckout(env, args) {
|
|
|
6683
6719
|
const successUrl = args.successUrl ?? env.WALLET_CHECKOUT_SUCCESS_URL ?? DEFAULT_SUCCESS_URL;
|
|
6684
6720
|
const cancelUrl = args.cancelUrl ?? env.WALLET_CHECKOUT_CANCEL_URL ?? DEFAULT_CANCEL_URL;
|
|
6685
6721
|
const bonusLabel = bonusCents > 0 ? ` (+\u20AC${(bonusCents / 100).toFixed(2)} bonus)` : "";
|
|
6722
|
+
if (!env.CARRIER_USERS) {
|
|
6723
|
+
throw new Error(
|
|
6724
|
+
"Wallet top-up is not available in local stdio mode: the prepaid wallet is credited by the hosted Carrier service after payment, and this process cannot reach the customer record that crediting depends on. Creating the session here would bill the card against a duplicate Stripe customer and the wallet would never be credited. Top up from the console at https://app.carrier.llc/billing, or connect to the hosted MCP at https://mcp.carrier.llc/mcp, which has the binding. `wallet_balance` still works here if ATLAS_BASE_URL and CARRIER_INTERNAL_API_KEY are set."
|
|
6725
|
+
);
|
|
6726
|
+
}
|
|
6686
6727
|
const billingSub = await resolveBillingSub(env, args.orgId);
|
|
6687
6728
|
const existingCustomer = await env.CARRIER_USERS.get(`stripe_customer_id:${billingSub}`).catch(() => null);
|
|
6688
6729
|
const params = new URLSearchParams({
|
|
@@ -6732,7 +6773,7 @@ async function runAutoTopup(env, args) {
|
|
|
6732
6773
|
let packCents = args.packCents;
|
|
6733
6774
|
try {
|
|
6734
6775
|
const wallet = await getWallet(env, args.orgId);
|
|
6735
|
-
if (packCents === void 0) packCents = wallet.auto_topup_pack_cents;
|
|
6776
|
+
if (packCents === void 0) packCents = wallet.auto_topup_pack_cents ?? void 0;
|
|
6736
6777
|
} catch (e) {
|
|
6737
6778
|
if (e instanceof WalletClientError) {
|
|
6738
6779
|
return { charged: false, creditedCents: 0, reason: `wallet_unreachable: ${e.message}` };
|
|
@@ -6838,15 +6879,23 @@ function registerWalletTools(server2, ctx) {
|
|
|
6838
6879
|
description: "Read the caller organisation's Carrier prepaid wallet: current balance and auto-top-up settings. The wallet is what Carrier bills your own eSIM spend against \u2014 it is not an OCS balance and not your MCP plan credits. Params: none (the organisation is taken from the session). Returns: { org_id, balance_eur_cents, auto_topup_enabled, auto_topup_threshold_cents, auto_topup_pack_cents } \u2014 all amounts in EUR cents, not euros. Do NOT use this for a reseller account balance in OCS \u2014 use `get_reseller_info` or `list_reseller_accounts`. Do NOT use this for a subscriber's OCS balance \u2014 use `get_subscriber`. Do NOT use this for MCP plan credits \u2014 use `credit_balance`. Do NOT use this for money held at Stripe \u2014 use `stripe_connect_balance`.",
|
|
6839
6880
|
inputSchema: {},
|
|
6840
6881
|
// Derived from the object literal this handler builds below, not from the
|
|
6841
|
-
// description.
|
|
6842
|
-
//
|
|
6843
|
-
//
|
|
6882
|
+
// description. All five keys are always present on the success path, so
|
|
6883
|
+
// none is optional — but the two auto-top-up amounts are nullable, not
|
|
6884
|
+
// just unset. ATLAS types them `number | null` and synthesises an
|
|
6885
|
+
// all-null row for an org with no wallet yet (its toWalletView), so an
|
|
6886
|
+
// org that has never configured auto-top-up — every newly onboarded one
|
|
6887
|
+
// — returns null here. Requiring a number turned that, the most common
|
|
6888
|
+
// state a new operator is in, into an output validation error.
|
|
6844
6889
|
outputSchema: {
|
|
6845
6890
|
org_id: z7.string().describe("Carrier organisation the wallet belongs to"),
|
|
6846
6891
|
balance_eur_cents: z7.number().int().describe("Current balance in EUR cents"),
|
|
6847
6892
|
auto_topup_enabled: z7.boolean(),
|
|
6848
|
-
auto_topup_threshold_cents: z7.number().int().describe(
|
|
6849
|
-
|
|
6893
|
+
auto_topup_threshold_cents: z7.number().int().nullable().describe(
|
|
6894
|
+
"Balance at or below which an auto top-up fires, EUR cents. Null when auto-top-up is unconfigured."
|
|
6895
|
+
),
|
|
6896
|
+
auto_topup_pack_cents: z7.number().int().nullable().describe(
|
|
6897
|
+
"Amount an auto top-up charges, EUR cents. Null when auto-top-up is unconfigured."
|
|
6898
|
+
)
|
|
6850
6899
|
},
|
|
6851
6900
|
annotations: annotationsFor("wallet_balance", "read")
|
|
6852
6901
|
},
|
|
@@ -7038,7 +7087,39 @@ function registerWalletTools(server2, ctx) {
|
|
|
7038
7087
|
// src/stripe-connect-tools.ts
|
|
7039
7088
|
import { z as z8 } from "zod";
|
|
7040
7089
|
import * as Sentry3 from "@sentry/cloudflare";
|
|
7090
|
+
|
|
7091
|
+
// src/binding-unavailable.ts
|
|
7092
|
+
var HOSTED_MCP_URL = "https://mcp.carrier.llc/mcp";
|
|
7093
|
+
var BindingUnavailableError = class extends Error {
|
|
7094
|
+
constructor(tool, binding, message) {
|
|
7095
|
+
super(message);
|
|
7096
|
+
this.tool = tool;
|
|
7097
|
+
this.binding = binding;
|
|
7098
|
+
this.name = "BindingUnavailableError";
|
|
7099
|
+
}
|
|
7100
|
+
tool;
|
|
7101
|
+
binding;
|
|
7102
|
+
};
|
|
7103
|
+
function requireUserStore(env, tool, subject) {
|
|
7104
|
+
requireBinding(env.CARRIER_USERS, tool, "CARRIER_USERS", subject);
|
|
7105
|
+
}
|
|
7106
|
+
function requireBinding(binding, tool, name, subject) {
|
|
7107
|
+
if (binding) return;
|
|
7108
|
+
throw new BindingUnavailableError(
|
|
7109
|
+
tool,
|
|
7110
|
+
name,
|
|
7111
|
+
`${tool} cannot answer here: ${subject} is held by the hosted Carrier service, and this local MCP server has no connection to it. There is nothing to set in your environment \u2014 the data does not exist on this machine. Connect to the hosted MCP at ${HOSTED_MCP_URL}, or open the console at https://app.carrier.llc, to use this tool. Every OCS tool in this server works against your own token and is unaffected.`
|
|
7112
|
+
);
|
|
7113
|
+
}
|
|
7114
|
+
|
|
7115
|
+
// src/stripe-connect-tools.ts
|
|
7041
7116
|
async function verifyConfirmToken(env, sub, toolName, token2) {
|
|
7117
|
+
requireBinding(
|
|
7118
|
+
env.OAUTH_KV,
|
|
7119
|
+
toolName,
|
|
7120
|
+
"OAUTH_KV",
|
|
7121
|
+
"the short-lived confirmation token this operation requires"
|
|
7122
|
+
);
|
|
7042
7123
|
const key = `confirm:${sub}:${toolName}`;
|
|
7043
7124
|
const stored = await env.OAUTH_KV.get(key);
|
|
7044
7125
|
if (!stored || stored !== token2) return false;
|
|
@@ -7046,6 +7127,12 @@ async function verifyConfirmToken(env, sub, toolName, token2) {
|
|
|
7046
7127
|
return true;
|
|
7047
7128
|
}
|
|
7048
7129
|
async function issueConfirmToken(env, sub, toolName) {
|
|
7130
|
+
requireBinding(
|
|
7131
|
+
env.OAUTH_KV,
|
|
7132
|
+
toolName,
|
|
7133
|
+
"OAUTH_KV",
|
|
7134
|
+
"the short-lived confirmation token this operation requires"
|
|
7135
|
+
);
|
|
7049
7136
|
const bytes = crypto.getRandomValues(new Uint8Array(16));
|
|
7050
7137
|
const token2 = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
7051
7138
|
const key = `confirm:${sub}:${toolName}`;
|
|
@@ -8173,6 +8260,7 @@ var PRICING_TOOLS = [
|
|
|
8173
8260
|
required: []
|
|
8174
8261
|
},
|
|
8175
8262
|
handler: async (env, props2) => {
|
|
8263
|
+
requireUserStore(env, "credit_balance", "your MCP plan credit ledger");
|
|
8176
8264
|
const tier = props2.tier;
|
|
8177
8265
|
const summary = await getCreditSummary(env, props2.sub, tier);
|
|
8178
8266
|
const creditCheck = await checkCredits(env, props2.sub, tier, "read");
|
|
@@ -8254,6 +8342,7 @@ var PRICING_TOOLS = [
|
|
|
8254
8342
|
required: []
|
|
8255
8343
|
},
|
|
8256
8344
|
handler: async (env, props2, args) => {
|
|
8345
|
+
requireUserStore(env, "configure_billing", "your billing configuration");
|
|
8257
8346
|
const tier = props2.tier;
|
|
8258
8347
|
if (tier === "free") {
|
|
8259
8348
|
return {
|
|
@@ -8322,6 +8411,11 @@ var PRICING_TOOLS = [
|
|
|
8322
8411
|
required: []
|
|
8323
8412
|
},
|
|
8324
8413
|
handler: async (env, props2, args) => {
|
|
8414
|
+
requireUserStore(
|
|
8415
|
+
env,
|
|
8416
|
+
"usage_projection",
|
|
8417
|
+
"the consumption history a projection is drawn from"
|
|
8418
|
+
);
|
|
8325
8419
|
const tier = props2.tier;
|
|
8326
8420
|
const summary = await getCreditSummary(env, props2.sub, tier);
|
|
8327
8421
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -8470,6 +8564,7 @@ var PRICING_TOOLS = [
|
|
|
8470
8564
|
required: []
|
|
8471
8565
|
},
|
|
8472
8566
|
handler: async (env, props2, args) => {
|
|
8567
|
+
requireUserStore(env, "billing_events", "your billing event history");
|
|
8473
8568
|
const limit = Math.min(
|
|
8474
8569
|
typeof args.limit === "number" ? args.limit : 20,
|
|
8475
8570
|
50
|
|
@@ -8780,6 +8875,11 @@ var PROJECTS_TOOLS = [
|
|
|
8780
8875
|
required: ["new_token", "confirm"]
|
|
8781
8876
|
},
|
|
8782
8877
|
handler: async (env, props2, args) => {
|
|
8878
|
+
requireUserStore(
|
|
8879
|
+
env,
|
|
8880
|
+
"rotate_credentials",
|
|
8881
|
+
"the encrypted token vault this writes to"
|
|
8882
|
+
);
|
|
8783
8883
|
if (!args.confirm) {
|
|
8784
8884
|
return {
|
|
8785
8885
|
status: "cancelled",
|
|
@@ -8794,7 +8894,9 @@ var PROJECTS_TOOLS = [
|
|
|
8794
8894
|
}
|
|
8795
8895
|
const encryptionKey = env.CARRIER_TOKEN_ENCRYPTION_KEY;
|
|
8796
8896
|
if (!encryptionKey) {
|
|
8797
|
-
|
|
8897
|
+
throw new Error(
|
|
8898
|
+
"rotate_credentials cannot run here: CARRIER_TOKEN_ENCRYPTION_KEY is a secret of the hosted Carrier service and is not present in a local install, so there is no way to encrypt a token for the vault. Rotate from the console at https://app.carrier.llc, or connect to the hosted MCP at https://mcp.carrier.llc/mcp. In local stdio mode the OCS token comes from CARRIER_OCS_API_TOKEN in your own environment \u2014 change it there and restart, no rotation call needed."
|
|
8899
|
+
);
|
|
8798
8900
|
}
|
|
8799
8901
|
const encrypted = await encryptToken(newToken, encryptionKey);
|
|
8800
8902
|
const orgId = props2.org_id;
|
|
@@ -8943,13 +9045,17 @@ var PROJECTS_TOOLS = [
|
|
|
8943
9045
|
handler: async (env, props2) => {
|
|
8944
9046
|
const sub = props2.sub;
|
|
8945
9047
|
const orgId = props2.org_id;
|
|
9048
|
+
const hasStore = !!env.CARRIER_USERS;
|
|
8946
9049
|
let orgDetails = null;
|
|
8947
|
-
if (orgId) {
|
|
9050
|
+
if (orgId && hasStore) {
|
|
8948
9051
|
orgDetails = await env.CARRIER_USERS.get(`org:${orgId}`, "json").catch(() => null);
|
|
8949
9052
|
}
|
|
8950
|
-
const hasStripe = !!await env.CARRIER_USERS.get(`stripe_customer_id:${sub}`);
|
|
8951
|
-
const hasWebhook = !!await env.CARRIER_USERS.get(`webhook_url:${sub}`);
|
|
9053
|
+
const hasStripe = hasStore ? !!await env.CARRIER_USERS.get(`stripe_customer_id:${sub}`) : null;
|
|
9054
|
+
const hasWebhook = hasStore ? !!await env.CARRIER_USERS.get(`webhook_url:${sub}`) : null;
|
|
8952
9055
|
return {
|
|
9056
|
+
...hasStore ? {} : {
|
|
9057
|
+
note: "Running as a local stdio server. Fields reported as null are held by the hosted Carrier service and cannot be read from here; connect to https://mcp.carrier.llc/mcp to see them. Everything else below is this session's own configuration and is accurate."
|
|
9058
|
+
},
|
|
8953
9059
|
environment: {
|
|
8954
9060
|
user_sub: sub,
|
|
8955
9061
|
org_id: orgId ?? null,
|
|
@@ -9374,8 +9480,8 @@ var CURATED_ROUTER_TOOLS = [
|
|
|
9374
9480
|
},
|
|
9375
9481
|
{
|
|
9376
9482
|
name: "move_subscriber_range_to_account",
|
|
9377
|
-
description: "Move a range of subscribers
|
|
9378
|
-
input_schema: { type: "object", properties: {
|
|
9483
|
+
description: "Move a range of subscribers (by IMSI or ICCID) from one account to another. Intent: 'move subscribers', 'transfer SIMs to account'.",
|
|
9484
|
+
input_schema: { type: "object", properties: { srcAccountId: { type: "number" }, destAccount: { type: "number" }, rangeType: { type: "string" } } }
|
|
9379
9485
|
},
|
|
9380
9486
|
{
|
|
9381
9487
|
name: "hlr_get_bitrate",
|
|
@@ -9658,15 +9764,28 @@ var ROUTER_SYSTEM_PROMPT = `You are a carrier fleet operations router. Your job
|
|
|
9658
9764
|
|
|
9659
9765
|
${ROUTER_RULES}`;
|
|
9660
9766
|
var ROUTER_TIMEOUT_MS = 12e3;
|
|
9767
|
+
var AskRouterNotConfiguredError = class extends Error {
|
|
9768
|
+
constructor(missing) {
|
|
9769
|
+
super(routerRemediation(missing));
|
|
9770
|
+
this.missing = missing;
|
|
9771
|
+
this.name = "AskRouterNotConfiguredError";
|
|
9772
|
+
}
|
|
9773
|
+
missing;
|
|
9774
|
+
};
|
|
9775
|
+
function missingRouterCredentials(env) {
|
|
9776
|
+
const missing = [];
|
|
9777
|
+
if (!env.AWS_ACCESS_KEY_ID) missing.push("AWS_ACCESS_KEY_ID");
|
|
9778
|
+
if (!env.AWS_SECRET_ACCESS_KEY) missing.push("AWS_SECRET_ACCESS_KEY");
|
|
9779
|
+
if (env.CARRIER_ASK_ENABLED !== "true") missing.push("CARRIER_ASK_ENABLED=true");
|
|
9780
|
+
return missing;
|
|
9781
|
+
}
|
|
9782
|
+
function routerRemediation(missing) {
|
|
9783
|
+
return `carrier_ask cannot route: ${missing.join(", ")} ${missing.length === 1 ? "is" : "are"} not set. Set them in the environment of the process running this MCP server (for Claude Desktop / Cursor / Windsurf, the \`env\` block of the server entry in your MCP config), then restart it. The router calls Amazon Bedrock, so the credentials must belong to an IAM identity with bedrock:InvokeModel. Every other Carrier tool works without this \u2014 carrier_ask only picks which one to call, so you can call the tool you want directly in the meantime.`;
|
|
9784
|
+
}
|
|
9661
9785
|
async function _routeIntent(intent, context, env, opts = {}) {
|
|
9662
9786
|
const { attribution, onUsage } = opts;
|
|
9663
9787
|
if (env.CARRIER_ASK_ENABLED !== "true" || !env.AWS_ACCESS_KEY_ID || !env.AWS_SECRET_ACCESS_KEY) {
|
|
9664
|
-
|
|
9665
|
-
match: "routing_pending",
|
|
9666
|
-
intent_received: intent,
|
|
9667
|
-
note: "carrier_ask routing engine is not yet activated. Add AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY to Doppler carrier/dev+stg+prd and set CARRIER_ASK_ENABLED=true.",
|
|
9668
|
-
scaffold_version: "v2.0-bedrock"
|
|
9669
|
-
};
|
|
9788
|
+
throw new AskRouterNotConfiguredError(missingRouterCredentials(env));
|
|
9670
9789
|
}
|
|
9671
9790
|
const definedContext = Object.fromEntries(
|
|
9672
9791
|
Object.entries(context).filter(([, value]) => value !== void 0)
|
|
@@ -9922,6 +10041,34 @@ function registerAllCarrierAskTools(server2, ctx) {
|
|
|
9922
10041
|
}
|
|
9923
10042
|
});
|
|
9924
10043
|
} catch (err7) {
|
|
10044
|
+
if (err7 instanceof AskRouterNotConfiguredError) {
|
|
10045
|
+
writeCarrierAskAudit(ctx.env, {
|
|
10046
|
+
intent_hash: intentHash,
|
|
10047
|
+
match: "error",
|
|
10048
|
+
resolved_tool: "none",
|
|
10049
|
+
confirm_token_state: "none",
|
|
10050
|
+
status: "error",
|
|
10051
|
+
latency_ms: Date.now() - start,
|
|
10052
|
+
sub: ctx.props.sub,
|
|
10053
|
+
reseller_id: ctx.props.reseller_id,
|
|
10054
|
+
model_id: "none",
|
|
10055
|
+
tier: ctx.props.tier,
|
|
10056
|
+
usage: ZERO_USAGE
|
|
10057
|
+
});
|
|
10058
|
+
return {
|
|
10059
|
+
content: [
|
|
10060
|
+
{
|
|
10061
|
+
type: "text",
|
|
10062
|
+
text: JSON.stringify({
|
|
10063
|
+
error: "router_not_configured",
|
|
10064
|
+
missing: err7.missing,
|
|
10065
|
+
message: err7.message
|
|
10066
|
+
})
|
|
10067
|
+
}
|
|
10068
|
+
],
|
|
10069
|
+
isError: true
|
|
10070
|
+
};
|
|
10071
|
+
}
|
|
9925
10072
|
writeCarrierAskAudit(ctx.env, {
|
|
9926
10073
|
intent_hash: intentHash,
|
|
9927
10074
|
match: "error",
|
|
@@ -10279,6 +10426,12 @@ function registerListRecentOcsEventsTool(server2, ctx) {
|
|
|
10279
10426
|
};
|
|
10280
10427
|
}
|
|
10281
10428
|
}
|
|
10429
|
+
requireBinding(
|
|
10430
|
+
env.OCS_EVENT_ROUTING,
|
|
10431
|
+
"list_recent_ocs_events",
|
|
10432
|
+
"OCS_EVENT_ROUTING",
|
|
10433
|
+
"the OCS event ring buffer"
|
|
10434
|
+
);
|
|
10282
10435
|
const result2 = await listRecentOcsEvents2(
|
|
10283
10436
|
iccid,
|
|
10284
10437
|
limit,
|
|
@@ -10435,7 +10588,7 @@ function registerDepletionEventsTool(server2, ctx) {
|
|
|
10435
10588
|
const kv = ctx.env.RATE_LIMIT_KV;
|
|
10436
10589
|
if (!kv) {
|
|
10437
10590
|
return err5(
|
|
10438
|
-
"
|
|
10591
|
+
"subscriber_depletion_events cannot answer here. Depletion events are written by the Carrier webhook receiver as they arrive from the network and kept for 7 days in hosted storage; a local stdio server receives no webhooks and has nowhere to keep them, so there is no history on this machine to read. There is nothing to set in your environment. Use the hosted MCP at https://mcp.carrier.llc/mcp for this tool. To see a subscriber's current bundle state instead of its depletion history, `get_subscriber` and `list_subscriber_packages` query OCS directly and work here."
|
|
10439
10592
|
);
|
|
10440
10593
|
}
|
|
10441
10594
|
const { subscriberId, since } = args;
|
|
@@ -12353,7 +12506,23 @@ var stdioEnv = {
|
|
|
12353
12506
|
ATLAS_BASE_URL: process.env.ATLAS_BASE_URL,
|
|
12354
12507
|
CARRIER_INTERNAL_API_KEY: process.env.CARRIER_INTERNAL_API_KEY,
|
|
12355
12508
|
WALLET_CHECKOUT_SUCCESS_URL: process.env.WALLET_CHECKOUT_SUCCESS_URL,
|
|
12356
|
-
WALLET_CHECKOUT_CANCEL_URL: process.env.WALLET_CHECKOUT_CANCEL_URL
|
|
12509
|
+
WALLET_CHECKOUT_CANCEL_URL: process.env.WALLET_CHECKOUT_CANCEL_URL,
|
|
12510
|
+
// Bedrock credentials for carrier_ask, the natural-language router. None of
|
|
12511
|
+
// these appeared in this shim at all until now, so every read saw `undefined`
|
|
12512
|
+
// and the routing gate in tools-carrier-ask.ts could never open: the flagship
|
|
12513
|
+
// router had routed nothing from npm since it shipped. Same treatment as
|
|
12514
|
+
// STRIPE_SECRET_KEY and the wallet values above — read the environment, and
|
|
12515
|
+
// when absent let the tool refuse out loud rather than pretend it answered.
|
|
12516
|
+
AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
|
|
12517
|
+
AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
|
|
12518
|
+
AWS_REGION: process.env.AWS_REGION,
|
|
12519
|
+
BEDROCK_MODEL_ID: process.env.BEDROCK_MODEL_ID,
|
|
12520
|
+
// Defaults ON here, unlike the Worker. The flag is the Worker's staged
|
|
12521
|
+
// rollout switch; a local operator who has put AWS credentials on the process
|
|
12522
|
+
// has already opted in, and making them set a second variable they have never
|
|
12523
|
+
// heard of is just the same dead gate one step further along. Setting it to
|
|
12524
|
+
// anything other than "true" still turns the router off.
|
|
12525
|
+
CARRIER_ASK_ENABLED: process.env.CARRIER_ASK_ENABLED ?? "true"
|
|
12357
12526
|
};
|
|
12358
12527
|
var props = {
|
|
12359
12528
|
sub: "stdio@local",
|