@ogment-ai/cli 0.4.2 → 0.6.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.
- package/README.md +0 -9
- package/dist/cli/commands.d.ts +37 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +56 -0
- package/dist/cli/execute.d.ts +11 -0
- package/dist/cli/execute.d.ts.map +1 -0
- package/dist/cli/execute.js +468 -0
- package/dist/cli/invocations.d.ts +31 -0
- package/dist/cli/invocations.d.ts.map +1 -0
- package/dist/cli/invocations.js +1 -0
- package/dist/cli/parse-errors.d.ts +17 -0
- package/dist/cli/parse-errors.d.ts.map +1 -0
- package/dist/cli/parse-errors.js +184 -0
- package/dist/cli/program.d.ts +10 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +174 -0
- package/dist/cli/run.d.ts +6 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +83 -0
- package/dist/cli/runtime.d.ts +21 -0
- package/dist/cli/runtime.d.ts.map +1 -0
- package/dist/cli/runtime.js +80 -0
- package/dist/cli.d.ts +2 -20
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -737
- package/dist/commands/auth.d.ts +1 -4
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +0 -8
- package/dist/commands/catalog.d.ts +3 -1
- package/dist/commands/catalog.d.ts.map +1 -1
- package/dist/commands/catalog.js +19 -2
- package/dist/commands/invoke.d.ts.map +1 -1
- package/dist/commands/invoke.js +53 -3
- package/dist/infra/credentials.d.ts.map +1 -1
- package/dist/infra/credentials.js +0 -7
- package/dist/infra/http.d.ts +5 -1
- package/dist/infra/http.d.ts.map +1 -1
- package/dist/infra/http.js +62 -5
- package/dist/output/envelope.d.ts +5 -2
- package/dist/output/envelope.d.ts.map +1 -1
- package/dist/output/envelope.js +39 -23
- package/dist/output/manager.d.ts +9 -5
- package/dist/output/manager.d.ts.map +1 -1
- package/dist/output/manager.js +52 -9
- package/dist/services/account.d.ts.map +1 -1
- package/dist/services/account.js +9 -16
- package/dist/services/auth.d.ts +3 -15
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +32 -483
- package/dist/services/info.d.ts.map +1 -1
- package/dist/services/info.js +62 -0
- package/dist/services/mcp-error-mapping.d.ts +9 -0
- package/dist/services/mcp-error-mapping.d.ts.map +1 -0
- package/dist/services/mcp-error-mapping.js +129 -0
- package/dist/services/mcp.d.ts +8 -2
- package/dist/services/mcp.d.ts.map +1 -1
- package/dist/services/mcp.js +24 -14
- package/dist/shared/constants.d.ts +0 -2
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +0 -2
- package/dist/shared/error-codes.d.ts +4 -1
- package/dist/shared/error-codes.d.ts.map +1 -1
- package/dist/shared/error-presentation.d.ts +17 -0
- package/dist/shared/error-presentation.d.ts.map +1 -0
- package/dist/shared/error-presentation.js +151 -0
- package/dist/shared/errors.d.ts +34 -14
- package/dist/shared/errors.d.ts.map +1 -1
- package/dist/shared/errors.js +126 -25
- package/dist/shared/guards.d.ts +2 -1
- package/dist/shared/guards.d.ts.map +1 -1
- package/dist/shared/guards.js +1 -3
- package/dist/shared/recovery.d.ts +5 -0
- package/dist/shared/recovery.d.ts.map +1 -0
- package/dist/shared/recovery.js +123 -0
- package/dist/shared/schemas.d.ts +2 -3
- package/dist/shared/schemas.d.ts.map +1 -1
- package/dist/shared/schemas.js +2 -3
- package/dist/shared/types.d.ts +53 -13
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +1 -1
- package/package.json +2 -4
- package/dist/infra/browser.d.ts +0 -12
- package/dist/infra/browser.d.ts.map +0 -1
- package/dist/infra/browser.js +0 -20
- package/dist/shared/retry.d.ts +0 -17
- package/dist/shared/retry.d.ts.map +0 -1
- package/dist/shared/retry.js +0 -27
package/dist/services/info.js
CHANGED
|
@@ -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
|
+
};
|
package/dist/services/mcp.d.ts
CHANGED
|
@@ -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
|
|
16
|
-
|
|
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;
|
|
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"}
|
package/dist/services/mcp.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { Client } from "@modelcontextprotocol/sdk/client";
|
|
2
2
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
3
3
|
import { Result } from "better-result";
|
|
4
|
+
import { createRemoteRequestErrorFromMcpCause } from "./mcp-error-mapping.js";
|
|
4
5
|
import { ERROR_CODE } from "../shared/error-codes.js";
|
|
5
6
|
import { RemoteRequestError } from "../shared/errors.js";
|
|
6
7
|
import { parseWithSchema } from "../shared/guards.js";
|
|
7
|
-
import { remoteRetryConfig } from "../shared/retry.js";
|
|
8
8
|
import { toolDefinitionSchema } from "../shared/schemas.js";
|
|
9
|
+
const MCP_CONNECT_TIMEOUT_MS = 10_000;
|
|
10
|
+
const MCP_DISCOVERY_TIMEOUT_MS = 10_000;
|
|
11
|
+
const MCP_INVOKE_TIMEOUT_MS = 45_000;
|
|
9
12
|
const defaultCreateClient = (version) => {
|
|
10
13
|
return new Client({
|
|
11
14
|
name: "ogment-cli",
|
|
@@ -73,21 +76,23 @@ const parseToolCallContent = (result) => {
|
|
|
73
76
|
export const createMcpService = (deps) => {
|
|
74
77
|
const createClient = deps.createClient ?? (() => defaultCreateClient(deps.version));
|
|
75
78
|
const createTransport = deps.createTransport ?? defaultCreateTransport;
|
|
76
|
-
const retryConfig = remoteRetryConfig();
|
|
77
79
|
const withClient = async (target, apiKey, handler) => {
|
|
78
80
|
const endpoint = `${deps.baseUrl}/api/v1/mcp/${target.orgSlug}/${target.serverPath}`;
|
|
79
81
|
const url = new URL(endpoint);
|
|
80
82
|
const transport = createTransport(url, apiKey);
|
|
81
83
|
const client = createClient();
|
|
82
84
|
const connectResult = await Result.tryPromise({
|
|
83
|
-
catch: (cause) =>
|
|
84
|
-
|
|
85
|
+
catch: (cause) => createRemoteRequestErrorFromMcpCause({
|
|
86
|
+
cause,
|
|
85
87
|
message: "Failed to connect to MCP server",
|
|
88
|
+
operation: "connect",
|
|
86
89
|
}),
|
|
87
90
|
try: async () => {
|
|
88
|
-
await client.connect(transport
|
|
91
|
+
await client.connect(transport, {
|
|
92
|
+
timeout: MCP_CONNECT_TIMEOUT_MS,
|
|
93
|
+
});
|
|
89
94
|
},
|
|
90
|
-
}
|
|
95
|
+
});
|
|
91
96
|
if (Result.isError(connectResult)) {
|
|
92
97
|
return connectResult;
|
|
93
98
|
}
|
|
@@ -103,24 +108,27 @@ export const createMcpService = (deps) => {
|
|
|
103
108
|
});
|
|
104
109
|
}
|
|
105
110
|
};
|
|
106
|
-
const
|
|
111
|
+
const withRemoteCall = async (action, message, operation) => {
|
|
107
112
|
return Result.tryPromise({
|
|
108
|
-
catch: (cause) =>
|
|
109
|
-
|
|
113
|
+
catch: (cause) => createRemoteRequestErrorFromMcpCause({
|
|
114
|
+
cause,
|
|
110
115
|
message,
|
|
116
|
+
operation,
|
|
111
117
|
}),
|
|
112
118
|
try: action,
|
|
113
|
-
}
|
|
119
|
+
});
|
|
114
120
|
};
|
|
115
121
|
return {
|
|
116
122
|
callTool: async (target, apiKey, toolName, args) => {
|
|
117
123
|
return withClient(target, apiKey, async (client) => {
|
|
118
|
-
const toolCallResult = await
|
|
124
|
+
const toolCallResult = await withRemoteCall(async () => {
|
|
119
125
|
return client.callTool({
|
|
120
126
|
arguments: args,
|
|
121
127
|
name: toolName,
|
|
128
|
+
}, undefined, {
|
|
129
|
+
timeout: MCP_INVOKE_TIMEOUT_MS,
|
|
122
130
|
});
|
|
123
|
-
}, "MCP tool call failed");
|
|
131
|
+
}, "MCP tool call failed", "tools/call");
|
|
124
132
|
if (Result.isError(toolCallResult)) {
|
|
125
133
|
return toolCallResult;
|
|
126
134
|
}
|
|
@@ -129,7 +137,9 @@ export const createMcpService = (deps) => {
|
|
|
129
137
|
},
|
|
130
138
|
listTools: async (target, apiKey) => {
|
|
131
139
|
return withClient(target, apiKey, async (client) => {
|
|
132
|
-
const toolsResult = await
|
|
140
|
+
const toolsResult = await withRemoteCall(async () => client.listTools(undefined, {
|
|
141
|
+
timeout: MCP_DISCOVERY_TIMEOUT_MS,
|
|
142
|
+
}), "MCP tools/list failed", "tools/list");
|
|
133
143
|
if (Result.isError(toolsResult)) {
|
|
134
144
|
return toolsResult;
|
|
135
145
|
}
|
|
@@ -137,7 +147,7 @@ export const createMcpService = (deps) => {
|
|
|
137
147
|
for (const tool of toolsResult.value.tools) {
|
|
138
148
|
const parsed = parseWithSchema(toolDefinitionSchema, tool, "MCP tool definition", {
|
|
139
149
|
code: ERROR_CODE.toolInputSchemaViolation,
|
|
140
|
-
|
|
150
|
+
recovery: { command: "ogment catalog" },
|
|
141
151
|
});
|
|
142
152
|
if (Result.isError(parsed)) {
|
|
143
153
|
return parsed;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export declare const APP_NAME = "ogment";
|
|
2
2
|
export declare const APP_DESCRIPTION = "Ogment CLI - secure your AI agents' SaaS credentials";
|
|
3
3
|
export declare const DEFAULT_OGMENT_BASE_URL = "https://dashboard.ogment.ai";
|
|
4
|
-
export declare const CLI_CLIENT_NAME = "Ogment CLI";
|
|
5
|
-
export declare const CLI_REDIRECT_HOST = "127.0.0.1";
|
|
6
4
|
export declare const VERSION: string;
|
|
7
5
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ,WAAW,CAAC;AACjC,eAAO,MAAM,eAAe,yDAAyD,CAAC;AAEtF,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ,WAAW,CAAC;AACjC,eAAO,MAAM,eAAe,yDAAyD,CAAC;AAEtF,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAQrE,eAAO,MAAM,OAAO,QAAsB,CAAC"}
|
package/dist/shared/constants.js
CHANGED
|
@@ -2,7 +2,5 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
export const APP_NAME = "ogment";
|
|
3
3
|
export const APP_DESCRIPTION = "Ogment CLI - secure your AI agents' SaaS credentials";
|
|
4
4
|
export const DEFAULT_OGMENT_BASE_URL = "https://dashboard.ogment.ai";
|
|
5
|
-
export const CLI_CLIENT_NAME = "Ogment CLI";
|
|
6
|
-
export const CLI_REDIRECT_HOST = "127.0.0.1";
|
|
7
5
|
const packageJson = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
|
|
8
6
|
export const VERSION = packageJson.version;
|
|
@@ -24,5 +24,8 @@ export declare const ERROR_CODE: {
|
|
|
24
24
|
readonly transportRequestFailed: "TRANSPORT_REQUEST_FAILED";
|
|
25
25
|
readonly validationInvalidInput: "VALIDATION_INVALID_INPUT";
|
|
26
26
|
};
|
|
27
|
-
export type
|
|
27
|
+
export type StaticErrorCode = (typeof ERROR_CODE)[keyof typeof ERROR_CODE];
|
|
28
|
+
export type HttpStatusErrorCode = `HTTP_${number}`;
|
|
29
|
+
export type McpNumericErrorCode = `MCP_${number}`;
|
|
30
|
+
export type ErrorCode = StaticErrorCode | HttpStatusErrorCode | McpNumericErrorCode;
|
|
28
31
|
//# sourceMappingURL=error-codes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../../src/shared/error-codes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;;;;;;;CAUjB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,OAAO,cAAc,CAAC,CAAC;AAEjF,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAab,CAAC;AAEX,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../../src/shared/error-codes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;;;;;;;CAUjB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,OAAO,cAAc,CAAC,CAAC;AAEjF,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAab,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAC3E,MAAM,MAAM,mBAAmB,GAAG,QAAQ,MAAM,EAAE,CAAC;AACnD,MAAM,MAAM,mBAAmB,GAAG,OAAO,MAAM,EAAE,CAAC;AAClD,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,mBAAmB,GAAG,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type AppError } from "./errors.js";
|
|
2
|
+
import type { CliRuntimeErrorPayload } from "./types.js";
|
|
3
|
+
interface PresentAppErrorOptions {
|
|
4
|
+
contextDiagnostics?: Record<string, unknown>;
|
|
5
|
+
includeDebug: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const presentRuntimeErrorPayload: (error: AppError, options: PresentAppErrorOptions) => CliRuntimeErrorPayload;
|
|
8
|
+
export declare const presentCatalogFailureError: (error: AppError, options: PresentAppErrorOptions) => {
|
|
9
|
+
code: string;
|
|
10
|
+
detail: string;
|
|
11
|
+
diagnostics: Record<string, unknown>;
|
|
12
|
+
related_codes?: string[];
|
|
13
|
+
retryable: boolean;
|
|
14
|
+
title: string;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=error-presentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-presentation.d.ts","sourceRoot":"","sources":["../../src/shared/error-presentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,QAAQ,EAEd,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,UAAU,sBAAsB;IAC9B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,YAAY,EAAE,OAAO,CAAC;CACvB;AA+ID,eAAO,MAAM,0BAA0B,GACrC,OAAO,QAAQ,EACf,SAAS,sBAAsB,KAC9B,sBA2BF,CAAC;AAEF,eAAO,MAAM,0BAA0B,GACrC,OAAO,QAAQ,EACf,SAAS,sBAAsB,KAC9B;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CAWf,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { appErrorDiagnostics, appErrorMeta, appErrorTitle, formatAppError, } from "./errors.js";
|
|
2
|
+
const isRecord = (value) => {
|
|
3
|
+
return typeof value === "object" && value !== null;
|
|
4
|
+
};
|
|
5
|
+
const toHttpCode = (status) => {
|
|
6
|
+
return `HTTP_${status}`;
|
|
7
|
+
};
|
|
8
|
+
const toMcpCode = (code) => {
|
|
9
|
+
return `MCP_${code}`;
|
|
10
|
+
};
|
|
11
|
+
const sanitizeRemoteMessage = (value) => {
|
|
12
|
+
const trimmed = value.trim();
|
|
13
|
+
if (trimmed.length === 0) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
if (/^[\w]+Error$/u.test(trimmed)) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const normalized = trimmed.replace(/^[\w]+Error:\s*/u, "").trim();
|
|
20
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
21
|
+
};
|
|
22
|
+
const extractMessageFromRecord = (record) => {
|
|
23
|
+
if (typeof record["message"] === "string") {
|
|
24
|
+
return sanitizeRemoteMessage(record["message"]);
|
|
25
|
+
}
|
|
26
|
+
const nested = record["error"];
|
|
27
|
+
if (isRecord(nested) && typeof nested["message"] === "string") {
|
|
28
|
+
return sanitizeRemoteMessage(nested["message"]);
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
};
|
|
32
|
+
const extractMessageFromBody = (body) => {
|
|
33
|
+
if (typeof body !== "string" || body.length === 0) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const parsed = (() => {
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(body);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
})();
|
|
44
|
+
if (isRecord(parsed)) {
|
|
45
|
+
const fromParsed = extractMessageFromRecord(parsed);
|
|
46
|
+
if (fromParsed !== undefined) {
|
|
47
|
+
return fromParsed;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return sanitizeRemoteMessage(body);
|
|
51
|
+
};
|
|
52
|
+
const extractRemoteUserMessage = (error) => {
|
|
53
|
+
if (error.source !== "mcp_transport_http" && error.source !== "mcp_jsonrpc") {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
if (isRecord(error.raw)) {
|
|
57
|
+
const fromRaw = extractMessageFromRecord(error.raw);
|
|
58
|
+
if (fromRaw !== undefined) {
|
|
59
|
+
return fromRaw;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const fromBody = extractMessageFromBody(error.body);
|
|
63
|
+
if (fromBody !== undefined) {
|
|
64
|
+
return fromBody;
|
|
65
|
+
}
|
|
66
|
+
if (typeof error.mcpData === "string") {
|
|
67
|
+
const fromData = sanitizeRemoteMessage(error.mcpData);
|
|
68
|
+
if (fromData !== undefined) {
|
|
69
|
+
return fromData;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
};
|
|
74
|
+
const resolvePrimaryCode = (error) => {
|
|
75
|
+
const meta = appErrorMeta(error);
|
|
76
|
+
if (error._tag === "RemoteRequestError") {
|
|
77
|
+
if (typeof error.httpStatus === "number") {
|
|
78
|
+
return toHttpCode(error.httpStatus);
|
|
79
|
+
}
|
|
80
|
+
if (typeof error.mcpCode === "number") {
|
|
81
|
+
return toMcpCode(error.mcpCode);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return String(meta.code);
|
|
85
|
+
};
|
|
86
|
+
const resolveRelatedCodes = (error, primaryCode) => {
|
|
87
|
+
if (error._tag !== "RemoteRequestError") {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const relatedCodes = [
|
|
91
|
+
...(typeof error.httpStatus === "number" ? [toHttpCode(error.httpStatus)] : []),
|
|
92
|
+
...(typeof error.mcpCode === "number" ? [toMcpCode(error.mcpCode)] : []),
|
|
93
|
+
].filter((code, index, array) => {
|
|
94
|
+
return code !== primaryCode && array.indexOf(code) === index;
|
|
95
|
+
});
|
|
96
|
+
return relatedCodes.length > 0 ? relatedCodes : undefined;
|
|
97
|
+
};
|
|
98
|
+
const defaultDiagnostics = (error) => {
|
|
99
|
+
if (error._tag !== "RemoteRequestError") {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
source: error.source,
|
|
104
|
+
...(error.operation === undefined ? {} : { operation: error.operation }),
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
const resolveDetail = (error) => {
|
|
108
|
+
if (error._tag === "RemoteRequestError") {
|
|
109
|
+
const userMessage = extractRemoteUserMessage(error);
|
|
110
|
+
if (userMessage !== undefined) {
|
|
111
|
+
return userMessage;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return formatAppError(error);
|
|
115
|
+
};
|
|
116
|
+
export const presentRuntimeErrorPayload = (error, options) => {
|
|
117
|
+
const meta = appErrorMeta(error);
|
|
118
|
+
const primaryCode = resolvePrimaryCode(error);
|
|
119
|
+
const relatedCodes = resolveRelatedCodes(error, primaryCode);
|
|
120
|
+
const diagnostics = options.includeDebug === true
|
|
121
|
+
? {
|
|
122
|
+
tag: error._tag,
|
|
123
|
+
...appErrorDiagnostics(error),
|
|
124
|
+
}
|
|
125
|
+
: {
|
|
126
|
+
...defaultDiagnostics(error),
|
|
127
|
+
};
|
|
128
|
+
if (options.contextDiagnostics !== undefined) {
|
|
129
|
+
Object.assign(diagnostics, options.contextDiagnostics);
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
category: meta.category,
|
|
133
|
+
code: primaryCode,
|
|
134
|
+
detail: resolveDetail(error),
|
|
135
|
+
diagnostics,
|
|
136
|
+
...(relatedCodes === undefined ? {} : { related_codes: relatedCodes }),
|
|
137
|
+
retryable: meta.retryable,
|
|
138
|
+
title: appErrorTitle(error),
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
export const presentCatalogFailureError = (error, options) => {
|
|
142
|
+
const payload = presentRuntimeErrorPayload(error, options);
|
|
143
|
+
return {
|
|
144
|
+
code: payload.code,
|
|
145
|
+
detail: payload.detail,
|
|
146
|
+
diagnostics: payload.diagnostics,
|
|
147
|
+
...(payload.related_codes === undefined ? {} : { related_codes: payload.related_codes }),
|
|
148
|
+
retryable: payload.retryable,
|
|
149
|
+
title: payload.title,
|
|
150
|
+
};
|
|
151
|
+
};
|