@ogment-ai/cli 0.3.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 (65) hide show
  1. package/README.md +124 -0
  2. package/dist/cli.d.ts +19 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +337 -0
  5. package/dist/commands/call.d.ts +14 -0
  6. package/dist/commands/call.d.ts.map +1 -0
  7. package/dist/commands/call.js +51 -0
  8. package/dist/commands/context.d.ts +15 -0
  9. package/dist/commands/context.d.ts.map +1 -0
  10. package/dist/commands/context.js +1 -0
  11. package/dist/commands/describe.d.ts +4 -0
  12. package/dist/commands/describe.d.ts.map +1 -0
  13. package/dist/commands/describe.js +94 -0
  14. package/dist/commands/server-context.d.ts +14 -0
  15. package/dist/commands/server-context.d.ts.map +1 -0
  16. package/dist/commands/server-context.js +26 -0
  17. package/dist/commands/servers.d.ts +13 -0
  18. package/dist/commands/servers.d.ts.map +1 -0
  19. package/dist/commands/servers.js +29 -0
  20. package/dist/index.d.ts +4 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +3 -0
  23. package/dist/infra/browser.d.ts +12 -0
  24. package/dist/infra/browser.d.ts.map +1 -0
  25. package/dist/infra/browser.js +20 -0
  26. package/dist/infra/credentials.d.ts +22 -0
  27. package/dist/infra/credentials.d.ts.map +1 -0
  28. package/dist/infra/credentials.js +81 -0
  29. package/dist/infra/env.d.ts +11 -0
  30. package/dist/infra/env.d.ts.map +1 -0
  31. package/dist/infra/env.js +98 -0
  32. package/dist/infra/http.d.ts +12 -0
  33. package/dist/infra/http.d.ts.map +1 -0
  34. package/dist/infra/http.js +27 -0
  35. package/dist/output/manager.d.ts +30 -0
  36. package/dist/output/manager.d.ts.map +1 -0
  37. package/dist/output/manager.js +79 -0
  38. package/dist/services/account.d.ts +16 -0
  39. package/dist/services/account.d.ts.map +1 -0
  40. package/dist/services/account.js +66 -0
  41. package/dist/services/auth.d.ts +38 -0
  42. package/dist/services/auth.d.ts.map +1 -0
  43. package/dist/services/auth.js +617 -0
  44. package/dist/services/mcp.d.ts +33 -0
  45. package/dist/services/mcp.d.ts.map +1 -0
  46. package/dist/services/mcp.js +158 -0
  47. package/dist/shared/constants.d.ts +8 -0
  48. package/dist/shared/constants.d.ts.map +1 -0
  49. package/dist/shared/constants.js +7 -0
  50. package/dist/shared/errors.d.ts +35 -0
  51. package/dist/shared/errors.d.ts.map +1 -0
  52. package/dist/shared/errors.js +31 -0
  53. package/dist/shared/exit-codes.d.ts +12 -0
  54. package/dist/shared/exit-codes.d.ts.map +1 -0
  55. package/dist/shared/exit-codes.js +27 -0
  56. package/dist/shared/guards.d.ts +6 -0
  57. package/dist/shared/guards.d.ts.map +1 -0
  58. package/dist/shared/guards.js +26 -0
  59. package/dist/shared/schemas.d.ts +57 -0
  60. package/dist/shared/schemas.d.ts.map +1 -0
  61. package/dist/shared/schemas.js +36 -0
  62. package/dist/shared/types.d.ts +53 -0
  63. package/dist/shared/types.d.ts.map +1 -0
  64. package/dist/shared/types.js +1 -0
  65. package/package.json +81 -0
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Ogment CLI
2
+
3
+ **Secure your AI agents' SaaS credentials.**
4
+
5
+ Ogment sits between your AI agent and your SaaS tools. Your agent gets a scoped, revocable API key — your real credentials never leave Ogment.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ # Log in (opens browser for OAuth + agent selection)
11
+ npx ogment login
12
+
13
+ # List available servers
14
+ npx ogment servers
15
+
16
+ # Call a tool
17
+ npx ogment call <server> <tool> '{"param": "value"}'
18
+ ```
19
+
20
+ ## Development
21
+
22
+ ### Run Tests
23
+
24
+ ```bash
25
+ pnpm run test # Watch mode
26
+ pnpm run test:run # Single run
27
+ pnpm run test:coverage # Coverage (text + html + lcov)
28
+ pnpm run test:ui # Vitest UI
29
+ pnpm run test:changed # Run tests related to changed files
30
+ pnpm run test:ci # CI profile (coverage + CI reporters)
31
+ ```
32
+
33
+ ## Commands
34
+
35
+ ### `ogment login`
36
+
37
+ Authenticate with the Ogment platform. Opens your browser for OAuth sign-in, then shows an agent picker where you create or select an agent. The resulting API key is stored locally.
38
+
39
+ ```bash
40
+ npx ogment login
41
+ ```
42
+
43
+ ### `ogment login --device`
44
+
45
+ For headless or remote environments (VMs, CI servers) where a browser isn't available. Displays a short code that you enter on the Ogment dashboard from any device.
46
+
47
+ ```bash
48
+ npx ogment login --device
49
+
50
+ # Shows:
51
+ # Enter this code on the Ogment dashboard:
52
+ # ABCD-1234
53
+ # Open: https://dashboard.ogment.ai/cli/activate
54
+ ```
55
+
56
+ ### `ogment servers [path]`
57
+
58
+ List configured servers or inspect a server's tools.
59
+
60
+ ```bash
61
+ npx ogment servers # List all servers
62
+ npx ogment servers <path> # Inspect tools
63
+ npx ogment servers --json # Machine-readable output
64
+ ```
65
+
66
+ ### `ogment call <server> <tool> [args]`
67
+
68
+ Call a tool on an Ogment server. Always outputs JSON.
69
+
70
+ ```bash
71
+ npx ogment call ecommerce-api get__health
72
+ npx ogment call ecommerce-api get__api_products_ '{"limit":2}'
73
+ ```
74
+
75
+ ### `ogment logout`
76
+
77
+ Delete local credentials. To revoke the API key (prevent all access), use the Ogment dashboard.
78
+
79
+ ```bash
80
+ npx ogment logout
81
+ ```
82
+
83
+ ## Authentication Model
84
+
85
+ Ogment uses **Clerk API keys** for machine authentication:
86
+
87
+ 1. **`ogment login`** — Human authenticates via OAuth, picks an agent → Clerk API key created
88
+ 2. **API key stored locally** — At `~/.config/ogment/credentials.json`
89
+ 3. **All requests use the API key** — Sent as `Authorization: Bearer <api-key>`
90
+ 4. **Revoke anytime** — In the Ogment dashboard → Agents tab
91
+
92
+ ### For Remote VMs
93
+
94
+ Use the device flow (`ogment login --device`) — the human approves from their own device, the VM never sees credentials or a browser. The API key is the only credential the VM receives.
95
+
96
+ ## Environment Variables
97
+
98
+ | Variable | Default | Description |
99
+ |---|---|---|
100
+ | `OGMENT_BASE_URL` | `https://dashboard.ogment.ai` | Ogment platform URL (for development) |
101
+ | `OGMENT_API_KEY` | — | API key (alternative to `ogment login`) |
102
+
103
+ ## How It Works
104
+
105
+ ```
106
+ AI Agent (Claude, Cursor, ChatGPT)
107
+
108
+ │ Clerk API key (long-lived, revocable)
109
+
110
+ ┌─────────────────────────────────┐
111
+ │ Ogment MCP Proxy │
112
+ │ ✓ Validate API key │
113
+ │ ✓ Inject real credentials │
114
+ │ ✓ Log every tool call │
115
+ └──────────────┬──────────────────┘
116
+
117
+ ┌──────────┼──────────┐
118
+ ▼ ▼ ▼
119
+ Salesforce Linear Snowflake
120
+ ```
121
+
122
+ ## License
123
+
124
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import type { CommandContext } from "./commands/context.js";
3
+ import { OutputManager } from "./output/manager.js";
4
+ import { type ExitCode } from "./shared/exit-codes.js";
5
+ export interface GlobalCliOptions {
6
+ apiKey: string | undefined;
7
+ json: boolean | undefined;
8
+ nonInteractive: boolean | undefined;
9
+ quiet: boolean | undefined;
10
+ yes: boolean | undefined;
11
+ }
12
+ interface Runtime {
13
+ context: CommandContext;
14
+ output: OutputManager;
15
+ }
16
+ export declare const runCli: (argv?: readonly string[], runtime?: Runtime) => Promise<ExitCode>;
17
+ export declare const executeCli: () => Promise<void>;
18
+ export {};
19
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAQA,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,uBAAuB,CAAC;AAO7E,OAAO,EAAE,aAAa,EAA0B,MAAM,qBAAqB,CAAC;AAK5E,OAAO,EAAa,KAAK,QAAQ,EAAoB,MAAM,wBAAwB,CAAC;AAIpF,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,GAAG,EAAE,OAAO,GAAG,SAAS,CAAC;CAC1B;AAED,UAAU,OAAO;IACf,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC;CACvB;AA4XD,eAAO,MAAM,MAAM,GACjB,OAAM,SAAS,MAAM,EAA0B,EAC/C,UAAS,OAAyB,KACjC,OAAO,CAAC,QAAQ,CAmBlB,CAAC;AAEF,eAAO,MAAM,UAAU,QAAa,OAAO,CAAC,IAAI,CAG/C,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,337 @@
1
+ #!/usr/bin/env node
2
+ import { pathToFileURL } from "node:url";
3
+ import { Command, CommanderError } from "commander";
4
+ import { runCallCommand } from "./commands/call.js";
5
+ import { runDescribeCommand } from "./commands/describe.js";
6
+ import { runServersCommand } from "./commands/servers.js";
7
+ import { createBrowserOpener } from "./infra/browser.js";
8
+ import { createFileCredentialsStore } from "./infra/credentials.js";
9
+ import { createRuntimeConfig } from "./infra/env.js";
10
+ import { createHttpClient } from "./infra/http.js";
11
+ import { OutputManager } from "./output/manager.js";
12
+ import { createAccountService } from "./services/account.js";
13
+ import { createAuthService } from "./services/auth.js";
14
+ import { createMcpService } from "./services/mcp.js";
15
+ import { UnexpectedError, ValidationError } from "./shared/errors.js";
16
+ import { EXIT_CODE, exitCodeForError } from "./shared/exit-codes.js";
17
+ import { APP_DESCRIPTION, APP_NAME, AGENT_SUCCESS_HINT, VERSION } from "./shared/constants.js";
18
+ class CliExitError extends Error {
19
+ exitCode;
20
+ constructor(exitCode) {
21
+ super("CLI exit");
22
+ this.exitCode = exitCode;
23
+ }
24
+ }
25
+ const createRuntime = () => {
26
+ const runtimeConfig = createRuntimeConfig();
27
+ const output = new OutputManager();
28
+ const credentialsStore = createFileCredentialsStore({
29
+ configDir: runtimeConfig.configDir,
30
+ credentialsPath: runtimeConfig.credentialsPath,
31
+ });
32
+ const httpClient = createHttpClient();
33
+ const browserOpener = createBrowserOpener();
34
+ const services = {
35
+ account: createAccountService({
36
+ baseUrl: runtimeConfig.baseUrl,
37
+ httpClient,
38
+ }),
39
+ auth: createAuthService({
40
+ baseUrl: runtimeConfig.baseUrl,
41
+ browserOpener,
42
+ credentialsStore,
43
+ envApiKey: runtimeConfig.envApiKey,
44
+ httpClient,
45
+ }),
46
+ mcp: createMcpService({
47
+ baseUrl: runtimeConfig.baseUrl,
48
+ version: runtimeConfig.version,
49
+ }),
50
+ };
51
+ return {
52
+ context: {
53
+ apiKeyOverride: undefined,
54
+ output,
55
+ services,
56
+ },
57
+ output,
58
+ };
59
+ };
60
+ const asGlobalOptions = (command) => {
61
+ const options = command.optsWithGlobals();
62
+ return {
63
+ apiKey: options.apiKey,
64
+ json: options.json,
65
+ nonInteractive: options.nonInteractive,
66
+ quiet: options.quiet,
67
+ yes: options.yes,
68
+ };
69
+ };
70
+ const mapGlobalOutputOptions = (options) => {
71
+ return {
72
+ json: options.json,
73
+ nonInteractive: options.nonInteractive,
74
+ quiet: options.quiet,
75
+ yes: options.yes,
76
+ };
77
+ };
78
+ const throwCommandError = (error) => {
79
+ throw new CliExitError(exitCodeForError(error));
80
+ };
81
+ const isRecord = (value) => {
82
+ return typeof value === "object" && value !== null;
83
+ };
84
+ const ensureSuccess = (result, output) => {
85
+ if (result.status === "error") {
86
+ output.error(result.error);
87
+ throwCommandError(result.error);
88
+ }
89
+ return result.value;
90
+ };
91
+ const formatSchemaType = (property) => {
92
+ if (Array.isArray(property.enum) && property.enum.length > 0) {
93
+ return property.enum.map(String).join(" | ");
94
+ }
95
+ if (property.type === "array" && typeof property.items?.type === "string") {
96
+ return `${property.items.type}[]`;
97
+ }
98
+ if (typeof property.type === "string" && property.type.length > 0) {
99
+ return property.type;
100
+ }
101
+ return "unknown";
102
+ };
103
+ const renderSchemaParameters = (output, schema) => {
104
+ const required = new Set();
105
+ const requiredValue = schema["required"];
106
+ if (Array.isArray(requiredValue)) {
107
+ for (const item of requiredValue) {
108
+ if (typeof item === "string") {
109
+ required.add(item);
110
+ }
111
+ }
112
+ }
113
+ const propertiesValue = schema["properties"];
114
+ if (!isRecord(propertiesValue)) {
115
+ output.info(" Parameters: none");
116
+ return;
117
+ }
118
+ const entries = Object.entries(propertiesValue);
119
+ if (entries.length === 0) {
120
+ output.info(" Parameters: none");
121
+ return;
122
+ }
123
+ output.info(" Parameters:");
124
+ for (const [name, propertyValue] of entries) {
125
+ if (!isRecord(propertyValue)) {
126
+ continue;
127
+ }
128
+ const property = propertyValue;
129
+ const type = formatSchemaType(property);
130
+ const requirement = required.has(name) ? "required" : "optional";
131
+ const description = typeof property.description === "string" && property.description.length > 0
132
+ ? ` - ${property.description}`
133
+ : "";
134
+ output.info(` ${name} (${type}, ${requirement})${description}`);
135
+ }
136
+ };
137
+ const renderSchemaBlock = (output, label, schema) => {
138
+ if (schema === undefined) {
139
+ output.info(` ${label}: unavailable`);
140
+ return;
141
+ }
142
+ output.info(` ${label}:`);
143
+ const lines = JSON.stringify(schema, null, 2).split("\n");
144
+ for (const line of lines) {
145
+ output.info(` ${line}`);
146
+ }
147
+ };
148
+ const renderServersListHuman = (output, servers) => {
149
+ if (servers.length === 0) {
150
+ output.info("No servers available.");
151
+ return;
152
+ }
153
+ for (const server of servers) {
154
+ const description = typeof server.description === "string" && server.description.length > 0
155
+ ? ` - ${server.description}`
156
+ : "";
157
+ output.info(`${server.path} (${server.orgSlug}) ${server.name}${description}`);
158
+ }
159
+ output.info("Inspect tools with: ogment servers <path>");
160
+ };
161
+ const renderServerDetailsHuman = (output, payload) => {
162
+ output.info(`Server ${payload.server.name} (${payload.server.path}, ${payload.server.orgSlug})`);
163
+ if (payload.tools.length === 0) {
164
+ output.info("No tools available.");
165
+ return;
166
+ }
167
+ for (const tool of payload.tools) {
168
+ const description = typeof tool.description === "string" && tool.description.length > 0
169
+ ? ` - ${tool.description}`
170
+ : "";
171
+ output.info(` ${tool.name}${description}`);
172
+ renderSchemaParameters(output, tool.inputSchema);
173
+ renderSchemaBlock(output, "Input schema", tool.inputSchema);
174
+ renderSchemaBlock(output, "Output schema", tool.outputSchema);
175
+ }
176
+ };
177
+ const createProgram = (runtime) => {
178
+ const program = new Command();
179
+ program.exitOverride();
180
+ program.configureOutput({
181
+ writeErr: () => undefined,
182
+ });
183
+ program
184
+ .name(APP_NAME)
185
+ .description(APP_DESCRIPTION)
186
+ .version(VERSION)
187
+ .option("--apiKey <key>", "API key override")
188
+ .option("--json", "Output machine-readable JSON")
189
+ .option("--quiet", "Suppress non-essential output")
190
+ .option("--non-interactive", "Disable interactive behavior")
191
+ .option("--yes", "Assume yes for any confirmation")
192
+ .hook("preAction", (thisCommand) => {
193
+ const options = asGlobalOptions(thisCommand);
194
+ runtime.output.configure(mapGlobalOutputOptions(options));
195
+ runtime.context.apiKeyOverride = options.apiKey;
196
+ });
197
+ program
198
+ .command("login")
199
+ .description("Authenticate with Ogment")
200
+ .option("--device", "Use device flow explicitly")
201
+ .action(async (options) => {
202
+ const result = await runtime.context.services.auth.login({
203
+ device: options.device === true,
204
+ nonInteractive: runtime.output.nonInteractive,
205
+ onPending: ({ userCode, verificationUri }) => {
206
+ runtime.output.info(`Open ${verificationUri}`);
207
+ runtime.output.info(`Enter code: ${userCode}`);
208
+ },
209
+ });
210
+ const data = ensureSuccess(result, runtime.output);
211
+ const humanMessage = data.alreadyLoggedIn
212
+ ? `Already logged in as ${data.agentName}.`
213
+ : `Logged in as ${data.agentName}. ${AGENT_SUCCESS_HINT}`;
214
+ runtime.output.success(data, humanMessage);
215
+ });
216
+ program
217
+ .command("logout")
218
+ .description("Revoke token and delete local credentials")
219
+ .action(async () => {
220
+ const result = await runtime.context.services.auth.logout();
221
+ const data = ensureSuccess(result, runtime.output);
222
+ let humanMessage = "Not logged in.";
223
+ if (data.localCredentialsDeleted) {
224
+ humanMessage = data.revoked
225
+ ? "Logged out and revoked API key."
226
+ : "Local credentials deleted. Server revocation not confirmed.";
227
+ }
228
+ runtime.output.success(data, humanMessage);
229
+ });
230
+ program
231
+ .command("servers [path]")
232
+ .description("List servers or inspect tools for one server")
233
+ .action(async (path) => {
234
+ const result = await runServersCommand(runtime.context, { path });
235
+ const data = ensureSuccess(result, runtime.output);
236
+ if (runtime.output.mode === "human") {
237
+ if ("servers" in data) {
238
+ renderServersListHuman(runtime.output, data.servers);
239
+ return;
240
+ }
241
+ renderServerDetailsHuman(runtime.output, data);
242
+ return;
243
+ }
244
+ runtime.output.success(data);
245
+ });
246
+ program
247
+ .command("call <serverPath> <toolName> [argsJson]")
248
+ .description("Call a tool on an Ogment server")
249
+ .action(async (serverPath, toolName, argsJson) => {
250
+ const result = await runCallCommand(runtime.context, {
251
+ argsJson,
252
+ serverPath,
253
+ toolName,
254
+ });
255
+ const data = ensureSuccess(result, runtime.output);
256
+ if (runtime.output.mode === "human") {
257
+ runtime.output.json(data.result);
258
+ return;
259
+ }
260
+ runtime.output.success(data);
261
+ });
262
+ program
263
+ .command("describe")
264
+ .description("Describe this CLI as a tool set for agent registration")
265
+ .action(() => {
266
+ const result = runDescribeCommand();
267
+ const data = ensureSuccess(result, runtime.output);
268
+ runtime.output.json(data);
269
+ });
270
+ program.action(() => {
271
+ if (runtime.output.mode === "json") {
272
+ runtime.output.success({
273
+ commands: ["login", "logout", "servers", "call", "describe"],
274
+ });
275
+ return;
276
+ }
277
+ runtime.output.info(`${APP_NAME} v${VERSION}`);
278
+ runtime.output.info(APP_DESCRIPTION);
279
+ runtime.output.info("");
280
+ runtime.output.info("Commands:");
281
+ runtime.output.info(" login [--device]");
282
+ runtime.output.info(" servers [path]");
283
+ runtime.output.info(" call <serverPath> <toolName> [argsJson]");
284
+ runtime.output.info(" logout");
285
+ runtime.output.info(" describe");
286
+ });
287
+ return program;
288
+ };
289
+ const normalizeCommanderError = (error) => {
290
+ if (error instanceof CommanderError) {
291
+ return new ValidationError({
292
+ details: error.message,
293
+ message: "Invalid CLI usage",
294
+ });
295
+ }
296
+ if (error instanceof Error) {
297
+ return new UnexpectedError({
298
+ cause: error,
299
+ message: error.message,
300
+ });
301
+ }
302
+ return new UnexpectedError({
303
+ cause: error,
304
+ message: "Unexpected CLI failure",
305
+ });
306
+ };
307
+ const normalizeCliArgv = (argv) => {
308
+ if (argv[0] === "--") {
309
+ return argv.slice(1);
310
+ }
311
+ return argv;
312
+ };
313
+ export const runCli = async (argv = process.argv.slice(2), runtime = createRuntime()) => {
314
+ const program = createProgram(runtime);
315
+ try {
316
+ await program.parseAsync(normalizeCliArgv(argv), { from: "user" });
317
+ return EXIT_CODE.success;
318
+ }
319
+ catch (error) {
320
+ if (error instanceof CliExitError) {
321
+ return error.exitCode;
322
+ }
323
+ if (error instanceof CommanderError && error.exitCode === EXIT_CODE.success) {
324
+ return EXIT_CODE.success;
325
+ }
326
+ const normalized = normalizeCommanderError(error);
327
+ runtime.output.error(normalized);
328
+ return exitCodeForError(normalized);
329
+ }
330
+ };
331
+ export const executeCli = async () => {
332
+ const code = await runCli();
333
+ process.exitCode = code;
334
+ };
335
+ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {
336
+ await executeCli();
337
+ }
@@ -0,0 +1,14 @@
1
+ import type { Result as ResultType } from "better-result";
2
+ import type { McpServiceError } from "../services/mcp.js";
3
+ import { NotFoundError, ValidationError } from "../shared/errors.js";
4
+ import type { ToolCallSuccess } from "../shared/types.js";
5
+ import type { CommandContext } from "./context.js";
6
+ import { type ResolveServerStateError } from "./server-context.js";
7
+ export interface CallCommandOptions {
8
+ argsJson: string | undefined;
9
+ serverPath: string;
10
+ toolName: string;
11
+ }
12
+ export type CallCommandError = McpServiceError | NotFoundError | ResolveServerStateError | ValidationError;
13
+ export declare const runCallCommand: (context: CommandContext, options: CallCommandOptions) => Promise<ResultType<ToolCallSuccess, CallCommandError>>;
14
+ //# sourceMappingURL=call.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../src/commands/call.ts"],"names":[],"mappings":"AACA,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,MAAM,qBAAqB,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,gBAAgB,GACxB,eAAe,GACf,aAAa,GACb,uBAAuB,GACvB,eAAe,CAAC;AAiCpB,eAAO,MAAM,cAAc,GACzB,SAAS,cAAc,EACvB,SAAS,kBAAkB,KAC1B,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAqCvD,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { Result } from "better-result";
2
+ import { NotFoundError, ValidationError } from "../shared/errors.js";
3
+ import { findServerByPath, resolveServerState, } from "./server-context.js";
4
+ const parseArgs = (argsJson) => {
5
+ if (argsJson === undefined || argsJson.length === 0) {
6
+ return Result.ok({});
7
+ }
8
+ const parsed = Result.try({
9
+ catch: () => new ValidationError({
10
+ details: argsJson,
11
+ message: "Invalid JSON arguments",
12
+ }),
13
+ try: () => JSON.parse(argsJson),
14
+ });
15
+ if (Result.isError(parsed)) {
16
+ return parsed;
17
+ }
18
+ if (typeof parsed.value !== "object" || parsed.value === null || Array.isArray(parsed.value)) {
19
+ return Result.err(new ValidationError({
20
+ message: "Tool arguments must be a JSON object",
21
+ }));
22
+ }
23
+ return Result.ok(parsed.value);
24
+ };
25
+ export const runCallCommand = async (context, options) => {
26
+ const argsResult = parseArgs(options.argsJson);
27
+ if (Result.isError(argsResult)) {
28
+ return argsResult;
29
+ }
30
+ const stateResult = await resolveServerState(context);
31
+ if (Result.isError(stateResult)) {
32
+ return stateResult;
33
+ }
34
+ const targetServerResult = findServerByPath(stateResult.value.servers, options.serverPath);
35
+ if (Result.isError(targetServerResult)) {
36
+ return targetServerResult;
37
+ }
38
+ const targetServer = targetServerResult.value;
39
+ const callResult = await context.services.mcp.callTool({
40
+ orgSlug: targetServer.orgSlug,
41
+ serverPath: targetServer.path,
42
+ }, stateResult.value.apiKey, options.toolName, argsResult.value);
43
+ if (Result.isError(callResult)) {
44
+ return callResult;
45
+ }
46
+ return Result.ok({
47
+ result: callResult.value.structuredContent,
48
+ serverPath: options.serverPath,
49
+ toolName: options.toolName,
50
+ });
51
+ };
@@ -0,0 +1,15 @@
1
+ import type { OutputManager } from "../output/manager.js";
2
+ import type { AccountService } from "../services/account.js";
3
+ import type { AuthService } from "../services/auth.js";
4
+ import type { McpService } from "../services/mcp.js";
5
+ export interface CommandServices {
6
+ account: AccountService;
7
+ auth: AuthService;
8
+ mcp: McpService;
9
+ }
10
+ export interface CommandContext {
11
+ apiKeyOverride: string | undefined;
12
+ output: OutputManager;
13
+ services: CommandServices;
14
+ }
15
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,eAAe,CAAC;CAC3B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { Result as ResultType } from "better-result";
2
+ import type { DescribePayload } from "../shared/schemas.js";
3
+ export declare const runDescribeCommand: () => ResultType<DescribePayload, never>;
4
+ //# sourceMappingURL=describe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/commands/describe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAI1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAiH5D,eAAO,MAAM,kBAAkB,QAAO,UAAU,CAAC,eAAe,EAAE,KAAK,CAItE,CAAC"}
@@ -0,0 +1,94 @@
1
+ import { Result } from "better-result";
2
+ import { z } from "zod";
3
+ import { zodToJsonSchema } from "zod-to-json-schema";
4
+ const asObjectRecord = (value) => {
5
+ if (typeof value === "object" && value !== null) {
6
+ return value;
7
+ }
8
+ return {};
9
+ };
10
+ const toJsonSchemaObject = (schema, title) => {
11
+ return asObjectRecord(zodToJsonSchema(schema, title));
12
+ };
13
+ const commandDefinitions = () => {
14
+ const loginInputSchema = z.object({
15
+ device: z.boolean().optional(),
16
+ });
17
+ const loginOutputSchema = z.object({
18
+ agentName: z.string(),
19
+ alreadyLoggedIn: z.boolean(),
20
+ });
21
+ const serversInputSchema = z.object({
22
+ path: z.string().optional(),
23
+ });
24
+ const serversOutputSchema = z.object({
25
+ server: z
26
+ .object({
27
+ enabled: z.boolean(),
28
+ name: z.string(),
29
+ orgSlug: z.string(),
30
+ path: z.string(),
31
+ })
32
+ .optional(),
33
+ servers: z
34
+ .array(z.object({
35
+ enabled: z.boolean(),
36
+ name: z.string(),
37
+ orgSlug: z.string(),
38
+ path: z.string(),
39
+ }))
40
+ .optional(),
41
+ tools: z
42
+ .array(z.object({
43
+ description: z.string().nullable(),
44
+ inputSchema: z.record(z.string(), z.unknown()),
45
+ name: z.string(),
46
+ }))
47
+ .optional(),
48
+ });
49
+ const callInputSchema = z.object({
50
+ args: z.record(z.string(), z.unknown()).optional(),
51
+ serverPath: z.string(),
52
+ toolName: z.string(),
53
+ });
54
+ const callOutputSchema = z.object({
55
+ result: z.unknown(),
56
+ serverPath: z.string(),
57
+ toolName: z.string(),
58
+ });
59
+ const logoutOutputSchema = z.object({
60
+ localCredentialsDeleted: z.boolean(),
61
+ revoked: z.boolean(),
62
+ });
63
+ return [
64
+ {
65
+ description: "Authenticate with Ogment. Uses browser-assisted device flow by default.",
66
+ name: "ogment_login",
67
+ outputSchema: toJsonSchemaObject(loginOutputSchema, "ogmentLoginOutput"),
68
+ parameters: toJsonSchemaObject(loginInputSchema, "ogmentLoginInput"),
69
+ },
70
+ {
71
+ description: "List available servers or inspect one server's tools.",
72
+ name: "ogment_servers",
73
+ outputSchema: toJsonSchemaObject(serversOutputSchema, "ogmentServersOutput"),
74
+ parameters: toJsonSchemaObject(serversInputSchema, "ogmentServersInput"),
75
+ },
76
+ {
77
+ description: "Call a tool on a server.",
78
+ name: "ogment_call",
79
+ outputSchema: toJsonSchemaObject(callOutputSchema, "ogmentCallOutput"),
80
+ parameters: toJsonSchemaObject(callInputSchema, "ogmentCallInput"),
81
+ },
82
+ {
83
+ description: "Revoke current session and delete local credentials.",
84
+ name: "ogment_logout",
85
+ outputSchema: toJsonSchemaObject(logoutOutputSchema, "ogmentLogoutOutput"),
86
+ parameters: toJsonSchemaObject(z.object({}), "ogmentLogoutInput"),
87
+ },
88
+ ];
89
+ };
90
+ export const runDescribeCommand = () => {
91
+ return Result.ok({
92
+ tools: commandDefinitions(),
93
+ });
94
+ };