@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.
- package/README.md +124 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +337 -0
- package/dist/commands/call.d.ts +14 -0
- package/dist/commands/call.d.ts.map +1 -0
- package/dist/commands/call.js +51 -0
- package/dist/commands/context.d.ts +15 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +1 -0
- package/dist/commands/describe.d.ts +4 -0
- package/dist/commands/describe.d.ts.map +1 -0
- package/dist/commands/describe.js +94 -0
- package/dist/commands/server-context.d.ts +14 -0
- package/dist/commands/server-context.d.ts.map +1 -0
- package/dist/commands/server-context.js +26 -0
- package/dist/commands/servers.d.ts +13 -0
- package/dist/commands/servers.d.ts.map +1 -0
- package/dist/commands/servers.js +29 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/infra/browser.d.ts +12 -0
- package/dist/infra/browser.d.ts.map +1 -0
- package/dist/infra/browser.js +20 -0
- package/dist/infra/credentials.d.ts +22 -0
- package/dist/infra/credentials.d.ts.map +1 -0
- package/dist/infra/credentials.js +81 -0
- package/dist/infra/env.d.ts +11 -0
- package/dist/infra/env.d.ts.map +1 -0
- package/dist/infra/env.js +98 -0
- package/dist/infra/http.d.ts +12 -0
- package/dist/infra/http.d.ts.map +1 -0
- package/dist/infra/http.js +27 -0
- package/dist/output/manager.d.ts +30 -0
- package/dist/output/manager.d.ts.map +1 -0
- package/dist/output/manager.js +79 -0
- package/dist/services/account.d.ts +16 -0
- package/dist/services/account.d.ts.map +1 -0
- package/dist/services/account.js +66 -0
- package/dist/services/auth.d.ts +38 -0
- package/dist/services/auth.d.ts.map +1 -0
- package/dist/services/auth.js +617 -0
- package/dist/services/mcp.d.ts +33 -0
- package/dist/services/mcp.d.ts.map +1 -0
- package/dist/services/mcp.js +158 -0
- package/dist/shared/constants.d.ts +8 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +7 -0
- package/dist/shared/errors.d.ts +35 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +31 -0
- package/dist/shared/exit-codes.d.ts +12 -0
- package/dist/shared/exit-codes.d.ts.map +1 -0
- package/dist/shared/exit-codes.js +27 -0
- package/dist/shared/guards.d.ts +6 -0
- package/dist/shared/guards.d.ts.map +1 -0
- package/dist/shared/guards.js +26 -0
- package/dist/shared/schemas.d.ts +57 -0
- package/dist/shared/schemas.d.ts.map +1 -0
- package/dist/shared/schemas.js +36 -0
- package/dist/shared/types.d.ts +53 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Result as ResultType } from "better-result";
|
|
2
|
+
import type { FetchAccountError } from "../services/account.js";
|
|
3
|
+
import type { ResolveApiKeyError } from "../services/auth.js";
|
|
4
|
+
import { NotFoundError } from "../shared/errors.js";
|
|
5
|
+
import type { ServerWithOrg } from "../shared/types.js";
|
|
6
|
+
import type { CommandContext } from "./context.js";
|
|
7
|
+
export interface ResolvedServerState {
|
|
8
|
+
apiKey: string;
|
|
9
|
+
servers: ServerWithOrg[];
|
|
10
|
+
}
|
|
11
|
+
export type ResolveServerStateError = FetchAccountError | ResolveApiKeyError;
|
|
12
|
+
export declare const resolveServerState: (context: CommandContext) => Promise<ResultType<ResolvedServerState, ResolveServerStateError>>;
|
|
13
|
+
export declare const findServerByPath: (servers: readonly ServerWithOrg[], path: string) => ResultType<ServerWithOrg, NotFoundError>;
|
|
14
|
+
//# sourceMappingURL=server-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-context.d.ts","sourceRoot":"","sources":["../../src/commands/server-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAE7E,eAAO,MAAM,kBAAkB,GAC7B,SAAS,cAAc,KACtB,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,uBAAuB,CAAC,CAelE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,SAAS,SAAS,aAAa,EAAE,EACjC,MAAM,MAAM,KACX,UAAU,CAAC,aAAa,EAAE,aAAa,CAazC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Result } from "better-result";
|
|
2
|
+
import { NotFoundError } from "../shared/errors.js";
|
|
3
|
+
export const resolveServerState = async (context) => {
|
|
4
|
+
const apiKeyResult = await context.services.auth.resolveApiKey(context.apiKeyOverride);
|
|
5
|
+
if (Result.isError(apiKeyResult)) {
|
|
6
|
+
return apiKeyResult;
|
|
7
|
+
}
|
|
8
|
+
const serversResult = await context.services.account.listServers(apiKeyResult.value);
|
|
9
|
+
if (Result.isError(serversResult)) {
|
|
10
|
+
return serversResult;
|
|
11
|
+
}
|
|
12
|
+
return Result.ok({
|
|
13
|
+
apiKey: apiKeyResult.value,
|
|
14
|
+
servers: serversResult.value,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
export const findServerByPath = (servers, path) => {
|
|
18
|
+
const server = servers.find((item) => item.path === path);
|
|
19
|
+
if (server === undefined) {
|
|
20
|
+
return Result.err(new NotFoundError({
|
|
21
|
+
message: `Server \"${path}\" not found`,
|
|
22
|
+
resource: path,
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
return Result.ok(server);
|
|
26
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Result as ResultType } from "better-result";
|
|
2
|
+
import type { McpServiceError } from "../services/mcp.js";
|
|
3
|
+
import { NotFoundError } from "../shared/errors.js";
|
|
4
|
+
import type { ServerDetailsSuccess, ServersListSuccess } from "../shared/types.js";
|
|
5
|
+
import type { CommandContext } from "./context.js";
|
|
6
|
+
import { type ResolveServerStateError } from "./server-context.js";
|
|
7
|
+
export interface ServersCommandOptions {
|
|
8
|
+
path: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
export type ServersCommandSuccess = ServerDetailsSuccess | ServersListSuccess;
|
|
11
|
+
export type ServersCommandError = McpServiceError | NotFoundError | ResolveServerStateError;
|
|
12
|
+
export declare const runServersCommand: (context: CommandContext, options: ServersCommandOptions) => Promise<ResultType<ServersCommandSuccess, ServersCommandError>>;
|
|
13
|
+
//# sourceMappingURL=servers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"servers.d.ts","sourceRoot":"","sources":["../../src/commands/servers.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,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED,MAAM,MAAM,qBAAqB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AAE9E,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,aAAa,GAAG,uBAAuB,CAAC;AAE5F,eAAO,MAAM,iBAAiB,GAC5B,SAAS,cAAc,EACvB,SAAS,qBAAqB,KAC7B,OAAO,CAAC,UAAU,CAAC,qBAAqB,EAAE,mBAAmB,CAAC,CAiChE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Result } from "better-result";
|
|
2
|
+
import { NotFoundError } from "../shared/errors.js";
|
|
3
|
+
import { findServerByPath, resolveServerState, } from "./server-context.js";
|
|
4
|
+
export const runServersCommand = async (context, options) => {
|
|
5
|
+
const stateResult = await resolveServerState(context);
|
|
6
|
+
if (Result.isError(stateResult)) {
|
|
7
|
+
return stateResult;
|
|
8
|
+
}
|
|
9
|
+
if (typeof options.path !== "string" || options.path.length === 0) {
|
|
10
|
+
return Result.ok({
|
|
11
|
+
servers: stateResult.value.servers,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const serverResult = findServerByPath(stateResult.value.servers, options.path);
|
|
15
|
+
if (Result.isError(serverResult)) {
|
|
16
|
+
return serverResult;
|
|
17
|
+
}
|
|
18
|
+
const toolsResult = await context.services.mcp.listTools({
|
|
19
|
+
orgSlug: serverResult.value.orgSlug,
|
|
20
|
+
serverPath: serverResult.value.path,
|
|
21
|
+
}, stateResult.value.apiKey);
|
|
22
|
+
if (Result.isError(toolsResult)) {
|
|
23
|
+
return toolsResult;
|
|
24
|
+
}
|
|
25
|
+
return Result.ok({
|
|
26
|
+
server: serverResult.value,
|
|
27
|
+
tools: toolsResult.value,
|
|
28
|
+
});
|
|
29
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
import { Result } from "better-result";
|
|
3
|
+
import { UnexpectedError } from "../shared/errors.js";
|
|
4
|
+
export interface BrowserOpener {
|
|
5
|
+
open(url: string): Promise<Result<void, UnexpectedError>>;
|
|
6
|
+
}
|
|
7
|
+
interface BrowserOpenerDeps {
|
|
8
|
+
openFn?: typeof open;
|
|
9
|
+
}
|
|
10
|
+
export declare const createBrowserOpener: (deps?: BrowserOpenerDeps) => BrowserOpener;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/infra/browser.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC;CAC3D;AAED,UAAU,iBAAiB;IACzB,MAAM,CAAC,EAAE,OAAO,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,GAAI,OAAM,iBAAsB,KAAG,aAkBlE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
import { Result } from "better-result";
|
|
3
|
+
import { UnexpectedError } from "../shared/errors.js";
|
|
4
|
+
export const createBrowserOpener = (deps = {}) => {
|
|
5
|
+
const openFn = deps.openFn ?? open;
|
|
6
|
+
return {
|
|
7
|
+
open: async (url) => {
|
|
8
|
+
return Result.tryPromise({
|
|
9
|
+
catch: (cause) => new UnexpectedError({
|
|
10
|
+
cause,
|
|
11
|
+
message: "Failed to open browser for authentication",
|
|
12
|
+
}),
|
|
13
|
+
try: async () => {
|
|
14
|
+
const childProcess = await openFn(url);
|
|
15
|
+
childProcess.unref();
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { Result } from "better-result";
|
|
3
|
+
import { UnexpectedError } from "../shared/errors.js";
|
|
4
|
+
import type { Credentials } from "../shared/types.js";
|
|
5
|
+
export interface CredentialsStore {
|
|
6
|
+
delete(): Result<void, UnexpectedError>;
|
|
7
|
+
load(): Result<Credentials | null, UnexpectedError>;
|
|
8
|
+
save(credentials: Credentials): Result<void, UnexpectedError>;
|
|
9
|
+
}
|
|
10
|
+
interface CredentialsStoreDeps {
|
|
11
|
+
credentialsPath: string;
|
|
12
|
+
configDir: string;
|
|
13
|
+
existsSyncFn?: typeof existsSync;
|
|
14
|
+
lstatSyncFn?: typeof lstatSync;
|
|
15
|
+
mkdirSyncFn?: typeof mkdirSync;
|
|
16
|
+
readFileSyncFn?: typeof readFileSync;
|
|
17
|
+
unlinkSyncFn?: typeof unlinkSync;
|
|
18
|
+
writeFileSyncFn?: typeof writeFileSync;
|
|
19
|
+
}
|
|
20
|
+
export declare const createFileCredentialsStore: (deps: CredentialsStoreDeps) => CredentialsStore;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/infra/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEpG,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACxC,IAAI,IAAI,MAAM,CAAC,WAAW,GAAG,IAAI,EAAE,eAAe,CAAC,CAAC;IACpD,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;CAC/D;AAED,UAAU,oBAAoB;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,UAAU,CAAC;IACjC,WAAW,CAAC,EAAE,OAAO,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,SAAS,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,YAAY,CAAC;IACrC,YAAY,CAAC,EAAE,OAAO,UAAU,CAAC;IACjC,eAAe,CAAC,EAAE,OAAO,aAAa,CAAC;CACxC;AAsCD,eAAO,MAAM,0BAA0B,GAAI,MAAM,oBAAoB,KAAG,gBAyDvE,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { Result } from "better-result";
|
|
3
|
+
import { UnexpectedError } from "../shared/errors.js";
|
|
4
|
+
import { parseWithSchema } from "../shared/guards.js";
|
|
5
|
+
import { credentialsFileSchema } from "../shared/schemas.js";
|
|
6
|
+
const deleteIfExists = (path, existsSyncFn, unlinkSyncFn) => {
|
|
7
|
+
if (existsSyncFn(path)) {
|
|
8
|
+
unlinkSyncFn(path);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const normalizeCredentials = (value) => {
|
|
12
|
+
const parsed = parseWithSchema(credentialsFileSchema, value, "credentials file");
|
|
13
|
+
if (Result.isError(parsed)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (typeof parsed.value.apiKey === "string" && parsed.value.apiKey.length > 0) {
|
|
17
|
+
const credentials = { apiKey: parsed.value.apiKey };
|
|
18
|
+
if (typeof parsed.value.agentName === "string") {
|
|
19
|
+
credentials.agentName = parsed.value.agentName;
|
|
20
|
+
}
|
|
21
|
+
return credentials;
|
|
22
|
+
}
|
|
23
|
+
if (typeof parsed.value.accessToken === "string" && parsed.value.accessToken.length > 0) {
|
|
24
|
+
const credentials = { apiKey: parsed.value.accessToken };
|
|
25
|
+
if (typeof parsed.value.agentName === "string") {
|
|
26
|
+
credentials.agentName = parsed.value.agentName;
|
|
27
|
+
}
|
|
28
|
+
return credentials;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
};
|
|
32
|
+
export const createFileCredentialsStore = (deps) => {
|
|
33
|
+
const existsSyncFn = deps.existsSyncFn ?? existsSync;
|
|
34
|
+
const lstatSyncFn = deps.lstatSyncFn ?? lstatSync;
|
|
35
|
+
const mkdirSyncFn = deps.mkdirSyncFn ?? mkdirSync;
|
|
36
|
+
const readFileSyncFn = deps.readFileSyncFn ?? readFileSync;
|
|
37
|
+
const unlinkSyncFn = deps.unlinkSyncFn ?? unlinkSync;
|
|
38
|
+
const writeFileSyncFn = deps.writeFileSyncFn ?? writeFileSync;
|
|
39
|
+
return {
|
|
40
|
+
delete: () => {
|
|
41
|
+
return Result.try({
|
|
42
|
+
catch: (cause) => new UnexpectedError({ cause, message: "Failed to delete credentials" }),
|
|
43
|
+
try: () => {
|
|
44
|
+
deleteIfExists(deps.credentialsPath, existsSyncFn, unlinkSyncFn);
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
load: () => {
|
|
49
|
+
return Result.try({
|
|
50
|
+
catch: (cause) => new UnexpectedError({ cause, message: "Failed to load credentials" }),
|
|
51
|
+
try: () => {
|
|
52
|
+
if (!existsSyncFn(deps.credentialsPath)) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const raw = readFileSyncFn(deps.credentialsPath, "utf8");
|
|
56
|
+
const parsed = JSON.parse(raw);
|
|
57
|
+
const normalized = normalizeCredentials(parsed);
|
|
58
|
+
if (normalized === null) {
|
|
59
|
+
deleteIfExists(deps.credentialsPath, existsSyncFn, unlinkSyncFn);
|
|
60
|
+
}
|
|
61
|
+
return normalized;
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
save: (credentials) => {
|
|
66
|
+
return Result.try({
|
|
67
|
+
catch: (cause) => new UnexpectedError({ cause, message: "Failed to save credentials" }),
|
|
68
|
+
try: () => {
|
|
69
|
+
mkdirSyncFn(deps.configDir, { recursive: true });
|
|
70
|
+
if (existsSyncFn(deps.credentialsPath) &&
|
|
71
|
+
lstatSyncFn(deps.credentialsPath).isSymbolicLink()) {
|
|
72
|
+
unlinkSyncFn(deps.credentialsPath);
|
|
73
|
+
}
|
|
74
|
+
writeFileSyncFn(deps.credentialsPath, JSON.stringify(credentials, null, 2), {
|
|
75
|
+
mode: 0o600,
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface RuntimeConfig {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
configDir: string;
|
|
4
|
+
credentialsPath: string;
|
|
5
|
+
envApiKey: string | undefined;
|
|
6
|
+
version: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const createRuntimeConfig: (env?: NodeJS.ProcessEnv, homeDirectory?: string) => RuntimeConfig;
|
|
9
|
+
export declare const isInteractiveOutput: (stdout?: NodeJS.WriteStream) => boolean;
|
|
10
|
+
export declare const detectExecutionEnvironment: (env?: NodeJS.ProcessEnv) => string;
|
|
11
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/infra/env.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,mBAAmB,GAC9B,MAAK,MAAM,CAAC,UAAwB,EACpC,gBAAe,MAAkB,KAChC,aAUF,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,SAAQ,MAAM,CAAC,WAA4B,KAAG,OAEjF,CAAC;AA+BF,eAAO,MAAM,0BAA0B,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,MA+DjF,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { DEFAULT_OGMENT_BASE_URL, VERSION } from "../shared/constants.js";
|
|
5
|
+
export const createRuntimeConfig = (env = process.env, homeDirectory = homedir()) => {
|
|
6
|
+
const configDir = join(homeDirectory, ".config", "ogment");
|
|
7
|
+
return {
|
|
8
|
+
baseUrl: env["OGMENT_BASE_URL"] ?? DEFAULT_OGMENT_BASE_URL,
|
|
9
|
+
configDir,
|
|
10
|
+
credentialsPath: join(configDir, "credentials.json"),
|
|
11
|
+
envApiKey: env["OGMENT_API_KEY"],
|
|
12
|
+
version: VERSION,
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export const isInteractiveOutput = (stdout = process.stdout) => {
|
|
16
|
+
return Boolean(stdout.isTTY);
|
|
17
|
+
};
|
|
18
|
+
const getAncestorProcesses = () => {
|
|
19
|
+
try {
|
|
20
|
+
let pid = process.ppid;
|
|
21
|
+
const ancestors = [];
|
|
22
|
+
for (let depth = 0; depth < 5; depth += 1) {
|
|
23
|
+
const command = execSync(`ps -p ${pid} -o comm=`, { timeout: 500 }).toString().trim().split("/").pop() ??
|
|
24
|
+
"";
|
|
25
|
+
if (command.length === 0) {
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
ancestors.push(command);
|
|
29
|
+
const parentPid = execSync(`ps -p ${pid} -o ppid=`, { timeout: 500 }).toString().trim();
|
|
30
|
+
if (parentPid.length === 0 || parentPid === "0" || parentPid === "1") {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
pid = Number(parentPid);
|
|
34
|
+
}
|
|
35
|
+
return ancestors;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export const detectExecutionEnvironment = (env = process.env) => {
|
|
42
|
+
if (env["CURSOR_TRACE_ID"] !== undefined || env["CURSOR_SESSION_ID"] !== undefined) {
|
|
43
|
+
return "Cursor";
|
|
44
|
+
}
|
|
45
|
+
if (env["VSCODE_PID"] !== undefined || env["VSCODE_IPC_HOOK"] !== undefined) {
|
|
46
|
+
return "VS Code";
|
|
47
|
+
}
|
|
48
|
+
if (env["WINDSURF_SESSION_ID"] !== undefined) {
|
|
49
|
+
return "Windsurf";
|
|
50
|
+
}
|
|
51
|
+
if (typeof env["JETBRAINS_IDE"] === "string" && env["JETBRAINS_IDE"].length > 0) {
|
|
52
|
+
return env["JETBRAINS_IDE"];
|
|
53
|
+
}
|
|
54
|
+
if (env["CLAUDE_CODE_DISABLE_TELEMETRY"] !== undefined ||
|
|
55
|
+
env["CLAUDE_CODE_MAX_TOKENS"] !== undefined ||
|
|
56
|
+
env["CLAUDE_CODE_AUTO_APPROVE"] !== undefined) {
|
|
57
|
+
return "Claude Code";
|
|
58
|
+
}
|
|
59
|
+
if (env["CI"] !== undefined) {
|
|
60
|
+
return "CI";
|
|
61
|
+
}
|
|
62
|
+
const ancestors = getAncestorProcesses();
|
|
63
|
+
const ancestorNames = ancestors.join(" ").toLowerCase();
|
|
64
|
+
if (ancestorNames.includes("claude")) {
|
|
65
|
+
return "Claude Code";
|
|
66
|
+
}
|
|
67
|
+
if (ancestorNames.includes("codex")) {
|
|
68
|
+
return "Codex";
|
|
69
|
+
}
|
|
70
|
+
if (ancestorNames.includes("cursor")) {
|
|
71
|
+
return "Cursor";
|
|
72
|
+
}
|
|
73
|
+
if (ancestorNames.includes("windsurf")) {
|
|
74
|
+
return "Windsurf";
|
|
75
|
+
}
|
|
76
|
+
if (ancestorNames.includes("warp")) {
|
|
77
|
+
return "Warp";
|
|
78
|
+
}
|
|
79
|
+
if (ancestors.some((value) => value.toLowerCase() === "code")) {
|
|
80
|
+
return "VS Code";
|
|
81
|
+
}
|
|
82
|
+
if (env["TERM_PROGRAM"] === "iTerm.app") {
|
|
83
|
+
return "iTerm";
|
|
84
|
+
}
|
|
85
|
+
if (env["TERM_PROGRAM"] === "Apple_Terminal") {
|
|
86
|
+
return "Terminal.app";
|
|
87
|
+
}
|
|
88
|
+
if (env["TERM_PROGRAM"] === "WezTerm") {
|
|
89
|
+
return "WezTerm";
|
|
90
|
+
}
|
|
91
|
+
if (env["TERM_PROGRAM"] === "Hyper") {
|
|
92
|
+
return "Hyper";
|
|
93
|
+
}
|
|
94
|
+
if (typeof env["TERM_PROGRAM"] === "string" && env["TERM_PROGRAM"].length > 0) {
|
|
95
|
+
return env["TERM_PROGRAM"];
|
|
96
|
+
}
|
|
97
|
+
return "unknown";
|
|
98
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Result } from "better-result";
|
|
2
|
+
import { RemoteRequestError } from "../shared/errors.js";
|
|
3
|
+
export interface HttpClient {
|
|
4
|
+
request(input: RequestInfo | URL, init?: RequestInit): Promise<Result<Response, RemoteRequestError>>;
|
|
5
|
+
}
|
|
6
|
+
interface HttpClientDeps {
|
|
7
|
+
fetchFn?: typeof fetch;
|
|
8
|
+
}
|
|
9
|
+
export declare const createHttpClient: (deps?: HttpClientDeps) => HttpClient;
|
|
10
|
+
export declare const readResponseText: (response: Response) => Promise<string>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Result } from "better-result";
|
|
2
|
+
import { RemoteRequestError } from "../shared/errors.js";
|
|
3
|
+
export const createHttpClient = (deps = {}) => {
|
|
4
|
+
const fetchFn = deps.fetchFn ?? fetch;
|
|
5
|
+
return {
|
|
6
|
+
request: async (input, init) => {
|
|
7
|
+
return Result.tryPromise({
|
|
8
|
+
catch: (cause) => new RemoteRequestError({
|
|
9
|
+
body: JSON.stringify({ cause }),
|
|
10
|
+
message: "HTTP request failed",
|
|
11
|
+
}),
|
|
12
|
+
try: async () => fetchFn(input, init),
|
|
13
|
+
});
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export const readResponseText = async (response) => {
|
|
18
|
+
return Result.tryPromise({
|
|
19
|
+
catch: () => "",
|
|
20
|
+
try: async () => response.text(),
|
|
21
|
+
}).then((result) => {
|
|
22
|
+
if (Result.isError(result)) {
|
|
23
|
+
return "";
|
|
24
|
+
}
|
|
25
|
+
return result.value;
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AppError } from "../shared/errors.js";
|
|
2
|
+
export type OutputMode = "human" | "json" | "quiet";
|
|
3
|
+
export interface OutputInitOptions {
|
|
4
|
+
json: boolean | undefined;
|
|
5
|
+
nonInteractive: boolean | undefined;
|
|
6
|
+
quiet: boolean | undefined;
|
|
7
|
+
yes: boolean | undefined;
|
|
8
|
+
}
|
|
9
|
+
interface WritableLike {
|
|
10
|
+
write(chunk: string): boolean;
|
|
11
|
+
}
|
|
12
|
+
interface OutputManagerDeps {
|
|
13
|
+
isTty?: boolean;
|
|
14
|
+
noColor?: boolean;
|
|
15
|
+
stderr?: WritableLike;
|
|
16
|
+
stdout?: WritableLike;
|
|
17
|
+
}
|
|
18
|
+
export declare class OutputManager {
|
|
19
|
+
#private;
|
|
20
|
+
constructor(deps?: OutputManagerDeps);
|
|
21
|
+
configure(options: OutputInitOptions): void;
|
|
22
|
+
get mode(): OutputMode;
|
|
23
|
+
get nonInteractive(): boolean;
|
|
24
|
+
error(error: AppError): void;
|
|
25
|
+
info(message: string): void;
|
|
26
|
+
json(value: unknown): void;
|
|
27
|
+
success(data: unknown, humanMessage?: string): void;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +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;AAEpD,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,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,YAAY;IACpB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED,UAAU,iBAAiB;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAMD,qBAAa,aAAa;;gBAOL,IAAI,GAAE,iBAAsB;IASxC,SAAS,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAWlD,IAAW,IAAI,IAAI,UAAU,CAE5B;IAED,IAAW,cAAc,IAAI,OAAO,CAEnC;IAEM,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAsB5B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ3B,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI1B,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;CAwB3D"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const toJson = (value) => {
|
|
2
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
3
|
+
};
|
|
4
|
+
export class OutputManager {
|
|
5
|
+
#isTty;
|
|
6
|
+
#mode;
|
|
7
|
+
#nonInteractive = false;
|
|
8
|
+
#stderr;
|
|
9
|
+
#stdout;
|
|
10
|
+
constructor(deps = {}) {
|
|
11
|
+
this.#isTty = deps.isTty ?? Boolean(process.stdout.isTTY);
|
|
12
|
+
this.#stderr = deps.stderr ?? process.stderr;
|
|
13
|
+
this.#stdout = deps.stdout ?? process.stdout;
|
|
14
|
+
const colorDisabled = deps.noColor ?? process.env["NO_COLOR"] !== undefined;
|
|
15
|
+
this.#mode = this.#isTty && !colorDisabled ? "human" : "quiet";
|
|
16
|
+
}
|
|
17
|
+
configure(options) {
|
|
18
|
+
if (options.json === true) {
|
|
19
|
+
this.#mode = "json";
|
|
20
|
+
}
|
|
21
|
+
else if (options.quiet === true) {
|
|
22
|
+
this.#mode = "quiet";
|
|
23
|
+
}
|
|
24
|
+
this.#nonInteractive =
|
|
25
|
+
options.nonInteractive === true || options.yes === true || this.#isTty === false;
|
|
26
|
+
}
|
|
27
|
+
get mode() {
|
|
28
|
+
return this.#mode;
|
|
29
|
+
}
|
|
30
|
+
get nonInteractive() {
|
|
31
|
+
return this.#nonInteractive;
|
|
32
|
+
}
|
|
33
|
+
error(error) {
|
|
34
|
+
const payload = {
|
|
35
|
+
error: {
|
|
36
|
+
details: "details" in error ? error.details : undefined,
|
|
37
|
+
message: error.message,
|
|
38
|
+
type: error._tag,
|
|
39
|
+
},
|
|
40
|
+
status: "error",
|
|
41
|
+
};
|
|
42
|
+
if (this.#mode === "json") {
|
|
43
|
+
this.#stdout.write(toJson(payload));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (this.#mode === "quiet") {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.#stderr.write(`${error.message}\n`);
|
|
50
|
+
}
|
|
51
|
+
info(message) {
|
|
52
|
+
if (this.#mode !== "human") {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.#stdout.write(`${message}\n`);
|
|
56
|
+
}
|
|
57
|
+
json(value) {
|
|
58
|
+
this.#stdout.write(toJson(value));
|
|
59
|
+
}
|
|
60
|
+
success(data, humanMessage) {
|
|
61
|
+
if (this.#mode === "json") {
|
|
62
|
+
this.#stdout.write(toJson({
|
|
63
|
+
data,
|
|
64
|
+
status: "success",
|
|
65
|
+
}));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (this.#mode === "quiet") {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (typeof humanMessage === "string" && humanMessage.length > 0) {
|
|
72
|
+
this.#stdout.write(`${humanMessage}\n`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (typeof data === "string" && data.length > 0) {
|
|
76
|
+
this.#stdout.write(`${data}\n`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Result as ResultType } from "better-result";
|
|
2
|
+
import type { HttpClient } from "../infra/http.js";
|
|
3
|
+
import { AuthError, RemoteRequestError, type ValidationError } from "../shared/errors.js";
|
|
4
|
+
import type { AccountProfile, ServerWithOrg } from "../shared/types.js";
|
|
5
|
+
export type FetchAccountError = AuthError | RemoteRequestError | ValidationError;
|
|
6
|
+
export interface AccountService {
|
|
7
|
+
fetchAccount(apiKey: string): Promise<ResultType<AccountProfile, FetchAccountError>>;
|
|
8
|
+
listServers(apiKey: string): Promise<ResultType<ServerWithOrg[], FetchAccountError>>;
|
|
9
|
+
}
|
|
10
|
+
interface AccountServiceDeps {
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
httpClient: HttpClient;
|
|
13
|
+
}
|
|
14
|
+
export declare const createAccountService: (deps: AccountServiceDeps) => AccountService;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=account.d.ts.map
|
|
@@ -0,0 +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;AAEnD,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,cAyE/D,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Result } from "better-result";
|
|
2
|
+
import { readResponseText } from "../infra/http.js";
|
|
3
|
+
import { AuthError, RemoteRequestError } from "../shared/errors.js";
|
|
4
|
+
import { parseWithSchema } from "../shared/guards.js";
|
|
5
|
+
import { accountMeSchema } from "../shared/schemas.js";
|
|
6
|
+
const authHeader = (apiKey) => {
|
|
7
|
+
return {
|
|
8
|
+
Authorization: `Bearer ${apiKey}`,
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export const createAccountService = (deps) => {
|
|
12
|
+
const fetchAccount = async (apiKey) => {
|
|
13
|
+
const responseResult = await deps.httpClient.request(`${deps.baseUrl}/api/v1/mcp-auth/me`, {
|
|
14
|
+
headers: authHeader(apiKey),
|
|
15
|
+
});
|
|
16
|
+
if (Result.isError(responseResult)) {
|
|
17
|
+
return responseResult;
|
|
18
|
+
}
|
|
19
|
+
if (!responseResult.value.ok) {
|
|
20
|
+
if (responseResult.value.status === 401) {
|
|
21
|
+
return Result.err(new AuthError({
|
|
22
|
+
message: "Authentication failed. Run `ogment login` again.",
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
const body = await readResponseText(responseResult.value);
|
|
26
|
+
return Result.err(new RemoteRequestError({
|
|
27
|
+
body,
|
|
28
|
+
message: "Failed to fetch account details",
|
|
29
|
+
status: responseResult.value.status,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
const jsonResult = await Result.tryPromise({
|
|
33
|
+
catch: () => new RemoteRequestError({
|
|
34
|
+
message: "Failed to parse account response JSON",
|
|
35
|
+
status: responseResult.value.status,
|
|
36
|
+
}),
|
|
37
|
+
try: async () => responseResult.value.json(),
|
|
38
|
+
});
|
|
39
|
+
if (Result.isError(jsonResult)) {
|
|
40
|
+
return jsonResult;
|
|
41
|
+
}
|
|
42
|
+
const parsed = parseWithSchema(accountMeSchema, jsonResult.value, "account response");
|
|
43
|
+
if (Result.isError(parsed)) {
|
|
44
|
+
return parsed;
|
|
45
|
+
}
|
|
46
|
+
return Result.ok(parsed.value.data);
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
fetchAccount,
|
|
50
|
+
listServers: async (apiKey) => {
|
|
51
|
+
const profileResult = await fetchAccount(apiKey);
|
|
52
|
+
if (Result.isError(profileResult)) {
|
|
53
|
+
return profileResult;
|
|
54
|
+
}
|
|
55
|
+
const servers = profileResult.value.orgs.flatMap((organization) => {
|
|
56
|
+
return organization.servers.map((server) => {
|
|
57
|
+
return {
|
|
58
|
+
...server,
|
|
59
|
+
orgSlug: organization.orgSlug,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
return Result.ok(servers);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
};
|