@amerged/ohmyhost-mcp 0.1.27 → 0.1.29
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 +1 -1
- package/THIRD_PARTY_NOTICES.md +1419 -0
- package/dist/{chunk-QF7MOXLY.js → chunk-BWVBJWRR.js} +69 -23
- package/dist/index.js +1 -1
- package/dist/stdio-main.js +24158 -2353
- package/package.json +1 -1
- package/src/apps/mcp/package.json +1 -1
- package/src/apps/mcp/src/local-client.ts +12 -2
- package/src/apps/mcp/src/local-server.ts +333 -4
- package/src/apps/product-cli/package.json +4 -2
- package/src/apps/product-cli/src/cli.ts +312 -2
- package/src/apps/product-cli/src/command.ts +261 -0
- package/src/apps/product-cli/src/composition.ts +74 -4
- package/src/apps/product-cli/src/index.ts +6 -0
- package/src/apps/product-cli/src/product-api.ts +5 -0
- package/src/apps/product-cli/src/project-link-store.ts +92 -1
- package/src/apps/product-cli/src/repository-init.ts +12 -0
- package/src/apps/product-cli/src/runtime-contract.ts +34 -1
- package/src/apps/product-cli/src/source-managed-client.ts +189 -0
- package/src/apps/product-cli/src/source-publication-store.ts +563 -0
- package/src/apps/product-cli/src/source-publisher.ts +195 -0
- package/src/apps/product-cli/src/source-workspace.ts +552 -0
- package/src/packages/agent-skills/src/generated-skill-resources.ts +20 -10
- package/src/packages/agent-skills/src/index.ts +1 -1
- package/src/packages/contracts/package.json +10 -0
- package/src/packages/contracts/src/index.ts +5 -0
- package/src/packages/contracts/src/managed-sources.ts +582 -0
- package/src/packages/contracts/src/mcp-source-codec.ts +150 -0
- package/src/packages/contracts/src/operation-failure.ts +22 -6
- package/src/packages/contracts/src/problem-policy.ts +68 -14
- package/src/packages/sdk-ts/package.json +1 -1
- package/src/packages/sdk-ts/src/generated/index.ts +92 -0
- package/src/packages/sdk-ts/src/generated/sdk.gen.ts +541 -0
- package/src/packages/sdk-ts/src/generated/types.gen.ts +912 -4
- package/src/packages/workos-auth-contracts/src/tokens.ts +61 -4
package/package.json
CHANGED
|
@@ -105,6 +105,7 @@ import {
|
|
|
105
105
|
type OhMyHostClient,
|
|
106
106
|
type Operation,
|
|
107
107
|
type OperationEvent,
|
|
108
|
+
type ProjectSource,
|
|
108
109
|
} from "@ohmyhost/sdk-ts";
|
|
109
110
|
|
|
110
111
|
import type {
|
|
@@ -128,6 +129,7 @@ import {
|
|
|
128
129
|
parsePaidDomainPlan,
|
|
129
130
|
parseOperation,
|
|
130
131
|
parseProjectDataChangePlan,
|
|
132
|
+
parseProjectSource,
|
|
131
133
|
parseAccountProfile,
|
|
132
134
|
parseCurrentIdentity,
|
|
133
135
|
chooseWorkspace,
|
|
@@ -136,6 +138,8 @@ import {
|
|
|
136
138
|
selectWorkspace,
|
|
137
139
|
InteractiveSessionRequiredError,
|
|
138
140
|
NativeKeyringProfileRegistry,
|
|
141
|
+
GeneratedSdkManagedSourceApi,
|
|
142
|
+
type ManagedSourceApi,
|
|
139
143
|
type AuthenticatedProductApiOverrides,
|
|
140
144
|
type EffectiveContext,
|
|
141
145
|
type LocalProfile,
|
|
@@ -205,6 +209,8 @@ export async function createAuthenticatedLocalMcpClient(
|
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
212
|
+
public readonly managedSource: ManagedSourceApi;
|
|
213
|
+
public readonly productApiOrigin: string;
|
|
208
214
|
#client: OhMyHostClient;
|
|
209
215
|
|
|
210
216
|
#workspace: WorkspaceSession | undefined;
|
|
@@ -225,6 +231,8 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
|
225
231
|
) {
|
|
226
232
|
this.#rescope = (token) => createClient({ auth: token, baseUrl, fetch, throwOnError: true });
|
|
227
233
|
this.#client = this.#rescope(accessToken);
|
|
234
|
+
this.productApiOrigin = baseUrl;
|
|
235
|
+
this.managedSource = new GeneratedSdkManagedSourceApi(() => this.#client);
|
|
228
236
|
this.#workspace = workspace;
|
|
229
237
|
this.#context = context ?? {
|
|
230
238
|
credential: workspace === undefined ? "environment_token" : "profile",
|
|
@@ -811,8 +819,10 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
|
811
819
|
{ client: this.#client },
|
|
812
820
|
);
|
|
813
821
|
}
|
|
814
|
-
public getSource(projectId: string) {
|
|
815
|
-
|
|
822
|
+
public async getSource(projectId: string): Promise<ProjectSource> {
|
|
823
|
+
const source = await getProjectSource({ project_id: projectId }, { client: this.#client });
|
|
824
|
+
if (source !== null) parseProjectSource(source);
|
|
825
|
+
return source as ProjectSource;
|
|
816
826
|
}
|
|
817
827
|
public async getOperation(operationId: string): Promise<Operation> {
|
|
818
828
|
return parseOperation(
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { isUserSecretName, USER_SECRET_NAME_PATTERN } from "@ohmyhost/contracts/secret-names";
|
|
2
|
+
import {
|
|
3
|
+
normalizeMcpSourceChanges,
|
|
4
|
+
formatMcpSourceFileResponse,
|
|
5
|
+
McpSourceChangesInputError,
|
|
6
|
+
} from "@ohmyhost/contracts/mcp-source-codec";
|
|
2
7
|
import type { ManagedMailCommand } from "@ohmyhost/sdk-ts";
|
|
8
|
+
import {
|
|
9
|
+
parseManagedSourceRequest,
|
|
10
|
+
isManagedSourcePath,
|
|
11
|
+
} from "@ohmyhost/contracts/managed-sources";
|
|
12
|
+
import {
|
|
13
|
+
createSourceSnapshot,
|
|
14
|
+
inspectSourceWorkspace,
|
|
15
|
+
publishSourceSnapshot,
|
|
16
|
+
SourceWorkspaceError,
|
|
17
|
+
type ManagedSourceApi,
|
|
18
|
+
prepareLocalSourcePublication,
|
|
19
|
+
completeLocalSourcePublication,
|
|
20
|
+
inspectLocalSourcePublications,
|
|
21
|
+
LocalSourcePublicationError,
|
|
22
|
+
} from "@ohmyhost/product-cli";
|
|
3
23
|
import mcpPackage from "../package.json" with { type: "json" };
|
|
4
24
|
import { SavedLoginCredentialError } from "./local-client.js";
|
|
5
25
|
import {
|
|
@@ -57,6 +77,8 @@ import type {
|
|
|
57
77
|
} from "@ohmyhost/sdk-ts";
|
|
58
78
|
|
|
59
79
|
export interface LocalMcpProductClient {
|
|
80
|
+
readonly managedSource?: ManagedSourceApi;
|
|
81
|
+
readonly productApiOrigin?: string;
|
|
60
82
|
checkProjectHandle(input: { handle: string }): Promise<unknown>;
|
|
61
83
|
changeProjectHandle(input: {
|
|
62
84
|
projectId: string;
|
|
@@ -449,13 +471,42 @@ const deletableSecretName = z
|
|
|
449
471
|
);
|
|
450
472
|
|
|
451
473
|
const LOCAL_SERVER_INSTRUCTIONS =
|
|
452
|
-
"Operate the user's ohmyho.st hosting account: projects, GitHub deployments, databases, domains, mail, usage and budgets. " +
|
|
474
|
+
"Operate the user's ohmyho.st hosting account: projects, managed or GitHub sources and deployments, databases, domains, mail, usage and budgets. " +
|
|
475
|
+
"Use the existing project source binding first. A local or cloud workspace can contain Git without GitHub. If unbound current files have no relevant GitHub source, ask once whether to deploy directly with ohmyho.st saving versions or set up GitHub; do not require GitHub just because no connection exists. " +
|
|
453
476
|
"Start by reading the resource skill://ohmyhost/ohmyhost-get-started/SKILL.md and calling identity_get; read project_context_get before acting on a project. " +
|
|
454
477
|
"This server is also ohmyho.st support: report a bug, issue or feature request with feedback_submit, give the user the receipt ID and follow up with feedback_status (https://docs.ohmyho.st/support).";
|
|
455
478
|
|
|
456
479
|
export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDependencies) {
|
|
457
480
|
const { commandPrefix } = resolveProductCliEnvironment(dependencies.environment);
|
|
458
481
|
const server = createOhmyhostMcpServer("ohmyhost-local", LOCAL_SERVER_INSTRUCTIONS);
|
|
482
|
+
server.registerTool(
|
|
483
|
+
"source_inspect",
|
|
484
|
+
{
|
|
485
|
+
title: "Inspect local application source",
|
|
486
|
+
description:
|
|
487
|
+
"Read local working-directory, Git/worktree, monorepo and sanitized remote context without sign-in. This tool exists only in local MCP and never proves repository authorization. No source files or history are uploaded.",
|
|
488
|
+
inputSchema: z.object({ directory: z.string().min(1).max(4096).default(".") }),
|
|
489
|
+
annotations: readAnnotations(),
|
|
490
|
+
},
|
|
491
|
+
async (input) => {
|
|
492
|
+
try {
|
|
493
|
+
return toolResult({
|
|
494
|
+
...(await inspectSourceWorkspace(input.directory)),
|
|
495
|
+
pending_publications: await inspectLocalSourcePublications(input.directory),
|
|
496
|
+
});
|
|
497
|
+
} catch (error) {
|
|
498
|
+
if (error instanceof SourceWorkspaceError)
|
|
499
|
+
return {
|
|
500
|
+
...toolResult({
|
|
501
|
+
error: { code: error.code, retryable: false, suggested_action: error.message },
|
|
502
|
+
}),
|
|
503
|
+
isError: true,
|
|
504
|
+
};
|
|
505
|
+
return toolError(error, dependencies);
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
);
|
|
509
|
+
registerManagedSourceTools(server, dependencies);
|
|
459
510
|
registerProductTool(
|
|
460
511
|
server,
|
|
461
512
|
dependencies,
|
|
@@ -1355,9 +1406,14 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
|
|
|
1355
1406
|
server,
|
|
1356
1407
|
dependencies,
|
|
1357
1408
|
"source_get",
|
|
1358
|
-
"Get linked source status",
|
|
1359
|
-
z.object({ project_id: identifier }),
|
|
1360
|
-
(client, input) =>
|
|
1409
|
+
"Get linked source status. Set include_binding to true to read the source connection ID and generation before managed changes or an explicit source switch.",
|
|
1410
|
+
z.object({ project_id: identifier, include_binding: z.boolean().default(false) }),
|
|
1411
|
+
(client, input) => {
|
|
1412
|
+
if (input.include_binding !== true) return client.getSource(input.project_id);
|
|
1413
|
+
if (client.managedSource === undefined)
|
|
1414
|
+
throw new Error("Managed source client is unavailable");
|
|
1415
|
+
return client.managedSource.getSource(input.project_id);
|
|
1416
|
+
},
|
|
1361
1417
|
);
|
|
1362
1418
|
registerProductTool(
|
|
1363
1419
|
server,
|
|
@@ -1831,6 +1887,258 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
|
|
|
1831
1887
|
return server;
|
|
1832
1888
|
}
|
|
1833
1889
|
|
|
1890
|
+
function registerManagedSourceTools(
|
|
1891
|
+
server: McpServer,
|
|
1892
|
+
dependencies: LocalOhmyhostMcpDependencies,
|
|
1893
|
+
): void {
|
|
1894
|
+
const generation = z.number().int().min(0).max(2147483646);
|
|
1895
|
+
const path = z.string().refine(isManagedSourcePath);
|
|
1896
|
+
const message = z.string().min(1).max(200);
|
|
1897
|
+
const parent = {
|
|
1898
|
+
project_id: identifier,
|
|
1899
|
+
expected_source_generation: generation,
|
|
1900
|
+
expected_commit_sha: commitSha.nullable(),
|
|
1901
|
+
message,
|
|
1902
|
+
idempotency_key: idempotencyKey,
|
|
1903
|
+
};
|
|
1904
|
+
const port = (client: LocalMcpProductClient): ManagedSourceApi => {
|
|
1905
|
+
if (client.managedSource === undefined) throw new Error("Managed source client is unavailable");
|
|
1906
|
+
return client.managedSource;
|
|
1907
|
+
};
|
|
1908
|
+
registerProductTool(
|
|
1909
|
+
server,
|
|
1910
|
+
dependencies,
|
|
1911
|
+
"source_initialize",
|
|
1912
|
+
"Create managed version history for an unbound project. Normal blank chat uses vite-react; existing local files use source_publish instead. Returns an asynchronous operation; poll operation_get and source_get with include_binding true before planning the resulting commit. Does not publish an application.",
|
|
1913
|
+
z.object({
|
|
1914
|
+
project_id: identifier,
|
|
1915
|
+
template: z.enum(["empty", "vite-react"]).default("vite-react"),
|
|
1916
|
+
expected_source_generation: generation,
|
|
1917
|
+
idempotency_key: idempotencyKey,
|
|
1918
|
+
}),
|
|
1919
|
+
(client, input) =>
|
|
1920
|
+
port(client).initialize({
|
|
1921
|
+
projectId: input.project_id,
|
|
1922
|
+
idempotencyKey: input.idempotency_key,
|
|
1923
|
+
body: parseManagedSourceRequest("initialize", {
|
|
1924
|
+
template: input.template,
|
|
1925
|
+
expected_source_generation: input.expected_source_generation,
|
|
1926
|
+
}),
|
|
1927
|
+
}),
|
|
1928
|
+
mutationAnnotations(),
|
|
1929
|
+
);
|
|
1930
|
+
registerProductTool(
|
|
1931
|
+
server,
|
|
1932
|
+
dependencies,
|
|
1933
|
+
"source_files",
|
|
1934
|
+
"List the exact managed source tree at a version; omit commit_sha to read current main. Read source_get with include_binding true before changing files and keep the generation and commit for concurrency checks.",
|
|
1935
|
+
z.object({ project_id: identifier, commit_sha: commitSha.optional() }),
|
|
1936
|
+
(client, input) =>
|
|
1937
|
+
port(client).files({ projectId: input.project_id, commitSha: input.commit_sha }),
|
|
1938
|
+
);
|
|
1939
|
+
registerProductTool(
|
|
1940
|
+
server,
|
|
1941
|
+
dependencies,
|
|
1942
|
+
"source_file",
|
|
1943
|
+
"Read one managed source file with its exact hash and mode. UTF-8 content_text is the default; binary files retain content_base64 with guidance. Use format base64 for legacy byte payloads, and keep the executable flag when replacing a file.",
|
|
1944
|
+
z.object({
|
|
1945
|
+
project_id: identifier,
|
|
1946
|
+
path,
|
|
1947
|
+
commit_sha: commitSha.optional(),
|
|
1948
|
+
format: z.enum(["text", "base64"]).default("text"),
|
|
1949
|
+
}),
|
|
1950
|
+
async (client, input) =>
|
|
1951
|
+
formatMcpSourceFileResponse(
|
|
1952
|
+
await port(client).files({
|
|
1953
|
+
projectId: input.project_id,
|
|
1954
|
+
path: input.path,
|
|
1955
|
+
commitSha: input.commit_sha,
|
|
1956
|
+
}),
|
|
1957
|
+
input.format,
|
|
1958
|
+
),
|
|
1959
|
+
);
|
|
1960
|
+
registerProductTool(
|
|
1961
|
+
server,
|
|
1962
|
+
dependencies,
|
|
1963
|
+
"source_versions",
|
|
1964
|
+
"Read managed version history for this project; next_commit_sha continues the same history page.",
|
|
1965
|
+
z.object({
|
|
1966
|
+
project_id: identifier,
|
|
1967
|
+
limit: z.number().int().min(1).max(100).default(50),
|
|
1968
|
+
before_commit_sha: commitSha.optional(),
|
|
1969
|
+
}),
|
|
1970
|
+
(client, input) =>
|
|
1971
|
+
port(client).versions({
|
|
1972
|
+
projectId: input.project_id,
|
|
1973
|
+
limit: input.limit,
|
|
1974
|
+
beforeCommitSha: input.before_commit_sha,
|
|
1975
|
+
}),
|
|
1976
|
+
);
|
|
1977
|
+
registerProductTool(
|
|
1978
|
+
server,
|
|
1979
|
+
dependencies,
|
|
1980
|
+
"source_diff",
|
|
1981
|
+
"Compare two managed versions without changing files or deployments.",
|
|
1982
|
+
z.object({ project_id: identifier, from_commit_sha: commitSha, to_commit_sha: commitSha }),
|
|
1983
|
+
(client, input) =>
|
|
1984
|
+
port(client).diff({
|
|
1985
|
+
projectId: input.project_id,
|
|
1986
|
+
fromCommitSha: input.from_commit_sha,
|
|
1987
|
+
toCommitSha: input.to_commit_sha,
|
|
1988
|
+
}),
|
|
1989
|
+
);
|
|
1990
|
+
registerProductTool(
|
|
1991
|
+
server,
|
|
1992
|
+
dependencies,
|
|
1993
|
+
"source_changes",
|
|
1994
|
+
"Save an atomic file batch against the generation and parent commit you read. Each file takes exactly one UTF-8 content_text or binary/legacy content_base64; null content_base64 deletes it. Keep executable flags. A conflict requires reading the new version; publication is separate.",
|
|
1995
|
+
z.object({
|
|
1996
|
+
...parent,
|
|
1997
|
+
changes: z
|
|
1998
|
+
.array(
|
|
1999
|
+
z
|
|
2000
|
+
.object({
|
|
2001
|
+
path,
|
|
2002
|
+
content_text: z
|
|
2003
|
+
.string()
|
|
2004
|
+
.max(2 * 1024 * 1024)
|
|
2005
|
+
.optional(),
|
|
2006
|
+
content_base64: z.string().max(2_796_204).nullable().optional(),
|
|
2007
|
+
executable: z.boolean().default(false),
|
|
2008
|
+
})
|
|
2009
|
+
.strict(),
|
|
2010
|
+
)
|
|
2011
|
+
.min(1)
|
|
2012
|
+
.max(2000),
|
|
2013
|
+
}),
|
|
2014
|
+
(client, input) =>
|
|
2015
|
+
port(client).changes({
|
|
2016
|
+
projectId: input.project_id,
|
|
2017
|
+
idempotencyKey: input.idempotency_key,
|
|
2018
|
+
body: normalizeMcpSourceChanges({
|
|
2019
|
+
expected_source_generation: input.expected_source_generation,
|
|
2020
|
+
expected_commit_sha: input.expected_commit_sha,
|
|
2021
|
+
message: input.message,
|
|
2022
|
+
changes: input.changes,
|
|
2023
|
+
}),
|
|
2024
|
+
}),
|
|
2025
|
+
mutationAnnotations(),
|
|
2026
|
+
);
|
|
2027
|
+
registerProductTool(
|
|
2028
|
+
server,
|
|
2029
|
+
dependencies,
|
|
2030
|
+
"source_restore",
|
|
2031
|
+
"Restore an earlier managed file tree as a new version against current generation and parent. This preserves history and does not automatically deploy or revert database data.",
|
|
2032
|
+
z.object({ ...parent, restore_commit_sha: commitSha }),
|
|
2033
|
+
(client, input) =>
|
|
2034
|
+
port(client).restore({
|
|
2035
|
+
projectId: input.project_id,
|
|
2036
|
+
idempotencyKey: input.idempotency_key,
|
|
2037
|
+
body: parseManagedSourceRequest("restore", {
|
|
2038
|
+
expected_source_generation: input.expected_source_generation,
|
|
2039
|
+
expected_commit_sha: input.expected_commit_sha,
|
|
2040
|
+
message: input.message,
|
|
2041
|
+
restore_commit_sha: input.restore_commit_sha,
|
|
2042
|
+
}),
|
|
2043
|
+
}),
|
|
2044
|
+
mutationAnnotations(),
|
|
2045
|
+
);
|
|
2046
|
+
registerProductTool(
|
|
2047
|
+
server,
|
|
2048
|
+
dependencies,
|
|
2049
|
+
"source_publish",
|
|
2050
|
+
"Local MCP only: capture current filtered files, including uncommitted/new files, and save one managed version without importing Git history. Use initialize for unbound source, commit for managed source, or explicit switch for the current GitHub project's move to managed; project URL and data stay with that project. Honors nested ignore rules and excludes credentials, links, dependencies and generated output. Rejects symlinks and changing files. Reuse the key after uncertainty and observe the upload before any new attempt; publication is a separate deployment action.",
|
|
2051
|
+
z.object({
|
|
2052
|
+
...parent,
|
|
2053
|
+
expected_commit_sha: commitSha.nullable().optional(),
|
|
2054
|
+
directory: z.string().min(1).max(4096).default("."),
|
|
2055
|
+
mode: z.enum(["initialize", "commit", "switch"]),
|
|
2056
|
+
expected_source_connection_id: identifier.nullable(),
|
|
2057
|
+
}),
|
|
2058
|
+
async (client, input, signal) => {
|
|
2059
|
+
const current = await client.getCurrentIdentity(signal);
|
|
2060
|
+
const snapshot = await createSourceSnapshot({ directory: input.directory });
|
|
2061
|
+
const request = parseManagedSourceRequest("upload", {
|
|
2062
|
+
expected_source_generation: input.expected_source_generation,
|
|
2063
|
+
expected_commit_sha: input.expected_commit_sha ?? null,
|
|
2064
|
+
expected_source_connection_id: input.expected_source_connection_id,
|
|
2065
|
+
mode: input.mode,
|
|
2066
|
+
message: input.message,
|
|
2067
|
+
});
|
|
2068
|
+
const prepared = await prepareLocalSourcePublication({
|
|
2069
|
+
directory: input.directory,
|
|
2070
|
+
metadataDirectory: resolveProductCliEnvironment(dependencies.environment).linkDirectory,
|
|
2071
|
+
apiOrigin:
|
|
2072
|
+
client.productApiOrigin ??
|
|
2073
|
+
resolveProductCliEnvironment(dependencies.environment).apiOrigin,
|
|
2074
|
+
identity: { actor_id: current.actor_id, organization_ids: current.organization_ids },
|
|
2075
|
+
projectId: input.project_id,
|
|
2076
|
+
request,
|
|
2077
|
+
explicitExpectedCommit: input.expected_commit_sha !== undefined,
|
|
2078
|
+
snapshotSha256: snapshot.sha256,
|
|
2079
|
+
idempotencyKey: input.idempotency_key,
|
|
2080
|
+
});
|
|
2081
|
+
const result = await publishSourceSnapshot({
|
|
2082
|
+
api: port(client),
|
|
2083
|
+
projectId: input.project_id,
|
|
2084
|
+
snapshot,
|
|
2085
|
+
idempotencyKey: input.idempotency_key,
|
|
2086
|
+
signal,
|
|
2087
|
+
request: prepared.request,
|
|
2088
|
+
accepted: prepared.accepted,
|
|
2089
|
+
rejected: prepared.rejected,
|
|
2090
|
+
});
|
|
2091
|
+
return {
|
|
2092
|
+
...result,
|
|
2093
|
+
snapshot: {
|
|
2094
|
+
sha256: snapshot.sha256,
|
|
2095
|
+
total_bytes: snapshot.totalBytes,
|
|
2096
|
+
files: snapshot.files.length,
|
|
2097
|
+
},
|
|
2098
|
+
next_action:
|
|
2099
|
+
"Poll operation_get, then call source_publish_complete with the same directory, project, operation and login to confirm this directory's base. Do not ask the user again.",
|
|
2100
|
+
};
|
|
2101
|
+
},
|
|
2102
|
+
mutationAnnotations(),
|
|
2103
|
+
);
|
|
2104
|
+
registerProductTool(
|
|
2105
|
+
server,
|
|
2106
|
+
dependencies,
|
|
2107
|
+
"source_publish_complete",
|
|
2108
|
+
"Complete a local pending source publication after polling its operation. Uses the owner-only directory record and verified login, checks the exact confirmed source manifest, and stores that operation's commit as this directory's base even when another chat has advanced main. Never reads a fresh remote head as the local base. No files are uploaded and no deployment starts.",
|
|
2109
|
+
z.object({
|
|
2110
|
+
project_id: identifier,
|
|
2111
|
+
directory: z.string().min(1).max(4096).default("."),
|
|
2112
|
+
operation_id: identifier.optional(),
|
|
2113
|
+
}),
|
|
2114
|
+
async (client, input, signal) => {
|
|
2115
|
+
const current = await client.getCurrentIdentity(signal);
|
|
2116
|
+
return completeLocalSourcePublication({
|
|
2117
|
+
directory: input.directory,
|
|
2118
|
+
metadataDirectory: resolveProductCliEnvironment(dependencies.environment).linkDirectory,
|
|
2119
|
+
apiOrigin:
|
|
2120
|
+
client.productApiOrigin ??
|
|
2121
|
+
resolveProductCliEnvironment(dependencies.environment).apiOrigin,
|
|
2122
|
+
identity: { actor_id: current.actor_id, organization_ids: current.organization_ids },
|
|
2123
|
+
projectId: input.project_id,
|
|
2124
|
+
operationId: input.operation_id,
|
|
2125
|
+
api: port(client),
|
|
2126
|
+
getOperation: (id) => client.getOperation(id),
|
|
2127
|
+
});
|
|
2128
|
+
},
|
|
2129
|
+
mutationAnnotations(),
|
|
2130
|
+
);
|
|
2131
|
+
registerProductTool(
|
|
2132
|
+
server,
|
|
2133
|
+
dependencies,
|
|
2134
|
+
"source_upload",
|
|
2135
|
+
"Observe the exact managed snapshot upload after an uncertain response. sealed and committed uploads must not be uploaded again; commit_sha identifies the saved version.",
|
|
2136
|
+
z.object({ project_id: identifier, operation_id: identifier }),
|
|
2137
|
+
(client, input) =>
|
|
2138
|
+
port(client).getUpload({ projectId: input.project_id, operationId: input.operation_id }),
|
|
2139
|
+
);
|
|
2140
|
+
}
|
|
2141
|
+
|
|
1834
2142
|
export const createLocalOhmyhostMcpHandler = (dependencies: LocalOhmyhostMcpDependencies) =>
|
|
1835
2143
|
createMcpHandler(() => createLocalOhmyhostMcpServer(dependencies));
|
|
1836
2144
|
|
|
@@ -1997,6 +2305,27 @@ function toolError(
|
|
|
1997
2305
|
* problem. What no branch recognizes is reported as such, never as a guessed cause.
|
|
1998
2306
|
*/
|
|
1999
2307
|
function safeFailure(error: unknown, commandPrefix: string): SafeFailure {
|
|
2308
|
+
if (error instanceof McpSourceChangesInputError)
|
|
2309
|
+
return {
|
|
2310
|
+
code: "invalid_request",
|
|
2311
|
+
retryable: false,
|
|
2312
|
+
suggestedAction:
|
|
2313
|
+
"Provide exactly one content_text or content_base64 per file, within the 2 MiB source limits. Use null content_base64 to delete a file.",
|
|
2314
|
+
};
|
|
2315
|
+
if (error instanceof LocalSourcePublicationError)
|
|
2316
|
+
return {
|
|
2317
|
+
code: error.code,
|
|
2318
|
+
retryable: error.code === "source_publication_pending",
|
|
2319
|
+
suggestedAction:
|
|
2320
|
+
error.message +
|
|
2321
|
+
(error.operation === undefined ? "" : ` Read operation_get ${error.operation.id}.`),
|
|
2322
|
+
};
|
|
2323
|
+
if (error instanceof SourceWorkspaceError)
|
|
2324
|
+
return {
|
|
2325
|
+
code: error.code,
|
|
2326
|
+
retryable: error.code === "source_snapshot_changed",
|
|
2327
|
+
suggestedAction: error.message,
|
|
2328
|
+
};
|
|
2000
2329
|
if (error instanceof UserTokenFileError)
|
|
2001
2330
|
return { code: error.code, retryable: false, suggestedAction: error.message };
|
|
2002
2331
|
if (error instanceof DOMException && error.name === "TimeoutError")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ohmyhost/product-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.29",
|
|
4
4
|
"private": true,
|
|
5
5
|
"ohmyhost": {
|
|
6
6
|
"deployment": "production",
|
|
@@ -39,7 +39,9 @@
|
|
|
39
39
|
"@napi-rs/keyring": "1.3.0",
|
|
40
40
|
"@ohmyhost/contracts": "workspace:*",
|
|
41
41
|
"@ohmyhost/sdk-ts": "workspace:*",
|
|
42
|
-
"@ohmyhost/workos-auth-contracts": "workspace:*"
|
|
42
|
+
"@ohmyhost/workos-auth-contracts": "workspace:*",
|
|
43
|
+
"ignore": "7.0.12",
|
|
44
|
+
"isomorphic-git": "1.43.0"
|
|
43
45
|
},
|
|
44
46
|
"license": "Apache-2.0"
|
|
45
47
|
}
|