@amerged/ohmyhost-mcp 0.1.14 → 0.1.17
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/dist/{chunk-S2LJAGEP.js → chunk-SVJRXROG.js} +10 -10
- package/dist/index.js +1 -1
- package/dist/stdio-main.js +216 -16
- package/package.json +1 -1
- package/src/apps/mcp/local-client.ts +56 -1
- package/src/apps/mcp/local-server.ts +110 -9
- package/src/apps/product-cli/cli.ts +89 -10
- package/src/apps/product-cli/command.ts +135 -10
- package/src/apps/product-cli/composition.ts +47 -3
- package/src/apps/product-cli/index.ts +1 -0
- package/src/apps/product-cli/product-api.ts +55 -1
- package/src/apps/product-cli/project-link-store.ts +45 -2
- package/src/apps/product-cli/repository-init.ts +2 -1
- package/src/apps/product-cli/runtime-contract.ts +56 -3
- package/src/packages/agent-skills/generated-skill-resources.ts +9 -9
- package/src/packages/sdk-ts/generated/index.ts +33 -0
- package/src/packages/sdk-ts/generated/sdk.gen.ts +241 -3
- package/src/packages/sdk-ts/generated/types.gen.ts +337 -10
- package/src/packages/sdk-ts/managed-mail-response.ts +7 -0
- package/src/packages/sdk-ts/managed-mail.ts +7 -1
package/dist/index.js
CHANGED
package/dist/stdio-main.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
serverIdentityOf,
|
|
27
27
|
setNegotiatedProtocolVersion,
|
|
28
28
|
validateEnvelopeMeta
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-SVJRXROG.js";
|
|
30
30
|
|
|
31
31
|
// node_modules/.pnpm/@modelcontextprotocol+server@2.0.0/node_modules/@modelcontextprotocol/server/dist/stdio.mjs
|
|
32
32
|
var StdioServerTransport = class {
|
|
@@ -799,7 +799,7 @@ function exact2(v, keys) {
|
|
|
799
799
|
// apps/product-cli/package.json
|
|
800
800
|
var package_default = {
|
|
801
801
|
name: "@ohmyhost/product-cli",
|
|
802
|
-
version: "0.1.
|
|
802
|
+
version: "0.1.17",
|
|
803
803
|
private: true,
|
|
804
804
|
ohmyhost: {
|
|
805
805
|
deployment: "production",
|
|
@@ -1571,7 +1571,7 @@ var PROBLEM_POLICY = {
|
|
|
1571
1571
|
cloudflare_zone_not_bound: {
|
|
1572
1572
|
status: 409,
|
|
1573
1573
|
retryable: false,
|
|
1574
|
-
action: "Configure the project domain first with 'ohmyhost domain paid plan' then 'ohmyhost domain paid apply', or configure its sender domain with 'ohmyhost mail
|
|
1574
|
+
action: "Configure the project domain first with 'ohmyhost domain paid plan' then 'ohmyhost domain paid apply', or configure its sender domain with 'ohmyhost mail setup'. Then request Cloudflare authorization for that domain's zone."
|
|
1575
1575
|
},
|
|
1576
1576
|
github_connection_required: {
|
|
1577
1577
|
status: 409,
|
|
@@ -1726,6 +1726,11 @@ var PROBLEM_POLICY = {
|
|
|
1726
1726
|
retryable: false,
|
|
1727
1727
|
action: "Select the current succeeded dev deployment and target prod."
|
|
1728
1728
|
},
|
|
1729
|
+
mail_capacity_unavailable: {
|
|
1730
|
+
status: 503,
|
|
1731
|
+
retryable: true,
|
|
1732
|
+
action: "Report this request ID through feedback. The stored mail setup continues automatically once ohmyho.st has capacity; follow mail status and keep the original idempotency key."
|
|
1733
|
+
},
|
|
1729
1734
|
mail_domain_conflict: {
|
|
1730
1735
|
status: 409,
|
|
1731
1736
|
retryable: false,
|
|
@@ -1734,13 +1739,23 @@ var PROBLEM_POLICY = {
|
|
|
1734
1739
|
mail_domain_required: {
|
|
1735
1740
|
status: 409,
|
|
1736
1741
|
retryable: false,
|
|
1737
|
-
action: "
|
|
1742
|
+
action: "This app declares mail.enabled. Configure the project's own sender domain with 'ohmyhost mail setup' using its Prod environment ID, or set mail.enabled to false if the app sends no mail, then plan again."
|
|
1738
1743
|
},
|
|
1739
1744
|
storage_jurisdiction_conflict: {
|
|
1740
1745
|
status: 409,
|
|
1741
1746
|
retryable: false,
|
|
1742
1747
|
action: "Set storage.jurisdiction in ohmyhost.yaml to the project's hosting region shown by project status, then plan again."
|
|
1743
1748
|
},
|
|
1749
|
+
shared_data_requires_promotion: {
|
|
1750
|
+
status: 409,
|
|
1751
|
+
retryable: false,
|
|
1752
|
+
action: "Plan and deploy this commit to Dev, then run 'ohmyhost deployment promote plan' to reach Prod."
|
|
1753
|
+
},
|
|
1754
|
+
production_deployment_required: {
|
|
1755
|
+
status: 409,
|
|
1756
|
+
retryable: false,
|
|
1757
|
+
action: "Deploy to Prod first: run 'ohmyhost plan --environment prod' and deploy that plan, or promote the current Dev deployment with 'ohmyhost deployment promote plan'. Then plan the domain again."
|
|
1758
|
+
},
|
|
1744
1759
|
framework_conversion_required: {
|
|
1745
1760
|
status: 409,
|
|
1746
1761
|
retryable: false,
|
|
@@ -1888,6 +1903,12 @@ var parseCloudflareDnsAuthorizationStatus = (value) => {
|
|
|
1888
1903
|
}
|
|
1889
1904
|
return input;
|
|
1890
1905
|
};
|
|
1906
|
+
var parseDevAccessState = (value) => {
|
|
1907
|
+
const input = exactRecord2(value, ["project_id", "mode", "share_url"]);
|
|
1908
|
+
if (!isUlid(input["project_id"]) || input["mode"] !== "protected" && input["mode"] !== "public" || input["mode"] === "public" && input["share_url"] !== null || input["share_url"] !== null && (typeof input["share_url"] !== "string" || !/^https:\/\/dev-[a-z0-9]+(?:-[a-z0-9]+){0,4}\.(?:dev\.)?check\.omh\.st\/\.ohmyhost\/dev-access\/redeem\?stage=dev&ticket=[A-Za-z0-9_-]{43}$/u.test(input["share_url"])))
|
|
1909
|
+
throw new ResponseContractError();
|
|
1910
|
+
return input;
|
|
1911
|
+
};
|
|
1891
1912
|
var parseDevAccessTicket = (value) => {
|
|
1892
1913
|
const input = exactRecord2(value, [
|
|
1893
1914
|
"ticket_id",
|
|
@@ -1966,8 +1987,10 @@ var parseSafeProblem = (value) => {
|
|
|
1966
1987
|
const retryAfter = input["retry_after_seconds"];
|
|
1967
1988
|
if (retryAfter !== void 0 && (code !== "rate_limited" || typeof retryAfter !== "number" || !Number.isSafeInteger(retryAfter) || retryAfter < 1 || retryAfter > 86400))
|
|
1968
1989
|
throw new ResponseContractError();
|
|
1990
|
+
const docsUrl = String(input["type"]);
|
|
1969
1991
|
return {
|
|
1970
1992
|
requestId: input["request_id"],
|
|
1993
|
+
...docsUrl.startsWith("https://docs.ohmyho.st/errors/") ? { docsUrl } : {},
|
|
1971
1994
|
code,
|
|
1972
1995
|
retryable: policy.retryable,
|
|
1973
1996
|
suggestedAction: (code === "framework_conversion_required" ? parseFrameworkConversionDetail(input["detail"]) ?? policy.action : policy.action) + (retryAfter === void 0 ? "" : ` Retry after ${String(retryAfter)} seconds.`),
|
|
@@ -2137,12 +2160,16 @@ var HELP_USAGE = Object.freeze({
|
|
|
2137
2160
|
"token list": "ohmyhost token list --organization ULID [--after KEY_ID] --json",
|
|
2138
2161
|
"token revoke": "ohmyhost token revoke --organization ULID --key KEY_ID --yes --json",
|
|
2139
2162
|
"feedback submit": "ohmyhost feedback submit --organization ULID --kind bug|issue|feature_request --title TITLE --description REDACTED_REPORT [--project ULID] [--environment ULID] [--operation ULID] [--error-code CODE] [--client-version VERSION] --idempotency-key KEY --json",
|
|
2140
|
-
"project create": "ohmyhost project create --organization ULID --name NAME [--data-mode shared|isolated] [--region us|eu] --idempotency-key KEY --json (the region is chosen once: us is the default, eu places the database, files and builds in the EU; it cannot be changed later)",
|
|
2163
|
+
"project create": "ohmyhost project create --organization ULID --name NAME [--data-mode shared|isolated] [--dev-access-mode protected|public] [--region us|eu] --idempotency-key KEY --json (the region is chosen once: us is the default, eu places the database, files and builds in the EU; it cannot be changed later)",
|
|
2141
2164
|
"project list": "ohmyhost project list [--cursor ULID] [--limit LIMIT] --json",
|
|
2142
2165
|
"project context": "ohmyhost project context --project ULID --json",
|
|
2143
2166
|
"project notes set": "ohmyhost project notes set --project ULID --version NUMBER --markdown TEXT --idempotency-key KEY --json (no credentials or signed URLs)",
|
|
2144
2167
|
"project status": "ohmyhost project status --project ULID --json",
|
|
2145
2168
|
"project dev-access create": "ohmyhost project dev-access create --project ULID --json",
|
|
2169
|
+
"project dev-share link": "ohmyhost project dev-share link --project ULID --json",
|
|
2170
|
+
"project dev-share rotate": "ohmyhost project dev-share rotate --project ULID --idempotency-key KEY --yes --json",
|
|
2171
|
+
"project dev-share revoke": "ohmyhost project dev-share revoke --project ULID --idempotency-key KEY --yes --json",
|
|
2172
|
+
"project dev-access mode": "ohmyhost project dev-access mode --project ULID --mode protected|public --idempotency-key KEY --yes --json",
|
|
2146
2173
|
"project handle check": "ohmyhost project handle check --handle HANDLE --json (is this address free? answers with a reason and free alternatives; the address becomes HANDLE.check.omh.st)",
|
|
2147
2174
|
"project handle set": "ohmyhost project handle set --project ULID --handle HANDLE --if-match ETAG --idempotency-key KEY --json (moves the project to a free address; the old one stops working and anyone may claim it)",
|
|
2148
2175
|
"database compute set": "ohmyhost database compute set --project ULID --environment dev|prod --profile standard|performance --idempotency-key KEY --yes [--wait] --json\n standard: Free 0.25 CU/1 GB/60s idle, Paid 0.5 CU/2 GB/60s idle. performance: Paid 1 CU/4 GB/300s idle, 2.5x database compute credits per equal active minute; longer idle time also consumes credits.",
|
|
@@ -2163,8 +2190,8 @@ var HELP_USAGE = Object.freeze({
|
|
|
2163
2190
|
"domain paid apply": "ohmyhost domain paid apply --project ULID --hostname HOST --idempotency-key KEY --yes --json",
|
|
2164
2191
|
"domain paid status": "ohmyhost domain paid status --project ULID --json",
|
|
2165
2192
|
"domain paid delete": "ohmyhost domain paid delete --project ULID --hostname HOST --idempotency-key KEY --yes --json",
|
|
2166
|
-
plan: "ohmyhost plan --project ULID --commit SHA --json",
|
|
2167
|
-
deploy: "ohmyhost deploy --project ULID --plan-id ULID --idempotency-key KEY --yes [--wait] --json",
|
|
2193
|
+
plan: "ohmyhost plan --project ULID --commit SHA [--environment dev|prod] --json",
|
|
2194
|
+
deploy: "ohmyhost deploy --project ULID (--plan-id ULID | --commit SHA [--environment dev|prod]) --idempotency-key KEY --yes [--wait] --json",
|
|
2168
2195
|
logs: "ohmyhost logs OPERATION_ULID --follow --json",
|
|
2169
2196
|
"deployment logs": "ohmyhost deployment logs --project ULID --deployment ULID --follow --json",
|
|
2170
2197
|
"rollback plan": "ohmyhost rollback plan --project ULID --deployment DEPLOYMENT_ULID --json",
|
|
@@ -2186,7 +2213,8 @@ var HELP_USAGE = Object.freeze({
|
|
|
2186
2213
|
"mail messages get": "ohmyhost mail messages get --project ULID --environment ULID --message ULID --json",
|
|
2187
2214
|
"mail messages retry": "ohmyhost mail messages retry --project ULID --environment ULID --message ULID --idempotency-key KEY --json",
|
|
2188
2215
|
"mail domain set": "ohmyhost mail domain set --project ULID --environment ULID --domain DOMAIN --sending true --receiving false --idempotency-key KEY --json",
|
|
2189
|
-
"mail domain status": "ohmyhost mail domain status --project ULID --environment ULID --json"
|
|
2216
|
+
"mail domain status": "ohmyhost mail domain status --project ULID --environment ULID --json",
|
|
2217
|
+
"mail domain delete": "ohmyhost mail domain delete --project ULID --environment ULID --idempotency-key KEY --yes --json"
|
|
2190
2218
|
});
|
|
2191
2219
|
var HELP_COMMANDS = Object.freeze(Object.entries(HELP_USAGE).map(([command, usage]) => Object.freeze({ command, usage })));
|
|
2192
2220
|
var SIGN_IN_WINDOW_MS = 30 * 60 * 1e3;
|
|
@@ -3584,6 +3612,83 @@ var getProjectHandleAvailability = (parameters, options) => {
|
|
|
3584
3612
|
...params
|
|
3585
3613
|
});
|
|
3586
3614
|
};
|
|
3615
|
+
var revokeProjectDevShareLink = (parameters, options) => {
|
|
3616
|
+
const params = buildClientParams([parameters], [
|
|
3617
|
+
{
|
|
3618
|
+
args: [
|
|
3619
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
3620
|
+
{ in: "headers", key: "Idempotency-Key" },
|
|
3621
|
+
{ in: "path", key: "project_id" }
|
|
3622
|
+
]
|
|
3623
|
+
}
|
|
3624
|
+
]);
|
|
3625
|
+
return (options?.client ?? client).delete({
|
|
3626
|
+
responseStyle: "data",
|
|
3627
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
3628
|
+
url: "/v1/projects/{project_id}/dev-share-link",
|
|
3629
|
+
...options,
|
|
3630
|
+
...params
|
|
3631
|
+
});
|
|
3632
|
+
};
|
|
3633
|
+
var ensureProjectDevShareLink = (parameters, options) => {
|
|
3634
|
+
const params = buildClientParams([parameters], [
|
|
3635
|
+
{
|
|
3636
|
+
args: [
|
|
3637
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
3638
|
+
{ in: "path", key: "project_id" }
|
|
3639
|
+
]
|
|
3640
|
+
}
|
|
3641
|
+
]);
|
|
3642
|
+
return (options?.client ?? client).post({
|
|
3643
|
+
responseStyle: "data",
|
|
3644
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
3645
|
+
url: "/v1/projects/{project_id}/dev-share-link",
|
|
3646
|
+
...options,
|
|
3647
|
+
...params
|
|
3648
|
+
});
|
|
3649
|
+
};
|
|
3650
|
+
var rotateProjectDevShareLink = (parameters, options) => {
|
|
3651
|
+
const params = buildClientParams([parameters], [
|
|
3652
|
+
{
|
|
3653
|
+
args: [
|
|
3654
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
3655
|
+
{ in: "headers", key: "Idempotency-Key" },
|
|
3656
|
+
{ in: "path", key: "project_id" }
|
|
3657
|
+
]
|
|
3658
|
+
}
|
|
3659
|
+
]);
|
|
3660
|
+
return (options?.client ?? client).post({
|
|
3661
|
+
responseStyle: "data",
|
|
3662
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
3663
|
+
url: "/v1/projects/{project_id}/dev-share-link:rotate",
|
|
3664
|
+
...options,
|
|
3665
|
+
...params
|
|
3666
|
+
});
|
|
3667
|
+
};
|
|
3668
|
+
var setProjectDevAccessMode = (parameters, options) => {
|
|
3669
|
+
const params = buildClientParams([parameters], [
|
|
3670
|
+
{
|
|
3671
|
+
args: [
|
|
3672
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
3673
|
+
{ in: "headers", key: "Idempotency-Key" },
|
|
3674
|
+
{ in: "path", key: "project_id" },
|
|
3675
|
+
{ key: "setDevAccessModeRequest", map: "body" }
|
|
3676
|
+
]
|
|
3677
|
+
}
|
|
3678
|
+
]);
|
|
3679
|
+
return (options?.client ?? client).put({
|
|
3680
|
+
responseStyle: "data",
|
|
3681
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
3682
|
+
url: "/v1/projects/{project_id}/dev-access-mode",
|
|
3683
|
+
...options,
|
|
3684
|
+
...params,
|
|
3685
|
+
headers: {
|
|
3686
|
+
"Content-Type": "application/json",
|
|
3687
|
+
...options?.headers,
|
|
3688
|
+
...params.headers
|
|
3689
|
+
}
|
|
3690
|
+
});
|
|
3691
|
+
};
|
|
3587
3692
|
var createProjectDevAccessTicket = (parameters, options) => {
|
|
3588
3693
|
const params = buildClientParams([parameters], [
|
|
3589
3694
|
{
|
|
@@ -4254,6 +4359,25 @@ var streamOperationEvents = (parameters, options) => {
|
|
|
4254
4359
|
...params
|
|
4255
4360
|
});
|
|
4256
4361
|
};
|
|
4362
|
+
var deleteManagedMailDomain = (parameters, options) => {
|
|
4363
|
+
const params = buildClientParams([parameters], [
|
|
4364
|
+
{
|
|
4365
|
+
args: [
|
|
4366
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
4367
|
+
{ in: "headers", key: "Idempotency-Key" },
|
|
4368
|
+
{ in: "path", key: "project_id" },
|
|
4369
|
+
{ in: "path", key: "environment_id" }
|
|
4370
|
+
]
|
|
4371
|
+
}
|
|
4372
|
+
]);
|
|
4373
|
+
return (options?.client ?? client).delete({
|
|
4374
|
+
responseStyle: "data",
|
|
4375
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
4376
|
+
url: "/v1/projects/{project_id}/environments/{environment_id}/mail-domain",
|
|
4377
|
+
...options,
|
|
4378
|
+
...params
|
|
4379
|
+
});
|
|
4380
|
+
};
|
|
4257
4381
|
var getManagedMailDomain = (parameters, options) => {
|
|
4258
4382
|
const params = buildClientParams([parameters], [
|
|
4259
4383
|
{
|
|
@@ -4480,6 +4604,14 @@ function assertManagedMailResponse(value, input) {
|
|
|
4480
4604
|
invalid3();
|
|
4481
4605
|
return;
|
|
4482
4606
|
}
|
|
4607
|
+
if (input.action === "domain_delete") {
|
|
4608
|
+
exact3(r, ["status", "domain", "dns_records"]);
|
|
4609
|
+
if (r["status"] !== "deleted")
|
|
4610
|
+
invalid3();
|
|
4611
|
+
domain(r["domain"]);
|
|
4612
|
+
records(r["dns_records"]);
|
|
4613
|
+
return;
|
|
4614
|
+
}
|
|
4483
4615
|
if (input.action === "messages_list") {
|
|
4484
4616
|
exact3(r, ["items"]);
|
|
4485
4617
|
if (!Array.isArray(r["items"]) || r["items"].length > 50)
|
|
@@ -4608,6 +4740,8 @@ function requestManagedMail(client2, input) {
|
|
|
4608
4740
|
return verifyManagedMailWebhook({ ...scope, "Idempotency-Key": input.idempotencyKey }, { client: client2 });
|
|
4609
4741
|
case "webhook_disable":
|
|
4610
4742
|
return disableManagedMailReceiving({ ...scope, "Idempotency-Key": input.idempotencyKey }, { client: client2 });
|
|
4743
|
+
case "domain_delete":
|
|
4744
|
+
return deleteManagedMailDomain({ ...scope, "Idempotency-Key": input.idempotencyKey }, { client: client2 });
|
|
4611
4745
|
case "messages_list":
|
|
4612
4746
|
return listManagedMailMessages({ ...scope, ...input.after ? { after: input.after } : {} }, { client: client2 });
|
|
4613
4747
|
case "message_get":
|
|
@@ -5204,6 +5338,25 @@ var GeneratedSdkLocalMcpClient = class {
|
|
|
5204
5338
|
getProject(projectId) {
|
|
5205
5339
|
return getProject({ project_id: projectId }, { client: this.#client });
|
|
5206
5340
|
}
|
|
5341
|
+
async ensureDevShareLink(projectId) {
|
|
5342
|
+
const result = parseDevAccessState(await ensureProjectDevShareLink({ project_id: projectId }, { client: this.#client }));
|
|
5343
|
+
if (result.project_id !== projectId)
|
|
5344
|
+
throw new TypeError("Unexpected Dev share project");
|
|
5345
|
+
return result;
|
|
5346
|
+
}
|
|
5347
|
+
async setDevAccessMode(input) {
|
|
5348
|
+
return parseDevAccessState(await setProjectDevAccessMode({
|
|
5349
|
+
project_id: input.projectId,
|
|
5350
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
5351
|
+
setDevAccessModeRequest: { mode: input.mode }
|
|
5352
|
+
}, { client: this.#client }));
|
|
5353
|
+
}
|
|
5354
|
+
async rotateDevShareLink(input) {
|
|
5355
|
+
return parseDevAccessState(await rotateProjectDevShareLink({ project_id: input.projectId, "Idempotency-Key": input.idempotencyKey }, { client: this.#client }));
|
|
5356
|
+
}
|
|
5357
|
+
async revokeDevShareLink(input) {
|
|
5358
|
+
return parseDevAccessState(await revokeProjectDevShareLink({ project_id: input.projectId, "Idempotency-Key": input.idempotencyKey }, { client: this.#client }));
|
|
5359
|
+
}
|
|
5207
5360
|
async createDevAccessTicket(projectId) {
|
|
5208
5361
|
const ticket = parseDevAccessTicket(await createProjectDevAccessTicket({ project_id: projectId }, { client: this.#client }));
|
|
5209
5362
|
if (ticket.project_id !== projectId)
|
|
@@ -5314,6 +5467,7 @@ var GeneratedSdkLocalMcpClient = class {
|
|
|
5314
5467
|
organization_id: input.organizationId,
|
|
5315
5468
|
name: input.name,
|
|
5316
5469
|
...input.dataMode === void 0 ? {} : { data_mode: input.dataMode },
|
|
5470
|
+
...input.devAccessMode === void 0 ? {} : { dev_access_mode: input.devAccessMode },
|
|
5317
5471
|
...input.region === void 0 ? {} : { region: input.region }
|
|
5318
5472
|
}
|
|
5319
5473
|
}, { client: this.#client });
|
|
@@ -5339,7 +5493,10 @@ var GeneratedSdkLocalMcpClient = class {
|
|
|
5339
5493
|
}, { client: this.#client });
|
|
5340
5494
|
}
|
|
5341
5495
|
planDeployment(input) {
|
|
5342
|
-
return planDeployment({
|
|
5496
|
+
return planDeployment({
|
|
5497
|
+
project_id: input.projectId,
|
|
5498
|
+
planDeploymentRequest: { commit_sha: input.commitSha, environment: input.environment }
|
|
5499
|
+
}, { client: this.#client });
|
|
5343
5500
|
}
|
|
5344
5501
|
createDeployment(input) {
|
|
5345
5502
|
return createDeployment({
|
|
@@ -5521,8 +5678,8 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
5521
5678
|
idempotencyKey: input.idempotency_key
|
|
5522
5679
|
}), mutationAnnotations());
|
|
5523
5680
|
registerProductTool(server, dependencies, "domain_cloudflare_status", "Read the project's customer DNS authorization state, zone, scopes and expiry without credentials. authorized is not DNS/TLS readiness. For a Paid hostname, use domain_paid_apply with the original hostname/key after consent, then domain_paid_status. If DNS/TLS is pending, tell the customer to ask their agent again after 60 minutes; do not repeat correct records or create another deployment.", external_exports.object({ project_id: identifier2 }), (client2, input) => client2.getCloudflareDnsStatus(input.project_id));
|
|
5524
|
-
registerProductTool(server, dependencies, "domain_paid_plan", "Plan a customer-owned production hostname and return the manual CNAME/validation instructions. This does not activate or change DNS. Free projects use their platform domain without customer DNS authorization.", external_exports.object({ project_id: identifier2, hostname: domainName }), (client2, input) => client2.planPaidDomain({ projectId: input.project_id, hostname: input.hostname }));
|
|
5525
|
-
registerProductTool(server, dependencies, "domain_paid_apply", "Activate the explicitly requested customer hostname. Requires Paid; the backend may reuse only its scoped customer OAuth grant. After domain_cloudflare_status is authorized, replay the original hostname/key to reconcile its exact DNS records. Otherwise return the manual DNS records to the human. Preserve the original hostname/key after uncertainty; no arbitrary DNS or provider credentials are accepted.", external_exports.object({
|
|
5681
|
+
registerProductTool(server, dependencies, "domain_paid_plan", "Plan a customer-owned production hostname and return the manual CNAME/validation instructions. This does not activate or change DNS. Free projects use their platform domain without customer DNS authorization. production_deployment_required means Prod has no active deployment: deploy to Prod or promote the current Dev deployment, then plan again.", external_exports.object({ project_id: identifier2, hostname: domainName }), (client2, input) => client2.planPaidDomain({ projectId: input.project_id, hostname: input.hostname }));
|
|
5682
|
+
registerProductTool(server, dependencies, "domain_paid_apply", "Activate the explicitly requested customer hostname. Requires Paid; the backend may reuse only its scoped customer OAuth grant. After domain_cloudflare_status is authorized, replay the original hostname/key to reconcile its exact DNS records. Otherwise return the manual DNS records to the human. Preserve the original hostname/key after uncertainty; no arbitrary DNS or provider credentials are accepted. production_deployment_required changed nothing: deploy to Prod or promote Dev first, then repeat the same hostname/key.", external_exports.object({
|
|
5526
5683
|
project_id: identifier2,
|
|
5527
5684
|
hostname: domainName,
|
|
5528
5685
|
idempotency_key: idempotencyKey,
|
|
@@ -5751,22 +5908,42 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
5751
5908
|
const { idempotency_key, ...report } = input;
|
|
5752
5909
|
return client2.submitFeedback({ report, idempotencyKey: idempotency_key });
|
|
5753
5910
|
}, mutationAnnotations());
|
|
5754
|
-
registerProductTool(server, dependencies, "project_create", "Create an ohmyho.st project. Recommend isolated Dev/Prod data, but respect the customer's choice and added database consumption. shared is the default and uses one database/file namespace; isolated separates database/Auth records and files. Choose before provisioning; changing the established mode requires a data migration. region defaults to us; eu places the project's database, files and builds in the EU at the same prices. The region cannot be changed later, and ohmyhost.yaml storage.jurisdiction must equal it.", external_exports.object({
|
|
5911
|
+
registerProductTool(server, dependencies, "project_create", "Create an ohmyho.st project. Ask whether Dev should be protected (default) or public before creation; public means anyone with the Dev URL can open it, including when Dev and Prod share data. Recommend isolated Dev/Prod data, but respect the customer's choice and added database consumption. shared is the default and uses one database/file namespace; isolated separates database/Auth records and files. Choose before provisioning; changing the established mode requires a data migration. region defaults to us; eu places the project's database, files and builds in the EU at the same prices. The region cannot be changed later, and ohmyhost.yaml storage.jurisdiction must equal it.", external_exports.object({
|
|
5755
5912
|
organization_id: identifier2,
|
|
5756
5913
|
name: external_exports.string().min(1).max(128),
|
|
5757
5914
|
data_mode: external_exports.enum(["shared", "isolated"]).optional(),
|
|
5915
|
+
dev_access_mode: external_exports.enum(["protected", "public"]).optional(),
|
|
5758
5916
|
region: external_exports.enum(["us", "eu"]).optional(),
|
|
5759
5917
|
idempotency_key: idempotencyKey
|
|
5760
5918
|
}), (client2, input) => client2.createProject({
|
|
5761
5919
|
organizationId: input.organization_id,
|
|
5762
5920
|
name: input.name,
|
|
5763
5921
|
...input.data_mode === void 0 ? {} : { dataMode: input.data_mode },
|
|
5922
|
+
...input.dev_access_mode === void 0 ? {} : { devAccessMode: input.dev_access_mode },
|
|
5764
5923
|
...input.region === void 0 ? {} : { region: input.region },
|
|
5765
5924
|
idempotencyKey: input.idempotency_key
|
|
5766
5925
|
}), mutationAnnotations());
|
|
5767
5926
|
registerProductTool(server, dependencies, "project_get", "Get one project", external_exports.object({ project_id: identifier2 }), (client2, input) => client2.getProject(input.project_id));
|
|
5768
|
-
registerProductTool(server, dependencies, "project_status", "Get source, both Dev/Prod environment IDs, deployment URLs, latest operation and cleanup status. Dev
|
|
5769
|
-
registerProductTool(server, dependencies, "
|
|
5927
|
+
registerProductTool(server, dependencies, "project_status", "Get source, both Dev/Prod environment IDs, deployment URLs, Dev access mode, latest operation and cleanup status. Protected Dev needs project_dev_share_link_get for a persistent share link. Select environments by name when configuring secrets; never infer a Prod ID from the default Dev environment.", external_exports.object({ project_id: identifier2 }), (client2, input) => client2.getProjectStatus(input.project_id));
|
|
5928
|
+
registerProductTool(server, dependencies, "project_dev_share_link_get", "Owner only: get or create the persistent protected Dev link. The same link works for multiple visitors and has no automatic expiry. Keep it out of notes and logs.", external_exports.object({ project_id: identifier2 }), (client2, input) => client2.ensureDevShareLink(input.project_id), mutationAnnotations());
|
|
5929
|
+
registerProductTool(server, dependencies, "project_dev_access_mode_set", "Owner only: choose public Dev (no platform token) or protected Dev (share link required). A switch takes effect on the next request; switching back creates a new link.", external_exports.object({
|
|
5930
|
+
project_id: identifier2,
|
|
5931
|
+
mode: external_exports.enum(["protected", "public"]),
|
|
5932
|
+
idempotency_key: idempotencyKey
|
|
5933
|
+
}), (client2, input) => client2.setDevAccessMode({
|
|
5934
|
+
projectId: input.project_id,
|
|
5935
|
+
mode: input.mode,
|
|
5936
|
+
idempotencyKey: input.idempotency_key
|
|
5937
|
+
}), destructiveAnnotations());
|
|
5938
|
+
registerProductTool(server, dependencies, "project_dev_share_link_rotate", "Owner only: replace the persistent Dev link and immediately revoke old links and sessions. Repeat the same key after uncertainty.", external_exports.object({ project_id: identifier2, idempotency_key: idempotencyKey }), (client2, input) => client2.rotateDevShareLink({
|
|
5939
|
+
projectId: input.project_id,
|
|
5940
|
+
idempotencyKey: input.idempotency_key
|
|
5941
|
+
}), destructiveAnnotations());
|
|
5942
|
+
registerProductTool(server, dependencies, "project_dev_share_link_revoke", "Owner only: revoke the persistent Dev link and active sessions immediately; Dev stays protected until a new link is obtained.", external_exports.object({ project_id: identifier2, idempotency_key: idempotencyKey }), (client2, input) => client2.revokeDevShareLink({
|
|
5943
|
+
projectId: input.project_id,
|
|
5944
|
+
idempotencyKey: input.idempotency_key
|
|
5945
|
+
}), destructiveAnnotations());
|
|
5946
|
+
registerProductTool(server, dependencies, "project_dev_access_create", "Create an owner-only one-hour single-use access link for the protected Dev app. Anonymous Dev HTTP 404 is expected; it does not prove deployment failure. Open redeem_url once in the intended browser or isolated cookie jar, then use the clean origin with its session cookie. Keep the link and cookie private, out of reports, logs and project notes. A new ticket invalidates earlier one-time ticket sessions and unused owner tickets but not the persistent share link; do not blindly retry an uncertain request. This grants no customer application login or Prod access.", external_exports.object({ project_id: identifier2 }), (client2, input) => client2.createDevAccessTicket(input.project_id), { ...mutationAnnotations(), idempotentHint: false });
|
|
5770
5947
|
registerProductTool(server, dependencies, "github_connect", "Owner or Admin: connect GitHub once for this workspace. Give authorization_url to the customer and repeat identical arguments and key to observe completion. One connection covers subsequent source_link calls; no provider token is returned. Failed or expired attempts require a fresh key for this same workspace, never a new project.", external_exports.object({ organization_id: identifier2, idempotency_key: idempotencyKey }), (client2, input) => client2.connectGithub({
|
|
5771
5948
|
organizationId: input.organization_id,
|
|
5772
5949
|
idempotencyKey: input.idempotency_key
|
|
@@ -5784,7 +5961,15 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
5784
5961
|
idempotencyKey: input.idempotency_key
|
|
5785
5962
|
}), mutationAnnotations());
|
|
5786
5963
|
registerProductTool(server, dependencies, "source_get", "Get linked source status", external_exports.object({ project_id: identifier2 }), (client2, input) => client2.getSource(input.project_id));
|
|
5787
|
-
registerProductTool(server, dependencies, "deployment_plan", "Plan an immutable deployment. Preserve the customer's existing authentication integration, such as Better Auth or WorkOS, and use the same generic Next.js/Vite/TanStack runtime contract. ohmyho.st login is separate. Read the app Skill's auth guidance and report actual plan blockers, required secret names/callback configuration and unverified runtime compatibility. Never assume a working platform login proves application login or silently replace its auth provider.
|
|
5964
|
+
registerProductTool(server, dependencies, "deployment_plan", "Plan an immutable deployment. Preserve the customer's existing authentication integration, such as Better Auth or WorkOS, and use the same generic Next.js/Vite/TanStack runtime contract. ohmyho.st login is separate. Read the app Skill's auth guidance and report actual plan blockers, required secret names/callback configuration and unverified runtime compatibility. Hosting, including Better Auth, needs no mail domain unless the app declares mail.enabled. Never assume a working platform login proves application login or silently replace its auth provider. The plan builds into Dev unless environment is prod; prod builds straight into Prod without a Dev deployment (a project with shared data and a database must deploy to Dev and promote instead). The plan stays valid for 24 hours.", external_exports.object({
|
|
5965
|
+
project_id: identifier2,
|
|
5966
|
+
commit_sha: commitSha,
|
|
5967
|
+
environment: external_exports.enum(["dev", "prod"]).optional()
|
|
5968
|
+
}), (client2, input) => client2.planDeployment({
|
|
5969
|
+
projectId: input.project_id,
|
|
5970
|
+
commitSha: input.commit_sha,
|
|
5971
|
+
environment: input.environment ?? "dev"
|
|
5972
|
+
}));
|
|
5788
5973
|
registerProductTool(server, dependencies, "deployment_create", "Start a reviewed deployment plan", external_exports.object({ project_id: identifier2, plan_id: identifier2, idempotency_key: idempotencyKey }), (client2, input) => client2.createDeployment({
|
|
5789
5974
|
projectId: input.project_id,
|
|
5790
5975
|
planId: input.plan_id,
|
|
@@ -5831,7 +6016,7 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
5831
6016
|
operationId: input.operation_id,
|
|
5832
6017
|
idempotencyKey: input.idempotency_key
|
|
5833
6018
|
})), mutationAnnotations());
|
|
5834
|
-
registerProductTool(server, dependencies, "mail_setup", "Configure the customer's one production mail domain using the project Prod environment ID. The Dev and Prod application URLs do not create separate mail domains. Ask whether they want sending and receiving. Configure sending first; receiving requires mail_webhook_set, application signature verification and mail_webhook_verify. Preserve existing mailbox MX records. No Resend account or key is needed.", external_exports.object({
|
|
6019
|
+
registerProductTool(server, dependencies, "mail_setup", "Configure the customer's one production mail domain using the project Prod environment ID, only when the customer wants mail or the app declares mail.enabled; hosting needs no mail domain and none is registered automatically. The Dev and Prod application URLs do not create separate mail domains. Ask whether they want sending and receiving. Configure sending first; receiving requires mail_webhook_set, application signature verification and mail_webhook_verify. Preserve existing mailbox MX records. No Resend account or key is needed.", external_exports.object({
|
|
5835
6020
|
project_id: identifier2,
|
|
5836
6021
|
environment_id: identifier2,
|
|
5837
6022
|
domain: external_exports.string(),
|
|
@@ -5952,6 +6137,21 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
5952
6137
|
environmentId: input.environment_id
|
|
5953
6138
|
});
|
|
5954
6139
|
});
|
|
6140
|
+
registerProductTool(server, dependencies, "mail_domain_delete", "Retire the project's mail domain while the project stays active; use its Prod environment ID. Sending and receiving stop at once, then its provider domain and key are removed. DNS is not changed: remove the returned dns_records from the domain's DNS. Only when the customer no longer wants mail. Requires explicit confirmation; repeat the same key after uncertainty.", external_exports.object({
|
|
6141
|
+
project_id: identifier2,
|
|
6142
|
+
environment_id: identifier2,
|
|
6143
|
+
idempotency_key: idempotencyKey,
|
|
6144
|
+
confirm: external_exports.literal(true)
|
|
6145
|
+
}), async (client2, input) => {
|
|
6146
|
+
if (!client2.managedMail)
|
|
6147
|
+
throw new Error("Mail unavailable");
|
|
6148
|
+
return client2.managedMail({
|
|
6149
|
+
action: "domain_delete",
|
|
6150
|
+
projectId: input.project_id,
|
|
6151
|
+
environmentId: input.environment_id,
|
|
6152
|
+
idempotencyKey: input.idempotency_key
|
|
6153
|
+
});
|
|
6154
|
+
}, destructiveAnnotations());
|
|
5955
6155
|
registerProductTool(server, dependencies, "secrets_list", "List secret metadata without values", external_exports.object({ project_id: identifier2, environment_id: identifier2 }), (client2, input) => client2.listEnvironmentSecrets({
|
|
5956
6156
|
projectId: input.project_id,
|
|
5957
6157
|
environmentId: input.environment_id
|
package/package.json
CHANGED
|
@@ -24,6 +24,10 @@ import {
|
|
|
24
24
|
} from "@ohmyhost/contracts/billing";
|
|
25
25
|
import {
|
|
26
26
|
createProjectDevAccessTicket,
|
|
27
|
+
ensureProjectDevShareLink,
|
|
28
|
+
setProjectDevAccessMode,
|
|
29
|
+
rotateProjectDevShareLink,
|
|
30
|
+
revokeProjectDevShareLink,
|
|
27
31
|
createCloudflareDnsAuthorization,
|
|
28
32
|
getAccountProfile,
|
|
29
33
|
getCloudflareDnsAuthorizationStatus,
|
|
@@ -87,6 +91,7 @@ import {
|
|
|
87
91
|
reconcileOperation,
|
|
88
92
|
streamOperationEvents,
|
|
89
93
|
type DevAccessTicket,
|
|
94
|
+
type DevAccessState,
|
|
90
95
|
type CloudflareDnsAuthorization,
|
|
91
96
|
type CloudflareDnsAuthorizationStatus,
|
|
92
97
|
type OhMyHostClient,
|
|
@@ -104,6 +109,7 @@ import {
|
|
|
104
109
|
prepareUserTokenFile,
|
|
105
110
|
ProductApiAuthenticationError,
|
|
106
111
|
parseDevAccessTicket,
|
|
112
|
+
parseDevAccessState,
|
|
107
113
|
parseCloudflareDnsAuthorization,
|
|
108
114
|
parseCloudflareDnsAuthorizationStatus,
|
|
109
115
|
parsePaidDomain,
|
|
@@ -507,6 +513,51 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
|
507
513
|
public getProject(projectId: string) {
|
|
508
514
|
return getProject({ project_id: projectId }, { client: this.#client });
|
|
509
515
|
}
|
|
516
|
+
public async ensureDevShareLink(projectId: string): Promise<DevAccessState> {
|
|
517
|
+
const result = parseDevAccessState(
|
|
518
|
+
await ensureProjectDevShareLink({ project_id: projectId }, { client: this.#client }),
|
|
519
|
+
);
|
|
520
|
+
if (result.project_id !== projectId) throw new TypeError("Unexpected Dev share project");
|
|
521
|
+
return result;
|
|
522
|
+
}
|
|
523
|
+
public async setDevAccessMode(input: {
|
|
524
|
+
projectId: string;
|
|
525
|
+
mode: "protected" | "public";
|
|
526
|
+
idempotencyKey: string;
|
|
527
|
+
}): Promise<DevAccessState> {
|
|
528
|
+
return parseDevAccessState(
|
|
529
|
+
await setProjectDevAccessMode(
|
|
530
|
+
{
|
|
531
|
+
project_id: input.projectId,
|
|
532
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
533
|
+
setDevAccessModeRequest: { mode: input.mode },
|
|
534
|
+
},
|
|
535
|
+
{ client: this.#client },
|
|
536
|
+
),
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
public async rotateDevShareLink(input: {
|
|
540
|
+
projectId: string;
|
|
541
|
+
idempotencyKey: string;
|
|
542
|
+
}): Promise<DevAccessState> {
|
|
543
|
+
return parseDevAccessState(
|
|
544
|
+
await rotateProjectDevShareLink(
|
|
545
|
+
{ project_id: input.projectId, "Idempotency-Key": input.idempotencyKey },
|
|
546
|
+
{ client: this.#client },
|
|
547
|
+
),
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
public async revokeDevShareLink(input: {
|
|
551
|
+
projectId: string;
|
|
552
|
+
idempotencyKey: string;
|
|
553
|
+
}): Promise<DevAccessState> {
|
|
554
|
+
return parseDevAccessState(
|
|
555
|
+
await revokeProjectDevShareLink(
|
|
556
|
+
{ project_id: input.projectId, "Idempotency-Key": input.idempotencyKey },
|
|
557
|
+
{ client: this.#client },
|
|
558
|
+
),
|
|
559
|
+
);
|
|
560
|
+
}
|
|
510
561
|
public async createDevAccessTicket(projectId: string): Promise<DevAccessTicket> {
|
|
511
562
|
const ticket = parseDevAccessTicket(
|
|
512
563
|
await createProjectDevAccessTicket({ project_id: projectId }, { client: this.#client }),
|
|
@@ -675,6 +726,7 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
|
675
726
|
organization_id: input.organizationId,
|
|
676
727
|
name: input.name,
|
|
677
728
|
...(input.dataMode === undefined ? {} : { data_mode: input.dataMode }),
|
|
729
|
+
...(input.devAccessMode === undefined ? {} : { dev_access_mode: input.devAccessMode }),
|
|
678
730
|
...(input.region === undefined ? {} : { region: input.region }),
|
|
679
731
|
},
|
|
680
732
|
},
|
|
@@ -716,7 +768,10 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
|
716
768
|
|
|
717
769
|
public planDeployment(input: Parameters<LocalMcpProductClient["planDeployment"]>[0]) {
|
|
718
770
|
return planDeployment(
|
|
719
|
-
{
|
|
771
|
+
{
|
|
772
|
+
project_id: input.projectId,
|
|
773
|
+
planDeploymentRequest: { commit_sha: input.commitSha, environment: input.environment },
|
|
774
|
+
},
|
|
720
775
|
{ client: this.#client },
|
|
721
776
|
);
|
|
722
777
|
}
|