@amerged/ohmyhost-mcp 0.1.20 → 0.1.22
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-NESQZ3BS.js → chunk-NLBFEH6H.js} +13 -13
- package/dist/index.js +1 -1
- package/dist/stdio-main.js +126 -11
- package/package.json +8 -1
- package/src/apps/mcp/index.ts +5 -2
- package/src/apps/mcp/local-client.ts +33 -0
- package/src/apps/mcp/local-server.ts +48 -4
- package/src/apps/product-cli/cli.ts +33 -0
- package/src/apps/product-cli/command.ts +52 -0
- package/src/apps/product-cli/index.ts +2 -0
- package/src/apps/product-cli/product-api.ts +28 -0
- package/src/apps/product-cli/runtime-contract.ts +48 -3
- package/src/packages/agent-skills/generated-skill-resources.ts +10 -10
- package/src/packages/contracts/operation-failure.ts +3 -3
- package/src/packages/sdk-ts/generated/index.ts +21 -0
- package/src/packages/sdk-ts/generated/sdk.gen.ts +142 -0
- package/src/packages/sdk-ts/generated/types.gen.ts +200 -2
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-NLBFEH6H.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 {
|
|
@@ -516,7 +516,7 @@ function toError(value) {
|
|
|
516
516
|
var failures = {
|
|
517
517
|
operation_abandoned: [
|
|
518
518
|
"The operation stopped renewing its execution lease and was ended.",
|
|
519
|
-
"Inspect project status and
|
|
519
|
+
"Inspect project status and, when this operation names a deployment_id, its diagnostics with 'ohmyhost deployment logs --project PROJECT_ULID --deployment DEPLOYMENT_ULID --follow --json' or MCP deployment_logs before creating a fresh plan. Keep this operation ID; the expired execution cannot resume."
|
|
520
520
|
],
|
|
521
521
|
database_write_rejected: [
|
|
522
522
|
"The database rejected this write; it was not committed.",
|
|
@@ -580,7 +580,7 @@ var failures = {
|
|
|
580
580
|
],
|
|
581
581
|
build_failed: [
|
|
582
582
|
"The build did not produce a verified deployable artifact.",
|
|
583
|
-
"
|
|
583
|
+
"Read the BUILD_FAILED diagnostic of this operation's deployment_id with 'ohmyhost deployment logs --project PROJECT_ULID --deployment DEPLOYMENT_ULID --follow --json' or MCP deployment_logs; its excerpt is the tail of the install and build output. Correct that failure and verify the commands for the admitted commit before planning a new deployment."
|
|
584
584
|
],
|
|
585
585
|
insufficient_organization_credits: [
|
|
586
586
|
"The organization does not have sufficient available credits for this operation.",
|
|
@@ -596,7 +596,7 @@ var failures = {
|
|
|
596
596
|
],
|
|
597
597
|
runtime_candidate_failed: [
|
|
598
598
|
"The deployed candidate failed its runtime checks.",
|
|
599
|
-
"
|
|
599
|
+
"Read the HEALTH_CHECK_FAILED diagnostic of this operation's deployment_id with 'ohmyhost deployment logs --project PROJECT_ULID --deployment DEPLOYMENT_ULID --follow --json' or MCP deployment_logs. Its route must answer 2xx to a cookieless GET without a redirect; status_code and, for owners, excerpt show what it answered. Fix that, often a missing secret or a redirect, then plan a new deployment."
|
|
600
600
|
],
|
|
601
601
|
runtime_candidate_rejected: [
|
|
602
602
|
"The runtime rejected the built Worker script.",
|
|
@@ -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.22",
|
|
803
803
|
private: true,
|
|
804
804
|
ohmyhost: {
|
|
805
805
|
deployment: "production",
|
|
@@ -2168,6 +2168,11 @@ var PROBLEM_POLICY = {
|
|
|
2168
2168
|
retryable: false,
|
|
2169
2169
|
action: "Finish database provisioning, then request the export again. No backup was accepted."
|
|
2170
2170
|
},
|
|
2171
|
+
powered_by_flag_required: {
|
|
2172
|
+
status: 409,
|
|
2173
|
+
retryable: false,
|
|
2174
|
+
action: "Keep the flag on, remove the custom domain with 'ohmyhost domain paid delete', or buy Paid, then switch the flag off."
|
|
2175
|
+
},
|
|
2171
2176
|
rate_limited: { status: 429, retryable: true, action: "Retry after the server delay." },
|
|
2172
2177
|
insufficient_organization_credits: {
|
|
2173
2178
|
status: 402,
|
|
@@ -2182,7 +2187,7 @@ var PROBLEM_POLICY = {
|
|
|
2182
2187
|
paid_plan_required: {
|
|
2183
2188
|
status: 402,
|
|
2184
2189
|
retryable: false,
|
|
2185
|
-
action: "Ask the organization Owner to activate Paid through billing checkout, then retry. Top-ups and signup credits do not activate Paid."
|
|
2190
|
+
action: "Ask the organization Owner to activate Paid through billing checkout, then retry. Top-ups and signup credits do not activate Paid. For a website domain alone, a Free workspace may instead show the powered-by flag on the project."
|
|
2186
2191
|
},
|
|
2187
2192
|
interactive_login_required: {
|
|
2188
2193
|
status: 403,
|
|
@@ -2290,6 +2295,18 @@ var parseDevAccessState = (value) => {
|
|
|
2290
2295
|
throw new ResponseContractError();
|
|
2291
2296
|
return input;
|
|
2292
2297
|
};
|
|
2298
|
+
var parsePoweredByFlag = (value) => {
|
|
2299
|
+
const input = exactRecord2(value, ["project_id", "enabled", "enabled_at"]);
|
|
2300
|
+
if (!isUlid(input["project_id"]) || typeof input["enabled"] !== "boolean" || (input["enabled"] ? !isIsoInstant(input["enabled_at"]) : input["enabled_at"] !== null))
|
|
2301
|
+
throw new ResponseContractError();
|
|
2302
|
+
return input;
|
|
2303
|
+
};
|
|
2304
|
+
var parseOrganizationReferral = (value) => {
|
|
2305
|
+
const input = exactRecord2(value, ["organization_id", "referral_url"]);
|
|
2306
|
+
if (!isUlid(input["organization_id"]) || input["referral_url"] !== `https://ohmyho.st/?r=ref-${String(input["organization_id"]).toLowerCase()}`)
|
|
2307
|
+
throw new ResponseContractError();
|
|
2308
|
+
return input;
|
|
2309
|
+
};
|
|
2293
2310
|
var parseDevAccessTicket = (value) => {
|
|
2294
2311
|
const input = exactRecord2(value, [
|
|
2295
2312
|
"ticket_id",
|
|
@@ -2381,6 +2398,7 @@ var parseSafeProblem = (value) => {
|
|
|
2381
2398
|
var parseOperation = (value) => {
|
|
2382
2399
|
const input = exactRecord2(value, [
|
|
2383
2400
|
"blocking_operation_id",
|
|
2401
|
+
"deployment_id",
|
|
2384
2402
|
"id",
|
|
2385
2403
|
"state",
|
|
2386
2404
|
"created_at",
|
|
@@ -2396,7 +2414,8 @@ var parseOperation = (value) => {
|
|
|
2396
2414
|
const updatedAt = input["updated_at"];
|
|
2397
2415
|
const result = input["result"];
|
|
2398
2416
|
const blockingOperationId = input["blocking_operation_id"];
|
|
2399
|
-
|
|
2417
|
+
const deploymentId = input["deployment_id"];
|
|
2418
|
+
if (blockingOperationId !== void 0 && (state !== "queued" || !isUlid(blockingOperationId) || blockingOperationId === id3) || deploymentId !== void 0 && !isUlid(deploymentId))
|
|
2400
2419
|
throw new ResponseContractError();
|
|
2401
2420
|
if (!isUlid(id3) || !isOperationState(state) || !isIsoInstant(createdAt) || !isIsoInstant(updatedAt) || result !== void 0 && !isRecord2(result)) {
|
|
2402
2421
|
throw new ResponseContractError();
|
|
@@ -2443,6 +2462,7 @@ var parseOperation = (value) => {
|
|
|
2443
2462
|
created_at: createdAt,
|
|
2444
2463
|
updated_at: updatedAt,
|
|
2445
2464
|
...blockingOperationId === void 0 ? {} : { blocking_operation_id: blockingOperationId },
|
|
2465
|
+
...deploymentId === void 0 ? {} : { deployment_id: deploymentId },
|
|
2446
2466
|
...progress === void 0 ? {} : { progress },
|
|
2447
2467
|
...result === void 0 ? {} : { result },
|
|
2448
2468
|
...error === void 0 ? {} : { error },
|
|
@@ -2597,6 +2617,7 @@ var HELP_USAGE = Object.freeze({
|
|
|
2597
2617
|
"export create": "ohmyhost export create --project ULID --idempotency-key KEY --stdin --json (password on stdin only; one accepted SQL ZIP per project per 24 hours)",
|
|
2598
2618
|
"export get": "ohmyhost export get EXPORT_ULID --project ULID --json (poll the original job; signed ZIP download lasts 24 hours)",
|
|
2599
2619
|
"credits account": "ohmyhost credits account --organization ULID --json",
|
|
2620
|
+
"referral link": "ohmyhost referral link --organization ULID --json (the workspace's link to share; a new user who signs up through it starts with a free Paid month and 1,000 credits, and their first payment gives this workspace the same)",
|
|
2600
2621
|
"credits balance": "ohmyhost credits balance --organization ULID --json",
|
|
2601
2622
|
"billing recharge get": "ohmyhost billing recharge get --organization ULID --json",
|
|
2602
2623
|
"billing recharge set": "ohmyhost billing recharge set --organization ULID --enabled true|false --monthly-limit-minor CENTS --revision N --idempotency-key KEY [--consent off_session_v1] --json (explicit Owner consent required before enabling)",
|
|
@@ -2626,6 +2647,8 @@ var HELP_USAGE = Object.freeze({
|
|
|
2626
2647
|
"project dev-share rotate": "ohmyhost project dev-share rotate --project ULID --idempotency-key KEY --yes --json",
|
|
2627
2648
|
"project dev-share revoke": "ohmyhost project dev-share revoke --project ULID --idempotency-key KEY --yes --json",
|
|
2628
2649
|
"project dev-access mode": "ohmyhost project dev-access mode --project ULID --mode protected|public --idempotency-key KEY --yes --json",
|
|
2650
|
+
"project flag status": "ohmyhost project flag status --project ULID --json",
|
|
2651
|
+
"project flag set": "ohmyhost project flag set --project ULID --enabled true|false --idempotency-key KEY --json (shows the small Powered by ohmyho.st flag on the production site; while it shows, a Free workspace may connect its own domain without the domain fee and each Paid period adds 250 credits)",
|
|
2629
2652
|
"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)",
|
|
2630
2653
|
"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)",
|
|
2631
2654
|
"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.",
|
|
@@ -3567,6 +3590,23 @@ var getGithubOrganizationConnection = (parameters, options) => {
|
|
|
3567
3590
|
...params
|
|
3568
3591
|
});
|
|
3569
3592
|
};
|
|
3593
|
+
var getOrganizationReferral = (parameters, options) => {
|
|
3594
|
+
const params = buildClientParams([parameters], [
|
|
3595
|
+
{
|
|
3596
|
+
args: [
|
|
3597
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
3598
|
+
{ in: "path", key: "organization_id" }
|
|
3599
|
+
]
|
|
3600
|
+
}
|
|
3601
|
+
]);
|
|
3602
|
+
return (options?.client ?? client).get({
|
|
3603
|
+
responseStyle: "data",
|
|
3604
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
3605
|
+
url: "/v1/organizations/{organization_id}/referral",
|
|
3606
|
+
...options,
|
|
3607
|
+
...params
|
|
3608
|
+
});
|
|
3609
|
+
};
|
|
3570
3610
|
var getOrganizationAccount = (parameters, options) => {
|
|
3571
3611
|
const params = buildClientParams([parameters], [{ args: [{ in: "path", key: "organization_id" }] }]);
|
|
3572
3612
|
return (options?.client ?? client).get({
|
|
@@ -4171,6 +4211,47 @@ var setProjectDevAccessMode = (parameters, options) => {
|
|
|
4171
4211
|
}
|
|
4172
4212
|
});
|
|
4173
4213
|
};
|
|
4214
|
+
var getProjectPoweredByFlag = (parameters, options) => {
|
|
4215
|
+
const params = buildClientParams([parameters], [
|
|
4216
|
+
{
|
|
4217
|
+
args: [
|
|
4218
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
4219
|
+
{ in: "path", key: "project_id" }
|
|
4220
|
+
]
|
|
4221
|
+
}
|
|
4222
|
+
]);
|
|
4223
|
+
return (options?.client ?? client).get({
|
|
4224
|
+
responseStyle: "data",
|
|
4225
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
4226
|
+
url: "/v1/projects/{project_id}/powered-by-flag",
|
|
4227
|
+
...options,
|
|
4228
|
+
...params
|
|
4229
|
+
});
|
|
4230
|
+
};
|
|
4231
|
+
var setProjectPoweredByFlag = (parameters, options) => {
|
|
4232
|
+
const params = buildClientParams([parameters], [
|
|
4233
|
+
{
|
|
4234
|
+
args: [
|
|
4235
|
+
{ in: "headers", key: "X-Request-Id" },
|
|
4236
|
+
{ in: "headers", key: "Idempotency-Key" },
|
|
4237
|
+
{ in: "path", key: "project_id" },
|
|
4238
|
+
{ key: "setPoweredByFlagRequest", map: "body" }
|
|
4239
|
+
]
|
|
4240
|
+
}
|
|
4241
|
+
]);
|
|
4242
|
+
return (options?.client ?? client).put({
|
|
4243
|
+
responseStyle: "data",
|
|
4244
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
4245
|
+
url: "/v1/projects/{project_id}/powered-by-flag",
|
|
4246
|
+
...options,
|
|
4247
|
+
...params,
|
|
4248
|
+
headers: {
|
|
4249
|
+
"Content-Type": "application/json",
|
|
4250
|
+
...options?.headers,
|
|
4251
|
+
...params.headers
|
|
4252
|
+
}
|
|
4253
|
+
});
|
|
4254
|
+
};
|
|
4174
4255
|
var createProjectDevAccessTicket = (parameters, options) => {
|
|
4175
4256
|
const params = buildClientParams([parameters], [
|
|
4176
4257
|
{
|
|
@@ -5429,6 +5510,9 @@ var GeneratedSdkProductApi = class {
|
|
|
5429
5510
|
async getAccountProfile() {
|
|
5430
5511
|
return parseAccountProfile(await getAccountProfile({ client: this.#client }));
|
|
5431
5512
|
}
|
|
5513
|
+
getOrganizationReferral(organizationId) {
|
|
5514
|
+
return getOrganizationReferral({ organization_id: organizationId }, { client: this.#client });
|
|
5515
|
+
}
|
|
5432
5516
|
getOrganizationAccount(organizationId) {
|
|
5433
5517
|
return getOrganizationAccount({ organization_id: organizationId }, { client: this.#client });
|
|
5434
5518
|
}
|
|
@@ -5602,6 +5686,16 @@ var GeneratedSdkProductApi = class {
|
|
|
5602
5686
|
setDevAccessModeRequest: { mode }
|
|
5603
5687
|
}, { client: this.#client });
|
|
5604
5688
|
}
|
|
5689
|
+
async getPoweredByFlag(projectId) {
|
|
5690
|
+
return getProjectPoweredByFlag({ project_id: projectId }, { client: this.#client });
|
|
5691
|
+
}
|
|
5692
|
+
async setPoweredByFlag(projectId, enabled, idempotencyKey2) {
|
|
5693
|
+
return setProjectPoweredByFlag({
|
|
5694
|
+
project_id: projectId,
|
|
5695
|
+
"Idempotency-Key": idempotencyKey2,
|
|
5696
|
+
setPoweredByFlagRequest: { enabled }
|
|
5697
|
+
}, { client: this.#client });
|
|
5698
|
+
}
|
|
5605
5699
|
async createDevAccessTicket(projectId) {
|
|
5606
5700
|
return createProjectDevAccessTicket({ project_id: projectId }, { client: this.#client });
|
|
5607
5701
|
}
|
|
@@ -6361,6 +6455,9 @@ var GeneratedSdkLocalMcpClient = class {
|
|
|
6361
6455
|
assertOrganizationAccount(account);
|
|
6362
6456
|
return account;
|
|
6363
6457
|
}
|
|
6458
|
+
async getOrganizationReferral(organizationId) {
|
|
6459
|
+
return parseOrganizationReferral(await getOrganizationReferral({ organization_id: organizationId }, { client: this.#client }));
|
|
6460
|
+
}
|
|
6364
6461
|
getOrganizationCredits(organizationId) {
|
|
6365
6462
|
return getOrganizationCredits({ organization_id: organizationId }, { client: this.#client });
|
|
6366
6463
|
}
|
|
@@ -6489,6 +6586,16 @@ var GeneratedSdkLocalMcpClient = class {
|
|
|
6489
6586
|
setDevAccessModeRequest: { mode: input.mode }
|
|
6490
6587
|
}, { client: this.#client }));
|
|
6491
6588
|
}
|
|
6589
|
+
async getPoweredByFlag(projectId) {
|
|
6590
|
+
return parsePoweredByFlag(await getProjectPoweredByFlag({ project_id: projectId }, { client: this.#client }));
|
|
6591
|
+
}
|
|
6592
|
+
async setPoweredByFlag(input) {
|
|
6593
|
+
return parsePoweredByFlag(await setProjectPoweredByFlag({
|
|
6594
|
+
project_id: input.projectId,
|
|
6595
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
6596
|
+
setPoweredByFlagRequest: { enabled: input.enabled }
|
|
6597
|
+
}, { client: this.#client }));
|
|
6598
|
+
}
|
|
6492
6599
|
async rotateDevShareLink(input) {
|
|
6493
6600
|
return parseDevAccessState(await rotateProjectDevShareLink({ project_id: input.projectId, "Idempotency-Key": input.idempotencyKey }, { client: this.#client }));
|
|
6494
6601
|
}
|
|
@@ -6773,9 +6880,10 @@ var PLATFORM_SECRET_NAMES = /* @__PURE__ */ new Set([
|
|
|
6773
6880
|
"OHMYHOST_MAIL_KEY",
|
|
6774
6881
|
"OHMYHOST_MAIL_GATEWAY_URL"
|
|
6775
6882
|
]);
|
|
6883
|
+
var LOCAL_SERVER_INSTRUCTIONS = "Operate the user's ohmyho.st hosting account: projects, GitHub deployments, databases, domains, mail, usage and budgets. 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. 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).";
|
|
6776
6884
|
function createLocalOhmyhostMcpServer(dependencies) {
|
|
6777
6885
|
const { commandPrefix } = resolveProductCliEnvironment(dependencies.environment);
|
|
6778
|
-
const server = createOhmyhostMcpServer("ohmyhost-local");
|
|
6886
|
+
const server = createOhmyhostMcpServer("ohmyhost-local", LOCAL_SERVER_INSTRUCTIONS);
|
|
6779
6887
|
registerProductTool(server, dependencies, "database_compute_get", "Read current managed database size, memory, region and compute state without running SQL or waking the database. Shared Dev/Prod resolves to one physical database. A null database means no confirmed managed placement. suspend_timeout_seconds=0 uses the provider default; -1 disables scale to zero. A configured value is not proof that an in-progress resize finished. This read never resizes or changes billing.", external_exports.object({ project_id: identifier2, environment: external_exports.enum(["dev", "prod"]).default("dev") }), (client2, input) => client2.getDatabaseCompute({ projectId: input.project_id, environment: input.environment }));
|
|
6780
6888
|
registerProductTool(server, dependencies, "database_compute_set", "Select standard or performance compute for an existing database: Free 0.25 CU/1 GB/60-second idle suspension, Paid 0.5 CU/2 GB/60-second idle suspension. First read database_compute_get and explain actual size, metered compute cost, possible brief connection interruption and that shared data changes both Dev and Prod. Require the user's decision before confirm=true. SQL data is preserved. Poll the returned operation every 60 seconds; never submit a second change while it runs. Performance requires active Paid access and selects 1 CU/4 GB/300-second idle suspension at 2.5x Paid-standard compute credits per equal active minute; the longer idle window also consumes more active time. This affects only database compute. Read organization_credits_get for the published rate and active meter first. A successful choice is remembered per physical database; automatic Free downgrades preserve it, and an explicit standard choice clears it. Mixed/uncertain transition hours waive the premium; never multiply raw CU usage again.", external_exports.object({
|
|
6781
6889
|
project_id: identifier2,
|
|
@@ -6894,6 +7002,7 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
6894
7002
|
...input.cursor ? { cursor: input.cursor } : {}
|
|
6895
7003
|
}));
|
|
6896
7004
|
registerProductTool(server, dependencies, "organization_account_get", "Owner-only: read the effective Free/Paid plan, its Stripe or granted source, available expiring Free credits and purchased credits that never expire, reservations and next expiry. Granted Paid features do not imply a Stripe subscription or extra monthly Paid allowance. This read grants no access or credits.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationAccount(input.organization_id));
|
|
7005
|
+
registerProductTool(server, dependencies, "referral_link_get", "Read the workspace's referral link to share. A new user whose first workspace comes from it starts with a free Paid month and 1,000 credits; that workspace's first payment gives this workspace the same. Any member may read it.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationReferral(input.organization_id));
|
|
6897
7006
|
registerProductTool(server, dependencies, "organization_credits_get", "Read the owner's shared organization credit pool, seven-day grace_started_at/grace_expires_at and published rate_cards. Existing services/domains are not immediately shut down at zero credit; an explicit project stop budget is separate. One credit is 1000000 microcredits. Each rate states credit_micros for units_per_charge; publication alone does not enable billing. active_meters identifies billed sources; provider outages and platform overrun are not customer debt. Works at zero credit.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationCredits(input.organization_id));
|
|
6898
7007
|
registerProductTool(server, dependencies, "project_budget_get", "Read the owner's project UTC-month budget, measured usage and open reservations. A budget never allocates a second wallet.", external_exports.object({ project_id: identifier2 }), (client2, input) => client2.getProjectCreditBudget(input.project_id));
|
|
6899
7008
|
registerProductTool(server, dependencies, "project_budget_set", "Set an owner's optional monthly project budget in microcredits (1000000 = one credit). continue is the default and uses the org pool after the threshold; stop blocks new billable work. null clears the budget and requires continue. Changing it never resets usage or adds credits. Replay the same key after uncertainty; read the budget again for current usage.", external_exports.object({
|
|
@@ -7052,7 +7161,7 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
7052
7161
|
...input.cursor === void 0 ? {} : { cursor: input.cursor },
|
|
7053
7162
|
...input.limit === void 0 ? {} : { limit: input.limit }
|
|
7054
7163
|
}));
|
|
7055
|
-
registerProductTool(server, dependencies, "feedback_submit", "Report a bug, suspected issue or feature request to ohmyho.st. Submit a redacted expected/actual description and minimal reproduction; never credentials, raw logs, environment dumps or personal records. Available at zero credits. Reuse the same key after uncertainty; only a returned receipt ID confirms submission, not triage or a fix.", external_exports.object({
|
|
7164
|
+
registerProductTool(server, dependencies, "feedback_submit", "Report a bug, suspected issue or feature request to ohmyho.st. Submit a redacted expected/actual description and minimal reproduction; never credentials, raw logs, environment dumps or personal records. Available at zero credits. Reuse the same key after uncertainty; only a returned receipt ID confirms submission, not triage or a fix. This is ohmyho.st support for a signed-in agent: give the user the receipt ID and follow up with feedback_status (https://docs.ohmyho.st/support).", external_exports.object({
|
|
7056
7165
|
organization_id: identifier2,
|
|
7057
7166
|
project_id: identifier2.optional(),
|
|
7058
7167
|
environment_id: identifier2.optional(),
|
|
@@ -7095,6 +7204,12 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
7095
7204
|
mode: input.mode,
|
|
7096
7205
|
idempotencyKey: input.idempotency_key
|
|
7097
7206
|
}), destructiveAnnotations());
|
|
7207
|
+
registerProductTool(server, dependencies, "powered_by_flag_get", 'Read whether the production site shows the opt-in "Powered by ohmyho.st" flag.', external_exports.object({ project_id: identifier2 }), (client2, input) => client2.getPoweredByFlag(input.project_id));
|
|
7208
|
+
registerProductTool(server, dependencies, "powered_by_flag_set", `Owner only, ask the human first: show or hide a small "Powered by ohmyho.st" flag on the right edge of the production site. While it is on, a Free workspace may connect its own domain to this project free of the domain fee, and each Paid period adds 250 credits. Hiding it is refused while a Free workspace's domain depends on it. Replay the same key and value after uncertainty to get the first answer without switching again; every new switch needs a new key.`, external_exports.object({ project_id: identifier2, enabled: external_exports.boolean(), idempotency_key: idempotencyKey }), (client2, input) => client2.setPoweredByFlag({
|
|
7209
|
+
projectId: input.project_id,
|
|
7210
|
+
enabled: input.enabled,
|
|
7211
|
+
idempotencyKey: input.idempotency_key
|
|
7212
|
+
}), mutationAnnotations());
|
|
7098
7213
|
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({
|
|
7099
7214
|
projectId: input.project_id,
|
|
7100
7215
|
idempotencyKey: input.idempotency_key
|
|
@@ -7145,7 +7260,7 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
7145
7260
|
...input.limit === void 0 ? {} : { limit: input.limit }
|
|
7146
7261
|
}));
|
|
7147
7262
|
registerProductTool(server, dependencies, "deployment_get", "Get one deployment", external_exports.object({ project_id: identifier2, deployment_id: identifier2 }), (client2, input) => client2.getDeployment({ projectId: input.project_id, deploymentId: input.deployment_id }));
|
|
7148
|
-
registerProductTool(server, dependencies, "deployment_logs", "List the newest normalized diagnostics of one deployment (build, control, runtime and function failures with catalog codes). A BUILD_FAILED item carries excerpt: the sanitized tail of the customer's own install/build output, newest lines last, with excerpt_truncated when earlier output was omitted. Read
|
|
7263
|
+
registerProductTool(server, dependencies, "deployment_logs", "List the newest normalized diagnostics of one deployment (build, control, runtime and function failures with catalog codes). A failed operation_get names the deployment as deployment_id. A BUILD_FAILED item carries excerpt: the sanitized tail of the customer's own install/build output, newest lines last, with excerpt_truncated when earlier output was omitted. A HEALTH_CHECK_FAILED item carries the probed route and status_code and, only for a project owner, excerpt: the head (at most 4096 characters, control characters removed, never a header) of what the app answered. The probe is a cookieless GET that follows no redirect, 5 s per try and up to four tries, so a 3xx or an empty 503 is unhealthy too. Read the item before changing source; scheduled runs are in function_runs_list, not here.", external_exports.object({
|
|
7149
7264
|
project_id: identifier2,
|
|
7150
7265
|
deployment_id: identifier2,
|
|
7151
7266
|
limit: external_exports.number().int().min(1).max(100).default(100)
|
|
@@ -7154,7 +7269,7 @@ function createLocalOhmyhostMcpServer(dependencies) {
|
|
|
7154
7269
|
deploymentId: input.deployment_id,
|
|
7155
7270
|
limit: input.limit
|
|
7156
7271
|
}));
|
|
7157
|
-
registerProductTool(server, dependencies, "operation_get", "Get durable operation status and current deployment progress/reconciliation guidance. Follow progress.phase and progress.suggested_action. waiting_for_mail requires mail_domain_status now for the current verification issue and DNS records; publishing means the build completed but runtime preparation/publication is unfinished. Poll this operation after progress.next_poll_after_seconds. A queued/running operation with reconciliation.state=required needs one confirmed operation_reconcile using the same operation; pending means poll this operation after 60 seconds. Never infer deployment success from a completed reconciliation attempt or start another build to recover it.", external_exports.object({ operation_id: identifier2 }), (client2, input) => client2.getOperation(input.operation_id));
|
|
7272
|
+
registerProductTool(server, dependencies, "operation_get", "Get durable operation status and current deployment progress/reconciliation guidance. Follow progress.phase and progress.suggested_action. waiting_for_mail requires mail_domain_status now for the current verification issue and DNS records; publishing means the build completed but runtime preparation/publication is unfinished. Poll this operation after progress.next_poll_after_seconds. A queued/running operation with reconciliation.state=required needs one confirmed operation_reconcile using the same operation; pending means poll this operation after 60 seconds. Never infer deployment success from a completed reconciliation attempt or start another build to recover it. A deploy, promotion or rollback names its deployment_id in every state; when state is failed, read that deployment with deployment_logs and follow error.suggested_action before changing source.", external_exports.object({ operation_id: identifier2 }), (client2, input) => client2.getOperation(input.operation_id));
|
|
7158
7273
|
registerProductTool(server, dependencies, "operation_logs", "Read available operation events for at most ten seconds, stopping earlier at max_events or a terminal event. This is a bounded snapshot, not a wait for deployment completion. Use operation_get for current progress and keep the same operation. Stream failures are errors, not empty logs.", external_exports.object({
|
|
7159
7274
|
operation_id: identifier2,
|
|
7160
7275
|
max_events: external_exports.number().int().min(1).max(100).default(50)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amerged/ohmyhost-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -24,6 +24,13 @@
|
|
|
24
24
|
},
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"homepage": "https://docs.ohmyho.st/",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://docs.ohmyho.st/support"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/amerged-org/ohmyhost-mcp.git"
|
|
33
|
+
},
|
|
27
34
|
"description": "ohmyho.st mcp client",
|
|
28
35
|
"publishConfig": {
|
|
29
36
|
"access": "public",
|
package/src/apps/mcp/index.ts
CHANGED
|
@@ -2,8 +2,11 @@ import mcpPackage from "../package.json" with { type: "json" };
|
|
|
2
2
|
import { createMcpHandler, McpServer } from "@modelcontextprotocol/server";
|
|
3
3
|
import { listOhmyhostSkillResources } from "@ohmyhost/agent-skills";
|
|
4
4
|
|
|
5
|
-
export function createOhmyhostMcpServer(name = "ohmyhost") {
|
|
6
|
-
const server = new McpServer(
|
|
5
|
+
export function createOhmyhostMcpServer(name = "ohmyhost", instructions?: string) {
|
|
6
|
+
const server = new McpServer(
|
|
7
|
+
{ name, version: mcpPackage.version },
|
|
8
|
+
instructions === undefined ? undefined : { instructions },
|
|
9
|
+
);
|
|
7
10
|
for (const resource of listOhmyhostSkillResources()) {
|
|
8
11
|
server.registerResource(
|
|
9
12
|
`${resource.skillName}:${resource.relativePath}`,
|
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
createProjectDevAccessTicket,
|
|
27
27
|
ensureProjectDevShareLink,
|
|
28
28
|
setProjectDevAccessMode,
|
|
29
|
+
getProjectPoweredByFlag,
|
|
30
|
+
setProjectPoweredByFlag,
|
|
29
31
|
rotateProjectDevShareLink,
|
|
30
32
|
revokeProjectDevShareLink,
|
|
31
33
|
createCloudflareDnsAuthorization,
|
|
@@ -52,6 +54,7 @@ import {
|
|
|
52
54
|
deletePaidProjectDomain,
|
|
53
55
|
getOrganizationCredits,
|
|
54
56
|
getOrganizationAccount,
|
|
57
|
+
getOrganizationReferral,
|
|
55
58
|
getOrganizationCreditUsage,
|
|
56
59
|
getProjectCreditBudget,
|
|
57
60
|
setProjectCreditBudget,
|
|
@@ -93,6 +96,8 @@ import {
|
|
|
93
96
|
streamOperationEvents,
|
|
94
97
|
type DevAccessTicket,
|
|
95
98
|
type DevAccessState,
|
|
99
|
+
type PoweredByFlag,
|
|
100
|
+
type OrganizationReferral,
|
|
96
101
|
type CloudflareDnsAuthorization,
|
|
97
102
|
type CloudflareDnsAuthorizationStatus,
|
|
98
103
|
type OhMyHostClient,
|
|
@@ -113,6 +118,8 @@ import {
|
|
|
113
118
|
ProductApiAuthenticationError,
|
|
114
119
|
parseDevAccessTicket,
|
|
115
120
|
parseDevAccessState,
|
|
121
|
+
parsePoweredByFlag,
|
|
122
|
+
parseOrganizationReferral,
|
|
116
123
|
parseCloudflareDnsAuthorization,
|
|
117
124
|
parseCloudflareDnsAuthorizationStatus,
|
|
118
125
|
parsePaidDomain,
|
|
@@ -419,6 +426,11 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
|
419
426
|
assertOrganizationAccount(account);
|
|
420
427
|
return account;
|
|
421
428
|
}
|
|
429
|
+
public async getOrganizationReferral(organizationId: string): Promise<OrganizationReferral> {
|
|
430
|
+
return parseOrganizationReferral(
|
|
431
|
+
await getOrganizationReferral({ organization_id: organizationId }, { client: this.#client }),
|
|
432
|
+
);
|
|
433
|
+
}
|
|
422
434
|
public getOrganizationCredits(organizationId: string) {
|
|
423
435
|
return getOrganizationCredits({ organization_id: organizationId }, { client: this.#client });
|
|
424
436
|
}
|
|
@@ -606,6 +618,27 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
|
|
|
606
618
|
),
|
|
607
619
|
);
|
|
608
620
|
}
|
|
621
|
+
public async getPoweredByFlag(projectId: string): Promise<PoweredByFlag> {
|
|
622
|
+
return parsePoweredByFlag(
|
|
623
|
+
await getProjectPoweredByFlag({ project_id: projectId }, { client: this.#client }),
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
public async setPoweredByFlag(input: {
|
|
627
|
+
projectId: string;
|
|
628
|
+
enabled: boolean;
|
|
629
|
+
idempotencyKey: string;
|
|
630
|
+
}): Promise<PoweredByFlag> {
|
|
631
|
+
return parsePoweredByFlag(
|
|
632
|
+
await setProjectPoweredByFlag(
|
|
633
|
+
{
|
|
634
|
+
project_id: input.projectId,
|
|
635
|
+
"Idempotency-Key": input.idempotencyKey,
|
|
636
|
+
setPoweredByFlagRequest: { enabled: input.enabled },
|
|
637
|
+
},
|
|
638
|
+
{ client: this.#client },
|
|
639
|
+
),
|
|
640
|
+
);
|
|
641
|
+
}
|
|
609
642
|
public async rotateDevShareLink(input: {
|
|
610
643
|
projectId: string;
|
|
611
644
|
idempotencyKey: string;
|
|
@@ -70,6 +70,12 @@ export interface LocalMcpProductClient {
|
|
|
70
70
|
projectId: string;
|
|
71
71
|
idempotencyKey: string;
|
|
72
72
|
}): Promise<import("@ohmyhost/sdk-ts").DevAccessState>;
|
|
73
|
+
getPoweredByFlag(projectId: string): Promise<import("@ohmyhost/sdk-ts").PoweredByFlag>;
|
|
74
|
+
setPoweredByFlag(input: {
|
|
75
|
+
projectId: string;
|
|
76
|
+
enabled: boolean;
|
|
77
|
+
idempotencyKey: string;
|
|
78
|
+
}): Promise<import("@ohmyhost/sdk-ts").PoweredByFlag>;
|
|
73
79
|
revokeDevShareLink(input: {
|
|
74
80
|
projectId: string;
|
|
75
81
|
idempotencyKey: string;
|
|
@@ -156,6 +162,9 @@ export interface LocalMcpProductClient {
|
|
|
156
162
|
getOrganizationAccount(
|
|
157
163
|
organizationId: string,
|
|
158
164
|
): Promise<import("@ohmyhost/sdk-ts").OrganizationAccount>;
|
|
165
|
+
getOrganizationReferral(
|
|
166
|
+
organizationId: string,
|
|
167
|
+
): Promise<import("@ohmyhost/sdk-ts").OrganizationReferral>;
|
|
159
168
|
getOrganizationCredits(
|
|
160
169
|
organizationId: string,
|
|
161
170
|
): Promise<import("@ohmyhost/sdk-ts").OrganizationCredits>;
|
|
@@ -419,9 +428,14 @@ const PLATFORM_SECRET_NAMES = new Set([
|
|
|
419
428
|
"OHMYHOST_MAIL_GATEWAY_URL",
|
|
420
429
|
]);
|
|
421
430
|
|
|
431
|
+
const LOCAL_SERVER_INSTRUCTIONS =
|
|
432
|
+
"Operate the user's ohmyho.st hosting account: projects, GitHub deployments, databases, domains, mail, usage and budgets. " +
|
|
433
|
+
"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. " +
|
|
434
|
+
"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).";
|
|
435
|
+
|
|
422
436
|
export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDependencies) {
|
|
423
437
|
const { commandPrefix } = resolveProductCliEnvironment(dependencies.environment);
|
|
424
|
-
const server = createOhmyhostMcpServer("ohmyhost-local");
|
|
438
|
+
const server = createOhmyhostMcpServer("ohmyhost-local", LOCAL_SERVER_INSTRUCTIONS);
|
|
425
439
|
registerProductTool(
|
|
426
440
|
server,
|
|
427
441
|
dependencies,
|
|
@@ -706,6 +720,14 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
|
|
|
706
720
|
z.object({ organization_id: identifier }),
|
|
707
721
|
(client, input) => client.getOrganizationAccount(input.organization_id),
|
|
708
722
|
);
|
|
723
|
+
registerProductTool(
|
|
724
|
+
server,
|
|
725
|
+
dependencies,
|
|
726
|
+
"referral_link_get",
|
|
727
|
+
"Read the workspace's referral link to share. A new user whose first workspace comes from it starts with a free Paid month and 1,000 credits; that workspace's first payment gives this workspace the same. Any member may read it.",
|
|
728
|
+
z.object({ organization_id: identifier }),
|
|
729
|
+
(client, input) => client.getOrganizationReferral(input.organization_id),
|
|
730
|
+
);
|
|
709
731
|
registerProductTool(
|
|
710
732
|
server,
|
|
711
733
|
dependencies,
|
|
@@ -1061,7 +1083,7 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
|
|
|
1061
1083
|
server,
|
|
1062
1084
|
dependencies,
|
|
1063
1085
|
"feedback_submit",
|
|
1064
|
-
"Report a bug, suspected issue or feature request to ohmyho.st. Submit a redacted expected/actual description and minimal reproduction; never credentials, raw logs, environment dumps or personal records. Available at zero credits. Reuse the same key after uncertainty; only a returned receipt ID confirms submission, not triage or a fix.",
|
|
1086
|
+
"Report a bug, suspected issue or feature request to ohmyho.st. Submit a redacted expected/actual description and minimal reproduction; never credentials, raw logs, environment dumps or personal records. Available at zero credits. Reuse the same key after uncertainty; only a returned receipt ID confirms submission, not triage or a fix. This is ohmyho.st support for a signed-in agent: give the user the receipt ID and follow up with feedback_status (https://docs.ohmyho.st/support).",
|
|
1065
1087
|
z
|
|
1066
1088
|
.object({
|
|
1067
1089
|
organization_id: identifier,
|
|
@@ -1163,6 +1185,28 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
|
|
|
1163
1185
|
}),
|
|
1164
1186
|
destructiveAnnotations(),
|
|
1165
1187
|
);
|
|
1188
|
+
registerProductTool(
|
|
1189
|
+
server,
|
|
1190
|
+
dependencies,
|
|
1191
|
+
"powered_by_flag_get",
|
|
1192
|
+
'Read whether the production site shows the opt-in "Powered by ohmyho.st" flag.',
|
|
1193
|
+
z.object({ project_id: identifier }),
|
|
1194
|
+
(client, input) => client.getPoweredByFlag(input.project_id),
|
|
1195
|
+
);
|
|
1196
|
+
registerProductTool(
|
|
1197
|
+
server,
|
|
1198
|
+
dependencies,
|
|
1199
|
+
"powered_by_flag_set",
|
|
1200
|
+
'Owner only, ask the human first: show or hide a small "Powered by ohmyho.st" flag on the right edge of the production site. While it is on, a Free workspace may connect its own domain to this project free of the domain fee, and each Paid period adds 250 credits. Hiding it is refused while a Free workspace\'s domain depends on it. Replay the same key and value after uncertainty to get the first answer without switching again; every new switch needs a new key.',
|
|
1201
|
+
z.object({ project_id: identifier, enabled: z.boolean(), idempotency_key: idempotencyKey }),
|
|
1202
|
+
(client, input) =>
|
|
1203
|
+
client.setPoweredByFlag({
|
|
1204
|
+
projectId: input.project_id,
|
|
1205
|
+
enabled: input.enabled,
|
|
1206
|
+
idempotencyKey: input.idempotency_key,
|
|
1207
|
+
}),
|
|
1208
|
+
mutationAnnotations(),
|
|
1209
|
+
);
|
|
1166
1210
|
registerProductTool(
|
|
1167
1211
|
server,
|
|
1168
1212
|
dependencies,
|
|
@@ -1308,7 +1352,7 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
|
|
|
1308
1352
|
server,
|
|
1309
1353
|
dependencies,
|
|
1310
1354
|
"deployment_logs",
|
|
1311
|
-
"List the newest normalized diagnostics of one deployment (build, control, runtime and function failures with catalog codes). A BUILD_FAILED item carries excerpt: the sanitized tail of the customer's own install/build output, newest lines last, with excerpt_truncated when earlier output was omitted. Read
|
|
1355
|
+
"List the newest normalized diagnostics of one deployment (build, control, runtime and function failures with catalog codes). A failed operation_get names the deployment as deployment_id. A BUILD_FAILED item carries excerpt: the sanitized tail of the customer's own install/build output, newest lines last, with excerpt_truncated when earlier output was omitted. A HEALTH_CHECK_FAILED item carries the probed route and status_code and, only for a project owner, excerpt: the head (at most 4096 characters, control characters removed, never a header) of what the app answered. The probe is a cookieless GET that follows no redirect, 5 s per try and up to four tries, so a 3xx or an empty 503 is unhealthy too. Read the item before changing source; scheduled runs are in function_runs_list, not here.",
|
|
1312
1356
|
z.object({
|
|
1313
1357
|
project_id: identifier,
|
|
1314
1358
|
deployment_id: identifier,
|
|
@@ -1325,7 +1369,7 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
|
|
|
1325
1369
|
server,
|
|
1326
1370
|
dependencies,
|
|
1327
1371
|
"operation_get",
|
|
1328
|
-
"Get durable operation status and current deployment progress/reconciliation guidance. Follow progress.phase and progress.suggested_action. waiting_for_mail requires mail_domain_status now for the current verification issue and DNS records; publishing means the build completed but runtime preparation/publication is unfinished. Poll this operation after progress.next_poll_after_seconds. A queued/running operation with reconciliation.state=required needs one confirmed operation_reconcile using the same operation; pending means poll this operation after 60 seconds. Never infer deployment success from a completed reconciliation attempt or start another build to recover it.",
|
|
1372
|
+
"Get durable operation status and current deployment progress/reconciliation guidance. Follow progress.phase and progress.suggested_action. waiting_for_mail requires mail_domain_status now for the current verification issue and DNS records; publishing means the build completed but runtime preparation/publication is unfinished. Poll this operation after progress.next_poll_after_seconds. A queued/running operation with reconciliation.state=required needs one confirmed operation_reconcile using the same operation; pending means poll this operation after 60 seconds. Never infer deployment success from a completed reconciliation attempt or start another build to recover it. A deploy, promotion or rollback names its deployment_id in every state; when state is failed, read that deployment with deployment_logs and follow error.suggested_action before changing source.",
|
|
1329
1373
|
z.object({ operation_id: identifier }),
|
|
1330
1374
|
(client, input) => client.getOperation(input.operation_id),
|
|
1331
1375
|
);
|
|
@@ -80,6 +80,8 @@ import {
|
|
|
80
80
|
parseProjectCreditBudget,
|
|
81
81
|
parseDevAccessTicket,
|
|
82
82
|
parseDevAccessState,
|
|
83
|
+
parsePoweredByFlag,
|
|
84
|
+
parseOrganizationReferral,
|
|
83
85
|
parseGuardedActionPlan,
|
|
84
86
|
parseEnvironmentSecret,
|
|
85
87
|
parseEnvironmentSecretDeletion,
|
|
@@ -304,6 +306,8 @@ const HELP_USAGE = Object.freeze({
|
|
|
304
306
|
"export get":
|
|
305
307
|
"ohmyhost export get EXPORT_ULID --project ULID --json (poll the original job; signed ZIP download lasts 24 hours)",
|
|
306
308
|
"credits account": "ohmyhost credits account --organization ULID --json",
|
|
309
|
+
"referral link":
|
|
310
|
+
"ohmyhost referral link --organization ULID --json (the workspace's link to share; a new user who signs up through it starts with a free Paid month and 1,000 credits, and their first payment gives this workspace the same)",
|
|
307
311
|
"credits balance": "ohmyhost credits balance --organization ULID --json",
|
|
308
312
|
"billing recharge get": "ohmyhost billing recharge get --organization ULID --json",
|
|
309
313
|
"billing recharge set":
|
|
@@ -350,6 +354,9 @@ const HELP_USAGE = Object.freeze({
|
|
|
350
354
|
"ohmyhost project dev-share revoke --project ULID --idempotency-key KEY --yes --json",
|
|
351
355
|
"project dev-access mode":
|
|
352
356
|
"ohmyhost project dev-access mode --project ULID --mode protected|public --idempotency-key KEY --yes --json",
|
|
357
|
+
"project flag status": "ohmyhost project flag status --project ULID --json",
|
|
358
|
+
"project flag set":
|
|
359
|
+
"ohmyhost project flag set --project ULID --enabled true|false --idempotency-key KEY --json (shows the small Powered by ohmyho.st flag on the production site; while it shows, a Free workspace may connect its own domain without the domain fee and each Paid period adds 250 credits)",
|
|
353
360
|
"project handle check":
|
|
354
361
|
"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)",
|
|
355
362
|
"project handle set":
|
|
@@ -619,6 +626,13 @@ export class ProductCli {
|
|
|
619
626
|
}
|
|
620
627
|
return success(name, { status: "succeeded", billing: result });
|
|
621
628
|
}
|
|
629
|
+
if (command.kind === "referral-link") {
|
|
630
|
+
const api = await this.authenticatedApi(command.credentialStore, signal);
|
|
631
|
+
const referral = parseOrganizationReferral(
|
|
632
|
+
await api.getOrganizationReferral(command.organizationId),
|
|
633
|
+
);
|
|
634
|
+
return success("referral link", { status: "succeeded", referral });
|
|
635
|
+
}
|
|
622
636
|
if (command.kind === "credits-account") {
|
|
623
637
|
const api = await this.authenticatedApi(command.credentialStore, signal);
|
|
624
638
|
const account = await api.getOrganizationAccount(command.organizationId);
|
|
@@ -809,6 +823,22 @@ export class ProductCli {
|
|
|
809
823
|
if (command.kind === "project-status") return await this.getProjectStatus(command, signal);
|
|
810
824
|
if (command.kind === "project-dev-access-create")
|
|
811
825
|
return await this.createDevAccessTicket(command, signal);
|
|
826
|
+
if (command.kind === "project-flag-status" || command.kind === "project-flag-set") {
|
|
827
|
+
const api = await this.authenticatedApi(command.credentialStore, signal);
|
|
828
|
+
const flag = parsePoweredByFlag(
|
|
829
|
+
command.kind === "project-flag-status"
|
|
830
|
+
? await api.getPoweredByFlag(command.projectId)
|
|
831
|
+
: await api.setPoweredByFlag(
|
|
832
|
+
command.projectId,
|
|
833
|
+
command.enabled,
|
|
834
|
+
command.idempotencyKey,
|
|
835
|
+
),
|
|
836
|
+
);
|
|
837
|
+
return success(
|
|
838
|
+
command.kind === "project-flag-status" ? "project flag status" : "project flag set",
|
|
839
|
+
{ status: "succeeded", flag },
|
|
840
|
+
);
|
|
841
|
+
}
|
|
812
842
|
if (
|
|
813
843
|
command.kind === "project-dev-share-link" ||
|
|
814
844
|
command.kind === "project-dev-share-rotate" ||
|
|
@@ -2450,6 +2480,7 @@ const parsedCommandName = (command: ProductCliCommand): CommandLabel => {
|
|
|
2450
2480
|
if (command.kind === "billing-status") return "billing status";
|
|
2451
2481
|
if (command.kind === "billing-portal") return "billing portal";
|
|
2452
2482
|
if (command.kind === "credits-account") return "credits account";
|
|
2483
|
+
if (command.kind === "referral-link") return "referral link";
|
|
2453
2484
|
if (command.kind === "credits-balance") return "credits balance";
|
|
2454
2485
|
if (command.kind === "credits-usage") return "credits usage";
|
|
2455
2486
|
if (command.kind === "budget-get") return "budget get";
|
|
@@ -2475,6 +2506,8 @@ const parsedCommandName = (command: ProductCliCommand): CommandLabel => {
|
|
|
2475
2506
|
if (command.kind === "project-dev-share-rotate") return "project dev-share rotate";
|
|
2476
2507
|
if (command.kind === "project-dev-share-revoke") return "project dev-share revoke";
|
|
2477
2508
|
if (command.kind === "project-dev-access-mode-set") return "project dev-access mode";
|
|
2509
|
+
if (command.kind === "project-flag-status") return "project flag status";
|
|
2510
|
+
if (command.kind === "project-flag-set") return "project flag set";
|
|
2478
2511
|
if (command.kind === "project-handle-check") return "project handle check";
|
|
2479
2512
|
if (command.kind === "project-handle-set") return "project handle set";
|
|
2480
2513
|
if (command.kind === "database-write") return "database write";
|