@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
@@ -1,11 +1,12 @@
1
1
  import type { Result as ResultType } from "better-result";
2
2
  import type { McpServiceError } from "../services/mcp.js";
3
3
  import { NotFoundError, ValidationError } from "../shared/errors.js";
4
- import type { CatalogSummarySuccess, CatalogToolDetailsSuccess, CatalogToolsSuccess } from "../shared/types.js";
4
+ import type { CatalogServerFailure, CatalogSummarySuccess, CatalogToolDetailsSuccess, CatalogToolsSuccess } from "../shared/types.js";
5
5
  import type { CommandContext } from "./context.js";
6
6
  import { type ResolveServerStateError } from "./server-context.js";
7
7
  export interface CatalogCommandOptions {
8
8
  cursor?: string | undefined;
9
+ includeDebug?: boolean | undefined;
9
10
  limit?: number | undefined;
10
11
  serverId?: string | undefined;
11
12
  }
@@ -17,6 +18,7 @@ export interface CatalogToolDetailsCommandOptions {
17
18
  toolName: string;
18
19
  }
19
20
  export interface CatalogSummaryPage {
21
+ failures: CatalogServerFailure[];
20
22
  nextCursor: string | null;
21
23
  servers: CatalogSummarySuccess["servers"];
22
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/commands/catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAEV,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EAEpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AA0B7B,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC;CAC3C;AAED,MAAM,MAAM,mBAAmB,GAC3B,eAAe,GACf,aAAa,GACb,uBAAuB,GACvB,eAAe,CAAC;AAEpB,MAAM,MAAM,wBAAwB,GAAG,eAAe,GAAG,aAAa,GAAG,uBAAuB,CAAC;AAEjG,MAAM,MAAM,8BAA8B,GACtC,eAAe,GACf,aAAa,GACb,uBAAuB,CAAC;AAiD5B,eAAO,MAAM,iBAAiB,GAC5B,SAAS,cAAc,EACvB,SAAS,qBAAqB,KAC7B,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAqE7D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,SAAS,cAAc,EACvB,SAAS,0BAA0B,KAClC,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,wBAAwB,CAAC,CAoBnE,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,SAAS,cAAc,EACvB,SAAS,gCAAgC,KACxC,OAAO,CAAC,UAAU,CAAC,yBAAyB,EAAE,8BAA8B,CAAC,CAiC/E,CAAC"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/commands/catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EACV,oBAAoB,EAEpB,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EAEpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AA0B7B,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC;CAC3C;AAED,MAAM,MAAM,mBAAmB,GAC3B,eAAe,GACf,aAAa,GACb,uBAAuB,GACvB,eAAe,CAAC;AAEpB,MAAM,MAAM,wBAAwB,GAAG,eAAe,GAAG,aAAa,GAAG,uBAAuB,CAAC;AAEjG,MAAM,MAAM,8BAA8B,GACtC,eAAe,GACf,aAAa,GACb,uBAAuB,CAAC;AA+D5B,eAAO,MAAM,iBAAiB,GAC5B,SAAS,cAAc,EACvB,SAAS,qBAAqB,KAC7B,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAmF7D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,SAAS,cAAc,EACvB,SAAS,0BAA0B,KAClC,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,wBAAwB,CAAC,CAoBnE,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,SAAS,cAAc,EACvB,SAAS,gCAAgC,KACxC,OAAO,CAAC,UAAU,CAAC,yBAAyB,EAAE,8BAA8B,CAAC,CAiC/E,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { Result } from "better-result";
2
2
  import { ERROR_CODE } from "../shared/error-codes.js";
3
+ import { presentCatalogFailureError } from "../shared/error-presentation.js";
3
4
  import { NotFoundError, ValidationError } from "../shared/errors.js";
4
5
  import { findServerByPath, resolveServerState, } from "./server-context.js";
5
6
  const toServerSummary = (server, toolCount) => {
@@ -28,6 +29,15 @@ const listServerTools = async (context, apiKey, server) => {
28
29
  }, apiKey);
29
30
  };
30
31
  const TOOL_COUNT_CONCURRENCY = 4;
32
+ const toCatalogServerFailure = (server, error, includeDebug) => {
33
+ return {
34
+ error: presentCatalogFailureError(error, {
35
+ includeDebug,
36
+ }),
37
+ orgSlug: server.orgSlug,
38
+ serverId: server.path,
39
+ };
40
+ };
31
41
  const mapWithConcurrency = async (items, concurrency, mapItem) => {
32
42
  if (items.length === 0) {
33
43
  return [];
@@ -69,14 +79,20 @@ export const runCatalogCommand = async (context, options) => {
69
79
  };
70
80
  });
71
81
  const summaries = [];
82
+ const failures = [];
72
83
  for (const serverSummary of serverSummaries) {
73
84
  if (Result.isError(serverSummary.toolsResult)) {
74
- return serverSummary.toolsResult;
85
+ if (options.serverId !== undefined) {
86
+ return serverSummary.toolsResult;
87
+ }
88
+ failures.push(toCatalogServerFailure(serverSummary.server, serverSummary.toolsResult.error, options.includeDebug === true));
89
+ continue;
75
90
  }
76
91
  summaries.push(toServerSummary(serverSummary.server, serverSummary.toolsResult.value.length));
77
92
  }
78
93
  if (options.serverId !== undefined) {
79
94
  return Result.ok({
95
+ failures: [],
80
96
  nextCursor: null,
81
97
  servers: summaries,
82
98
  });
@@ -89,7 +105,7 @@ export const runCatalogCommand = async (context, options) => {
89
105
  return Result.err(new ValidationError({
90
106
  code: ERROR_CODE.validationInvalidInput,
91
107
  message: `Invalid --cursor value: "${options.cursor}"`,
92
- suggestedCommand: "ogment catalog",
108
+ recovery: { command: "ogment catalog" },
93
109
  }));
94
110
  }
95
111
  startIndex = cursorIndex + 1;
@@ -98,6 +114,7 @@ export const runCatalogCommand = async (context, options) => {
98
114
  const hasMore = startIndex + limit < summaries.length;
99
115
  const nextCursor = hasMore ? (servers.at(-1)?.serverId ?? null) : null;
100
116
  return Result.ok({
117
+ failures,
101
118
  nextCursor,
102
119
  servers,
103
120
  });
@@ -1 +1 @@
1
- {"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/commands/invoke.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,iBAAiB;IACzB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;CAChE;AAED,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,aAAa,GACb,uBAAuB,GACvB,eAAe,GACf,eAAe,CAAC;AAgIpB,eAAO,MAAM,gBAAgB,GAC3B,SAAS,cAAc,EACvB,SAAS,oBAAoB,EAC7B,OAAM,iBAAsB,KAC3B,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAwCvD,CAAC"}
1
+ {"version":3,"file":"invoke.d.ts","sourceRoot":"","sources":["../../src/commands/invoke.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EACL,aAAa,EAEb,eAAe,EACf,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,iBAAiB;IACzB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;CAChE;AAED,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,aAAa,GACb,uBAAuB,GACvB,eAAe,GACf,eAAe,CAAC;AAmKpB,eAAO,MAAM,gBAAgB,GAC3B,SAAS,cAAc,EACvB,SAAS,oBAAoB,EAC7B,OAAM,iBAAsB,KAC3B,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,kBAAkB,CAAC,CA0EvD,CAAC"}
@@ -1,7 +1,32 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { Result } from "better-result";
3
- import { NotFoundError, UnexpectedError, ValidationError } from "../shared/errors.js";
3
+ import { NotFoundError, RemoteRequestError, UnexpectedError, ValidationError, } from "../shared/errors.js";
4
4
  import { findServerByPath, resolveServerState, } from "./server-context.js";
5
+ const parseToolErrorDetails = (payload) => {
6
+ if (typeof payload !== "object" || payload === null) {
7
+ return {};
8
+ }
9
+ const record = payload;
10
+ const directCode = record["code"];
11
+ const directMessage = record["message"];
12
+ if (typeof directCode === "number" || typeof directMessage === "string") {
13
+ return {
14
+ ...(typeof directCode === "number" ? { mcpCode: directCode } : {}),
15
+ ...(typeof directMessage === "string" ? { message: directMessage } : {}),
16
+ ...(Object.hasOwn(record, "data") ? { mcpData: record["data"] } : {}),
17
+ };
18
+ }
19
+ const nestedError = record["error"];
20
+ if (typeof nestedError !== "object" || nestedError === null) {
21
+ return {};
22
+ }
23
+ const nestedRecord = nestedError;
24
+ return {
25
+ ...(typeof nestedRecord["code"] === "number" ? { mcpCode: nestedRecord["code"] } : {}),
26
+ ...(typeof nestedRecord["message"] === "string" ? { message: nestedRecord["message"] } : {}),
27
+ ...(Object.hasOwn(nestedRecord, "data") ? { mcpData: nestedRecord["data"] } : {}),
28
+ };
29
+ };
5
30
  const parseTarget = (target) => {
6
31
  const separatorIndex = target.lastIndexOf("/");
7
32
  if (separatorIndex <= 0 || separatorIndex >= target.length - 1) {
@@ -108,13 +133,38 @@ export const runInvokeCommand = async (context, options, deps = {}) => {
108
133
  if (Result.isError(serverResult)) {
109
134
  return serverResult;
110
135
  }
111
- const callResult = await context.services.mcp.callTool({
136
+ const mcpTarget = {
112
137
  orgSlug: serverResult.value.orgSlug,
113
138
  serverPath: serverResult.value.path,
114
- }, stateResult.value.apiKey, targetResult.value.toolName, argsResult.value);
139
+ };
140
+ const callResult = await context.services.mcp.callTool(mcpTarget, stateResult.value.apiKey, targetResult.value.toolName, argsResult.value);
115
141
  if (Result.isError(callResult)) {
142
+ if (callResult.error._tag === "RemoteRequestError") {
143
+ const toolsResult = await context.services.mcp.listTools(mcpTarget, stateResult.value.apiKey);
144
+ if (Result.isOk(toolsResult)) {
145
+ const toolExists = toolsResult.value.some((tool) => tool.name === targetResult.value.toolName);
146
+ if (!toolExists) {
147
+ return Result.err(new NotFoundError({
148
+ message: `Tool "${targetResult.value.toolName}" not found`,
149
+ resource: targetResult.value.toolName,
150
+ }));
151
+ }
152
+ }
153
+ }
116
154
  return callResult;
117
155
  }
156
+ if (callResult.value.isError) {
157
+ const details = parseToolErrorDetails(callResult.value.structuredContent);
158
+ return Result.err(new RemoteRequestError({
159
+ ...(details.mcpCode === undefined ? {} : { mcpCode: details.mcpCode }),
160
+ ...(details.mcpData === undefined ? {} : { mcpData: details.mcpData }),
161
+ message: details.message ?? "MCP tool call returned an error result",
162
+ operation: "tools/call",
163
+ raw: callResult.value.structuredContent,
164
+ retryable: false,
165
+ source: "mcp_jsonrpc",
166
+ }));
167
+ }
118
168
  return Result.ok({
119
169
  result: callResult.value.structuredContent,
120
170
  serverId: targetResult.value.serverId,
@@ -1,9 +1,13 @@
1
1
  import { Result } from "better-result";
2
2
  import { RemoteRequestError } from "../shared/errors.js";
3
3
  export interface HttpClient {
4
- request(input: RequestInfo | URL, init?: RequestInit): Promise<Result<Response, RemoteRequestError>>;
4
+ request(input: RequestInfo | URL, init?: RequestInit, options?: {
5
+ operation?: string;
6
+ timeoutMs?: number;
7
+ }): Promise<Result<Response, RemoteRequestError>>;
5
8
  }
6
9
  interface HttpClientDeps {
10
+ defaultTimeoutMs?: number;
7
11
  fetchFn?: typeof fetch;
8
12
  }
9
13
  export declare const createHttpClient: (deps?: HttpClientDeps) => HttpClient;
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/infra/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,UAAU;IACzB,OAAO,CACL,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC;CAClD;AAED,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAM,cAAmB,KAAG,UAe5D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,UAAU,QAAQ,KAAG,OAAO,CAAC,MAAM,CAWzE,CAAC"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/infra/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAIzD,MAAM,WAAW,UAAU;IACzB,OAAO,CACL,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GACA,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC;CAClD;AAED,UAAU,cAAc;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAcD,eAAO,MAAM,gBAAgB,GAAI,OAAM,cAAmB,KAAG,UAoE5D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,UAAU,QAAQ,KAAG,OAAO,CAAC,MAAM,CAWzE,CAAC"}
@@ -1,15 +1,72 @@
1
1
  import { Result } from "better-result";
2
2
  import { RemoteRequestError } from "../shared/errors.js";
3
+ const DEFAULT_HTTP_TIMEOUT_MS = 10_000;
4
+ const isAbortError = (cause) => {
5
+ if (cause instanceof DOMException) {
6
+ return cause.name === "AbortError" || cause.name === "TimeoutError";
7
+ }
8
+ if (cause instanceof Error) {
9
+ return cause.name === "AbortError" || cause.name === "TimeoutError";
10
+ }
11
+ return false;
12
+ };
3
13
  export const createHttpClient = (deps = {}) => {
14
+ const defaultTimeoutMs = deps.defaultTimeoutMs ?? DEFAULT_HTTP_TIMEOUT_MS;
4
15
  const fetchFn = deps.fetchFn ?? fetch;
5
16
  return {
6
- request: async (input, init) => {
7
- return Result.tryPromise({
17
+ request: async (input, init, options) => {
18
+ const abortController = new AbortController();
19
+ const timeoutMs = options?.timeoutMs ?? defaultTimeoutMs;
20
+ const cleanupCallbacks = [];
21
+ const abortWithReason = (reason) => {
22
+ if (!abortController.signal.aborted) {
23
+ abortController.abort(reason);
24
+ }
25
+ };
26
+ const upstreamSignal = init?.signal ?? undefined;
27
+ if (upstreamSignal !== undefined) {
28
+ if (upstreamSignal.aborted) {
29
+ abortWithReason(upstreamSignal.reason);
30
+ }
31
+ else {
32
+ const onAbort = () => {
33
+ abortWithReason(upstreamSignal.reason);
34
+ };
35
+ upstreamSignal.addEventListener("abort", onAbort);
36
+ cleanupCallbacks.push(() => {
37
+ upstreamSignal.removeEventListener("abort", onAbort);
38
+ });
39
+ }
40
+ }
41
+ const timeoutId = setTimeout(() => {
42
+ abortWithReason(new DOMException("HTTP request timed out", "TimeoutError"));
43
+ }, timeoutMs);
44
+ cleanupCallbacks.push(() => {
45
+ clearTimeout(timeoutId);
46
+ });
47
+ const requestPromise = Result.tryPromise({
8
48
  catch: (cause) => new RemoteRequestError({
9
- body: JSON.stringify({ cause }),
10
- message: "HTTP request failed",
49
+ message: isAbortError(cause) ? "HTTP request timed out" : "HTTP request failed",
50
+ ...(options?.operation === undefined ? {} : { operation: options.operation }),
51
+ raw: cause instanceof Error
52
+ ? {
53
+ message: cause.message,
54
+ name: cause.name,
55
+ stack: cause.stack,
56
+ }
57
+ : cause,
58
+ retryable: isAbortError(cause),
59
+ source: "network",
11
60
  }),
12
- try: async () => fetchFn(input, init),
61
+ try: async () => fetchFn(input, {
62
+ ...init,
63
+ signal: abortController.signal,
64
+ }),
65
+ });
66
+ return requestPromise.finally(() => {
67
+ for (const cleanup of cleanupCallbacks) {
68
+ cleanup();
69
+ }
13
70
  });
14
71
  },
15
72
  };
@@ -1,10 +1,12 @@
1
1
  import type { AppError } from "../shared/errors.js";
2
- import { type CliErrorEnvelope, type CliNextAction, type CliPaginationMeta, type CliSuccessEnvelope } from "../shared/types.js";
2
+ import type { CliErrorEnvelope, CliNextAction, CliParseErrorPayload, CliPaginationMeta, CliSuccessEnvelope } from "../shared/types.js";
3
3
  export interface EnvelopeContext {
4
4
  command: string;
5
+ diagnostics?: Record<string, unknown>;
5
6
  entity?: Record<string, unknown> | null;
7
+ includeDebug?: boolean;
6
8
  nextActions?: CliNextAction[];
7
- pagination?: CliPaginationMeta | null;
9
+ pagination?: CliPaginationMeta;
8
10
  }
9
11
  interface EnvelopeBuilderDeps {
10
12
  createRequestId?: () => string;
@@ -12,6 +14,7 @@ interface EnvelopeBuilderDeps {
12
14
  }
13
15
  export interface EnvelopeBuilder {
14
16
  error: (error: AppError, context: EnvelopeContext) => CliErrorEnvelope;
17
+ parseError: (payload: CliParseErrorPayload, context: EnvelopeContext) => CliErrorEnvelope;
15
18
  success: <T>(data: T, context: EnvelopeContext) => CliSuccessEnvelope<T>;
16
19
  }
17
20
  export declare const createEnvelopeBuilder: (deps?: EnvelopeBuilderDeps) => EnvelopeBuilder;
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/output/envelope.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,aAAa,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACvC;AAED,UAAU,mBAAmB;IAC3B,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,KAAK,gBAAgB,CAAC;IACvE,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,KAAK,kBAAkB,CAAC,CAAC,CAAC,CAAC;CAC1E;AAED,eAAO,MAAM,qBAAqB,GAAI,OAAM,mBAAwB,KAAG,eAkDtE,CAAC"}
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/output/envelope.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,aAAa,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED,UAAU,mBAAmB;IAC3B,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,KAAK,gBAAgB,CAAC;IACvE,UAAU,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,eAAe,KAAK,gBAAgB,CAAC;IAC1F,OAAO,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,KAAK,kBAAkB,CAAC,CAAC,CAAC,CAAC;CAC1E;AAED,eAAO,MAAM,qBAAqB,GAAI,OAAM,mBAAwB,KAAG,eAqEtE,CAAC"}
@@ -1,40 +1,57 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { appErrorMeta, formatAppError } from "../shared/errors.js";
3
- import { CLI_CONTRACT_VERSION, } from "../shared/types.js";
2
+ import { presentRuntimeErrorPayload } from "../shared/error-presentation.js";
4
3
  export const createEnvelopeBuilder = (deps = {}) => {
5
4
  const createRequestId = deps.createRequestId ?? randomUUID;
6
5
  const now = deps.now ?? (() => new Date());
7
6
  const toMeta = (context) => {
8
- return {
7
+ const base = {
9
8
  command: context.command,
10
- entity: context.entity ?? null,
11
- pagination: context.pagination ?? null,
12
- requestId: createRequestId(),
13
- timestamp: now().toISOString(),
9
+ };
10
+ if (context.pagination !== undefined) {
11
+ return {
12
+ ...base,
13
+ pagination: context.pagination,
14
+ ...(context.includeDebug === true
15
+ ? {
16
+ entity: context.entity ?? null,
17
+ requestId: createRequestId(),
18
+ timestamp: now().toISOString(),
19
+ }
20
+ : {}),
21
+ };
22
+ }
23
+ return {
24
+ ...base,
25
+ ...(context.includeDebug === true
26
+ ? {
27
+ entity: context.entity ?? null,
28
+ requestId: createRequestId(),
29
+ timestamp: now().toISOString(),
30
+ }
31
+ : {}),
14
32
  };
15
33
  };
16
34
  return {
17
35
  error: (error, context) => {
18
- const meta = appErrorMeta(error);
36
+ const payload = presentRuntimeErrorPayload(error, {
37
+ ...(context.diagnostics === undefined ? {} : { contextDiagnostics: context.diagnostics }),
38
+ includeDebug: context.includeDebug === true,
39
+ });
40
+ return {
41
+ data: null,
42
+ error: payload,
43
+ meta: toMeta(context),
44
+ next_actions: context.nextActions ?? [],
45
+ ok: false,
46
+ };
47
+ },
48
+ parseError: (payload, context) => {
19
49
  return {
20
50
  data: null,
21
- error: {
22
- category: meta.category,
23
- code: meta.code,
24
- detail: formatAppError(error),
25
- diagnostics: {
26
- tag: error._tag,
27
- },
28
- docsUrl: null,
29
- retryAfterMs: null,
30
- retryable: meta.retryable,
31
- suggestedCommand: meta.suggestedCommand ?? null,
32
- title: error.message,
33
- },
51
+ error: payload,
34
52
  meta: toMeta(context),
35
53
  next_actions: context.nextActions ?? [],
36
54
  ok: false,
37
- version: CLI_CONTRACT_VERSION,
38
55
  };
39
56
  },
40
57
  success: (data, context) => {
@@ -44,7 +61,6 @@ export const createEnvelopeBuilder = (deps = {}) => {
44
61
  meta: toMeta(context),
45
62
  next_actions: context.nextActions ?? [],
46
63
  ok: true,
47
- version: CLI_CONTRACT_VERSION,
48
64
  };
49
65
  },
50
66
  };
@@ -1,7 +1,8 @@
1
- import type { AppError } from "../shared/errors.js";
2
- import type { CliErrorEnvelope, CliNextAction, CliPaginationMeta } from "../shared/types.js";
1
+ import { type AppError } from "../shared/errors.js";
2
+ import type { CliErrorEnvelope, CliNextAction, CliPaginationMeta, CliParseErrorPayload } from "../shared/types.js";
3
3
  export type OutputMode = "human" | "json" | "quiet";
4
4
  export interface OutputInitOptions {
5
+ debug?: boolean | undefined;
5
6
  human: boolean | undefined;
6
7
  json?: boolean | undefined;
7
8
  nonInteractive: boolean | undefined;
@@ -21,9 +22,10 @@ interface OutputManagerDeps {
21
22
  }
22
23
  interface EnvelopeOptions {
23
24
  command: string;
25
+ diagnostics?: Record<string, unknown>;
24
26
  entity?: Record<string, unknown> | null;
25
27
  nextActions?: CliNextAction[];
26
- pagination?: CliPaginationMeta | null;
28
+ pagination?: CliPaginationMeta;
27
29
  }
28
30
  interface SuccessOptions extends EnvelopeOptions {
29
31
  humanMessage?: string;
@@ -34,10 +36,14 @@ export declare class OutputManager {
34
36
  configure(options: OutputInitOptions): void;
35
37
  get mode(): OutputMode;
36
38
  get nonInteractive(): boolean;
39
+ get debug(): boolean;
37
40
  error(error: AppError, options: EnvelopeOptions): CliErrorEnvelope;
41
+ parseError(payload: CliParseErrorPayload, options: EnvelopeOptions): CliErrorEnvelope;
38
42
  info(message: string): void;
39
43
  json(value: unknown): void;
40
44
  success<T>(data: T, options: SuccessOptions): void;
45
+ writeStdout(chunk: string): void;
46
+ writeStderr(chunk: string): void;
41
47
  }
42
48
  export {};
43
49
  //# sourceMappingURL=manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/output/manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG7F,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,GAAG,EAAE,OAAO,GAAG,SAAS,CAAC;CAC1B;AAED,UAAU,YAAY;IACpB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED,UAAU,iBAAiB;IACzB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,aAAa,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACvC;AAED,UAAU,cAAe,SAAQ,eAAe;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,qBAAa,aAAa;;gBAQL,IAAI,GAAE,iBAAsB;IAWxC,SAAS,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAalD,IAAW,IAAI,IAAI,UAAU,CAE5B;IAED,IAAW,cAAc,IAAI,OAAO,CAEnC;IAEM,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,GAAG,gBAAgB;IAgBlE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ3B,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI1B,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI;CAmB1D"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/output/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,GAAG,EAAE,OAAO,GAAG,SAAS,CAAC;CAC1B;AAED,UAAU,YAAY;IACpB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED,UAAU,iBAAiB;IACzB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,aAAa,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED,UAAU,cAAe,SAAQ,eAAe;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA6BD,qBAAa,aAAa;;gBASL,IAAI,GAAE,iBAAsB;IAWxC,SAAS,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAclD,IAAW,IAAI,IAAI,UAAU,CAE5B;IAED,IAAW,cAAc,IAAI,OAAO,CAEnC;IAED,IAAW,KAAK,IAAI,OAAO,CAE1B;IAEM,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,GAAG,gBAAgB;IAoBlE,UAAU,CAAC,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,eAAe,GAAG,gBAAgB;IAmBrF,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ3B,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI1B,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI;IAuBlD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIhC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAGxC"}
@@ -1,11 +1,30 @@
1
+ import { appErrorMeta } from "../shared/errors.js";
1
2
  import { createEnvelopeBuilder } from "./envelope.js";
2
3
  const toJson = (value) => {
3
4
  return `${JSON.stringify(value, null, 2)}\n`;
4
5
  };
6
+ const mergeNextActions = (recovery, contextActions) => {
7
+ const merged = [
8
+ ...(recovery === undefined || recovery === null ? [] : [recovery]),
9
+ ...(contextActions ?? []),
10
+ ];
11
+ const deduped = [];
12
+ const seen = new Set();
13
+ for (const action of merged) {
14
+ const key = `${action.id}::${action.command}`;
15
+ if (seen.has(key)) {
16
+ continue;
17
+ }
18
+ seen.add(key);
19
+ deduped.push(action);
20
+ }
21
+ return deduped;
22
+ };
5
23
  export class OutputManager {
6
24
  #envelopeBuilder;
7
25
  #isTty;
8
26
  #mode;
27
+ #debug = false;
9
28
  #nonInteractive = false;
10
29
  #stderr;
11
30
  #stdout;
@@ -31,6 +50,7 @@ export class OutputManager {
31
50
  }
32
51
  this.#nonInteractive =
33
52
  options.nonInteractive === true || options.yes === true || this.#isTty === false;
53
+ this.#debug = options.debug === true;
34
54
  }
35
55
  get mode() {
36
56
  return this.#mode;
@@ -38,8 +58,30 @@ export class OutputManager {
38
58
  get nonInteractive() {
39
59
  return this.#nonInteractive;
40
60
  }
61
+ get debug() {
62
+ return this.#debug;
63
+ }
41
64
  error(error, options) {
42
- const envelope = this.#envelopeBuilder.error(error, options);
65
+ const envelope = this.#envelopeBuilder.error(error, {
66
+ ...options,
67
+ includeDebug: this.#debug,
68
+ nextActions: mergeNextActions(appErrorMeta(error).recovery, options.nextActions),
69
+ });
70
+ if (this.#mode === "json") {
71
+ this.#stdout.write(toJson(envelope));
72
+ return envelope;
73
+ }
74
+ if (this.#mode === "quiet") {
75
+ return envelope;
76
+ }
77
+ this.#stderr.write(`${envelope.error.code}: ${envelope.error.detail}\n`);
78
+ return envelope;
79
+ }
80
+ parseError(payload, options) {
81
+ const envelope = this.#envelopeBuilder.parseError(payload, {
82
+ ...options,
83
+ includeDebug: this.#debug,
84
+ });
43
85
  if (this.#mode === "json") {
44
86
  this.#stdout.write(toJson(envelope));
45
87
  return envelope;
@@ -60,7 +102,10 @@ export class OutputManager {
60
102
  this.#stdout.write(toJson(value));
61
103
  }
62
104
  success(data, options) {
63
- const envelope = this.#envelopeBuilder.success(data, options);
105
+ const envelope = this.#envelopeBuilder.success(data, {
106
+ ...options,
107
+ includeDebug: this.#debug,
108
+ });
64
109
  if (this.#mode === "json") {
65
110
  this.#stdout.write(toJson(envelope));
66
111
  return;
@@ -74,4 +119,10 @@ export class OutputManager {
74
119
  }
75
120
  this.#stdout.write(toJson(data));
76
121
  }
122
+ writeStdout(chunk) {
123
+ this.#stdout.write(chunk);
124
+ }
125
+ writeStderr(chunk) {
126
+ this.#stderr.write(chunk);
127
+ }
77
128
  }
@@ -1 +1 @@
1
- {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/services/account.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI1F,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExE,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAEjF,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACrF,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;CACtF;AAED,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;CACxB;AAQD,eAAO,MAAM,oBAAoB,GAAI,MAAM,kBAAkB,KAAG,cA8F/D,CAAC"}
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/services/account.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG1F,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExE,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAEjF,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACrF,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;CACtF;AAED,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;CACxB;AAQD,eAAO,MAAM,oBAAoB,GAAI,MAAM,kBAAkB,KAAG,cAoF/D,CAAC"}
@@ -3,7 +3,6 @@ import { readResponseText } from "../infra/http.js";
3
3
  import { ERROR_CODE } from "../shared/error-codes.js";
4
4
  import { AuthError, RemoteRequestError } from "../shared/errors.js";
5
5
  import { parseWithSchema } from "../shared/guards.js";
6
- import { remoteRetryConfig } from "../shared/retry.js";
7
6
  import { accountMeSchema } from "../shared/schemas.js";
8
7
  const authHeader = (apiKey) => {
9
8
  return {
@@ -23,20 +22,25 @@ export const createAccountService = (deps) => {
23
22
  return Result.err(new AuthError({
24
23
  code: ERROR_CODE.authInvalidCredentials,
25
24
  message: "Authentication failed. Run `ogment auth login` again.",
26
- suggestedCommand: "ogment auth login",
25
+ recovery: { command: "ogment auth login" },
27
26
  }));
28
27
  }
29
28
  const body = await readResponseText(responseResult.value);
30
29
  return Result.err(new RemoteRequestError({
31
30
  body,
31
+ httpStatus: responseResult.value.status,
32
32
  message: "Failed to fetch account details",
33
- status: responseResult.value.status,
33
+ operation: "account/fetch",
34
+ raw: body,
35
+ source: "http",
34
36
  }));
35
37
  }
36
38
  const jsonResult = await Result.tryPromise({
37
39
  catch: () => new RemoteRequestError({
40
+ httpStatus: responseResult.value.status,
38
41
  message: "Failed to parse account response JSON",
39
- status: responseResult.value.status,
42
+ operation: "account/fetch",
43
+ source: "http",
40
44
  }),
41
45
  try: async () => responseResult.value.json(),
42
46
  });
@@ -49,18 +53,7 @@ export const createAccountService = (deps) => {
49
53
  }
50
54
  return Result.ok(parsed.value.data);
51
55
  };
52
- const fetchAccount = async (apiKey) => {
53
- return Result.tryPromise({
54
- catch: (cause) => cause,
55
- try: async () => {
56
- const result = await fetchAccountOnce(apiKey);
57
- if (Result.isError(result)) {
58
- throw result.error;
59
- }
60
- return result.value;
61
- },
62
- }, remoteRetryConfig());
63
- };
56
+ const fetchAccount = async (apiKey) => fetchAccountOnce(apiKey);
64
57
  return {
65
58
  fetchAccount,
66
59
  listServers: async (apiKey) => {
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAMzC,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAa7B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEzF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,gBAAgB;IACxB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,kBAAmB,SAAQ,gBAAgB;IACnD,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC9C;AAED,UAAU,mBAAoB,SAAQ,gBAAgB;IACpD,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,UAAU,kBAAmB,SAAQ,gBAAgB;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,kBAAkB,GAAG,mBAAmB,GAAG,kBAAkB,CAAC;AAEzF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,kBAAkB,GAAG,eAAe,GAAG,eAAe,CAAC;AAE5F,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,eAAe,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC,CAAC;IAC9D,aAAa,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACxF,MAAM,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,CAAC;CAC1F;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,CAAC,EAAE,OAAO,YAAY,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;IAC1B,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAgTD,eAAO,MAAM,iBAAiB,GAAI,MAAM,eAAe,KAAG,WAioBzD,CAAC"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAMzC,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAY7B,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEzF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,gBAAgB;IACxB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,kBAAmB,SAAQ,gBAAgB;IACnD,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC9C;AAED,UAAU,mBAAoB,SAAQ,gBAAgB;IACpD,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,UAAU,kBAAmB,SAAQ,gBAAgB;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,MAAM,MAAM,YAAY,GAAG,kBAAkB,GAAG,mBAAmB,GAAG,kBAAkB,CAAC;AAEzF,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,kBAAkB,GAAG,eAAe,GAAG,eAAe,CAAC;AAE5F,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,eAAe,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC,CAAC;IAC9D,aAAa,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;IACxF,MAAM,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,CAAC;CAC1F;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,CAAC,EAAE,OAAO,YAAY,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;IAC1B,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAgTD,eAAO,MAAM,iBAAiB,GAAI,MAAM,eAAe,KAAG,WAgpBzD,CAAC"}