@mutagent/cli 0.2.54 → 0.2.56
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/bin/cli.js +111 -85
- package/dist/index.js +7 -1
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -1174,6 +1174,91 @@ var init_organization_scope = __esm(() => {
|
|
|
1174
1174
|
keyScopeConfirmations = new Map;
|
|
1175
1175
|
});
|
|
1176
1176
|
|
|
1177
|
+
// src/lib/key-scope-heal.ts
|
|
1178
|
+
function isOrgKeyWithoutWorkspace(status, body) {
|
|
1179
|
+
return status === 400 && body.toLowerCase().includes(ORG_KEY_NEEDS_WORKSPACE);
|
|
1180
|
+
}
|
|
1181
|
+
function codeOf(body) {
|
|
1182
|
+
try {
|
|
1183
|
+
return JSON.parse(body)?.code;
|
|
1184
|
+
} catch {
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
async function readKeySelf(key, fetchImpl) {
|
|
1189
|
+
try {
|
|
1190
|
+
const response = await fetchImpl(`${key.endpoint}/api/api-keys/self`, { headers: { "x-api-key": key.apiKey } });
|
|
1191
|
+
const self = response.ok ? await response.json() : undefined;
|
|
1192
|
+
return self?.scope === "workspace" || self?.scope === "organization" || self?.scope === "user" ? self : undefined;
|
|
1193
|
+
} catch {
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
async function explainSelectionDenial(status, body, ctx, key, fetchImpl = fetch) {
|
|
1198
|
+
if (status !== 403 || ctx.workspaceOrigin !== "selection" || ctx.keyScope !== "workspace" || ctx.keyWorkspace)
|
|
1199
|
+
return;
|
|
1200
|
+
if (codeOf(body) !== TENANCY_DENIED)
|
|
1201
|
+
return;
|
|
1202
|
+
const self = await readKeySelf(key, fetchImpl);
|
|
1203
|
+
if (!self)
|
|
1204
|
+
return;
|
|
1205
|
+
ctx.keyScope = self.scope;
|
|
1206
|
+
if (self.scope === "workspace") {
|
|
1207
|
+
ctx.keyWorkspace = self.workspace ?? undefined;
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
if (!envKeyReplacesFile())
|
|
1211
|
+
recordKeyScope(self);
|
|
1212
|
+
}
|
|
1213
|
+
async function explainThrownDenial(error, ctx, key) {
|
|
1214
|
+
if (ctx === undefined || !(error instanceof Error) || !("statusCode" in error) || typeof error.statusCode !== "number")
|
|
1215
|
+
return;
|
|
1216
|
+
const body = "body" in error && typeof error.body === "string" ? error.body : "";
|
|
1217
|
+
await explainSelectionDenial(error.statusCode, body, ctx, key);
|
|
1218
|
+
}
|
|
1219
|
+
function sameHeaders(a, b) {
|
|
1220
|
+
const keys = Object.keys(a);
|
|
1221
|
+
return keys.length === Object.keys(b).length && keys.every((k) => a[k] === b[k]);
|
|
1222
|
+
}
|
|
1223
|
+
async function fetchWithScopeHeal(input, init, target) {
|
|
1224
|
+
const spare = input instanceof Request ? input.clone() : undefined;
|
|
1225
|
+
const response = await (init == null ? fetch(input) : fetch(input, init));
|
|
1226
|
+
if (response.status === 403 && target.tenancy) {
|
|
1227
|
+
const denied = await response.clone().text().catch(() => "");
|
|
1228
|
+
await explainSelectionDenial(403, denied, target.tenancy, target);
|
|
1229
|
+
return response;
|
|
1230
|
+
}
|
|
1231
|
+
if (response.status !== 400)
|
|
1232
|
+
return response;
|
|
1233
|
+
const body = await response.clone().text().catch(() => "");
|
|
1234
|
+
if (!isOrgKeyWithoutWorkspace(response.status, body))
|
|
1235
|
+
return response;
|
|
1236
|
+
const before = target.headers();
|
|
1237
|
+
const self = await confirmKeyScope(target.apiKey, target.endpoint).catch(() => {
|
|
1238
|
+
return;
|
|
1239
|
+
});
|
|
1240
|
+
if (!self)
|
|
1241
|
+
return response;
|
|
1242
|
+
target.adopt(self);
|
|
1243
|
+
const after = target.headers();
|
|
1244
|
+
if (sameHeaders(before, after))
|
|
1245
|
+
return response;
|
|
1246
|
+
if (spare) {
|
|
1247
|
+
const headers = new Headers(spare.headers);
|
|
1248
|
+
for (const [name, value] of Object.entries(after))
|
|
1249
|
+
headers.set(name, value);
|
|
1250
|
+
return fetch(new Request(spare, { headers }));
|
|
1251
|
+
}
|
|
1252
|
+
const headers = { ...init?.headers, ...after };
|
|
1253
|
+
return fetch(input, { ...init, headers });
|
|
1254
|
+
}
|
|
1255
|
+
var ORG_KEY_NEEDS_WORKSPACE = "x-workspace-id header required";
|
|
1256
|
+
var init_key_scope_heal = __esm(() => {
|
|
1257
|
+
init_config();
|
|
1258
|
+
init_organization_scope();
|
|
1259
|
+
init_tenancy_error();
|
|
1260
|
+
});
|
|
1261
|
+
|
|
1177
1262
|
// src/lib/sdk-debug.ts
|
|
1178
1263
|
function isDebugEnabled(env = process.env) {
|
|
1179
1264
|
return TRUTHY.has((env.MUTAGENT_DEBUG ?? "").trim().toLowerCase());
|
|
@@ -1488,85 +1573,6 @@ function buildCreateProviderBody(data) {
|
|
|
1488
1573
|
return body;
|
|
1489
1574
|
}
|
|
1490
1575
|
|
|
1491
|
-
// src/lib/key-scope-heal.ts
|
|
1492
|
-
function isOrgKeyWithoutWorkspace(status, body) {
|
|
1493
|
-
return status === 400 && body.toLowerCase().includes(ORG_KEY_NEEDS_WORKSPACE);
|
|
1494
|
-
}
|
|
1495
|
-
function codeOf(body) {
|
|
1496
|
-
try {
|
|
1497
|
-
return JSON.parse(body)?.code;
|
|
1498
|
-
} catch {
|
|
1499
|
-
return;
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
async function readKeySelf(key, fetchImpl) {
|
|
1503
|
-
try {
|
|
1504
|
-
const response = await fetchImpl(`${key.endpoint}/api/api-keys/self`, { headers: { "x-api-key": key.apiKey } });
|
|
1505
|
-
const self = response.ok ? await response.json() : undefined;
|
|
1506
|
-
return self?.scope === "workspace" || self?.scope === "organization" || self?.scope === "user" ? self : undefined;
|
|
1507
|
-
} catch {
|
|
1508
|
-
return;
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
async function explainSelectionDenial(status, body, ctx, key, fetchImpl = fetch) {
|
|
1512
|
-
if (status !== 403 || ctx.workspaceOrigin !== "selection" || ctx.keyScope !== "workspace" || ctx.keyWorkspace)
|
|
1513
|
-
return;
|
|
1514
|
-
if (codeOf(body) !== TENANCY_DENIED)
|
|
1515
|
-
return;
|
|
1516
|
-
const self = await readKeySelf(key, fetchImpl);
|
|
1517
|
-
if (!self)
|
|
1518
|
-
return;
|
|
1519
|
-
ctx.keyScope = self.scope;
|
|
1520
|
-
if (self.scope === "workspace") {
|
|
1521
|
-
ctx.keyWorkspace = self.workspace ?? undefined;
|
|
1522
|
-
return;
|
|
1523
|
-
}
|
|
1524
|
-
if (!envKeyReplacesFile())
|
|
1525
|
-
recordKeyScope(self);
|
|
1526
|
-
}
|
|
1527
|
-
function sameHeaders(a, b) {
|
|
1528
|
-
const keys = Object.keys(a);
|
|
1529
|
-
return keys.length === Object.keys(b).length && keys.every((k) => a[k] === b[k]);
|
|
1530
|
-
}
|
|
1531
|
-
async function fetchWithScopeHeal(input, init, target) {
|
|
1532
|
-
const spare = input instanceof Request ? input.clone() : undefined;
|
|
1533
|
-
const response = await (init == null ? fetch(input) : fetch(input, init));
|
|
1534
|
-
if (response.status === 403 && target.tenancy) {
|
|
1535
|
-
const denied = await response.clone().text().catch(() => "");
|
|
1536
|
-
await explainSelectionDenial(403, denied, target.tenancy, target);
|
|
1537
|
-
return response;
|
|
1538
|
-
}
|
|
1539
|
-
if (response.status !== 400)
|
|
1540
|
-
return response;
|
|
1541
|
-
const body = await response.clone().text().catch(() => "");
|
|
1542
|
-
if (!isOrgKeyWithoutWorkspace(response.status, body))
|
|
1543
|
-
return response;
|
|
1544
|
-
const before = target.headers();
|
|
1545
|
-
const self = await confirmKeyScope(target.apiKey, target.endpoint).catch(() => {
|
|
1546
|
-
return;
|
|
1547
|
-
});
|
|
1548
|
-
if (!self)
|
|
1549
|
-
return response;
|
|
1550
|
-
target.adopt(self);
|
|
1551
|
-
const after = target.headers();
|
|
1552
|
-
if (sameHeaders(before, after))
|
|
1553
|
-
return response;
|
|
1554
|
-
if (spare) {
|
|
1555
|
-
const headers = new Headers(spare.headers);
|
|
1556
|
-
for (const [name, value] of Object.entries(after))
|
|
1557
|
-
headers.set(name, value);
|
|
1558
|
-
return fetch(new Request(spare, { headers }));
|
|
1559
|
-
}
|
|
1560
|
-
const headers = { ...init?.headers, ...after };
|
|
1561
|
-
return fetch(input, { ...init, headers });
|
|
1562
|
-
}
|
|
1563
|
-
var ORG_KEY_NEEDS_WORKSPACE = "x-workspace-id header required";
|
|
1564
|
-
var init_key_scope_heal = __esm(() => {
|
|
1565
|
-
init_config();
|
|
1566
|
-
init_organization_scope();
|
|
1567
|
-
init_tenancy_error();
|
|
1568
|
-
});
|
|
1569
|
-
|
|
1570
1576
|
// src/lib/sdk-mappers.ts
|
|
1571
1577
|
import { LlmProviderType as SDKProviderEnum } from "@mutagent/sdk/models";
|
|
1572
1578
|
function isProviderType(value) {
|
|
@@ -18080,6 +18086,7 @@ import chalk2 from "chalk";
|
|
|
18080
18086
|
// src/lib/agent/spec-api.ts
|
|
18081
18087
|
init_config();
|
|
18082
18088
|
init_errors();
|
|
18089
|
+
init_key_scope_heal();
|
|
18083
18090
|
init_known_secrets();
|
|
18084
18091
|
init_organization_scope();
|
|
18085
18092
|
init_sdk_debug();
|
|
@@ -18157,6 +18164,7 @@ async function connectAgentSpec() {
|
|
|
18157
18164
|
try {
|
|
18158
18165
|
return await fn(sdk.managedAgents);
|
|
18159
18166
|
} catch (error) {
|
|
18167
|
+
await explainThrownDenial(error, tenancy, { apiKey, endpoint: resolved.endpoint });
|
|
18160
18168
|
throw agentSpecError(error, { endpoint: resolved.endpoint, tenancy, slug });
|
|
18161
18169
|
}
|
|
18162
18170
|
}
|
|
@@ -31751,6 +31759,7 @@ import chalk42 from "chalk";
|
|
|
31751
31759
|
|
|
31752
31760
|
// src/lib/gateway-api.ts
|
|
31753
31761
|
init_config();
|
|
31762
|
+
init_key_scope_heal();
|
|
31754
31763
|
init_known_secrets();
|
|
31755
31764
|
init_organization_scope();
|
|
31756
31765
|
class GatewayApiError extends Error {
|
|
@@ -31851,6 +31860,7 @@ async function gatewayRequest(path, init = {}) {
|
|
|
31851
31860
|
if (!response.ok) {
|
|
31852
31861
|
const bodyText = await response.text().catch(() => "");
|
|
31853
31862
|
if (response.status === 403 && tenancyCodeOf(bodyText) === TENANCY_DENIED) {
|
|
31863
|
+
await explainSelectionDenial(403, bodyText, connection.tenancy, connection);
|
|
31854
31864
|
const denied = tenancyFailure(response.status, bodyText, connection.tenancy);
|
|
31855
31865
|
if (denied)
|
|
31856
31866
|
throw denied;
|
|
@@ -33718,6 +33728,7 @@ init_known_secrets();
|
|
|
33718
33728
|
|
|
33719
33729
|
// src/lib/gateway-sdk.ts
|
|
33720
33730
|
import { HTTPClient as HTTPClient4, Mutagent as Mutagent4 } from "@mutagent/sdk";
|
|
33731
|
+
init_key_scope_heal();
|
|
33721
33732
|
init_organization_scope();
|
|
33722
33733
|
init_sdk_debug();
|
|
33723
33734
|
var SDK_TRANSPORT_ERRORS3 = new Set(["ConnectionError", "RequestTimeoutError", "RequestAbortedError", "UnexpectedClientError"]);
|
|
@@ -33735,12 +33746,12 @@ function gatewaySdkError(error, connection, what) {
|
|
|
33735
33746
|
const body = "body" in error && typeof error.body === "string" ? error.body : "";
|
|
33736
33747
|
if (status === 401)
|
|
33737
33748
|
return deadKeyError();
|
|
33738
|
-
|
|
33739
|
-
if (status === 403 && parsed.code === TENANCY_DENIED) {
|
|
33749
|
+
if (status === 403 && tenancyCodeOf(body) === TENANCY_DENIED) {
|
|
33740
33750
|
const denied = tenancyFailure(status, body, connection.tenancy);
|
|
33741
33751
|
if (denied)
|
|
33742
33752
|
return denied;
|
|
33743
33753
|
}
|
|
33754
|
+
const parsed = parseGatewayErrorBody(status, body, "");
|
|
33744
33755
|
return new GatewayApiError(status, parsed.code, parsed.reason, parsed.fix);
|
|
33745
33756
|
}
|
|
33746
33757
|
return error;
|
|
@@ -33766,6 +33777,7 @@ async function callGatewaySdk(what, fn) {
|
|
|
33766
33777
|
try {
|
|
33767
33778
|
return await fn(sdk.gateway, connection);
|
|
33768
33779
|
} catch (error) {
|
|
33780
|
+
await explainThrownDenial(error, connection.tenancy, connection);
|
|
33769
33781
|
throw gatewaySdkError(error, connection, what);
|
|
33770
33782
|
}
|
|
33771
33783
|
}
|
|
@@ -34197,6 +34209,7 @@ import chalk50 from "chalk";
|
|
|
34197
34209
|
|
|
34198
34210
|
// src/lib/gateway-api-events.ts
|
|
34199
34211
|
import { GatewayStreamError, streamGatewayUpdates } from "@mutagent/sdk/custom/gateway-stream.js";
|
|
34212
|
+
init_key_scope_heal();
|
|
34200
34213
|
init_known_secrets();
|
|
34201
34214
|
init_organization_scope();
|
|
34202
34215
|
function iso3(value) {
|
|
@@ -34216,11 +34229,13 @@ async function listNotices(query) {
|
|
|
34216
34229
|
return scrubKnownSuccessDeep({ items, nextCursor: page.nextCursor });
|
|
34217
34230
|
});
|
|
34218
34231
|
}
|
|
34219
|
-
function streamError(error,
|
|
34232
|
+
async function streamError(error, connection) {
|
|
34220
34233
|
if (error.status === 401)
|
|
34221
34234
|
return deadKeyError();
|
|
34222
34235
|
if (error.status === 403 && error.code === TENANCY_DENIED) {
|
|
34223
|
-
const
|
|
34236
|
+
const body = JSON.stringify({ code: error.code });
|
|
34237
|
+
await explainSelectionDenial(403, body, connection.tenancy, connection);
|
|
34238
|
+
const denied = tenancyFailure(403, body, connection.tenancy);
|
|
34224
34239
|
if (denied)
|
|
34225
34240
|
return denied;
|
|
34226
34241
|
}
|
|
@@ -34239,7 +34254,7 @@ async function* followGateway(signal) {
|
|
|
34239
34254
|
});
|
|
34240
34255
|
} catch (error) {
|
|
34241
34256
|
if (error instanceof GatewayStreamError)
|
|
34242
|
-
throw streamError(error, connection
|
|
34257
|
+
throw await streamError(error, connection);
|
|
34243
34258
|
throw error;
|
|
34244
34259
|
}
|
|
34245
34260
|
}
|
|
@@ -34780,6 +34795,7 @@ init_output();
|
|
|
34780
34795
|
// src/lib/reports-api.ts
|
|
34781
34796
|
init_config();
|
|
34782
34797
|
init_errors();
|
|
34798
|
+
init_key_scope_heal();
|
|
34783
34799
|
init_known_secrets();
|
|
34784
34800
|
init_organization_scope();
|
|
34785
34801
|
init_sdk_debug();
|
|
@@ -34849,6 +34865,10 @@ function reportsError(error, ctx) {
|
|
|
34849
34865
|
return new MutagentError("REQUEST_FAILED", error instanceof Error ? error.message : "Request failed", "Run: mutagent reports --help");
|
|
34850
34866
|
}
|
|
34851
34867
|
function connection(sdk, ctx) {
|
|
34868
|
+
const explain = async (error) => {
|
|
34869
|
+
if (ctx.apiKey !== undefined)
|
|
34870
|
+
await explainThrownDenial(error, ctx.tenancy, { apiKey: ctx.apiKey, endpoint: ctx.endpoint });
|
|
34871
|
+
};
|
|
34852
34872
|
return {
|
|
34853
34873
|
endpoint: ctx.endpoint,
|
|
34854
34874
|
credential: ctx.credential,
|
|
@@ -34857,6 +34877,7 @@ function connection(sdk, ctx) {
|
|
|
34857
34877
|
try {
|
|
34858
34878
|
return await fn(sdk.reports);
|
|
34859
34879
|
} catch (error) {
|
|
34880
|
+
await explain(error);
|
|
34860
34881
|
throw reportsError(error, ctx);
|
|
34861
34882
|
}
|
|
34862
34883
|
},
|
|
@@ -34864,6 +34885,7 @@ function connection(sdk, ctx) {
|
|
|
34864
34885
|
try {
|
|
34865
34886
|
return await fn(sdk);
|
|
34866
34887
|
} catch (error) {
|
|
34888
|
+
await explain(error);
|
|
34867
34889
|
throw reportsError(error, ctx);
|
|
34868
34890
|
}
|
|
34869
34891
|
}
|
|
@@ -34917,6 +34939,7 @@ async function connectReports(opts) {
|
|
|
34917
34939
|
return connection(sdk, {
|
|
34918
34940
|
endpoint: tenancy.endpoint,
|
|
34919
34941
|
credential: "api-key",
|
|
34942
|
+
apiKey,
|
|
34920
34943
|
tenancy: {
|
|
34921
34944
|
keyScope: tenancy.keyScope,
|
|
34922
34945
|
workspaceId: tenancy.workspaceId,
|
|
@@ -36600,6 +36623,7 @@ function fixFor(code, serverFix, ctx) {
|
|
|
36600
36623
|
init_config();
|
|
36601
36624
|
init_errors();
|
|
36602
36625
|
import { HTTPClient as HTTPClient6, Mutagent as Mutagent6 } from "@mutagent/sdk";
|
|
36626
|
+
init_key_scope_heal();
|
|
36603
36627
|
init_known_secrets();
|
|
36604
36628
|
init_organization_scope();
|
|
36605
36629
|
init_sdk_debug();
|
|
@@ -36668,6 +36692,7 @@ async function connectIntegrations() {
|
|
|
36668
36692
|
const tenancy = await resolveKeyTenancy(apiKey);
|
|
36669
36693
|
if (tenancy.keyScope !== "workspace" && !tenancy.workspaceId)
|
|
36670
36694
|
throw noWorkspaceSelected();
|
|
36695
|
+
const key = { apiKey, endpoint: tenancy.endpoint };
|
|
36671
36696
|
const headers = tenancyHeaders({
|
|
36672
36697
|
keyScope: tenancy.keyScope,
|
|
36673
36698
|
workspaceId: tenancy.workspaceId,
|
|
@@ -36719,6 +36744,7 @@ async function connectIntegrations() {
|
|
|
36719
36744
|
try {
|
|
36720
36745
|
return await fn(sdk.integrations);
|
|
36721
36746
|
} catch (error) {
|
|
36747
|
+
await explainThrownDenial(error, tenancyCtx, key);
|
|
36722
36748
|
throw integrationsError(error, { endpoint: tenancy.endpoint, tenancy: tenancyCtx, call: callCtx });
|
|
36723
36749
|
}
|
|
36724
36750
|
}
|
|
@@ -38215,4 +38241,4 @@ if (process.env.CLI_VERSION) {
|
|
|
38215
38241
|
}
|
|
38216
38242
|
runCli(process.argv.slice(2), cliVersion);
|
|
38217
38243
|
|
|
38218
|
-
//# debugId=
|
|
38244
|
+
//# debugId=CAC2930F9F23245664756E2164756E21
|
package/dist/index.js
CHANGED
|
@@ -1477,6 +1477,12 @@ async function explainSelectionDenial(status, body, ctx, key, fetchImpl = fetch)
|
|
|
1477
1477
|
if (!envKeyReplacesFile())
|
|
1478
1478
|
recordKeyScope(self);
|
|
1479
1479
|
}
|
|
1480
|
+
async function explainThrownDenial(error, ctx, key) {
|
|
1481
|
+
if (ctx === undefined || !(error instanceof Error) || !("statusCode" in error) || typeof error.statusCode !== "number")
|
|
1482
|
+
return;
|
|
1483
|
+
const body = "body" in error && typeof error.body === "string" ? error.body : "";
|
|
1484
|
+
await explainSelectionDenial(error.statusCode, body, ctx, key);
|
|
1485
|
+
}
|
|
1480
1486
|
function sameHeaders(a, b) {
|
|
1481
1487
|
const keys = Object.keys(a);
|
|
1482
1488
|
return keys.length === Object.keys(b).length && keys.every((k) => a[k] === b[k]);
|
|
@@ -2039,4 +2045,4 @@ export {
|
|
|
2039
2045
|
version
|
|
2040
2046
|
};
|
|
2041
2047
|
|
|
2042
|
-
//# debugId=
|
|
2048
|
+
//# debugId=C31E7F3B419630CE64756E2164756E21
|
package/package.json
CHANGED