@ogment-ai/cli 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/cli/commands.d.ts +38 -0
  2. package/dist/cli/commands.d.ts.map +1 -0
  3. package/dist/cli/commands.js +57 -0
  4. package/dist/cli/execute.d.ts +11 -0
  5. package/dist/cli/execute.d.ts.map +1 -0
  6. package/dist/cli/execute.js +487 -0
  7. package/dist/cli/invocations.d.ts +32 -0
  8. package/dist/cli/invocations.d.ts.map +1 -0
  9. package/dist/cli/invocations.js +1 -0
  10. package/dist/cli/parse-errors.d.ts +17 -0
  11. package/dist/cli/parse-errors.d.ts.map +1 -0
  12. package/dist/cli/parse-errors.js +184 -0
  13. package/dist/cli/program.d.ts +10 -0
  14. package/dist/cli/program.d.ts.map +1 -0
  15. package/dist/cli/program.js +183 -0
  16. package/dist/cli/run.d.ts +6 -0
  17. package/dist/cli/run.d.ts.map +1 -0
  18. package/dist/cli/run.js +83 -0
  19. package/dist/cli/runtime.d.ts +22 -0
  20. package/dist/cli/runtime.d.ts.map +1 -0
  21. package/dist/cli/runtime.js +86 -0
  22. package/dist/cli.d.ts +2 -20
  23. package/dist/cli.d.ts.map +1 -1
  24. package/dist/cli.js +2 -737
  25. package/dist/commands/catalog.d.ts +3 -1
  26. package/dist/commands/catalog.d.ts.map +1 -1
  27. package/dist/commands/catalog.js +19 -2
  28. package/dist/commands/invoke.d.ts.map +1 -1
  29. package/dist/commands/invoke.js +53 -3
  30. package/dist/infra/http.d.ts +5 -1
  31. package/dist/infra/http.d.ts.map +1 -1
  32. package/dist/infra/http.js +62 -5
  33. package/dist/output/envelope.d.ts +5 -2
  34. package/dist/output/envelope.d.ts.map +1 -1
  35. package/dist/output/envelope.js +39 -23
  36. package/dist/output/manager.d.ts +9 -3
  37. package/dist/output/manager.d.ts.map +1 -1
  38. package/dist/output/manager.js +53 -2
  39. package/dist/services/account.d.ts.map +1 -1
  40. package/dist/services/account.js +9 -16
  41. package/dist/services/auth.d.ts.map +1 -1
  42. package/dist/services/auth.js +70 -52
  43. package/dist/services/info.d.ts.map +1 -1
  44. package/dist/services/info.js +62 -0
  45. package/dist/services/mcp-error-mapping.d.ts +9 -0
  46. package/dist/services/mcp-error-mapping.d.ts.map +1 -0
  47. package/dist/services/mcp-error-mapping.js +129 -0
  48. package/dist/services/mcp.d.ts +8 -2
  49. package/dist/services/mcp.d.ts.map +1 -1
  50. package/dist/services/mcp.js +24 -14
  51. package/dist/shared/error-codes.d.ts +4 -1
  52. package/dist/shared/error-codes.d.ts.map +1 -1
  53. package/dist/shared/error-presentation.d.ts +17 -0
  54. package/dist/shared/error-presentation.d.ts.map +1 -0
  55. package/dist/shared/error-presentation.js +151 -0
  56. package/dist/shared/errors.d.ts +34 -14
  57. package/dist/shared/errors.d.ts.map +1 -1
  58. package/dist/shared/errors.js +126 -25
  59. package/dist/shared/guards.d.ts +2 -1
  60. package/dist/shared/guards.d.ts.map +1 -1
  61. package/dist/shared/guards.js +1 -3
  62. package/dist/shared/recovery.d.ts +5 -0
  63. package/dist/shared/recovery.d.ts.map +1 -0
  64. package/dist/shared/recovery.js +123 -0
  65. package/dist/shared/types.d.ts +53 -13
  66. package/dist/shared/types.d.ts.map +1 -1
  67. package/dist/shared/types.js +1 -1
  68. package/package.json +2 -2
  69. package/dist/shared/retry.d.ts +0 -17
  70. package/dist/shared/retry.d.ts.map +0 -1
  71. package/dist/shared/retry.js +0 -27
@@ -9,7 +9,6 @@ import { CLI_CLIENT_NAME, CLI_REDIRECT_HOST } from "../shared/constants.js";
9
9
  import { ERROR_CODE } from "../shared/error-codes.js";
10
10
  import { AuthError, RemoteRequestError, UnexpectedError, ValidationError, } from "../shared/errors.js";
11
11
  import { parseWithSchema } from "../shared/guards.js";
12
- import { remoteRetryConfig } from "../shared/retry.js";
13
12
  import { browserAgentCallbackSchema, cliExchangeErrorSchema, cliExchangeRequestSchema, cliExchangeSuccessSchema, deviceCodeStartSchema, deviceTokenApprovedSchema, oauthClientRegistrationSchema, oauthTokenSchema, } from "../shared/schemas.js";
14
13
  const CALLBACK_TIMEOUT_MILLISECONDS = 5 * 60 * 1000;
15
14
  const defaultSleep = async (milliseconds) => {
@@ -127,7 +126,7 @@ const waitForOAuthCallback = async (server, port) => {
127
126
  return Result.err(new AuthError({
128
127
  code: ERROR_CODE.authInvalidCredentials,
129
128
  message: `OAuth error: ${oauthError}`,
130
- suggestedCommand: "ogment auth login --browser",
129
+ recovery: { command: "ogment auth login --browser" },
131
130
  }));
132
131
  }
133
132
  const code = url.searchParams.get("code");
@@ -139,7 +138,7 @@ const waitForOAuthCallback = async (server, port) => {
139
138
  return Result.err(new AuthError({
140
139
  code: ERROR_CODE.authInvalidCredentials,
141
140
  message: "No authorization code in callback",
142
- suggestedCommand: "ogment auth login --browser",
141
+ recovery: { command: "ogment auth login --browser" },
143
142
  }));
144
143
  }
145
144
  return Result.ok({
@@ -154,13 +153,13 @@ const waitForOAuthCallback = async (server, port) => {
154
153
  return Result.err(new AuthError({
155
154
  code: ERROR_CODE.authInvalidCredentials,
156
155
  message: "Login timed out. No callback received within 5 minutes.",
157
- suggestedCommand: "ogment auth login --browser",
156
+ recovery: { command: "ogment auth login --browser" },
158
157
  }));
159
158
  }
160
159
  return Result.err(new AuthError({
161
160
  code: ERROR_CODE.authInvalidCredentials,
162
161
  message: "Failed while waiting for OAuth callback.",
163
- suggestedCommand: "ogment auth login --browser",
162
+ recovery: { command: "ogment auth login --browser" },
164
163
  }));
165
164
  }
166
165
  finally {
@@ -169,7 +168,7 @@ const waitForOAuthCallback = async (server, port) => {
169
168
  return Result.err(new AuthError({
170
169
  code: ERROR_CODE.authInvalidCredentials,
171
170
  message: "Login timed out. No callback received within 5 minutes.",
172
- suggestedCommand: "ogment auth login --browser",
171
+ recovery: { command: "ogment auth login --browser" },
173
172
  }));
174
173
  };
175
174
  const waitForAgentCallback = async (server, port) => {
@@ -195,7 +194,7 @@ const waitForAgentCallback = async (server, port) => {
195
194
  return Result.err(new AuthError({
196
195
  code: ERROR_CODE.authInvalidCredentials,
197
196
  message: "No exchange code in callback",
198
- suggestedCommand: "ogment auth login --browser",
197
+ recovery: { command: "ogment auth login --browser" },
199
198
  }));
200
199
  }
201
200
  const agentName = parsedCallback.value.agent_name ?? "CLI Agent";
@@ -214,13 +213,13 @@ const waitForAgentCallback = async (server, port) => {
214
213
  return Result.err(new AuthError({
215
214
  code: ERROR_CODE.authInvalidCredentials,
216
215
  message: "Agent selection timed out.",
217
- suggestedCommand: "ogment auth login --browser",
216
+ recovery: { command: "ogment auth login --browser" },
218
217
  }));
219
218
  }
220
219
  return Result.err(new AuthError({
221
220
  code: ERROR_CODE.authInvalidCredentials,
222
221
  message: "Failed while waiting for agent callback.",
223
- suggestedCommand: "ogment auth login --browser",
222
+ recovery: { command: "ogment auth login --browser" },
224
223
  }));
225
224
  }
226
225
  finally {
@@ -229,7 +228,7 @@ const waitForAgentCallback = async (server, port) => {
229
228
  return Result.err(new AuthError({
230
229
  code: ERROR_CODE.authInvalidCredentials,
231
230
  message: "Agent selection timed out.",
232
- suggestedCommand: "ogment auth login --browser",
231
+ recovery: { command: "ogment auth login --browser" },
233
232
  }));
234
233
  };
235
234
  const deviceCodeUrl = (baseUrl) => `${baseUrl}/api/v1/mcp-auth/device/code`;
@@ -246,21 +245,11 @@ export const createAuthService = (deps) => {
246
245
  const createServerFn = deps.createServerFn ?? createServer;
247
246
  const detectEnvironment = deps.detectEnvironment ?? detectExecutionEnvironment;
248
247
  const hostnameFn = deps.hostnameFn ?? hostname;
249
- const retryConfig = remoteRetryConfig();
250
- const requestWithRetry = async (input, init) => {
251
- return Result.tryPromise({
252
- catch: (cause) => cause,
253
- try: async () => {
254
- const response = await deps.httpClient.request(input, init);
255
- if (Result.isError(response)) {
256
- throw response.error;
257
- }
258
- return response.value;
259
- },
260
- }, retryConfig);
248
+ const requestRemote = async (input, init) => {
249
+ return deps.httpClient.request(input, init);
261
250
  };
262
251
  const loginWithDevice = async (options) => {
263
- const startFlowResponse = await requestWithRetry(deviceCodeUrl(deps.baseUrl), {
252
+ const startFlowResponse = await requestRemote(deviceCodeUrl(deps.baseUrl), {
264
253
  headers: {
265
254
  "Content-Type": "application/json",
266
255
  },
@@ -273,14 +262,19 @@ export const createAuthService = (deps) => {
273
262
  const body = await readResponseText(startFlowResponse.value);
274
263
  return Result.err(new RemoteRequestError({
275
264
  body,
265
+ httpStatus: startFlowResponse.value.status,
276
266
  message: "Failed to start device login",
277
- status: startFlowResponse.value.status,
267
+ operation: "auth/device/start",
268
+ raw: body,
269
+ source: "http",
278
270
  }));
279
271
  }
280
272
  const startPayload = await Result.tryPromise({
281
273
  catch: () => new RemoteRequestError({
274
+ httpStatus: startFlowResponse.value.status,
282
275
  message: "Failed to parse device login start payload",
283
- status: startFlowResponse.value.status,
276
+ operation: "auth/device/start",
277
+ source: "http",
284
278
  }),
285
279
  try: async () => startFlowResponse.value.json(),
286
280
  });
@@ -299,7 +293,7 @@ export const createAuthService = (deps) => {
299
293
  const interval = parsedStartPayload.value.data.interval * 1000;
300
294
  while (now() < deadline) {
301
295
  await sleep(interval);
302
- const pollResponse = await requestWithRetry(deviceTokenUrl(deps.baseUrl), {
296
+ const pollResponse = await requestRemote(deviceTokenUrl(deps.baseUrl), {
303
297
  body: JSON.stringify({
304
298
  device_code: parsedStartPayload.value.data.device_code,
305
299
  }),
@@ -315,28 +309,33 @@ export const createAuthService = (deps) => {
315
309
  return Result.err(new AuthError({
316
310
  code: ERROR_CODE.authDeviceExpired,
317
311
  message: "Device login code expired. Run `ogment auth login` again.",
318
- suggestedCommand: "ogment auth login",
312
+ recovery: { command: "ogment auth login" },
319
313
  }));
320
314
  }
321
315
  if (pollResponse.value.status === 404) {
322
316
  return Result.err(new AuthError({
323
317
  code: ERROR_CODE.authInvalidCredentials,
324
318
  message: "Invalid device login code. Run `ogment auth login` again.",
325
- suggestedCommand: "ogment auth login",
319
+ recovery: { command: "ogment auth login" },
326
320
  }));
327
321
  }
328
322
  if (!pollResponse.value.ok) {
329
323
  const body = await readResponseText(pollResponse.value);
330
324
  return Result.err(new RemoteRequestError({
331
325
  body,
326
+ httpStatus: pollResponse.value.status,
332
327
  message: "Failed to poll device login status",
333
- status: pollResponse.value.status,
328
+ operation: "auth/device/poll",
329
+ raw: body,
330
+ source: "http",
334
331
  }));
335
332
  }
336
333
  const pollPayload = await Result.tryPromise({
337
334
  catch: () => new RemoteRequestError({
335
+ httpStatus: pollResponse.value.status,
338
336
  message: "Failed to parse device login poll payload",
339
- status: pollResponse.value.status,
337
+ operation: "auth/device/poll",
338
+ source: "http",
340
339
  }),
341
340
  try: async () => pollResponse.value.json(),
342
341
  });
@@ -359,13 +358,14 @@ export const createAuthService = (deps) => {
359
358
  }
360
359
  return Result.ok({
361
360
  agentName: approvedPayload.value.data.agent_name ?? "CLI Agent",
362
- alreadyLoggedIn: false,
361
+ loggedIn: true,
362
+ outcome: "authenticated",
363
363
  });
364
364
  }
365
365
  return Result.err(new AuthError({
366
366
  code: ERROR_CODE.authDeviceExpired,
367
367
  message: "Device login code expired. Run `ogment auth login` again.",
368
- suggestedCommand: "ogment auth login",
368
+ recovery: { command: "ogment auth login" },
369
369
  }));
370
370
  };
371
371
  const loginWithBrowser = async () => {
@@ -375,7 +375,7 @@ export const createAuthService = (deps) => {
375
375
  }
376
376
  const { port, server } = callbackServerResult.value;
377
377
  const redirectUri = `http://${CLI_REDIRECT_HOST}:${port}/callback`;
378
- const registerResponse = await requestWithRetry(oauthRegisterUrl(deps.baseUrl), {
378
+ const registerResponse = await requestRemote(oauthRegisterUrl(deps.baseUrl), {
379
379
  body: JSON.stringify({
380
380
  client_name: CLI_CLIENT_NAME,
381
381
  grant_types: ["authorization_code"],
@@ -397,14 +397,19 @@ export const createAuthService = (deps) => {
397
397
  await closeServer(server);
398
398
  return Result.err(new RemoteRequestError({
399
399
  body,
400
+ httpStatus: registerResponse.value.status,
400
401
  message: "Client registration failed",
401
- status: registerResponse.value.status,
402
+ operation: "auth/browser/register",
403
+ raw: body,
404
+ source: "http",
402
405
  }));
403
406
  }
404
407
  const registerPayload = await Result.tryPromise({
405
408
  catch: () => new RemoteRequestError({
409
+ httpStatus: registerResponse.value.status,
406
410
  message: "Failed to parse client registration payload",
407
- status: registerResponse.value.status,
411
+ operation: "auth/browser/register",
412
+ source: "http",
408
413
  }),
409
414
  try: async () => registerResponse.value.json(),
410
415
  });
@@ -447,7 +452,7 @@ export const createAuthService = (deps) => {
447
452
  return Result.err(new AuthError({
448
453
  code: ERROR_CODE.authInvalidCredentials,
449
454
  message: "OAuth state mismatch - possible CSRF attack.",
450
- suggestedCommand: "ogment auth login --browser",
455
+ recovery: { command: "ogment auth login --browser" },
451
456
  }));
452
457
  }
453
458
  const tokenBody = new URLSearchParams({
@@ -461,7 +466,7 @@ export const createAuthService = (deps) => {
461
466
  parsedClient.value.client_secret.length > 0) {
462
467
  tokenBody.set("client_secret", parsedClient.value.client_secret);
463
468
  }
464
- const tokenResponse = await requestWithRetry(oauthTokenUrl(deps.baseUrl), {
469
+ const tokenResponse = await requestRemote(oauthTokenUrl(deps.baseUrl), {
465
470
  body: tokenBody.toString(),
466
471
  headers: {
467
472
  "Content-Type": "application/x-www-form-urlencoded",
@@ -477,14 +482,19 @@ export const createAuthService = (deps) => {
477
482
  await closeServer(server);
478
483
  return Result.err(new RemoteRequestError({
479
484
  body,
485
+ httpStatus: tokenResponse.value.status,
480
486
  message: "Token exchange failed",
481
- status: tokenResponse.value.status,
487
+ operation: "auth/browser/token",
488
+ raw: body,
489
+ source: "http",
482
490
  }));
483
491
  }
484
492
  const tokenPayload = await Result.tryPromise({
485
493
  catch: () => new RemoteRequestError({
494
+ httpStatus: tokenResponse.value.status,
486
495
  message: "Failed to parse token payload",
487
- status: tokenResponse.value.status,
496
+ operation: "auth/browser/token",
497
+ source: "http",
488
498
  }),
489
499
  try: async () => tokenResponse.value.json(),
490
500
  });
@@ -518,7 +528,7 @@ export const createAuthService = (deps) => {
518
528
  if (Result.isError(parsedExchangeRequestPayload)) {
519
529
  return parsedExchangeRequestPayload;
520
530
  }
521
- const exchangeResponse = await requestWithRetry(cliExchangeUrl(deps.baseUrl), {
531
+ const exchangeResponse = await requestRemote(cliExchangeUrl(deps.baseUrl), {
522
532
  body: JSON.stringify(parsedExchangeRequestPayload.value),
523
533
  headers: {
524
534
  "Content-Type": "application/json",
@@ -542,36 +552,41 @@ export const createAuthService = (deps) => {
542
552
  return Result.err(new AuthError({
543
553
  code: ERROR_CODE.authDeviceExpired,
544
554
  message: "Browser login code expired. Run `ogment auth login --browser` again.",
545
- suggestedCommand: "ogment auth login --browser",
555
+ recovery: { command: "ogment auth login --browser" },
546
556
  }));
547
557
  }
548
558
  if (exchangeErrorCode === "invalid_exchange_code") {
549
559
  return Result.err(new AuthError({
550
560
  code: ERROR_CODE.authInvalidCredentials,
551
561
  message: "Invalid browser login code. Run `ogment auth login --browser` again.",
552
- suggestedCommand: "ogment auth login --browser",
562
+ recovery: { command: "ogment auth login --browser" },
553
563
  }));
554
564
  }
555
565
  if (exchangeErrorCode === "authorization_pending") {
556
566
  return Result.err(new AuthError({
557
567
  code: ERROR_CODE.authDevicePending,
558
568
  message: "Browser login authorization is still pending.",
569
+ recovery: { command: "ogment auth login --browser" },
559
570
  retryable: true,
560
- suggestedCommand: "ogment auth login --browser",
561
571
  }));
562
572
  }
563
573
  }
564
574
  }
565
575
  return Result.err(new RemoteRequestError({
566
576
  body,
577
+ httpStatus: exchangeResponse.value.status,
567
578
  message: "Failed to exchange browser login code",
568
- status: exchangeResponse.value.status,
579
+ operation: "auth/browser/exchange",
580
+ raw: body,
581
+ source: "http",
569
582
  }));
570
583
  }
571
584
  const exchangePayload = await Result.tryPromise({
572
585
  catch: () => new RemoteRequestError({
586
+ httpStatus: exchangeResponse.value.status,
573
587
  message: "Failed to parse browser exchange payload",
574
- status: exchangeResponse.value.status,
588
+ operation: "auth/browser/exchange",
589
+ source: "http",
575
590
  }),
576
591
  try: async () => exchangeResponse.value.json(),
577
592
  });
@@ -591,7 +606,8 @@ export const createAuthService = (deps) => {
591
606
  }
592
607
  return Result.ok({
593
608
  agentName: parsedExchangePayload.value.data.name,
594
- alreadyLoggedIn: false,
609
+ loggedIn: true,
610
+ outcome: "authenticated",
595
611
  });
596
612
  };
597
613
  return {
@@ -606,21 +622,22 @@ export const createAuthService = (deps) => {
606
622
  }
607
623
  return Result.ok({
608
624
  agentName: "CLI Agent",
609
- alreadyLoggedIn: false,
625
+ loggedIn: true,
626
+ outcome: "authenticated",
610
627
  });
611
628
  }
612
629
  if (options.mode === "apiKey") {
613
630
  return Result.err(new ValidationError({
614
631
  code: ERROR_CODE.validationInvalidInput,
615
632
  message: "Missing API key value. Provide a non-empty API key.",
616
- suggestedCommand: "ogment auth login --api-key <key>",
633
+ recovery: { command: "ogment auth login --api-key <key>" },
617
634
  }));
618
635
  }
619
636
  if (options.nonInteractive && options.mode === "browser") {
620
637
  return Result.err(new ValidationError({
621
638
  code: ERROR_CODE.validationInvalidInput,
622
639
  message: "Use `ogment auth login` in non-interactive mode.",
623
- suggestedCommand: "ogment auth login",
640
+ recovery: { command: "ogment auth login" },
624
641
  }));
625
642
  }
626
643
  const stored = deps.credentialsStore.load();
@@ -630,7 +647,8 @@ export const createAuthService = (deps) => {
630
647
  if (stored.value !== null) {
631
648
  return Result.ok({
632
649
  agentName: stored.value.agentName ?? "CLI Agent",
633
- alreadyLoggedIn: true,
650
+ loggedIn: true,
651
+ outcome: "already_authenticated",
634
652
  });
635
653
  }
636
654
  if (options.mode === "device") {
@@ -649,7 +667,7 @@ export const createAuthService = (deps) => {
649
667
  revoked: false,
650
668
  });
651
669
  }
652
- const revokeResult = await requestWithRetry(revokeUrl(deps.baseUrl), {
670
+ const revokeResult = await requestRemote(revokeUrl(deps.baseUrl), {
653
671
  headers: {
654
672
  Authorization: `Bearer ${stored.value.apiKey}`,
655
673
  },
@@ -682,7 +700,7 @@ export const createAuthService = (deps) => {
682
700
  return Result.err(new AuthError({
683
701
  code: ERROR_CODE.authRequired,
684
702
  message: "Not logged in. Run `ogment auth login` or set OGMENT_API_KEY.",
685
- suggestedCommand: "ogment auth login",
703
+ recovery: { command: "ogment auth login" },
686
704
  }));
687
705
  },
688
706
  status: async (overrideApiKey) => {
@@ -1 +1 @@
1
- {"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../src/services/info.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EACV,aAAa,EAGb,WAAW,EAEZ,MAAM,oBAAoB,CAAC;AAsB5B,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD;AAED,UAAU,eAAe;IACvB,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,4BAA4B,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5C,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAqFD,eAAO,MAAM,iBAAiB,GAAI,MAAM,eAAe,KAAG,WAgNzD,CAAC"}
1
+ {"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../src/services/info.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EACV,aAAa,EAGb,WAAW,EAEZ,MAAM,oBAAoB,CAAC;AAsB5B,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACxD;AAED,UAAU,eAAe;IACvB,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,4BAA4B,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5C,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAmGD,eAAO,MAAM,iBAAiB,GAAI,MAAM,eAAe,KAAG,WAwQzD,CAAC"}
@@ -68,6 +68,16 @@ const toSummary = (issues) => {
68
68
  status: issues.length > 0 ? "warning" : "ok",
69
69
  };
70
70
  };
71
+ const emptyAccountErrorDetails = () => {
72
+ return {
73
+ errorCode: null,
74
+ errorHttpStatus: null,
75
+ errorMcpCode: null,
76
+ errorRaw: null,
77
+ errorRetryable: null,
78
+ errorSource: null,
79
+ };
80
+ };
71
81
  export const createInfoService = (deps) => {
72
82
  const detectEnvironment = deps.detectExecutionEnvironmentFn ?? detectExecutionEnvironment;
73
83
  const existsSyncFn = deps.existsSyncFn ?? existsSync;
@@ -106,6 +116,7 @@ export const createInfoService = (deps) => {
106
116
  const collectAccount = async () => {
107
117
  if (selectedApiKey === null) {
108
118
  return {
119
+ ...emptyAccountErrorDetails(),
109
120
  errorType: null,
110
121
  latencyMs: null,
111
122
  message: "No API key available",
@@ -123,6 +134,7 @@ export const createInfoService = (deps) => {
123
134
  return organization.servers.map((server) => server.path);
124
135
  });
125
136
  return {
137
+ ...emptyAccountErrorDetails(),
126
138
  errorType: null,
127
139
  latencyMs: accountElapsedMs,
128
140
  message: null,
@@ -152,6 +164,56 @@ export const createInfoService = (deps) => {
152
164
  }
153
165
  }
154
166
  return {
167
+ ...("code" in accountResult.error
168
+ ? {
169
+ errorCode: String(accountResult.error.code),
170
+ }
171
+ : {
172
+ errorCode: null,
173
+ }),
174
+ ...("httpStatus" in accountResult.error
175
+ ? {
176
+ errorHttpStatus: typeof accountResult.error.httpStatus === "number"
177
+ ? accountResult.error.httpStatus
178
+ : null,
179
+ }
180
+ : {
181
+ errorHttpStatus: null,
182
+ }),
183
+ ...("mcpCode" in accountResult.error
184
+ ? {
185
+ errorMcpCode: typeof accountResult.error.mcpCode === "number"
186
+ ? accountResult.error.mcpCode
187
+ : null,
188
+ }
189
+ : {
190
+ errorMcpCode: null,
191
+ }),
192
+ ...("raw" in accountResult.error
193
+ ? {
194
+ errorRaw: accountResult.error.raw ?? null,
195
+ }
196
+ : {
197
+ errorRaw: null,
198
+ }),
199
+ ...("retryable" in accountResult.error
200
+ ? {
201
+ errorRetryable: typeof accountResult.error.retryable === "boolean"
202
+ ? accountResult.error.retryable
203
+ : null,
204
+ }
205
+ : {
206
+ errorRetryable: null,
207
+ }),
208
+ ...("source" in accountResult.error
209
+ ? {
210
+ errorSource: typeof accountResult.error.source === "string"
211
+ ? accountResult.error.source
212
+ : null,
213
+ }
214
+ : {
215
+ errorSource: null,
216
+ }),
155
217
  errorType: accountResult.error._tag,
156
218
  latencyMs: accountElapsedMs,
157
219
  message: accountResult.error.message,
@@ -0,0 +1,9 @@
1
+ import { RemoteRequestError } from "../shared/errors.js";
2
+ interface CreateRemoteRequestErrorOptions {
3
+ cause: unknown;
4
+ message: string;
5
+ operation: string;
6
+ }
7
+ export declare const createRemoteRequestErrorFromMcpCause: (options: CreateRemoteRequestErrorOptions) => RemoteRequestError;
8
+ export {};
9
+ //# sourceMappingURL=mcp-error-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-error-mapping.d.ts","sourceRoot":"","sources":["../../src/services/mcp-error-mapping.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAazD,UAAU,+BAA+B;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AA0ID,eAAO,MAAM,oCAAoC,GAC/C,SAAS,+BAA+B,KACvC,kBAaF,CAAC"}
@@ -0,0 +1,129 @@
1
+ import { StreamableHTTPError } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
2
+ import { McpError, isJSONRPCErrorResponse } from "@modelcontextprotocol/sdk/types.js";
3
+ import { RemoteRequestError } from "../shared/errors.js";
4
+ const toSerializable = (value) => {
5
+ if (value instanceof Error) {
6
+ return {
7
+ message: value.message,
8
+ name: value.name,
9
+ stack: value.stack,
10
+ };
11
+ }
12
+ try {
13
+ return structuredClone(value);
14
+ }
15
+ catch {
16
+ return String(value);
17
+ }
18
+ };
19
+ const toJsonRpcErrorPayload = (payload) => {
20
+ if (isJSONRPCErrorResponse(payload)) {
21
+ return {
22
+ code: payload.error.code,
23
+ data: payload.error.data,
24
+ raw: toSerializable(payload),
25
+ };
26
+ }
27
+ if (typeof payload !== "object" || payload === null || !Object.hasOwn(payload, "error")) {
28
+ return null;
29
+ }
30
+ const errorRecord = payload.error;
31
+ if (typeof errorRecord !== "object" || errorRecord === null) {
32
+ return null;
33
+ }
34
+ const asRecord = errorRecord;
35
+ const code = asRecord["code"];
36
+ if (typeof code !== "number") {
37
+ return null;
38
+ }
39
+ return {
40
+ code,
41
+ data: asRecord["data"],
42
+ raw: toSerializable(payload),
43
+ };
44
+ };
45
+ const extractStreamableBody = (message) => {
46
+ const marker = "Error POSTing to endpoint:";
47
+ const markerIndex = message.indexOf(marker);
48
+ if (markerIndex === -1) {
49
+ return undefined;
50
+ }
51
+ const body = message.slice(markerIndex + marker.length).trim();
52
+ return body.length > 0 ? body : undefined;
53
+ };
54
+ const mapStreamableHttpError = (error) => {
55
+ const body = extractStreamableBody(error.message);
56
+ const parsedBody = body === undefined
57
+ ? null
58
+ : (() => {
59
+ try {
60
+ return JSON.parse(body);
61
+ }
62
+ catch {
63
+ return null;
64
+ }
65
+ })();
66
+ const jsonRpcPayload = parsedBody === null ? null : toJsonRpcErrorPayload(parsedBody);
67
+ const httpStatus = typeof error.code === "number" && error.code >= 100 ? error.code : undefined;
68
+ const retryable = httpStatus === undefined
69
+ ? undefined
70
+ : httpStatus === 429 || httpStatus >= 500 || httpStatus === 408;
71
+ return {
72
+ ...(body === undefined ? {} : { body }),
73
+ ...(httpStatus === undefined ? {} : { httpStatus }),
74
+ ...(jsonRpcPayload === null ? {} : { mcpCode: jsonRpcPayload.code }),
75
+ ...(jsonRpcPayload === null ? {} : { mcpData: jsonRpcPayload.data }),
76
+ raw: jsonRpcPayload?.raw ?? toSerializable(parsedBody ?? error),
77
+ ...(retryable === undefined ? {} : { retryable }),
78
+ source: "mcp_transport_http",
79
+ };
80
+ };
81
+ const mapMcpError = (error) => {
82
+ return {
83
+ mcpCode: error.code,
84
+ mcpData: toSerializable(error.data),
85
+ raw: toSerializable({
86
+ code: error.code,
87
+ data: error.data,
88
+ message: error.message,
89
+ name: error.name,
90
+ }),
91
+ retryable: error.code === -32_001,
92
+ source: "mcp_jsonrpc",
93
+ };
94
+ };
95
+ const mapUnknownError = (cause) => {
96
+ if (cause instanceof Error) {
97
+ return {
98
+ raw: toSerializable(cause),
99
+ source: "network",
100
+ };
101
+ }
102
+ return {
103
+ raw: toSerializable(cause),
104
+ source: "unknown",
105
+ };
106
+ };
107
+ const mapCause = (cause) => {
108
+ if (cause instanceof StreamableHTTPError) {
109
+ return mapStreamableHttpError(cause);
110
+ }
111
+ if (cause instanceof McpError) {
112
+ return mapMcpError(cause);
113
+ }
114
+ return mapUnknownError(cause);
115
+ };
116
+ export const createRemoteRequestErrorFromMcpCause = (options) => {
117
+ const mapped = mapCause(options.cause);
118
+ return new RemoteRequestError({
119
+ ...(mapped.body === undefined ? {} : { body: mapped.body }),
120
+ ...(mapped.httpStatus === undefined ? {} : { httpStatus: mapped.httpStatus }),
121
+ ...(mapped.mcpCode === undefined ? {} : { mcpCode: mapped.mcpCode }),
122
+ ...(mapped.mcpData === undefined ? {} : { mcpData: mapped.mcpData }),
123
+ message: options.message,
124
+ operation: options.operation,
125
+ raw: mapped.raw,
126
+ ...(mapped.retryable === undefined ? {} : { retryable: mapped.retryable }),
127
+ source: mapped.source,
128
+ });
129
+ };
@@ -10,10 +10,16 @@ interface McpClientLike {
10
10
  callTool(params: {
11
11
  arguments: Record<string, unknown>;
12
12
  name: string;
13
+ }, resultSchema?: unknown, options?: {
14
+ timeout?: number;
13
15
  }): Promise<unknown>;
14
16
  close(): Promise<void>;
15
- connect(transport: unknown): Promise<void>;
16
- listTools(): Promise<{
17
+ connect(transport: unknown, options?: {
18
+ timeout?: number;
19
+ }): Promise<void>;
20
+ listTools(params?: unknown, options?: {
21
+ timeout?: number;
22
+ }): Promise<{
17
23
  tools: Array<Record<string, unknown>>;
18
24
  }>;
19
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/services/mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAEnG,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAG1D,OAAO,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI/E,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzE,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,QAAQ,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,SAAS,IAAI,OAAO,CAAC;QACnB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;KACvC,CAAC,CAAC;CACJ;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,aAAa,CAAC;IACnC,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,KAAK,6BAA6B,CAAC;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAEnE,MAAM,WAAW,UAAU;IACzB,QAAQ,CACN,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;IACxD,SAAS,CACP,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;CAC3D;AAkFD,eAAO,MAAM,gBAAgB,GAAI,MAAM,cAAc,KAAG,UAsHvD,CAAC"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/services/mcp.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AAEnG,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAI1D,OAAO,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG/E,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAMzE,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,aAAa;IACrB,QAAQ,CACN,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAC5D,YAAY,CAAC,EAAE,OAAO,EACtB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7B,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,SAAS,CACP,MAAM,CAAC,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7B,OAAO,CAAC;QACT,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;KACvC,CAAC,CAAC;CACJ;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,aAAa,CAAC;IACnC,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,KAAK,6BAA6B,CAAC;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAEnE,MAAM,WAAW,UAAU;IACzB,QAAQ,CACN,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;IACxD,SAAS,CACP,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;CAC3D;AAkFD,eAAO,MAAM,gBAAgB,GAAI,MAAM,cAAc,KAAG,UAkIvD,CAAC"}