@mutagent/cli 0.2.54 → 0.2.55

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 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
- const parsed = parseGatewayErrorBody(status, body, "");
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, tenancy) {
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 denied = tenancyFailure(403, JSON.stringify({ code: error.code }), tenancy);
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.tenancy);
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=C914B921636AC8AB64756E2164756E21
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=B6CD43FAA918848864756E2164756E21
2048
+ //# debugId=C31E7F3B419630CE64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutagent/cli",
3
- "version": "0.2.54",
3
+ "version": "0.2.55",
4
4
  "description": "Bun-native CLI for the MutagenT AI platform - auth, provider config, and lifecycle-tool installer for AI-native workflows",
5
5
  "type": "module",
6
6
  "bin": {